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
34int	ieee80211_ra_vht_next_intra_rate(struct ieee80211_ra_vht_node *,
35	    struct ieee80211_node *);
36const struct ieee80211_vht_rateset * ieee80211_ra_vht_next_rateset(
37		    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
38int	ieee80211_ra_vht_best_mcs_in_rateset(struct ieee80211_ra_vht_node *,
39	    const struct ieee80211_vht_rateset *);
40void	ieee80211_ra_vht_probe_next_rateset(struct ieee80211_ra_vht_node *,
41	    struct ieee80211_node *, const struct ieee80211_vht_rateset *);
42int	ieee80211_ra_vht_next_mcs(struct ieee80211_ra_vht_node *,
43	    struct ieee80211_node *);
44void	ieee80211_ra_vht_probe_done(struct ieee80211_ra_vht_node *, int);
45int	ieee80211_ra_vht_intra_mode_ra_finished(
46	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
47void	ieee80211_ra_vht_trigger_next_rateset(struct ieee80211_ra_vht_node *,
48	    struct ieee80211_node *);
49int	ieee80211_ra_vht_inter_mode_ra_finished(
50	    struct ieee80211_ra_vht_node *, struct ieee80211_node *);
51void	ieee80211_ra_vht_best_rate(struct ieee80211_ra_vht_node *,
52	    struct ieee80211_node *);
53void	ieee80211_ra_vht_probe_next_rate(struct ieee80211_ra_vht_node *,
54	    struct ieee80211_node *);
55void	ieee80211_ra_vht_init_valid_rates(struct ieee80211com *,
56	    struct ieee80211_node *, struct ieee80211_ra_vht_node *);
57int	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)
75int 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
82void
83ra_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
96char *
97ra_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
112const struct ieee80211_vht_rateset *
113ieee80211_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
129int
130ieee80211_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
151uint64_t
152ieee80211_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
173int
174ieee80211_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
183int
184ieee80211_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
214int
215ieee80211_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
231const struct ieee80211_vht_rateset *
232ieee80211_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
278int
279ieee80211_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
298void
299ieee80211_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
349int
350ieee80211_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
365void
366ieee80211_ra_vht_probe_clear(struct ieee80211_ra_vht_goodput_stats *g)
367{
368	g->nprobe_pkts = 0;
369	g->nprobe_fail = 0;
370}
371
372void
373ieee80211_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
381int
382ieee80211_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
454void
455ieee80211_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
468int
469ieee80211_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
475void
476ieee80211_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
529void
530ieee80211_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
538void
539ieee80211_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
562int
563ieee80211_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
577void
578ieee80211_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
644void
645ieee80211_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
753void
754ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node *rn)
755{
756	memset(rn, 0, sizeof(*rn));
757	rn->best_nss = 1;
758}
759