1 /* $OpenBSD: ieee80211_rssadapt.c,v 1.7 2008/09/01 20:00:19 damien Exp $ */
2 /* $NetBSD: ieee80211_rssadapt.c,v 1.7 2004/05/25 04:33:59 dyoung Exp $ */
3
4 /*-
5 * Copyright (c) 2003, 2004 David Young. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
9 * conditions are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * 3. The name of David Young may not be used to endorse or promote
17 * products derived from this software without specific prior
18 * written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY David Young ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL David
24 * Young BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
26 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31 * OF SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/socket.h>
37 #include <sys/sysctl.h>
38
39 #include <net/if.h>
40 #include <net/if_media.h>
41
42 #ifdef INET
43 #include <netinet/in.h>
44 #include <netinet/if_ether.h>
45 #endif
46
47 #include <net80211/ieee80211_var.h>
48 #include <net80211/ieee80211_rssadapt.h>
49
50 #ifdef interpolate
51 #undef interpolate
52 #endif
53 #define interpolate(parm, old, new) \
54 ((parm##_old * (old) + \
55 (parm##_denom - parm##_old) * (new)) / parm##_denom)
56
57 #ifdef IEEE80211_DEBUG
58 static struct timeval lastrateadapt; /* time of last rate adaptation msg */
59 static int currssadaptps = 0; /* rate-adaptation msgs this second */
60 static int ieee80211_adaptrate = 4; /* rate-adaptation max msgs/sec */
61
62 #define RSSADAPT_DO_PRINT() \
63 ((ieee80211_rssadapt_debug > 0) && \
64 ppsratecheck(&lastrateadapt, &currssadaptps, ieee80211_adaptrate))
65 #define RSSADAPT_PRINTF(X) \
66 if (RSSADAPT_DO_PRINT()) \
67 printf X
68
69 int ieee80211_rssadapt_debug = 0;
70
71 #else
72 #define RSSADAPT_DO_PRINT() (0)
73 #define RSSADAPT_PRINTF(X)
74 #endif
75
76 static const struct ieee80211_rssadapt_expavgctl master_expavgctl = {
77 .rc_decay_denom = 16,
78 .rc_decay_old = 15,
79 .rc_thresh_denom = 8,
80 .rc_thresh_old = 4,
81 .rc_avgrssi_denom = 8,
82 .rc_avgrssi_old = 4
83 };
84
85 int
86 ieee80211_rssadapt_choose(struct ieee80211_rssadapt *ra,
87 const struct ieee80211_rateset *rs, const struct ieee80211_frame *wh,
88 u_int len, int fixed_rate, const char *dvname, int do_not_adapt)
89 {
90 u_int16_t (*thrs)[IEEE80211_RATE_SIZE];
91 int flags = 0, i, rateidx = 0, thridx, top;
92
93 if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
94 flags |= IEEE80211_RATE_BASIC;
95
96 for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
97 i < IEEE80211_RSSADAPT_BKTS;
98 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) {
99 thridx = i;
100 if (len <= top)
101 break;
102 }
103
104 thrs = &ra->ra_rate_thresh[thridx];
105
106 if (fixed_rate != -1) {
107 if ((rs->rs_rates[fixed_rate] & flags) == flags) {
108 rateidx = fixed_rate;
109 goto out;
110 }
111 flags |= IEEE80211_RATE_BASIC;
112 i = fixed_rate;
113 } else
114 i = rs->rs_nrates;
115
116 while (--i >= 0) {
117 rateidx = i;
118 if ((rs->rs_rates[i] & flags) != flags)
119 continue;
120 if (do_not_adapt)
121 break;
122 if ((*thrs)[i] < ra->ra_avg_rssi)
123 break;
124 }
125
126 out:
127 #ifdef IEEE80211_DEBUG
128 if (ieee80211_rssadapt_debug && dvname != NULL) {
129 printf("%s: dst %s threshold[%d, %d.%d] %d < %d\n",
130 dvname, ether_sprintf((u_int8_t *)wh->i_addr1), len,
131 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) / 2,
132 (rs->rs_rates[rateidx] & IEEE80211_RATE_VAL) * 5 % 10,
133 (*thrs)[rateidx], ra->ra_avg_rssi);
134 }
135 #endif /* IEEE80211_DEBUG */
136 return rateidx;
137 }
138
139 void
140 ieee80211_rssadapt_updatestats(struct ieee80211_rssadapt *ra)
141 {
142 long interval;
143
144 ra->ra_pktrate =
145 (ra->ra_pktrate + 10 * (ra->ra_nfail + ra->ra_nok)) / 2;
146 ra->ra_nfail = ra->ra_nok = 0;
147
148 /* a node is eligible for its rate to be raised every 1/10 to 10
149 * seconds, more eligible in proportion to recent packet rates.
150 */
151 interval = MAX(100000, 10000000 / MAX(1, 10 * ra->ra_pktrate));
152 ra->ra_raise_interval.tv_sec = interval / (1000 * 1000);
153 ra->ra_raise_interval.tv_usec = interval % (1000 * 1000);
154 }
155
156 void
157 ieee80211_rssadapt_input(struct ieee80211com *ic,
158 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra, int rssi)
159 {
160 #ifdef IEEE80211_DEBUG
161 int last_avg_rssi = ra->ra_avg_rssi;
162 #endif
163
164 ra->ra_avg_rssi = interpolate(master_expavgctl.rc_avgrssi,
165 ra->ra_avg_rssi, (rssi << 8));
166
167 RSSADAPT_PRINTF(("%s: src %s rssi %d avg %d -> %d\n",
168 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr),
169 rssi, last_avg_rssi, ra->ra_avg_rssi));
170 }
171
172 /*
173 * Adapt the data rate to suit the conditions. When a transmitted
174 * packet is dropped after IEEE80211_RSSADAPT_RETRY_LIMIT retransmissions,
175 * raise the RSS threshold for transmitting packets of similar length at
176 * the same data rate.
177 */
178 void
179 ieee80211_rssadapt_lower_rate(struct ieee80211com *ic,
180 const struct ieee80211_node *ni, struct ieee80211_rssadapt *ra,
181 const struct ieee80211_rssdesc *id)
182 {
183 const struct ieee80211_rateset *rs = &ni->ni_rates;
184 u_int16_t last_thr;
185 u_int i, thridx, top;
186
187 ra->ra_nfail++;
188
189 if (id->id_rateidx >= rs->rs_nrates) {
190 RSSADAPT_PRINTF(("ieee80211_rssadapt_lower_rate: "
191 "%s rate #%d > #%d out of bounds\n",
192 ether_sprintf((u_int8_t *)ni->ni_macaddr), id->id_rateidx,
193 rs->rs_nrates - 1));
194 return;
195 }
196
197 for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
198 i < IEEE80211_RSSADAPT_BKTS;
199 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) {
200 thridx = i;
201 if (id->id_len <= top)
202 break;
203 }
204
205 last_thr = ra->ra_rate_thresh[thridx][id->id_rateidx];
206 ra->ra_rate_thresh[thridx][id->id_rateidx] =
207 interpolate(master_expavgctl.rc_thresh, last_thr,
208 (id->id_rssi << 8));
209
210 RSSADAPT_PRINTF(("%s: dst %s rssi %d threshold[%d, %d.%d] %d -> %d\n",
211 ic->ic_if.if_xname, ether_sprintf((u_int8_t *)ni->ni_macaddr),
212 id->id_rssi, id->id_len,
213 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) / 2,
214 (rs->rs_rates[id->id_rateidx] & IEEE80211_RATE_VAL) * 5 % 10,
215 last_thr, ra->ra_rate_thresh[thridx][id->id_rateidx]));
216 }
217
218 void
219 ieee80211_rssadapt_raise_rate(struct ieee80211com *ic,
220 struct ieee80211_rssadapt *ra, const struct ieee80211_rssdesc *id)
221 {
222 u_int16_t (*thrs)[IEEE80211_RATE_SIZE], newthr, oldthr;
223 const struct ieee80211_node *ni = id->id_node;
224 const struct ieee80211_rateset *rs = &ni->ni_rates;
225 int i, rate, top;
226 #ifdef IEEE80211_DEBUG
227 int j;
228 #endif
229
230 ra->ra_nok++;
231
232 if (!ratecheck(&ra->ra_last_raise, &ra->ra_raise_interval))
233 return;
234
235 for (i = 0, top = IEEE80211_RSSADAPT_BKT0;
236 i < IEEE80211_RSSADAPT_BKTS;
237 i++, top <<= IEEE80211_RSSADAPT_BKTPOWER) {
238 thrs = &ra->ra_rate_thresh[i];
239 if (id->id_len <= top)
240 break;
241 }
242
243 if (id->id_rateidx + 1 < rs->rs_nrates &&
244 (*thrs)[id->id_rateidx + 1] > (*thrs)[id->id_rateidx]) {
245 rate = (rs->rs_rates[id->id_rateidx + 1] & IEEE80211_RATE_VAL);
246
247 RSSADAPT_PRINTF(("%s: threshold[%d, %d.%d] decay %d ",
248 ic->ic_if.if_xname, IEEE80211_RSSADAPT_BKT0 <<
249 (IEEE80211_RSSADAPT_BKTPOWER * i),
250 rate / 2, rate * 5 % 10, (*thrs)[id->id_rateidx + 1]));
251 oldthr = (*thrs)[id->id_rateidx + 1];
252 if ((*thrs)[id->id_rateidx] == 0)
253 newthr = ra->ra_avg_rssi;
254 else
255 newthr = (*thrs)[id->id_rateidx];
256 (*thrs)[id->id_rateidx + 1] =
257 interpolate(master_expavgctl.rc_decay, oldthr, newthr);
258
259 RSSADAPT_PRINTF(("-> %d\n", (*thrs)[id->id_rateidx + 1]));
260 }
261
262 #ifdef IEEE80211_DEBUG
263 if (RSSADAPT_DO_PRINT()) {
264 printf("%s: dst %s thresholds\n", ic->ic_if.if_xname,
265 ether_sprintf((u_int8_t *)ni->ni_macaddr));
266 for (i = 0; i < IEEE80211_RSSADAPT_BKTS; i++) {
267 printf("%d-byte", IEEE80211_RSSADAPT_BKT0 <<
268 (IEEE80211_RSSADAPT_BKTPOWER * i));
269 for (j = 0; j < rs->rs_nrates; j++) {
270 rate = (rs->rs_rates[j] & IEEE80211_RATE_VAL);
271 printf(", T[%d.%d] = %d", rate / 2,
272 rate * 5 % 10, ra->ra_rate_thresh[i][j]);
273 }
274 printf("\n");
275 }
276 }
277 #endif /* IEEE80211_DEBUG */
278 }
Cache object: 4dba5b03c733082cbfde81a8157503fd
|