Line data Source code
1 : /* $OpenBSD: ieee80211_amrr.c,v 1.11 2016/01/05 18:41:16 stsp Exp $ */
2 :
3 : /*-
4 : * Copyright (c) 2006
5 : * Damien Bergamini <damien.bergamini@free.fr>
6 : *
7 : * Permission to use, copy, modify, and distribute this software for any
8 : * purpose with or without fee is hereby granted, provided that the above
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 :
20 : #include <sys/param.h>
21 : #include <sys/systm.h>
22 : #include <sys/kernel.h>
23 : #include <sys/socket.h>
24 :
25 : #include <net/if.h>
26 : #include <net/if_media.h>
27 :
28 : #include <netinet/in.h>
29 : #include <netinet/if_ether.h>
30 :
31 : #include <net80211/ieee80211_var.h>
32 : #include <net80211/ieee80211_priv.h>
33 : #include <net80211/ieee80211_amrr.h>
34 :
35 : #define is_success(amn) \
36 : ((amn)->amn_retrycnt < (amn)->amn_txcnt / 10)
37 : #define is_failure(amn) \
38 : ((amn)->amn_retrycnt > (amn)->amn_txcnt / 3)
39 : #define is_enough(amn) \
40 : ((amn)->amn_txcnt > 10)
41 : #define reset_cnt(amn) \
42 : do { (amn)->amn_txcnt = (amn)->amn_retrycnt = 0; } while (0)
43 :
44 : /*
45 : * XXX In HT mode we only support MCS 0-7, for now.
46 : * Beyond MCS 7, incrementing the MCS index does not imply a
47 : * higher data rate, so this simple implementation will need
48 : * to be enhanced.
49 : */
50 :
51 : static inline int
52 0 : is_min_rate(struct ieee80211_node *ni)
53 : {
54 0 : if (ni->ni_flags & IEEE80211_NODE_HT)
55 0 : return (ni->ni_txmcs == 0);
56 0 : return (ni->ni_txrate == 0);
57 0 : }
58 :
59 : static inline int
60 0 : is_max_rate(struct ieee80211_node *ni)
61 : {
62 0 : if (ni->ni_flags & IEEE80211_NODE_HT)
63 0 : return (ni->ni_txmcs == 7); /* XXX up to MCS 7 only */
64 0 : return (ni->ni_txrate == ni->ni_rates.rs_nrates - 1);
65 0 : }
66 :
67 : static inline void
68 0 : increase_rate(struct ieee80211_node *ni)
69 : {
70 0 : if (ni->ni_flags & IEEE80211_NODE_HT)
71 0 : ni->ni_txmcs++;
72 : else
73 0 : ni->ni_txrate++;
74 0 : }
75 :
76 : static inline void
77 0 : decrease_rate(struct ieee80211_node *ni)
78 : {
79 0 : if (ni->ni_flags & IEEE80211_NODE_HT)
80 0 : ni->ni_txmcs--;
81 : else
82 0 : ni->ni_txrate--;
83 0 : }
84 :
85 : void
86 0 : ieee80211_amrr_node_init(const struct ieee80211_amrr *amrr,
87 : struct ieee80211_amrr_node *amn)
88 : {
89 0 : amn->amn_success = 0;
90 0 : amn->amn_recovery = 0;
91 0 : amn->amn_txcnt = amn->amn_retrycnt = 0;
92 0 : amn->amn_success_threshold = amrr->amrr_min_success_threshold;
93 0 : }
94 :
95 : /*
96 : * Update ni->ni_txrate.
97 : */
98 : void
99 0 : ieee80211_amrr_choose(struct ieee80211_amrr *amrr, struct ieee80211_node *ni,
100 : struct ieee80211_amrr_node *amn)
101 : {
102 : #define RV(rate) ((rate) & IEEE80211_RATE_VAL)
103 : int need_change = 0;
104 :
105 0 : if (is_success(amn) && is_enough(amn)) {
106 0 : amn->amn_success++;
107 0 : if (amn->amn_success >= amn->amn_success_threshold &&
108 0 : !is_max_rate(ni)) {
109 0 : amn->amn_recovery = 1;
110 0 : amn->amn_success = 0;
111 0 : increase_rate(ni);
112 : DPRINTF(("increase rate=%d,#tx=%d,#retries=%d\n",
113 : (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
114 : RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
115 : amn->amn_txcnt, amn->amn_retrycnt));
116 : need_change = 1;
117 0 : } else {
118 0 : amn->amn_recovery = 0;
119 : }
120 0 : } else if (is_failure(amn)) {
121 0 : amn->amn_success = 0;
122 0 : if (!is_min_rate(ni)) {
123 0 : if (amn->amn_recovery) {
124 0 : amn->amn_success_threshold *= 2;
125 0 : if (amn->amn_success_threshold >
126 0 : amrr->amrr_max_success_threshold)
127 0 : amn->amn_success_threshold =
128 : amrr->amrr_max_success_threshold;
129 : } else {
130 0 : amn->amn_success_threshold =
131 0 : amrr->amrr_min_success_threshold;
132 : }
133 0 : decrease_rate(ni);
134 : DPRINTF(("decrease rate=%d,#tx=%d,#retries=%d\n",
135 : (ni->ni_flags & IEEE80211_NODE_HT) ? ni->ni_txmcs :
136 : RV(ni->ni_rates.rs_rates[ni->ni_txrate]),
137 : amn->amn_txcnt, amn->amn_retrycnt));
138 : need_change = 1;
139 0 : }
140 0 : amn->amn_recovery = 0;
141 0 : }
142 :
143 0 : if (is_enough(amn) || need_change)
144 0 : reset_cnt(amn);
145 : #undef RV
146 0 : }
|