Line data Source code
1 : /* $OpenBSD: ieee80211_mira.c,v 1.12 2018/07/11 21:18:23 nayden Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2016 Stefan Sperling <stsp@openbsd.org>
5 : * Copyright (c) 2016 Theo Buehler <tb@openbsd.org>
6 : * Copyright (c) 2006 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/param.h>
22 : #include <sys/systm.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_mira.h>
33 :
34 : /* Allow for aggressive down probing when channel quality changes. */
35 : #define MIRA_AGGRESSIVE_DOWNWARDS_PROBING
36 :
37 : const struct ieee80211_mira_rateset * ieee80211_mira_get_rateset(int);
38 : void ieee80211_mira_probe_timeout_up(void *);
39 : void ieee80211_mira_probe_timeout_down(void *);
40 : uint64_t ieee80211_mira_get_txrate(int);
41 : uint16_t ieee80211_mira_legacy_txtime(uint32_t, int, struct ieee80211com *);
42 : uint32_t ieee80211_mira_ht_txtime(uint32_t, int, int);
43 : int ieee80211_mira_best_basic_rate(struct ieee80211_node *);
44 : int ieee80211_mira_ack_rate(struct ieee80211_node *);
45 : uint64_t ieee80211_mira_toverhead(struct ieee80211_mira_node *,
46 : struct ieee80211com *, struct ieee80211_node *);
47 : void ieee80211_mira_update_stats(struct ieee80211_mira_node *,
48 : struct ieee80211com *, struct ieee80211_node *);
49 : void ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *);
50 : void ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *);
51 : int ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *,
52 : struct ieee80211_node *);
53 : int ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *,
54 : struct ieee80211_node *);
55 : const struct ieee80211_mira_rateset * ieee80211_mira_next_rateset(
56 : struct ieee80211_mira_node *, int);
57 : int ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *,
58 : const struct ieee80211_mira_rateset *);
59 : void ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *,
60 : struct ieee80211_node *, const struct ieee80211_mira_rateset *);
61 : int ieee80211_mira_next_mcs(struct ieee80211_mira_node *,
62 : struct ieee80211_node *);
63 : int ieee80211_mira_prev_mcs(struct ieee80211_mira_node *,
64 : struct ieee80211_node *);
65 : int ieee80211_mira_probe_valid(struct ieee80211_mira_node *,
66 : struct ieee80211_node *);
67 : void ieee80211_mira_probe_done(struct ieee80211_mira_node *);
68 : int ieee80211_mira_intra_mode_ra_finished(
69 : struct ieee80211_mira_node *, struct ieee80211_node *);
70 : void ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
71 : struct ieee80211_node *);
72 : int ieee80211_mira_inter_mode_ra_finished(
73 : struct ieee80211_mira_node *, struct ieee80211_node *);
74 : int ieee80211_mira_best_rate(struct ieee80211_mira_node *,
75 : struct ieee80211_node *);
76 : void ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *,
77 : struct ieee80211_mira_goodput_stats *);
78 : void ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *,
79 : struct ieee80211_node *);
80 : int ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *,
81 : struct ieee80211_node *);
82 : void ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *,
83 : struct ieee80211_node *);
84 : int ieee80211_mira_valid_tx_mcs(struct ieee80211com *, int);
85 : uint32_t ieee80211_mira_valid_rates(struct ieee80211com *,
86 : struct ieee80211_node *);
87 : uint32_t ieee80211_mira_mcs_below(struct ieee80211_mira_node *, int);
88 :
89 : /* We use fixed point arithmetic with 64 bit integers. */
90 : #define MIRA_FP_SHIFT 21
91 : #define MIRA_FP_INT(x) (x ## ULL << MIRA_FP_SHIFT) /* the integer x */
92 : #define MIRA_FP_1 MIRA_FP_INT(1)
93 :
94 : /* Multiply two fixed point numbers. */
95 : #define MIRA_FP_MUL(a, b) \
96 : (((a) * (b)) >> MIRA_FP_SHIFT)
97 :
98 : /* Divide two fixed point numbers. */
99 : #define MIRA_FP_DIV(a, b) \
100 : (b == 0 ? (uint64_t)-1 : (((a) << MIRA_FP_SHIFT) / (b)))
101 :
102 : #ifdef MIRA_DEBUG
103 : #define DPRINTF(x) do { if (mira_debug > 0) printf x; } while (0)
104 : #define DPRINTFN(n, x) do { if (mira_debug >= (n)) printf x; } while (0)
105 : int mira_debug = 0;
106 : #else
107 : #define DPRINTF(x) do { ; } while (0)
108 : #define DPRINTFN(n, x) do { ; } while (0)
109 : #endif
110 :
111 : #ifdef MIRA_DEBUG
112 : void
113 : mira_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp)
114 : {
115 : uint64_t tmp;
116 :
117 : /* integer part */
118 : *i = (fp >> MIRA_FP_SHIFT);
119 :
120 : /* fractional part */
121 : tmp = (fp & ((uint64_t)-1 >> (64 - MIRA_FP_SHIFT)));
122 : tmp *= 100;
123 : *f = (uint32_t)(tmp >> MIRA_FP_SHIFT);
124 : }
125 :
126 : char *
127 : mira_fp_sprintf(uint64_t fp)
128 : {
129 : uint32_t i, f;
130 : static char buf[64];
131 : int ret;
132 :
133 : mira_fixedp_split(&i, &f, fp);
134 : ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f);
135 : if (ret == -1 || ret >= sizeof(buf))
136 : return "ERR";
137 :
138 : return buf;
139 : }
140 :
141 : void
142 : mira_print_driver_stats(struct ieee80211_mira_node *mn,
143 : struct ieee80211_node *ni) {
144 : DPRINTF(("%s driver stats:\n", ether_sprintf(ni->ni_macaddr)));
145 : DPRINTF(("mn->frames = %u\n", mn->frames));
146 : DPRINTF(("mn->retries = %u\n", mn->retries));
147 : DPRINTF(("mn->txfail = %u\n", mn->txfail));
148 : DPRINTF(("mn->ampdu_size = %u\n", mn->ampdu_size));
149 : DPRINTF(("mn->agglen = %u\n", mn->agglen));
150 : }
151 : #endif /* MIRA_DEBUG */
152 :
153 : /*
154 : * Rate tables.
155 : */
156 :
157 : /* Index into ieee80211_mira_ratesets[] array. */
158 : #define IEEE80211_MIRA_RATESET_SISO 0
159 : #define IEEE80211_MIRA_RATESET_MIMO2 1
160 : #define IEEE80211_MIRA_RATESET_MIMO3 2
161 : #define IEEE80211_MIRA_RATESET_MIMO4 3
162 :
163 : #define IEEE80211_MIRA_RATESET_MAX 8 /* Maximum number of rates in a rateset. */
164 : struct ieee80211_mira_rateset {
165 : uint32_t nrates;
166 : uint32_t rates[IEEE80211_MIRA_RATESET_MAX];
167 : uint32_t mcs_mask;
168 : int min_mcs;
169 : int max_mcs;
170 : } ieee80211_mira_ratesets[] = {
171 : /* XXX We only support MCS 0-31, for now. */
172 : #ifdef notyet
173 : /* Legacy rates on a 2GHz channel. */
174 : { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
175 :
176 : /* Legacy rates on a 5GHz channel. */
177 : { 8, { 12, 18, 24, 36, 48, 72, 96, 108 }, 0x0, -1, -1 },
178 : #endif
179 : /* MCS 0-7, 20MHz channel, no SGI */
180 : { 8, { 13, 26, 39, 52, 78, 104, 117, 130 }, 0x000000ff, 0, 7 },
181 :
182 : /* MCS 8-15, 20MHz channel, no SGI */
183 : { 8, { 26, 52, 78, 104, 156, 208, 234, 260 }, 0x0000ff00, 8, 15 },
184 :
185 : /* MCS 16-23, 20MHz channel, no SGI */
186 : { 8, { 39, 78, 117, 156, 234, 312, 351, 390 }, 0x00ff0000, 16, 23 },
187 :
188 : /* MCS 24-31, 20MHz channel, no SGI */
189 : { 8, { 52, 104, 156, 208, 312, 416, 468, 520 }, 0xff000000, 24, 31 },
190 : };
191 :
192 : /* XXX We only support HT rates, for now. With legacy added, these differ. */
193 : #define IEEE80211_MIRA_NUM_MCS IEEE80211_MIRA_NUM_RATES
194 :
195 : const struct ieee80211_mira_rateset *
196 0 : ieee80211_mira_get_rateset(int mcs)
197 : {
198 : const struct ieee80211_mira_rateset *rs;
199 : int i;
200 :
201 0 : for (i = 0; i < nitems(ieee80211_mira_ratesets); i++) {
202 0 : rs = &ieee80211_mira_ratesets[i];
203 0 : if (mcs >= rs->min_mcs && mcs <= rs->max_mcs)
204 0 : return rs;
205 : }
206 :
207 0 : panic("MCS %d is not part of any rateset", mcs);
208 : }
209 :
210 : /*
211 : * Probe timers.
212 : */
213 :
214 : /* Constants related to timeouts for time-driven rate probing. */
215 : #define IEEE80211_MIRA_PROBE_TIMEOUT_MIN 2 /* in msec */
216 : #define IEEE80211_MIRA_PROBE_INTVAL_MAX (1 << 10) /* 2^10 */
217 :
218 : void
219 0 : ieee80211_mira_probe_timeout_up(void *arg)
220 : {
221 0 : struct ieee80211_mira_node *mn = arg;
222 : int s;
223 :
224 0 : s = splnet();
225 0 : mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] = 1;
226 : DPRINTFN(3, ("probe up timeout fired\n"));
227 0 : splx(s);
228 0 : }
229 :
230 : void
231 0 : ieee80211_mira_probe_timeout_down(void *arg)
232 : {
233 0 : struct ieee80211_mira_node *mn = arg;
234 : int s;
235 :
236 0 : s = splnet();
237 0 : mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN] = 1;
238 : DPRINTFN(3, ("probe down timeout fired\n"));
239 0 : splx(s);
240 0 : }
241 :
242 : /*
243 : * Update goodput statistics.
244 : */
245 :
246 : uint64_t
247 0 : ieee80211_mira_get_txrate(int mcs)
248 : {
249 : const struct ieee80211_mira_rateset *rs;
250 : uint64_t txrate;
251 :
252 0 : rs = ieee80211_mira_get_rateset(mcs);
253 0 : txrate = rs->rates[mcs - rs->min_mcs];
254 0 : txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */
255 0 : txrate *= 500; /* convert to kbit/s */
256 0 : txrate /= 1000; /* convert to mbit/s */
257 :
258 0 : return txrate;
259 : }
260 :
261 : /* Based on rt2661_txtime in the ral(4) driver. */
262 : uint16_t
263 0 : ieee80211_mira_legacy_txtime(uint32_t len, int rate, struct ieee80211com *ic)
264 : {
265 : #define MIRA_RATE_IS_OFDM(rate) ((rate) >= 12 && (rate) != 22)
266 : uint16_t txtime;
267 :
268 0 : if (MIRA_RATE_IS_OFDM(rate)) {
269 : /* IEEE Std 802.11g-2003, pp. 44 */
270 0 : txtime = (8 + 4 * len + 3 + rate - 1) / rate;
271 0 : txtime = 16 + 4 + 4 * txtime + 6;
272 0 : } else {
273 : /* IEEE Std 802.11b-1999, pp. 28 */
274 0 : txtime = (16 * len + rate - 1) / rate;
275 0 : if (rate != 2 && (ic->ic_flags & IEEE80211_F_SHPREAMBLE))
276 0 : txtime += 72 + 24;
277 : else
278 0 : txtime += 144 + 48;
279 : }
280 0 : return txtime;
281 : }
282 :
283 : uint32_t
284 0 : ieee80211_mira_ht_txtime(uint32_t len, int mcs, int is2ghz)
285 : {
286 : const struct ieee80211_mira_rateset *rs;
287 : /* XXX These constants should be macros in ieee80211.h instead. */
288 : const uint32_t t_lstf = 8; /* usec legacy short training field */
289 : const uint32_t t_lltf = 8; /* usec legacy long training field */
290 : const uint32_t t_lsig = 4; /* usec legacy signal field */
291 : const uint32_t t_htstf = 4; /* usec HT short training field */
292 : const uint32_t t_ltstf = 4; /* usec HT long training field */
293 : const uint32_t t_htsig = 8; /* usec HT signal field */
294 : const uint32_t t_sym = 4; /* usec symbol interval */
295 : uint32_t n_sym, n_dbps;
296 : uint32_t t_plcp;
297 : uint32_t t_data;
298 : uint32_t txtime;
299 :
300 : /*
301 : * Calculate approximate frame Tx time in usec.
302 : * See 802.11-2012, 20.4.3 "TXTIME calculation" and
303 : * 20.3.11.1 "Equation (20-32)".
304 : * XXX Assumes a 20MHz channel, HT-mixed frame format, no STBC.
305 : */
306 : t_plcp = t_lstf + t_lltf + t_lsig + t_htstf + 4 * t_ltstf + t_htsig;
307 0 : rs = ieee80211_mira_get_rateset(mcs);
308 0 : n_dbps = rs->rates[mcs - rs->min_mcs] * 2;
309 0 : n_sym = ((8 * len + 16 + 6) / n_dbps); /* "Equation (20-32)" */
310 0 : t_data = t_sym * n_sym;
311 :
312 0 : txtime = t_plcp + t_data;
313 0 : if (is2ghz)
314 0 : txtime += 6; /* aSignalExtension */
315 :
316 0 : return txtime;
317 : }
318 :
319 : int
320 0 : ieee80211_mira_best_basic_rate(struct ieee80211_node *ni)
321 : {
322 0 : struct ieee80211_rateset *rs = &ni->ni_rates;
323 : int i, best, rval;
324 :
325 : /* Default to 1 Mbit/s on 2GHz and 6 Mbit/s on 5GHz. */
326 0 : best = IEEE80211_IS_CHAN_2GHZ(ni->ni_chan) ? 2 : 12;
327 :
328 0 : for (i = 0; i < rs->rs_nrates; i++) {
329 0 : if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0)
330 : continue;
331 0 : rval = (rs->rs_rates[i] & IEEE80211_RATE_VAL);
332 0 : if (rval > best)
333 0 : best = rval;
334 : }
335 :
336 0 : return best;
337 : }
338 :
339 : /*
340 : * See 802.11-2012, 9.7.6.5 "Rate selection for control response frames".
341 : * XXX Does not support BlockAck.
342 : */
343 : int
344 0 : ieee80211_mira_ack_rate(struct ieee80211_node *ni)
345 : {
346 : /*
347 : * Assume the ACK was sent at a mandatory ERP OFDM rate.
348 : * In the worst case, the firmware has retried at non-HT rates,
349 : * so for MCS 0 assume we didn't actually send an OFDM frame
350 : * and ACKs arrived at a basic rate.
351 : */
352 0 : if (ni->ni_txmcs == 0)
353 0 : return ieee80211_mira_best_basic_rate(ni);
354 0 : else if (ni->ni_txmcs == 1)
355 0 : return 12; /* 6 Mbit/s */
356 0 : else if (ni->ni_txmcs >= 2)
357 0 : return 24; /* 12 Mbit/s */
358 : else
359 0 : return 48; /* 24 Mbit/s */
360 0 : }
361 :
362 : uint64_t
363 0 : ieee80211_mira_toverhead(struct ieee80211_mira_node *mn,
364 : struct ieee80211com *ic, struct ieee80211_node *ni)
365 : {
366 : /* XXX These should be macros in ieee80211.h. */
367 : #define MIRA_RTSLEN IEEE80211_MIN_LEN
368 : #define MIRA_CTSLEN (sizeof(struct ieee80211_frame_cts) + IEEE80211_CRC_LEN)
369 : uint32_t overhead;
370 : uint64_t toverhead;
371 : int rate, rts;
372 : enum ieee80211_htprot htprot;
373 :
374 0 : overhead = ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
375 0 : IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
376 :
377 0 : htprot = (ic->ic_bss->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
378 0 : if (htprot == IEEE80211_HTPROT_NONMEMBER ||
379 0 : htprot == IEEE80211_HTPROT_NONHT_MIXED)
380 0 : rts = 1;
381 0 : else if (htprot == IEEE80211_HTPROT_20MHZ &&
382 0 : (ic->ic_htcaps & IEEE80211_HTCAP_CBW20_40))
383 0 : rts = 1;
384 : else
385 0 : rts = (mn->ampdu_size > ic->ic_rtsthreshold);
386 :
387 0 : if (rts) {
388 : /* Assume RTS/CTS were sent at a basic rate. */
389 0 : rate = ieee80211_mira_best_basic_rate(ni);
390 0 : overhead += ieee80211_mira_legacy_txtime(MIRA_RTSLEN, rate, ic);
391 0 : overhead += ieee80211_mira_legacy_txtime(MIRA_CTSLEN, rate, ic);
392 0 : }
393 :
394 : /* XXX This does not yet support BlockAck. */
395 0 : rate = ieee80211_mira_ack_rate(ni);
396 0 : overhead += ieee80211_mira_legacy_txtime(IEEE80211_ACK_LEN, rate, ic);
397 :
398 0 : toverhead = overhead;
399 0 : toverhead <<= MIRA_FP_SHIFT; /* convert to fixed-point */
400 0 : toverhead /= 1000; /* convert to msec */
401 0 : toverhead /= 1000; /* convert to sec */
402 :
403 : #ifdef MIRA_DEBUG
404 : if (mira_debug > 3) {
405 : uint32_t txtime;
406 : txtime = ieee80211_mira_ht_txtime(mn->ampdu_size, ni->ni_txmcs,
407 : IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
408 : txtime += overhead - ieee80211_mira_ht_txtime(0, ni->ni_txmcs,
409 : IEEE80211_IS_CHAN_2GHZ(ni->ni_chan));
410 : DPRINTFN(4, ("txtime: %u usec\n", txtime));
411 : DPRINTFN(4, ("overhead: %u usec\n", overhead));
412 : DPRINTFN(4, ("toverhead: %s\n", mira_fp_sprintf(toverhead)));
413 : }
414 : #endif
415 0 : return toverhead;
416 : }
417 :
418 : void
419 0 : ieee80211_mira_update_stats(struct ieee80211_mira_node *mn,
420 : struct ieee80211com *ic, struct ieee80211_node *ni)
421 : {
422 : /* Magic numbers from MiRA paper. */
423 : static const uint64_t alpha = MIRA_FP_1 / 8; /* 1/8 = 0.125 */
424 : static const uint64_t beta = MIRA_FP_1 / 4; /* 1/4 = 0.25 */
425 : uint64_t sfer, delta, toverhead;
426 0 : uint64_t agglen = mn->agglen;
427 0 : uint64_t ampdu_size = mn->ampdu_size * 8; /* convert to bits */
428 0 : uint64_t rate = ieee80211_mira_get_txrate(ni->ni_txmcs);
429 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
430 :
431 0 : g->nprobes += mn->agglen;
432 0 : g->nprobe_bytes += mn->ampdu_size;
433 :
434 0 : ampdu_size <<= MIRA_FP_SHIFT; /* convert to fixed-point */
435 0 : agglen <<= MIRA_FP_SHIFT;
436 : /* XXX range checks? */
437 :
438 0 : ampdu_size = ampdu_size / 1000; /* kbit */
439 0 : ampdu_size = ampdu_size / 1000; /* mbit */
440 :
441 : /* Compute Sub-Frame Error Rate (see section 2.2 in MiRA paper). */
442 0 : sfer = (mn->frames * mn->retries + mn->txfail);
443 0 : if ((sfer >> MIRA_FP_SHIFT) != 0) { /* bug in wifi driver */
444 0 : if (ic->ic_if.if_flags & IFF_DEBUG) {
445 : #ifdef DIAGNOSTIC
446 0 : printf("%s: mira sfer overflow\n",
447 0 : ether_sprintf(ni->ni_macaddr));
448 : #endif
449 : #ifdef MIRA_DEBUG
450 : mira_print_driver_stats(mn, ni);
451 : #endif
452 0 : }
453 0 : ieee80211_mira_probe_done(mn);
454 0 : return;
455 : }
456 0 : sfer <<= MIRA_FP_SHIFT; /* convert to fixed-point */
457 0 : sfer /= ((mn->retries + 1) * mn->frames);
458 0 : if (sfer > MIRA_FP_1) { /* bug in wifi driver */
459 0 : if (ic->ic_if.if_flags & IFF_DEBUG) {
460 : #ifdef DIAGNOSTIC
461 0 : printf("%s: mira sfer > 1\n",
462 0 : ether_sprintf(ni->ni_macaddr));
463 : #endif
464 : #ifdef MIRA_DEBUG
465 : mira_print_driver_stats(mn, ni);
466 : #endif
467 0 : }
468 : sfer = MIRA_FP_1; /* round down */
469 0 : }
470 :
471 : /* Store current loss percentage SFER. */
472 0 : g->loss = sfer * 100;
473 : #ifdef MIRA_DEBUG
474 : if (g->loss && ieee80211_mira_probe_valid(mn, ni))
475 : DPRINTFN(2, ("frame error rate at MCS %d: %s%%\n",
476 : ni->ni_txmcs, mira_fp_sprintf(g->loss)));
477 : #endif
478 :
479 : /*
480 : * Update goodput statistics (see section 5.1.2 in MiRA paper).
481 : * We use a slightly modified but equivalent calculation which
482 : * is tuned towards our fixed-point number format.
483 : */
484 :
485 0 : g->average = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average);
486 0 : g->average += MIRA_FP_MUL(alpha, g->measured);
487 :
488 0 : g->stddeviation = MIRA_FP_MUL(MIRA_FP_1 - beta, g->stddeviation);
489 0 : if (g->average > g->measured)
490 0 : delta = g->average - g->measured;
491 : else
492 0 : delta = g->measured - g->average;
493 0 : g->stddeviation += MIRA_FP_MUL(beta, delta);
494 :
495 0 : g->average_agg = MIRA_FP_MUL(MIRA_FP_1 - alpha, g->average_agg);
496 0 : g->average_agg += MIRA_FP_MUL(alpha, agglen);
497 :
498 0 : toverhead = ieee80211_mira_toverhead(mn, ic, ni);
499 0 : toverhead = MIRA_FP_MUL(toverhead, rate);
500 0 : g->measured = MIRA_FP_DIV(MIRA_FP_1 - sfer, MIRA_FP_1 +
501 : MIRA_FP_DIV(toverhead, MIRA_FP_MUL(ampdu_size, g->average_agg)));
502 0 : g->measured = MIRA_FP_MUL(g->measured, rate);
503 0 : }
504 :
505 : void
506 0 : ieee80211_mira_reset_goodput_stats(struct ieee80211_mira_node *mn)
507 : {
508 : int i;
509 :
510 0 : for (i = 0; i < nitems(mn->g); i++) {
511 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[i];
512 0 : memset(g, 0, sizeof(*g));
513 0 : g->average_agg = 1;
514 0 : g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
515 : }
516 0 : }
517 :
518 : void
519 0 : ieee80211_mira_reset_driver_stats(struct ieee80211_mira_node *mn)
520 : {
521 0 : mn->frames = 0;
522 0 : mn->retries = 0;
523 0 : mn->txfail = 0;
524 0 : mn->ampdu_size = 0;
525 0 : mn->agglen = 1;
526 0 : }
527 :
528 : /*
529 : * Rate selection.
530 : */
531 :
532 : /* A rate's goodput has to be at least this much larger to be "better". */
533 : #define IEEE80211_MIRA_RATE_THRESHOLD (MIRA_FP_1 / 64) /* ~ 0.015 */
534 :
535 : #define IEEE80211_MIRA_LOSS_THRESHOLD 10 /* in percent */
536 :
537 : /* Number of (sub-)frames which render a probe valid. */
538 : #define IEEE80211_MIRA_MIN_PROBE_FRAMES 4
539 :
540 : /* Number of bytes which, alternatively, render a probe valid. */
541 : #define IEEE80211_MIRA_MIN_PROBE_BYTES IEEE80211_MAX_LEN
542 :
543 : int
544 0 : ieee80211_mira_next_lower_intra_rate(struct ieee80211_mira_node *mn,
545 : struct ieee80211_node *ni)
546 : {
547 : const struct ieee80211_mira_rateset *rs;
548 : int i, next;
549 :
550 0 : rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
551 0 : if (ni->ni_txmcs == rs->min_mcs)
552 0 : return rs->min_mcs;
553 :
554 : next = ni->ni_txmcs;
555 0 : for (i = rs->nrates - 1; i >= 0; i--) {
556 0 : if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
557 : continue;
558 0 : if (i + rs->min_mcs < ni->ni_txmcs) {
559 : next = i + rs->min_mcs;
560 0 : break;
561 : }
562 : }
563 :
564 0 : return next;
565 0 : }
566 :
567 : int
568 0 : ieee80211_mira_next_intra_rate(struct ieee80211_mira_node *mn,
569 : struct ieee80211_node *ni)
570 : {
571 : const struct ieee80211_mira_rateset *rs;
572 : int i, next;
573 :
574 0 : rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
575 0 : if (ni->ni_txmcs == rs->max_mcs)
576 0 : return rs->max_mcs;
577 :
578 : next = ni->ni_txmcs;
579 0 : for (i = 0; i < rs->nrates; i++) {
580 0 : if ((mn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
581 : continue;
582 0 : if (i + rs->min_mcs > ni->ni_txmcs) {
583 : next = i + rs->min_mcs;
584 0 : break;
585 : }
586 : }
587 :
588 0 : return next;
589 0 : }
590 :
591 : const struct ieee80211_mira_rateset *
592 0 : ieee80211_mira_next_rateset(struct ieee80211_mira_node *mn, int mcs)
593 : {
594 : const struct ieee80211_mira_rateset *rs, *rsnext;
595 : int next;
596 :
597 0 : rs = ieee80211_mira_get_rateset(mcs);
598 0 : if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
599 0 : if (rs->max_mcs == 7) /* MCS 0-7 */
600 0 : next = IEEE80211_MIRA_RATESET_MIMO2;
601 0 : else if (rs->max_mcs == 15) /* MCS 8-15 */
602 0 : next = IEEE80211_MIRA_RATESET_MIMO3;
603 0 : else if (rs->max_mcs == 23) /* MCS 16-23 */
604 : next = IEEE80211_MIRA_RATESET_MIMO4;
605 : else /* MCS 24-31 */
606 0 : return NULL;
607 0 : } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
608 0 : if (rs->min_mcs == 24) /* MCS 24-31 */
609 0 : next = IEEE80211_MIRA_RATESET_MIMO3;
610 0 : else if (rs->min_mcs == 16) /* MCS 16-23 */
611 0 : next = IEEE80211_MIRA_RATESET_MIMO2;
612 0 : else if (rs->min_mcs == 8) /* MCS 8-15 */
613 : next = IEEE80211_MIRA_RATESET_SISO;
614 : else /* MCS 0-7 */
615 0 : return NULL;
616 : } else
617 0 : panic("%s: invalid probing mode %d", __func__, mn->probing);
618 :
619 0 : rsnext = &ieee80211_mira_ratesets[next];
620 0 : if ((rsnext->mcs_mask & mn->valid_rates) == 0)
621 0 : return NULL;
622 :
623 0 : return rsnext;
624 0 : }
625 :
626 : int
627 0 : ieee80211_mira_best_mcs_in_rateset(struct ieee80211_mira_node *mn,
628 : const struct ieee80211_mira_rateset *rs)
629 : {
630 : uint64_t gmax = 0;
631 0 : int i, best_mcs = rs->min_mcs;
632 :
633 0 : for (i = 0; i < rs->nrates; i++) {
634 0 : int mcs = rs->min_mcs + i;
635 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[mcs];
636 0 : if (((1 << mcs) & mn->valid_rates) == 0)
637 0 : continue;
638 0 : if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) {
639 : gmax = g->measured;
640 : best_mcs = mcs;
641 0 : }
642 0 : }
643 :
644 0 : return best_mcs;
645 : }
646 :
647 : void
648 0 : ieee80211_mira_probe_next_rateset(struct ieee80211_mira_node *mn,
649 : struct ieee80211_node *ni, const struct ieee80211_mira_rateset *rsnext)
650 : {
651 : const struct ieee80211_mira_rateset *rs;
652 : struct ieee80211_mira_goodput_stats *g;
653 : int best_mcs, i;
654 :
655 : /* Find most recently measured best MCS from the current rateset. */
656 0 : rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
657 0 : best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
658 :
659 : /* Switch to the next rateset. */
660 0 : ni->ni_txmcs = rsnext->min_mcs;
661 0 : if ((mn->valid_rates & (1 << rsnext->min_mcs)) == 0)
662 0 : ni->ni_txmcs = ieee80211_mira_next_intra_rate(mn, ni);
663 :
664 : /* Select the lowest rate from the next rateset with loss-free
665 : * goodput close to the current best measurement. */
666 0 : g = &mn->g[best_mcs];
667 0 : for (i = 0; i < rsnext->nrates; i++) {
668 0 : int mcs = rsnext->min_mcs + i;
669 0 : uint64_t txrate = rsnext->rates[i];
670 :
671 0 : if ((mn->valid_rates & (1 << mcs)) == 0)
672 0 : continue;
673 :
674 0 : txrate = txrate * 500; /* convert to kbit/s */
675 0 : txrate <<= MIRA_FP_SHIFT; /* convert to fixed-point */
676 0 : txrate /= 1000; /* convert to mbit/s */
677 :
678 0 : if (txrate > g->measured + IEEE80211_MIRA_RATE_THRESHOLD) {
679 0 : ni->ni_txmcs = mcs;
680 0 : break;
681 : }
682 0 : }
683 :
684 : /* Add rates from the next rateset as candidates. */
685 0 : mn->candidate_rates |= (1 << ni->ni_txmcs);
686 0 : if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
687 0 : mn->candidate_rates |=
688 0 : (1 << ieee80211_mira_next_intra_rate(mn, ni));
689 0 : } else if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
690 : #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
691 0 : mn->candidate_rates |= ieee80211_mira_mcs_below(mn,
692 0 : ni->ni_txmcs);
693 : #else
694 : mn->candidate_rates |=
695 : (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
696 : #endif
697 : } else
698 0 : panic("%s: invalid probing mode %d", __func__, mn->probing);
699 0 : }
700 :
701 : int
702 0 : ieee80211_mira_next_mcs(struct ieee80211_mira_node *mn,
703 : struct ieee80211_node *ni)
704 : {
705 : int next;
706 :
707 0 : if (mn->probing & IEEE80211_MIRA_PROBING_DOWN)
708 0 : next = ieee80211_mira_next_lower_intra_rate(mn, ni);
709 0 : else if (mn->probing & IEEE80211_MIRA_PROBING_UP)
710 0 : next = ieee80211_mira_next_intra_rate(mn, ni);
711 : else
712 0 : panic("%s: invalid probing mode %d", __func__, mn->probing);
713 :
714 0 : return next;
715 : }
716 :
717 : int
718 0 : ieee80211_mira_prev_mcs(struct ieee80211_mira_node *mn,
719 : struct ieee80211_node *ni)
720 : {
721 : int next;
722 :
723 0 : if (mn->probing & IEEE80211_MIRA_PROBING_DOWN)
724 0 : next = ieee80211_mira_next_intra_rate(mn, ni);
725 0 : else if (mn->probing & IEEE80211_MIRA_PROBING_UP)
726 0 : next = ieee80211_mira_next_lower_intra_rate(mn, ni);
727 : else
728 0 : panic("%s: invalid probing mode %d", __func__, mn->probing);
729 :
730 0 : return next;
731 : }
732 :
733 : int
734 0 : ieee80211_mira_probe_valid(struct ieee80211_mira_node *mn,
735 : struct ieee80211_node *ni)
736 : {
737 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
738 :
739 0 : return (g->nprobes >= IEEE80211_MIRA_MIN_PROBE_FRAMES ||
740 0 : g->nprobe_bytes >= IEEE80211_MIRA_MIN_PROBE_BYTES);
741 : }
742 :
743 : void
744 0 : ieee80211_mira_probe_done(struct ieee80211_mira_node *mn)
745 : {
746 0 : ieee80211_mira_cancel_timeouts(mn);
747 0 : ieee80211_mira_reset_driver_stats(mn);
748 0 : mn->probing = IEEE80211_MIRA_NOT_PROBING;
749 0 : mn->probed_rates = 0;
750 0 : mn->candidate_rates = 0;
751 0 : }
752 :
753 : int
754 0 : ieee80211_mira_intra_mode_ra_finished(struct ieee80211_mira_node *mn,
755 : struct ieee80211_node *ni)
756 : {
757 : const struct ieee80211_mira_rateset *rs;
758 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
759 : int next_mcs, best_mcs, probed_rates;
760 : uint64_t next_rate;
761 :
762 0 : if (!ieee80211_mira_probe_valid(mn, ni))
763 0 : return 0;
764 :
765 0 : probed_rates = (mn->probed_rates | (1 << ni->ni_txmcs));
766 :
767 : /* Check if the min/max MCS in this rateset has been probed. */
768 0 : rs = ieee80211_mira_get_rateset(ni->ni_txmcs);
769 0 : if (mn->probing & IEEE80211_MIRA_PROBING_DOWN) {
770 0 : if (ni->ni_txmcs == rs->min_mcs ||
771 0 : probed_rates & (1 << rs->min_mcs)) {
772 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
773 0 : return 1;
774 : }
775 0 : } else if (mn->probing & IEEE80211_MIRA_PROBING_UP) {
776 0 : if (ni->ni_txmcs == rs->max_mcs ||
777 0 : probed_rates & (1 << rs->max_mcs)) {
778 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
779 0 : return 1;
780 : }
781 : }
782 :
783 : /*
784 : * Check if the measured goodput is better than the
785 : * loss-free goodput of the candidate rate.
786 : */
787 0 : next_mcs = ieee80211_mira_next_mcs(mn, ni);
788 0 : if (next_mcs == ni->ni_txmcs) {
789 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
790 0 : return 1;
791 : }
792 0 : next_rate = ieee80211_mira_get_txrate(next_mcs);
793 0 : if (g->measured >= next_rate + IEEE80211_MIRA_RATE_THRESHOLD) {
794 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
795 0 : return 1;
796 : }
797 :
798 : /* Check if we had a better measurement at a previously probed MCS. */
799 0 : best_mcs = ieee80211_mira_best_mcs_in_rateset(mn, rs);
800 0 : if ((mn->probed_rates & (1 << best_mcs))) {
801 0 : if ((mn->probing & IEEE80211_MIRA_PROBING_UP) &&
802 0 : best_mcs < ni->ni_txmcs) {
803 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
804 0 : return 1;
805 : }
806 0 : if ((mn->probing & IEEE80211_MIRA_PROBING_DOWN) &&
807 0 : best_mcs > ni->ni_txmcs) {
808 0 : ieee80211_mira_trigger_next_rateset(mn, ni);
809 0 : return 1;
810 : }
811 : }
812 :
813 : /* Check if all rates in the set of candidate rates have been probed. */
814 0 : if ((mn->candidate_rates & probed_rates) == mn->candidate_rates) {
815 : /* Remain in the current rateset until above checks trigger. */
816 0 : return 1;
817 : }
818 :
819 0 : return 0;
820 0 : }
821 :
822 : void
823 0 : ieee80211_mira_trigger_next_rateset(struct ieee80211_mira_node *mn,
824 : struct ieee80211_node *ni)
825 : {
826 : const struct ieee80211_mira_rateset *rsnext;
827 :
828 0 : rsnext = ieee80211_mira_next_rateset(mn, ni->ni_txmcs);
829 0 : if (rsnext) {
830 0 : ieee80211_mira_probe_next_rateset(mn, ni, rsnext);
831 0 : mn->probing |= IEEE80211_MIRA_PROBING_INTER;
832 0 : } else
833 0 : mn->probing &= ~IEEE80211_MIRA_PROBING_INTER;
834 0 : }
835 :
836 : int
837 0 : ieee80211_mira_inter_mode_ra_finished(struct ieee80211_mira_node *mn,
838 : struct ieee80211_node *ni)
839 : {
840 0 : return ((mn->probing & IEEE80211_MIRA_PROBING_INTER) == 0);
841 : }
842 :
843 : int
844 0 : ieee80211_mira_best_rate(struct ieee80211_mira_node *mn,
845 : struct ieee80211_node *ni)
846 : {
847 : int i, best = 0;
848 : uint64_t gmax = 0;
849 :
850 0 : for (i = 0; i < nitems(mn->g); i++) {
851 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[i];
852 0 : if (((1 << i) & mn->valid_rates) == 0)
853 0 : continue;
854 0 : if (g->measured > gmax + IEEE80211_MIRA_RATE_THRESHOLD) {
855 : gmax = g->measured;
856 : best = i;
857 0 : }
858 0 : }
859 :
860 : #ifdef MIRA_DEBUG
861 : if (mn->best_mcs != best) {
862 : DPRINTF(("MCS %d is best; MCS{Mbps|probe interval}:", best));
863 : for (i = 0; i < IEEE80211_MIRA_NUM_MCS; i++) {
864 : struct ieee80211_mira_goodput_stats *g = &mn->g[i];
865 : if ((mn->valid_rates & (1 << i)) == 0)
866 : continue;
867 : DPRINTF((" %d{%s|%dms}", i,
868 : mira_fp_sprintf(g->measured),
869 : g->probe_interval));
870 : }
871 : DPRINTF(("\n"));
872 : }
873 : #endif
874 0 : return best;
875 : }
876 :
877 : /* See section 5.1.1 (at "Adaptive probing interval") in MiRA paper. */
878 : void
879 0 : ieee80211_mira_update_probe_interval(struct ieee80211_mira_node *mn,
880 : struct ieee80211_mira_goodput_stats *g)
881 : {
882 : uint64_t lt;
883 : int intval;
884 :
885 0 : lt = g->loss / IEEE80211_MIRA_LOSS_THRESHOLD;
886 0 : if (lt < MIRA_FP_1)
887 : lt = MIRA_FP_1;
888 0 : lt >>= MIRA_FP_SHIFT; /* round to integer */
889 :
890 0 : intval = (1 << g->nprobes); /* 2^nprobes */
891 0 : if (intval > IEEE80211_MIRA_PROBE_INTVAL_MAX)
892 : intval = IEEE80211_MIRA_PROBE_INTVAL_MAX;
893 :
894 0 : g->probe_interval = IEEE80211_MIRA_PROBE_TIMEOUT_MIN * intval * lt;
895 0 : }
896 :
897 : void
898 0 : ieee80211_mira_schedule_probe_timers(struct ieee80211_mira_node *mn,
899 : struct ieee80211_node *ni)
900 : {
901 : struct ieee80211_mira_goodput_stats *g;
902 : struct timeout *to;
903 : int mcs;
904 :
905 0 : mcs = ieee80211_mira_next_intra_rate(mn, ni);
906 0 : to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP];
907 0 : g = &mn->g[mcs];
908 0 : if (mcs != ni->ni_txmcs && !timeout_pending(to) &&
909 0 : !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP]) {
910 0 : timeout_add_msec(to, g->probe_interval);
911 : DPRINTFN(3, ("start probing up for node %s at MCS %d in at "
912 : "least %d msec\n",
913 : ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval));
914 0 : }
915 :
916 0 : mcs = ieee80211_mira_next_lower_intra_rate(mn, ni);
917 0 : to = &mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN];
918 0 : g = &mn->g[mcs];
919 0 : if (mcs != ni->ni_txmcs && !timeout_pending(to) &&
920 0 : !mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
921 0 : timeout_add_msec(to, g->probe_interval);
922 : DPRINTFN(3, ("start probing down for node %s at MCS %d in at "
923 : "least %d msec\n",
924 : ether_sprintf(ni->ni_macaddr), mcs, g->probe_interval));
925 0 : }
926 0 : }
927 :
928 : int
929 0 : ieee80211_mira_check_probe_timers(struct ieee80211_mira_node *mn,
930 : struct ieee80211_node *ni)
931 : {
932 : int ret = 0, expired_timer = IEEE80211_MIRA_PROBE_TO_INVALID;
933 : int mcs;
934 :
935 0 : if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP] &&
936 0 : mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN]) {
937 0 : if (arc4random_uniform(2))
938 0 : expired_timer = IEEE80211_MIRA_PROBE_TO_UP;
939 : else
940 : expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN;
941 0 : } else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_DOWN])
942 0 : expired_timer = IEEE80211_MIRA_PROBE_TO_DOWN;
943 0 : else if (mn->probe_timer_expired[IEEE80211_MIRA_PROBE_TO_UP])
944 0 : expired_timer = IEEE80211_MIRA_PROBE_TO_UP;
945 :
946 0 : if (expired_timer != IEEE80211_MIRA_PROBE_TO_INVALID)
947 0 : mn->probe_timer_expired[expired_timer] = 0;
948 :
949 0 : switch (expired_timer) {
950 : case IEEE80211_MIRA_PROBE_TO_UP:
951 : /* Do time-based upwards probing on next frame. */
952 : DPRINTFN(2, ("probe timer expired: probe upwards\n"));
953 0 : mn->probing = IEEE80211_MIRA_PROBING_UP;
954 0 : mcs = ieee80211_mira_next_intra_rate(mn, ni);
955 0 : mn->candidate_rates = (1 << mcs);
956 : ret = 1;
957 0 : break;
958 : case IEEE80211_MIRA_PROBE_TO_DOWN:
959 : /* Do time-based downwards probing on next frame. */
960 : DPRINTFN(2, ("probe timer expired: probe downwards\n"));
961 0 : mn->probing = IEEE80211_MIRA_PROBING_DOWN;
962 0 : mcs = ieee80211_mira_next_lower_intra_rate(mn, ni);
963 0 : mn->candidate_rates = (1 << mcs);
964 : ret = 1;
965 0 : break;
966 : case IEEE80211_MIRA_PROBE_TO_INVALID:
967 : default:
968 : ret = 0;
969 0 : break;
970 : }
971 :
972 0 : return ret;
973 : }
974 :
975 : void
976 0 : ieee80211_mira_probe_next_rate(struct ieee80211_mira_node *mn,
977 : struct ieee80211_node *ni)
978 : {
979 : struct ieee80211_mira_goodput_stats *gprev, *g;
980 : int prev_mcs;
981 :
982 0 : prev_mcs = ieee80211_mira_prev_mcs(mn, ni);
983 0 : gprev = &mn->g[prev_mcs];
984 0 : g = &mn->g[ni->ni_txmcs];
985 : /* If the previous rate was worse, increase its probing interval. */
986 0 : if (prev_mcs != ni->ni_txmcs &&
987 0 : gprev->measured + IEEE80211_MIRA_RATE_THRESHOLD < g->measured)
988 0 : ieee80211_mira_update_probe_interval(mn, gprev);
989 :
990 : /* Select the next rate to probe. */
991 0 : mn->probed_rates |= (1 << ni->ni_txmcs);
992 0 : ni->ni_txmcs = ieee80211_mira_next_mcs(mn, ni);
993 0 : }
994 :
995 : int
996 0 : ieee80211_mira_valid_tx_mcs(struct ieee80211com *ic, int mcs)
997 : {
998 : uint32_t ntxstreams = 1;
999 : static const int max_mcs[] = { 7, 15, 23, 31 };
1000 :
1001 0 : if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0)
1002 0 : return isset(ic->ic_sup_mcs, mcs);
1003 :
1004 0 : ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2);
1005 0 : if (ntxstreams < 1 || ntxstreams > 4)
1006 0 : panic("invalid number of Tx streams: %u", ntxstreams);
1007 0 : return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs));
1008 0 : }
1009 :
1010 : uint32_t
1011 0 : ieee80211_mira_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni)
1012 : {
1013 : uint32_t valid_mcs = 0;
1014 : int i;
1015 :
1016 0 : for (i = 0;
1017 0 : i < MIN(IEEE80211_MIRA_NUM_MCS, IEEE80211_HT_NUM_MCS); i++) {
1018 0 : if (!isset(ni->ni_rxmcs, i))
1019 : continue;
1020 0 : if (!ieee80211_mira_valid_tx_mcs(ic, i))
1021 : continue;
1022 0 : valid_mcs |= (1 << i);
1023 0 : }
1024 :
1025 0 : return valid_mcs;
1026 : }
1027 :
1028 : uint32_t
1029 0 : ieee80211_mira_mcs_below(struct ieee80211_mira_node *mn, int mcs)
1030 : {
1031 : const struct ieee80211_mira_rateset *rs;
1032 : uint32_t mcs_mask;
1033 : int i;
1034 :
1035 0 : rs = ieee80211_mira_get_rateset(mcs);
1036 0 : mcs_mask = (1 << rs->min_mcs);
1037 0 : for (i = rs->min_mcs + 1; i < mcs; i++) {
1038 0 : if ((mn->valid_rates & (1 << i)) == 0)
1039 : continue;
1040 0 : mcs_mask |= (1 << i);
1041 0 : }
1042 :
1043 0 : return mcs_mask;
1044 : }
1045 :
1046 : void
1047 0 : ieee80211_mira_choose(struct ieee80211_mira_node *mn, struct ieee80211com *ic,
1048 : struct ieee80211_node *ni)
1049 : {
1050 0 : struct ieee80211_mira_goodput_stats *g = &mn->g[ni->ni_txmcs];
1051 : int s;
1052 :
1053 0 : s = splnet();
1054 :
1055 0 : if (mn->valid_rates == 0)
1056 0 : mn->valid_rates = ieee80211_mira_valid_rates(ic, ni);
1057 :
1058 : #ifdef MIRA_DEBUG
1059 : if (mira_debug >= 5)
1060 : mira_print_driver_stats(mn, ni);
1061 : #endif
1062 0 : ieee80211_mira_update_stats(mn, ic, ni);
1063 :
1064 0 : if (mn->probing) {
1065 : /* Probe another rate or settle at the best rate. */
1066 0 : if (!ieee80211_mira_intra_mode_ra_finished(mn, ni)) {
1067 0 : if (ieee80211_mira_probe_valid(mn, ni)) {
1068 0 : ieee80211_mira_probe_next_rate(mn, ni);
1069 0 : ieee80211_mira_reset_driver_stats(mn);
1070 0 : }
1071 : DPRINTFN(4, ("probing MCS %d\n", ni->ni_txmcs));
1072 0 : } else if (ieee80211_mira_inter_mode_ra_finished(mn, ni)) {
1073 0 : int best = ieee80211_mira_best_rate(mn, ni);
1074 0 : if (mn->best_mcs != best) {
1075 0 : mn->best_mcs = best;
1076 0 : ni->ni_txmcs = best;
1077 : /* Reset probe interval for new best rate. */
1078 0 : mn->g[best].probe_interval =
1079 : IEEE80211_MIRA_PROBE_TIMEOUT_MIN;
1080 0 : mn->g[best].nprobes = 0;
1081 0 : mn->g[best].nprobe_bytes = 0;
1082 0 : } else
1083 0 : ni->ni_txmcs = mn->best_mcs;
1084 0 : ieee80211_mira_probe_done(mn);
1085 0 : }
1086 :
1087 0 : splx(s);
1088 0 : return;
1089 : } else {
1090 0 : ieee80211_mira_reset_driver_stats(mn);
1091 0 : ieee80211_mira_schedule_probe_timers(mn, ni);
1092 : }
1093 :
1094 0 : if (ieee80211_mira_check_probe_timers(mn, ni)) {
1095 : /* Time-based probing has triggered. */
1096 0 : splx(s);
1097 0 : return;
1098 : }
1099 :
1100 : /* Check if event-based probing should be triggered. */
1101 0 : if (g->measured <= g->average - 2 * g->stddeviation) {
1102 : /* Channel becomes bad. Probe downwards. */
1103 : DPRINTFN(2, ("channel becomes bad; probe downwards\n"));
1104 : DPRINTFN(3, ("measured: %s Mbit/s\n",
1105 : mira_fp_sprintf(g->measured)));
1106 : DPRINTFN(3, ("average: %s Mbit/s\n",
1107 : mira_fp_sprintf(g->average)));
1108 : DPRINTFN(3, ("stddeviation: %s\n",
1109 : mira_fp_sprintf(g->stddeviation)));
1110 0 : mn->probing = IEEE80211_MIRA_PROBING_DOWN;
1111 0 : mn->probed_rates = 0;
1112 : #ifdef MIRA_AGGRESSIVE_DOWNWARDS_PROBING
1113 : /* Allow for probing all the way down within this rateset. */
1114 0 : mn->candidate_rates = ieee80211_mira_mcs_below(mn,
1115 0 : ni->ni_txmcs);
1116 : #else
1117 : /* Probe the lower candidate rate to see if it's any better. */
1118 : mn->candidate_rates =
1119 : (1 << ieee80211_mira_next_lower_intra_rate(mn, ni));
1120 : #endif
1121 0 : } else if (g->measured >= g->average + 2 * g->stddeviation) {
1122 : /* Channel becomes good. */
1123 : DPRINTFN(2, ("channel becomes good; probe upwards\n"));
1124 : DPRINTFN(3, ("measured: %s Mbit/s\n",
1125 : mira_fp_sprintf(g->measured)));
1126 : DPRINTFN(3, ("average: %s Mbit/s\n",
1127 : mira_fp_sprintf(g->average)));
1128 : DPRINTFN(3, ("stddeviation: %s\n",
1129 : mira_fp_sprintf(g->stddeviation)));
1130 0 : mn->probing = IEEE80211_MIRA_PROBING_UP;
1131 0 : mn->probed_rates = 0;
1132 : /* Probe the upper candidate rate to see if it's any better. */
1133 0 : mn->candidate_rates =
1134 0 : (1 << ieee80211_mira_next_intra_rate(mn, ni));
1135 0 : } else {
1136 : /* Remain at current rate. */
1137 0 : mn->probing = IEEE80211_MIRA_NOT_PROBING;
1138 0 : mn->probed_rates = 0;
1139 0 : mn->candidate_rates = 0;
1140 : }
1141 :
1142 0 : splx(s);
1143 0 : }
1144 :
1145 : void
1146 0 : ieee80211_mira_node_init(struct ieee80211_mira_node *mn)
1147 : {
1148 0 : memset(mn, 0, sizeof(*mn));
1149 0 : mn->agglen = 1;
1150 0 : ieee80211_mira_reset_goodput_stats(mn);
1151 :
1152 0 : timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_UP],
1153 : ieee80211_mira_probe_timeout_up, mn);
1154 0 : timeout_set(&mn->probe_to[IEEE80211_MIRA_PROBE_TO_DOWN],
1155 : ieee80211_mira_probe_timeout_down, mn);
1156 0 : }
1157 :
1158 : void
1159 0 : ieee80211_mira_cancel_timeouts(struct ieee80211_mira_node *mn)
1160 : {
1161 : int t;
1162 :
1163 0 : for (t = 0; t < nitems(mn->probe_to); t++)
1164 0 : timeout_del(&mn->probe_to[t]);
1165 0 : }
|