xref: /openbsd/sys/net80211/ieee80211_ra_vht.c (revision d9a0b74b)
1 /*	$OpenBSD: ieee80211_ra_vht.c,v 1.3 2022/03/23 09:21:47 stsp Exp $	*/
2 
3 /*
4  * Copyright (c) 2021 Christian Ehrhardt <ehrhardt@genua.de>
5  * Copyright (c) 2016, 2021, 2022 Stefan Sperling <stsp@openbsd.org>
6  * Copyright (c) 2016 Theo Buehler <tb@openbsd.org>
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_ra_vht.h>
33 
34 int	ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *,
35 	    struct ieee80211_node *);
36 const struct ieee80211_vht_rateset * ieee80211_ra_vht_next_rateset(
37 		    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
38 int	ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *,
39 	    const struct ieee80211_vht_rateset *);
40 void	ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *,
41 	    struct ieee80211_node *, const struct ieee80211_vht_rateset *);
42 int	ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *,
43 	    struct ieee80211_node *);
44 void	ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *, int);
45 int	ieee80211_ra_vht_intra_mode_ra_finished(
46 	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
47 void	ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *,
48 	    struct ieee80211_node *);
49 int	ieee80211_ra_vht_inter_mode_ra_finished(
50 	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
51 void	ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *,
52 	    struct ieee80211_node *);
53 void	ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *,
54 	    struct ieee80211_node *);
55 void	ieee80211_ra_vht_init_valid_rates(struct ieee80211com *,
56 	    struct ieee80211_node *, struct ieee80211_ra_vht_node *);
57 int	ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *);
58 
59 /* We use fixed point arithmetic with 64 bit integers. */
60 #define RA_FP_SHIFT	21
61 #define RA_FP_INT(x)	(x ## ULL << RA_FP_SHIFT) /* the integer x */
62 #define RA_FP_1	RA_FP_INT(1)
63 
64 /* Multiply two fixed point numbers. */
65 #define RA_FP_MUL(a, b) \
66 	(((a) * (b)) >> RA_FP_SHIFT)
67 
68 /* Divide two fixed point numbers. */
69 #define RA_FP_DIV(a, b) \
70 	(b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b)))
71 
72 #ifdef RA_DEBUG
73 #define DPRINTF(x)	do { if (ra_vht_debug > 0) printf x; } while (0)
74 #define DPRINTFN(n, x)	do { if (ra_vht_debug >= (n)) printf x; } while (0)
75 int ra_vht_debug = 0;
76 #else
77 #define DPRINTF(x)	do { ; } while (0)
78 #define DPRINTFN(n, x)	do { ; } while (0)
79 #endif
80 
81 #ifdef RA_DEBUG
82 void
ra_vht_fixedp_split(uint32_t * i,uint32_t * f,uint64_t fp)83 ra_vht_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp)
84 {
85 	uint64_t tmp;
86 
87 	/* integer part */
88 	*i = (fp >> RA_FP_SHIFT);
89 
90  	/* fractional part */
91 	tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT)));
92 	tmp *= 100;
93 	*f = (uint32_t)(tmp >> RA_FP_SHIFT);
94 }
95 
96 char *
ra_vht_fp_sprintf(uint64_t fp)97 ra_vht_fp_sprintf(uint64_t fp)
98 {
99 	uint32_t i, f;
100 	static char buf[64];
101 	int ret;
102 
103 	ra_vht_fixedp_split(&i, &f, fp);
104 	ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f);
105 	if (ret == -1 || ret >= sizeof(buf))
106 		return "ERR";
107 
108 	return buf;
109 }
110 #endif /* RA_DEBUG */
111 
112 const struct ieee80211_vht_rateset *
ieee80211_ra_vht_get_rateset(int mcs,int nss,int chan40,int chan80,int sgi)113 ieee80211_ra_vht_get_rateset(int mcs, int nss, int chan40, int chan80, int sgi)
114 {
115 	const struct ieee80211_vht_rateset *rs;
116 	int i;
117 
118 	for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
119 		rs = &ieee80211_std_ratesets_11ac[i];
120 		if (mcs < rs->nrates && rs->num_ss == nss &&
121 		    chan40 == rs->chan40 && chan80 == rs->chan80 &&
122 		    sgi == rs->sgi)
123 			return rs;
124 	}
125 
126 	panic("MCS %d NSS %d is not part of any rateset", mcs, nss);
127 }
128 
129 int
ieee80211_ra_vht_use_sgi(struct ieee80211_node * ni)130 ieee80211_ra_vht_use_sgi(struct ieee80211_node *ni)
131 {
132 	if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_160MHZ) &&
133 	    ieee80211_node_supports_vht_chan160(ni)) {
134 		if (ni->ni_flags & IEEE80211_NODE_VHT_SGI160)
135 			return 1;
136 	}
137 
138 	if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_80MHZ) &&
139 	    ieee80211_node_supports_vht_chan80(ni)) {
140 		if (ni->ni_flags & IEEE80211_NODE_VHT_SGI80)
141 			return 1;
142 	}
143 
144 	return 0;
145 }
146 
147 /*
148  * Update goodput statistics.
149  */
150 
151 uint64_t
ieee80211_ra_vht_get_txrate(int mcs,int nss,int chan40,int chan80,int sgi)152 ieee80211_ra_vht_get_txrate(int mcs, int nss, int chan40, int chan80, int sgi)
153 {
154 	const struct ieee80211_vht_rateset *rs;
155 	uint64_t txrate;
156 
157 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, chan40, chan80, sgi);
158 	txrate = rs->rates[mcs];
159 	txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
160 	txrate *= 500; /* convert to kbit/s */
161 	txrate /= 1000; /* convert to mbit/s */
162 
163 	return txrate;
164 }
165 
166 /*
167  * Rate selection.
168  */
169 
170 /* A rate's goodput has to be at least this much larger to be "better". */
171 #define IEEE80211_RA_RATE_THRESHOLD	(RA_FP_1 / 64) /* ~ 0.015 */
172 
173 int
ieee80211_ra_vht_next_lower_intra_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)174 ieee80211_ra_vht_next_lower_intra_rate(struct ieee80211_ra_vht_node *rn,
175     struct ieee80211_node *ni)
176 {
177 	if (ni->ni_txmcs <= 0)
178 		return 0;
179 
180 	return ni->ni_txmcs - 1;
181 }
182 
183 int
ieee80211_ra_vht_get_max_mcs(int vht_mcs,int nss,int chan40)184 ieee80211_ra_vht_get_max_mcs(int vht_mcs, int nss, int chan40)
185 {
186 	int supp_mcs = (vht_mcs & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >>
187 	    IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss);
188 	int max_mcs = -1;
189 
190 	switch (supp_mcs) {
191 	case IEEE80211_VHT_MCS_SS_NOT_SUPP:
192 		break;
193 	case IEEE80211_VHT_MCS_0_7:
194 		max_mcs = 7;
195 		break;
196 	case IEEE80211_VHT_MCS_0_8:
197 		max_mcs = 8;
198 		break;
199 	case IEEE80211_VHT_MCS_0_9:
200 		/* Disable VHT MCS 9 for 20MHz-only stations. */
201 		if (!chan40)
202 			max_mcs = 8;
203 		else
204 			max_mcs = 9;
205 		break;
206 	default:
207 		/* Should not happen; Values above cover the possible range. */
208 		panic("invalid VHT Rx MCS value %u", supp_mcs);
209 	}
210 
211 	return max_mcs;
212 }
213 
214 int
ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)215 ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *rn,
216     struct ieee80211_node *ni)
217 {
218 	int max_mcs;
219 
220 	max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs,
221 	    ni->ni_vht_ss, ieee80211_node_supports_ht_chan40(ni));
222 	if (max_mcs != 7 && max_mcs != 8 && max_mcs != 9)
223 		panic("ni->ni_vht_ss invalid: %u", ni->ni_vht_ss);
224 
225 	if (ni->ni_txmcs >= max_mcs)
226 		return max_mcs;
227 
228 	return ni->ni_txmcs + 1;
229 }
230 
231 const struct ieee80211_vht_rateset *
ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)232 ieee80211_ra_vht_next_rateset(struct ieee80211_ra_vht_node *rn,
233     struct ieee80211_node *ni)
234 {
235 	const struct ieee80211_vht_rateset *rs, *rsnext;
236 	int next;
237 	int sgi = ieee80211_ra_vht_use_sgi(ni);
238 	int mcs = ni->ni_txmcs;
239 	int nss = ni->ni_vht_ss;
240 
241 	/*
242 	 * We only probe 80MHz ratesets.
243 	 * Drivers handle retries on slower rates if needed.
244 	 */
245 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1, sgi);
246 	if (rn->probing & IEEE80211_RA_PROBING_UP) {
247 		switch (rs->idx) {
248 		case IEEE80211_VHT_RATESET_SISO_80:
249 			next = IEEE80211_VHT_RATESET_MIMO2_80;
250 			break;
251 		case IEEE80211_VHT_RATESET_SISO_80_SGI:
252 			next = IEEE80211_VHT_RATESET_MIMO2_80_SGI;
253 			break;
254 		default:
255 			return NULL;
256 		}
257 	} else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
258 		switch (rs->idx) {
259 		case IEEE80211_VHT_RATESET_MIMO2_80:
260 			next = IEEE80211_VHT_RATESET_SISO_80;
261 			break;
262 		case IEEE80211_VHT_RATESET_MIMO2_80_SGI:
263 			next = IEEE80211_VHT_RATESET_SISO_80_SGI;
264 			break;
265 		default:
266 			return NULL;
267 		}
268 	} else
269 		panic("%s: invalid probing mode %d", __func__, rn->probing);
270 
271 	rsnext = &ieee80211_std_ratesets_11ac[next];
272 	if (rn->valid_rates[rsnext->num_ss - 1] == 0)
273 		return NULL;
274 
275 	return rsnext;
276 }
277 
278 int
ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node * rn,const struct ieee80211_vht_rateset * rs)279 ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *rn,
280     const struct ieee80211_vht_rateset *rs)
281 {
282 	uint64_t gmax = 0;
283 	int mcs, best_mcs = 0;
284 
285 	for (mcs = 0; mcs < rs->nrates; mcs++) {
286 		struct ieee80211_ra_vht_goodput_stats *g = &rn->g[rs->idx][mcs];
287 		if (((1 << mcs) & rn->valid_rates[rs->num_ss - 1]) == 0)
288 			continue;
289 		if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
290 			gmax = g->measured;
291 			best_mcs = mcs;
292 		}
293 	}
294 
295 	return best_mcs;
296 }
297 
298 void
ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni,const struct ieee80211_vht_rateset * rsnext)299 ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *rn,
300     struct ieee80211_node *ni, const struct ieee80211_vht_rateset *rsnext)
301 {
302 	const struct ieee80211_vht_rateset *rs;
303 	struct ieee80211_ra_vht_goodput_stats *g;
304 	int best_mcs, mcs;
305 
306 	/* Find most recently measured best MCS from the current rateset. */
307 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, ni->ni_vht_ss, 0, 1,
308 	    ieee80211_ra_vht_use_sgi(ni));
309 	best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs);
310 
311 	/* Switch to the next rateset. */
312 	ni->ni_txmcs = 0;
313 	ni->ni_vht_ss = rsnext->num_ss;
314 
315 	/* Select the lowest rate from the next rateset with loss-free
316 	 * goodput close to the current best measurement. */
317 	g = &rn->g[rs->idx][best_mcs];
318 	for (mcs = 0; mcs < rsnext->nrates; mcs++) {
319 		uint64_t txrate = rsnext->rates[mcs];
320 
321 		if ((rn->valid_rates[rsnext->num_ss - 1] & (1 << mcs)) == 0)
322 			continue;
323 
324 		txrate = txrate * 500; /* convert to kbit/s */
325 		txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
326 		txrate /= 1000; /* convert to mbit/s */
327 
328 		if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) {
329 			ni->ni_txmcs = mcs;
330 			break;
331 		}
332 	}
333 	/* If all rates are lower then the best rate is the closest match. */
334 	if (mcs == rsnext->nrates)
335 		ni->ni_txmcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rsnext);
336 
337 	/* Add rates from the next rateset as candidates. */
338 	rn->candidate_rates[rsnext->num_ss - 1] |= (1 << ni->ni_txmcs);
339 	if (rn->probing & IEEE80211_RA_PROBING_UP) {
340 		rn->candidate_rates[rsnext->num_ss - 1] |=
341 		  (1 << ieee80211_ra_vht_next_intra_rate(rn, ni));
342 	} else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
343 		rn->candidate_rates[rsnext->num_ss - 1] |=
344 		    (1 << ieee80211_ra_vht_next_lower_intra_rate(rn, ni));
345 	} else
346 		panic("%s: invalid probing mode %d", __func__, rn->probing);
347 }
348 
349 int
ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)350 ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *rn,
351     struct ieee80211_node *ni)
352 {
353 	int next;
354 
355 	if (rn->probing & IEEE80211_RA_PROBING_DOWN)
356 		next = ieee80211_ra_vht_next_lower_intra_rate(rn, ni);
357 	else if (rn->probing & IEEE80211_RA_PROBING_UP)
358 		next = ieee80211_ra_vht_next_intra_rate(rn, ni);
359 	else
360 		panic("%s: invalid probing mode %d", __func__, rn->probing);
361 
362 	return next;
363 }
364 
365 void
ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats * g)366 ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats *g)
367 {
368 	g->nprobe_pkts = 0;
369 	g->nprobe_fail = 0;
370 }
371 
372 void
ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node * rn,int nss)373 ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *rn, int nss)
374 {
375 	rn->probing = IEEE80211_RA_NOT_PROBING;
376 	rn->probed_rates[nss - 1] = 0;
377 	rn->valid_probes[nss - 1] = 0;
378 	rn->candidate_rates[nss - 1] = 0;
379 }
380 
381 int
ieee80211_ra_vht_intra_mode_ra_finished(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)382 ieee80211_ra_vht_intra_mode_ra_finished(struct ieee80211_ra_vht_node *rn,
383     struct ieee80211_node *ni)
384 {
385 	const struct ieee80211_vht_rateset *rs;
386 	struct ieee80211_ra_vht_goodput_stats *g;
387 	int next_mcs, best_mcs;
388 	uint64_t next_rate;
389 	int nss = ni->ni_vht_ss;
390 	int sgi = ieee80211_ra_vht_use_sgi(ni);
391 
392 	rn->probed_rates[nss - 1] = (rn->probed_rates[nss - 1] |
393 	    (1 << ni->ni_txmcs));
394 
395 	/* Check if the min/max MCS in this rateset has been probed. */
396 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
397 	if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
398 		if (ni->ni_txmcs == 0 ||
399 		    rn->probed_rates[nss - 1] & (1 << 0)) {
400 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
401 			return 1;
402 		}
403 	} else if (rn->probing & IEEE80211_RA_PROBING_UP) {
404 		if (ni->ni_txmcs == rn->max_mcs[nss - 1] ||
405 		    rn->probed_rates[nss - 1] & (1 << rn->max_mcs[nss - 1])) {
406 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
407 			return 1;
408 		}
409 	}
410 
411 	/*
412 	 * Check if the measured goodput is loss-free and better than the
413 	 * loss-free goodput of the candidate rate.
414 	 */
415 	next_mcs = ieee80211_ra_vht_next_mcs(rn, ni);
416 	if (next_mcs == ni->ni_txmcs) {
417 		ieee80211_ra_vht_trigger_next_rateset(rn, ni);
418 		return 1;
419 	}
420 	next_rate = ieee80211_ra_vht_get_txrate(next_mcs, nss, 0, 1, sgi);
421 	g = &rn->g[rs->idx][ni->ni_txmcs];
422 	if (g->loss == 0 &&
423 	    g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) {
424 		ieee80211_ra_vht_trigger_next_rateset(rn, ni);
425 		return 1;
426 	}
427 
428 	/* Check if we had a better measurement at a previously probed MCS. */
429 	best_mcs = ieee80211_ra_vht_best_mcs_in_rateset(rn, rs);
430 	if (best_mcs != ni->ni_txmcs) {
431 		if ((rn->probing & IEEE80211_RA_PROBING_UP) &&
432 		    best_mcs < ni->ni_txmcs) {
433 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
434 			return 1;
435 		}
436 		if ((rn->probing & IEEE80211_RA_PROBING_DOWN) &&
437 		    best_mcs > ni->ni_txmcs) {
438 			ieee80211_ra_vht_trigger_next_rateset(rn, ni);
439 			return 1;
440 		}
441 	}
442 
443 	/* Check if all rates in the set of candidate rates have been probed. */
444 	if ((rn->candidate_rates[nss - 1] & rn->probed_rates[nss - 1]) ==
445 	    rn->candidate_rates[nss - 1]) {
446 		/* Remain in the current rateset until above checks trigger. */
447 		rn->probing &= ~IEEE80211_RA_PROBING_INTER;
448 		return 1;
449 	}
450 
451 	return 0;
452 }
453 
454 void
ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)455 ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *rn,
456     struct ieee80211_node *ni)
457 {
458 	const struct ieee80211_vht_rateset *rsnext;
459 
460 	rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
461 	if (rsnext) {
462 		ieee80211_ra_vht_probe_next_rateset(rn, ni, rsnext);
463 		rn->probing |= IEEE80211_RA_PROBING_INTER;
464 	} else
465 		rn->probing &= ~IEEE80211_RA_PROBING_INTER;
466 }
467 
468 int
ieee80211_ra_vht_inter_mode_ra_finished(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)469 ieee80211_ra_vht_inter_mode_ra_finished(struct ieee80211_ra_vht_node *rn,
470     struct ieee80211_node *ni)
471 {
472 	return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0);
473 }
474 
475 void
ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)476 ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *rn,
477     struct ieee80211_node *ni)
478 {
479 	const struct ieee80211_vht_rateset *rs;
480 	int i, j, best_mcs = rn->best_mcs, best_nss = rn->best_nss;
481 	uint64_t gmax;
482 
483 	rs = ieee80211_ra_vht_get_rateset(best_mcs, best_nss, 0, 1,
484 	    ieee80211_ra_vht_use_sgi(ni));
485 	gmax = rn->g[rs->idx][best_mcs].measured;
486 
487 	for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
488 		rs = &ieee80211_std_ratesets_11ac[i];
489 		for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) {
490 			struct ieee80211_ra_vht_goodput_stats *g = &rn->g[i][j];
491 			if (((1 << i) & rn->valid_rates[rs->num_ss - 1]) == 0)
492 				continue;
493 			if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
494 				gmax = g->measured;
495 				best_mcs = j;
496 				best_nss = rs->num_ss;
497 			}
498 		}
499 	}
500 
501 #ifdef RA_DEBUG
502 	if (rn->best_mcs != best_mcs || rn->best_nss != best_nss) {
503 		DPRINTF(("MCS,NSS %d,%d is best; MCS,NSS{cur|avg|loss}:",
504 		    best_mcs, best_nss));
505 		for (i = 0; i < IEEE80211_VHT_NUM_RATESETS; i++) {
506 			rs = &ieee80211_std_ratesets_11ac[i];
507 			if (rs->chan80 == 0 ||
508 			    rs->sgi != ieee80211_ra_vht_use_sgi(ni))
509 				continue;
510 			for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES; j++) {
511 				struct ieee80211_ra_vht_goodput_stats *g;
512 				g = &rn->g[i][j];
513 				if ((rn->valid_rates[rs->num_ss - 1] &
514 				    (1 << j)) == 0)
515 					continue;
516 				DPRINTF((" %d,%d{%s|", j, rs->num_ss,
517 				    ra_vht_fp_sprintf(g->measured)));
518 				DPRINTF(("%s|", ra_vht_fp_sprintf(g->average)));
519 				DPRINTF(("%s%%}", ra_vht_fp_sprintf(g->loss)));
520 			}
521 		}
522 		DPRINTF(("\n"));
523 	}
524 #endif
525 	rn->best_mcs = best_mcs;
526 	rn->best_nss = best_nss;
527 }
528 
529 void
ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node * rn,struct ieee80211_node * ni)530 ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *rn,
531     struct ieee80211_node *ni)
532 {
533 	/* Select the next rate to probe. */
534 	rn->probed_rates[ni->ni_vht_ss - 1] |= (1 << ni->ni_txmcs);
535 	ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
536 }
537 
538 void
ieee80211_ra_vht_init_valid_rates(struct ieee80211com * ic,struct ieee80211_node * ni,struct ieee80211_ra_vht_node * rn)539 ieee80211_ra_vht_init_valid_rates(struct ieee80211com *ic,
540     struct ieee80211_node *ni, struct ieee80211_ra_vht_node *rn)
541 {
542 	int nss, ic_max_mcs, ni_max_mcs, max_mcs;
543 
544 	memset(rn->max_mcs, 0, sizeof(rn->max_mcs));
545 	memset(rn->valid_rates, 0, sizeof(rn->valid_rates));
546 
547 	for (nss = 1; nss <= IEEE80211_VHT_NUM_SS; nss++) {
548 		ic_max_mcs = ieee80211_ra_vht_get_max_mcs(ic->ic_vht_txmcs,
549 		    nss, IEEE80211_CHAN_40MHZ_ALLOWED(ic->ic_bss->ni_chan));
550 		ni_max_mcs = ieee80211_ra_vht_get_max_mcs(ni->ni_vht_rxmcs,
551 		    nss, ieee80211_node_supports_ht_chan40(ni));
552 		if ((ic_max_mcs != 7 && ic_max_mcs != 8 && ic_max_mcs != 9) ||
553 		    (ni_max_mcs != 7 && ni_max_mcs != 8 && ni_max_mcs != 9))
554 			continue;
555 
556 		max_mcs = MIN(ic_max_mcs, ni_max_mcs);
557 		rn->max_mcs[nss - 1] = max_mcs;
558 		rn->valid_rates[nss - 1] = ((1 << (max_mcs + 1)) - 1);
559 	}
560 }
561 
562 int
ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats * g)563 ieee80211_ra_vht_probe_valid(struct ieee80211_ra_vht_goodput_stats *g)
564 {
565 	/* 128 packets make up a valid probe in any case. */
566 	if (g->nprobe_pkts >= 128)
567 		return 1;
568 
569 	/* 8 packets with > 75% loss make a valid probe, too. */
570 	if (g->nprobe_pkts >= 8 &&
571 	    g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4)
572 		return 1;
573 
574 	return 0;
575 }
576 
577 void
ieee80211_ra_vht_add_stats(struct ieee80211_ra_vht_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni,int mcs,int nss,uint32_t total,uint32_t fail)578 ieee80211_ra_vht_add_stats(struct ieee80211_ra_vht_node *rn,
579     struct ieee80211com *ic, struct ieee80211_node *ni,
580     int mcs, int nss, uint32_t total, uint32_t fail)
581 {
582 	static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */
583 	static const uint64_t beta =  RA_FP_1 / 4; /* 1/4 = 0.25 */
584 	int s;
585 	const struct ieee80211_vht_rateset *rs;
586 	struct ieee80211_ra_vht_goodput_stats *g;
587 	uint64_t sfer, rate, delta;
588 
589 	/*
590 	 * Ignore invalid values. These values may come from hardware
591 	 * so asserting valid values via panic is not appropriate.
592 	 */
593 	if (mcs < 0 || mcs >= IEEE80211_VHT_RATESET_MAX_NRATES)
594 		return;
595 	if (nss <= 0 || nss > IEEE80211_VHT_NUM_SS)
596 		return;
597 	if (total == 0)
598 		return;
599 
600 	s = splnet();
601 
602 	rs = ieee80211_ra_vht_get_rateset(mcs, nss, 0, 1,
603 	    ieee80211_ra_vht_use_sgi(ni));
604 	g = &rn->g[rs->idx][mcs];
605 	g->nprobe_pkts += total;
606 	g->nprobe_fail += fail;
607 
608 	if (!ieee80211_ra_vht_probe_valid(g)) {
609 		splx(s);
610 		return;
611 	}
612 	rn->valid_probes[nss - 1] |= 1U << mcs;
613 
614 	if (g->nprobe_fail > g->nprobe_pkts) {
615 		DPRINTF(("%s fail %u > pkts %u\n",
616 		    ether_sprintf(ni->ni_macaddr),
617 		    g->nprobe_fail, g->nprobe_pkts));
618 		g->nprobe_fail = g->nprobe_pkts;
619 	}
620 
621 	sfer = g->nprobe_fail << RA_FP_SHIFT;
622 	sfer /= g->nprobe_pkts;
623 	g->nprobe_fail = 0;
624 	g->nprobe_pkts = 0;
625 
626 	rate = ieee80211_ra_vht_get_txrate(mcs, nss, 0, 1,
627 	    ieee80211_ra_vht_use_sgi(ni));
628 
629 	g->loss = sfer * 100;
630 	g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate);
631 	g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average);
632 	g->average += RA_FP_MUL(alpha, g->measured);
633 
634 	g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation);
635 	if (g->average > g->measured)
636 		delta = g->average - g->measured;
637 	else
638 		delta = g->measured - g->average;
639 	g->stddeviation += RA_FP_MUL(beta, delta);
640 
641 	splx(s);
642 }
643 
644 void
ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni)645 ieee80211_ra_vht_choose(struct ieee80211_ra_vht_node *rn,
646     struct ieee80211com *ic, struct ieee80211_node *ni)
647 {
648 	struct ieee80211_ra_vht_goodput_stats *g;
649 	int s;
650 	int sgi = ieee80211_ra_vht_use_sgi(ni);
651 	const struct ieee80211_vht_rateset *rs, *rsnext;
652 	int nss = ni->ni_vht_ss;
653 
654 	s = splnet();
655 
656 	if (rn->valid_rates[0] == 0) {
657 		ieee80211_ra_vht_init_valid_rates(ic, ni, rn);
658 		if (rn->valid_rates[0] == 0)
659 			panic("VHT not supported");
660 	}
661 
662 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
663 	g = &rn->g[rs->idx][ni->ni_txmcs];
664 
665 	if (rn->probing) {
666 		/* Probe another rate or settle at the best rate. */
667 		if (!(rn->valid_probes[nss - 1] & (1UL << ni->ni_txmcs))) {
668 			splx(s);
669 			return;
670 		}
671 		ieee80211_ra_vht_probe_clear(g);
672 		if (!ieee80211_ra_vht_intra_mode_ra_finished(rn, ni)) {
673 			ieee80211_ra_vht_probe_next_rate(rn, ni);
674 			DPRINTFN(3, ("probing MCS,NSS %d,%d\n",
675 			    ni->ni_txmcs, ni->ni_vht_ss));
676 		} else if (ieee80211_ra_vht_inter_mode_ra_finished(rn, ni)) {
677 			ieee80211_ra_vht_best_rate(rn, ni);
678 			ni->ni_txmcs = rn->best_mcs;
679 			ni->ni_vht_ss = rn->best_nss;
680 			ieee80211_ra_vht_probe_done(rn, nss);
681 		}
682 
683 		splx(s);
684 		return;
685 	} else {
686 		rn->valid_probes[nss - 1] = 0;
687 	}
688 
689 
690 	rs = ieee80211_ra_vht_get_rateset(ni->ni_txmcs, nss, 0, 1, sgi);
691 	if ((g->measured >> RA_FP_SHIFT) == 0LL ||
692 	    (g->average >= 3 * g->stddeviation &&
693 	    g->measured < g->average - 3 * g->stddeviation)) {
694 		/* Channel becomes bad. Probe downwards. */
695 		rn->probing = IEEE80211_RA_PROBING_DOWN;
696 		rn->probed_rates[nss - 1] = 0;
697 		if (ni->ni_txmcs == 0) {
698 			rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
699 			if (rsnext) {
700 				ieee80211_ra_vht_probe_next_rateset(rn, ni,
701 				    rsnext);
702 			} else {
703 				/* Cannot probe further down. */
704 				rn->probing = IEEE80211_RA_NOT_PROBING;
705 			}
706 		} else {
707 			ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
708 			rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs);
709 		}
710 	} else if (g->loss < 2 * RA_FP_1 ||
711 	    g->measured > g->average + 3 * g->stddeviation) {
712 		/* Channel becomes good. */
713 		rn->probing = IEEE80211_RA_PROBING_UP;
714 		rn->probed_rates[nss - 1] = 0;
715 		if (ni->ni_txmcs == rn->max_mcs[nss - 1]) {
716 			rsnext = ieee80211_ra_vht_next_rateset(rn, ni);
717 			if (rsnext) {
718 				ieee80211_ra_vht_probe_next_rateset(rn, ni,
719 				    rsnext);
720 			} else {
721 				/* Cannot probe further up. */
722 				rn->probing = IEEE80211_RA_NOT_PROBING;
723 			}
724 		} else {
725 			ni->ni_txmcs = ieee80211_ra_vht_next_mcs(rn, ni);
726 			rn->candidate_rates[nss - 1] = (1 << ni->ni_txmcs);
727 		}
728 	} else {
729 		/* Remain at current rate. */
730 		rn->probing = IEEE80211_RA_NOT_PROBING;
731 		rn->probed_rates[nss - 1] = 0;
732 		rn->candidate_rates[nss - 1] = 0;
733 	}
734 
735 	splx(s);
736 
737 	if (rn->probing) {
738 		if (rn->probing & IEEE80211_RA_PROBING_UP)
739 			DPRINTFN(2, ("channel becomes good; probe up\n"));
740 		else
741 			DPRINTFN(2, ("channel becomes bad; probe down\n"));
742 
743 		DPRINTFN(3, ("measured: %s Mbit/s\n",
744 		    ra_vht_fp_sprintf(g->measured)));
745 		DPRINTFN(3, ("average: %s Mbit/s\n",
746 		    ra_vht_fp_sprintf(g->average)));
747 		DPRINTFN(3, ("stddeviation: %s\n",
748 		    ra_vht_fp_sprintf(g->stddeviation)));
749 		DPRINTFN(3, ("loss: %s%%\n", ra_vht_fp_sprintf(g->loss)));
750 	}
751 }
752 
753 void
ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node * rn)754 ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node *rn)
755 {
756 	memset(rn, 0, sizeof(*rn));
757 	rn->best_nss = 1;
758 }
759