1 | /* $NetBSD: ieee80211_amrr.c,v 1.3 2015/08/24 20:58:47 pooka Exp $ */ |
2 | /* $OpenBSD: ieee80211_amrr.c,v 1.1 2006/06/17 19:07:19 damien Exp $ */ |
3 | |
4 | /*- |
5 | * Copyright (c) 2006 |
6 | * Damien Bergamini <damien.bergamini@free.fr> |
7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include <sys/cdefs.h> |
22 | __KERNEL_RCSID(0, "$NetBSD: ieee80211_amrr.c,v 1.3 2015/08/24 20:58:47 pooka Exp $" ); |
23 | |
24 | #ifdef _KERNEL_OPT |
25 | #include "opt_inet.h" |
26 | #endif |
27 | |
28 | #include <sys/param.h> |
29 | #include <sys/kernel.h> |
30 | #include <sys/socket.h> |
31 | #include <sys/sysctl.h> |
32 | |
33 | #include <net/if.h> |
34 | #include <net/if_ether.h> |
35 | #include <net/if_media.h> |
36 | |
37 | #ifdef INET |
38 | #include <netinet/in.h> |
39 | #endif |
40 | |
41 | #include <net80211/ieee80211.h> |
42 | #include <net80211/ieee80211_var.h> |
43 | #include <net80211/ieee80211_amrr.h> |
44 | |
45 | #define is_success(amn) \ |
46 | ((amn)->amn_retrycnt < (amn)->amn_txcnt / 10) |
47 | #define is_failure(amn) \ |
48 | ((amn)->amn_retrycnt > (amn)->amn_txcnt / 3) |
49 | #define is_enough(amn) \ |
50 | ((amn)->amn_txcnt > 10) |
51 | #define is_min_rate(ni) \ |
52 | ((ni)->ni_txrate == 0) |
53 | #define is_max_rate(ni) \ |
54 | ((ni)->ni_txrate == (ni)->ni_rates.rs_nrates - 1) |
55 | #define increase_rate(ni) \ |
56 | ((ni)->ni_txrate++) |
57 | #define decrease_rate(ni) \ |
58 | ((ni)->ni_txrate--) |
59 | #define reset_cnt(amn) \ |
60 | do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0) |
61 | |
62 | void |
63 | ieee80211_amrr_node_init(struct ieee80211_amrr *amrr, |
64 | struct ieee80211_amrr_node *amn) |
65 | { |
66 | amn->amn_success = 0; |
67 | amn->amn_recovery = 0; |
68 | amn->amn_txcnt = amn->amn_retrycnt = 0; |
69 | amn->amn_success_threshold = amrr->amrr_min_success_threshold; |
70 | } |
71 | |
72 | /* |
73 | * Update ni->ni_txrate. |
74 | */ |
75 | void |
76 | ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni, |
77 | struct ieee80211_amrr_node *amn) |
78 | { |
79 | int need_change = 0; |
80 | |
81 | if (is_success(amn) && is_enough(amn)) { |
82 | amn->amn_success++; |
83 | if (amn->amn_success >= amn->amn_success_threshold && |
84 | !is_max_rate(ni)) { |
85 | amn->amn_recovery = 1; |
86 | amn->amn_success = 0; |
87 | increase_rate(ni); |
88 | IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_DEBUG, |
89 | "AMRR increasing rate %d (txcnt=%d retrycnt=%d)\n" , |
90 | ni->ni_rates.rs_rates[ni->ni_txrate] & |
91 | IEEE80211_RATE_VAL, |
92 | amn->amn_txcnt, amn->amn_retrycnt); |
93 | need_change = 1; |
94 | } else { |
95 | amn->amn_recovery = 0; |
96 | } |
97 | } else if (is_failure(amn)) { |
98 | amn->amn_success = 0; |
99 | if (!is_min_rate(ni)) { |
100 | if (amn->amn_recovery) { |
101 | amn->amn_success_threshold *= 2; |
102 | if (amn->amn_success_threshold > |
103 | amrr->amrr_max_success_threshold) |
104 | amn->amn_success_threshold = |
105 | amrr->amrr_max_success_threshold; |
106 | } else { |
107 | amn->amn_success_threshold = |
108 | amrr->amrr_min_success_threshold; |
109 | } |
110 | decrease_rate(ni); |
111 | IEEE80211_DPRINTF(ni->ni_ic, IEEE80211_MSG_DEBUG, |
112 | "AMRR decreasing rate %d (txcnt=%d retrycnt=%d)\n" , |
113 | ni->ni_rates.rs_rates[ni->ni_txrate] & |
114 | IEEE80211_RATE_VAL, |
115 | amn->amn_txcnt, amn->amn_retrycnt); |
116 | need_change = 1; |
117 | } |
118 | amn->amn_recovery = 0; |
119 | } |
120 | |
121 | if (is_enough(amn) || need_change) |
122 | reset_cnt(amn); |
123 | } |
124 | |