1*04171cfcSAugustin Cavalier /* $OpenBSD: ieee80211_ra.c,v 1.5 2022/03/19 10:28:44 stsp Exp $ */
2*04171cfcSAugustin Cavalier
3*04171cfcSAugustin Cavalier /*
4*04171cfcSAugustin Cavalier * Copyright (c) 2021 Christian Ehrhardt <ehrhardt@genua.de>
5*04171cfcSAugustin Cavalier * Copyright (c) 2016, 2021 Stefan Sperling <stsp@openbsd.org>
6*04171cfcSAugustin Cavalier * Copyright (c) 2016 Theo Buehler <tb@openbsd.org>
7*04171cfcSAugustin Cavalier *
8*04171cfcSAugustin Cavalier * Permission to use, copy, modify, and distribute this software for any
9*04171cfcSAugustin Cavalier * purpose with or without fee is hereby granted, provided that the above
10*04171cfcSAugustin Cavalier * copyright notice and this permission notice appear in all copies.
11*04171cfcSAugustin Cavalier *
12*04171cfcSAugustin Cavalier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13*04171cfcSAugustin Cavalier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14*04171cfcSAugustin Cavalier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15*04171cfcSAugustin Cavalier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16*04171cfcSAugustin Cavalier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17*04171cfcSAugustin Cavalier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18*04171cfcSAugustin Cavalier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19*04171cfcSAugustin Cavalier */
20*04171cfcSAugustin Cavalier
21*04171cfcSAugustin Cavalier #include <sys/param.h>
22*04171cfcSAugustin Cavalier #include <sys/systm.h>
23*04171cfcSAugustin Cavalier #include <sys/socket.h>
24*04171cfcSAugustin Cavalier
25*04171cfcSAugustin Cavalier #include <net/if.h>
26*04171cfcSAugustin Cavalier #include <net/if_media.h>
27*04171cfcSAugustin Cavalier
28*04171cfcSAugustin Cavalier #include <netinet/in.h>
29*04171cfcSAugustin Cavalier #include <netinet/if_ether.h>
30*04171cfcSAugustin Cavalier
31*04171cfcSAugustin Cavalier #include <net80211/ieee80211_var.h>
32*04171cfcSAugustin Cavalier #include <net80211/ieee80211_ra.h>
33*04171cfcSAugustin Cavalier
34*04171cfcSAugustin Cavalier int ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *,
35*04171cfcSAugustin Cavalier struct ieee80211_node *);
36*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset * ieee80211_ra_next_rateset(
37*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *);
38*04171cfcSAugustin Cavalier int ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *,
39*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *);
40*04171cfcSAugustin Cavalier void ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *,
41*04171cfcSAugustin Cavalier struct ieee80211_node *, const struct ieee80211_ht_rateset *);
42*04171cfcSAugustin Cavalier int ieee80211_ra_next_mcs(struct ieee80211_ra_node *,
43*04171cfcSAugustin Cavalier struct ieee80211_node *);
44*04171cfcSAugustin Cavalier void ieee80211_ra_probe_done(struct ieee80211_ra_node *);
45*04171cfcSAugustin Cavalier int ieee80211_ra_intra_mode_ra_finished(
46*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *);
47*04171cfcSAugustin Cavalier void ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *,
48*04171cfcSAugustin Cavalier struct ieee80211_node *);
49*04171cfcSAugustin Cavalier int ieee80211_ra_inter_mode_ra_finished(
50*04171cfcSAugustin Cavalier struct ieee80211_ra_node *, struct ieee80211_node *);
51*04171cfcSAugustin Cavalier int ieee80211_ra_best_rate(struct ieee80211_ra_node *,
52*04171cfcSAugustin Cavalier struct ieee80211_node *);
53*04171cfcSAugustin Cavalier void ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *,
54*04171cfcSAugustin Cavalier struct ieee80211_node *);
55*04171cfcSAugustin Cavalier int ieee80211_ra_valid_tx_mcs(struct ieee80211com *, int);
56*04171cfcSAugustin Cavalier uint32_t ieee80211_ra_valid_rates(struct ieee80211com *,
57*04171cfcSAugustin Cavalier struct ieee80211_node *);
58*04171cfcSAugustin Cavalier int ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *);
59*04171cfcSAugustin Cavalier
60*04171cfcSAugustin Cavalier /* We use fixed point arithmetic with 64 bit integers. */
61*04171cfcSAugustin Cavalier #define RA_FP_SHIFT 21
62*04171cfcSAugustin Cavalier #define RA_FP_INT(x) (x ## ULL << RA_FP_SHIFT) /* the integer x */
63*04171cfcSAugustin Cavalier #define RA_FP_1 RA_FP_INT(1)
64*04171cfcSAugustin Cavalier
65*04171cfcSAugustin Cavalier /* Multiply two fixed point numbers. */
66*04171cfcSAugustin Cavalier #define RA_FP_MUL(a, b) \
67*04171cfcSAugustin Cavalier (((a) * (b)) >> RA_FP_SHIFT)
68*04171cfcSAugustin Cavalier
69*04171cfcSAugustin Cavalier /* Divide two fixed point numbers. */
70*04171cfcSAugustin Cavalier #define RA_FP_DIV(a, b) \
71*04171cfcSAugustin Cavalier (b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT) / (b)))
72*04171cfcSAugustin Cavalier
73*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
74*04171cfcSAugustin Cavalier #define DPRINTF(x) do { if (ra_debug > 0) printf x; } while (0)
75*04171cfcSAugustin Cavalier #define DPRINTFN(n, x) do { if (ra_debug >= (n)) printf x; } while (0)
76*04171cfcSAugustin Cavalier int ra_debug = 0;
77*04171cfcSAugustin Cavalier #else
78*04171cfcSAugustin Cavalier #define DPRINTF(x) do { ; } while (0)
79*04171cfcSAugustin Cavalier #define DPRINTFN(n, x) do { ; } while (0)
80*04171cfcSAugustin Cavalier #endif
81*04171cfcSAugustin Cavalier
82*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
83*04171cfcSAugustin Cavalier void
ra_fixedp_split(uint32_t * i,uint32_t * f,uint64_t fp)84*04171cfcSAugustin Cavalier ra_fixedp_split(uint32_t *i, uint32_t *f, uint64_t fp)
85*04171cfcSAugustin Cavalier {
86*04171cfcSAugustin Cavalier uint64_t tmp;
87*04171cfcSAugustin Cavalier
88*04171cfcSAugustin Cavalier /* integer part */
89*04171cfcSAugustin Cavalier *i = (fp >> RA_FP_SHIFT);
90*04171cfcSAugustin Cavalier
91*04171cfcSAugustin Cavalier /* fractional part */
92*04171cfcSAugustin Cavalier tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT)));
93*04171cfcSAugustin Cavalier tmp *= 100;
94*04171cfcSAugustin Cavalier *f = (uint32_t)(tmp >> RA_FP_SHIFT);
95*04171cfcSAugustin Cavalier }
96*04171cfcSAugustin Cavalier
97*04171cfcSAugustin Cavalier char *
ra_fp_sprintf(uint64_t fp)98*04171cfcSAugustin Cavalier ra_fp_sprintf(uint64_t fp)
99*04171cfcSAugustin Cavalier {
100*04171cfcSAugustin Cavalier uint32_t i, f;
101*04171cfcSAugustin Cavalier static char buf[64];
102*04171cfcSAugustin Cavalier int ret;
103*04171cfcSAugustin Cavalier
104*04171cfcSAugustin Cavalier ra_fixedp_split(&i, &f, fp);
105*04171cfcSAugustin Cavalier ret = snprintf(buf, sizeof(buf), "%u.%02u", i, f);
106*04171cfcSAugustin Cavalier if (ret == -1 || ret >= sizeof(buf))
107*04171cfcSAugustin Cavalier return "ERR";
108*04171cfcSAugustin Cavalier
109*04171cfcSAugustin Cavalier return buf;
110*04171cfcSAugustin Cavalier }
111*04171cfcSAugustin Cavalier #endif /* RA_DEBUG */
112*04171cfcSAugustin Cavalier
113*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *
ieee80211_ra_get_ht_rateset(int mcs,int chan40,int sgi)114*04171cfcSAugustin Cavalier ieee80211_ra_get_ht_rateset(int mcs, int chan40, int sgi)
115*04171cfcSAugustin Cavalier {
116*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
117*04171cfcSAugustin Cavalier int i;
118*04171cfcSAugustin Cavalier
119*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_NUM_RATESETS; i++) {
120*04171cfcSAugustin Cavalier rs = &ieee80211_std_ratesets_11n[i];
121*04171cfcSAugustin Cavalier if (chan40 == rs->chan40 && sgi == rs->sgi &&
122*04171cfcSAugustin Cavalier mcs >= rs->min_mcs && mcs <= rs->max_mcs)
123*04171cfcSAugustin Cavalier return rs;
124*04171cfcSAugustin Cavalier }
125*04171cfcSAugustin Cavalier
126*04171cfcSAugustin Cavalier panic("MCS %d is not part of any rateset", mcs);
127*04171cfcSAugustin Cavalier }
128*04171cfcSAugustin Cavalier
129*04171cfcSAugustin Cavalier int
ieee80211_ra_use_ht_sgi(struct ieee80211_node * ni)130*04171cfcSAugustin Cavalier ieee80211_ra_use_ht_sgi(struct ieee80211_node *ni)
131*04171cfcSAugustin Cavalier {
132*04171cfcSAugustin Cavalier if ((ni->ni_chan->ic_flags & IEEE80211_CHAN_40MHZ) &&
133*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni)) {
134*04171cfcSAugustin Cavalier if (ni->ni_flags & IEEE80211_NODE_HT_SGI40)
135*04171cfcSAugustin Cavalier return 1;
136*04171cfcSAugustin Cavalier } else if (ni->ni_flags & IEEE80211_NODE_HT_SGI20)
137*04171cfcSAugustin Cavalier return 1;
138*04171cfcSAugustin Cavalier
139*04171cfcSAugustin Cavalier return 0;
140*04171cfcSAugustin Cavalier }
141*04171cfcSAugustin Cavalier
142*04171cfcSAugustin Cavalier /*
143*04171cfcSAugustin Cavalier * Update goodput statistics.
144*04171cfcSAugustin Cavalier */
145*04171cfcSAugustin Cavalier
146*04171cfcSAugustin Cavalier uint64_t
ieee80211_ra_get_txrate(int mcs,int chan40,int sgi)147*04171cfcSAugustin Cavalier ieee80211_ra_get_txrate(int mcs, int chan40, int sgi)
148*04171cfcSAugustin Cavalier {
149*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
150*04171cfcSAugustin Cavalier uint64_t txrate;
151*04171cfcSAugustin Cavalier
152*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi);
153*04171cfcSAugustin Cavalier txrate = rs->rates[mcs - rs->min_mcs];
154*04171cfcSAugustin Cavalier txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
155*04171cfcSAugustin Cavalier txrate *= 500; /* convert to kbit/s */
156*04171cfcSAugustin Cavalier txrate /= 1000; /* convert to mbit/s */
157*04171cfcSAugustin Cavalier
158*04171cfcSAugustin Cavalier return txrate;
159*04171cfcSAugustin Cavalier }
160*04171cfcSAugustin Cavalier
161*04171cfcSAugustin Cavalier /*
162*04171cfcSAugustin Cavalier * Rate selection.
163*04171cfcSAugustin Cavalier */
164*04171cfcSAugustin Cavalier
165*04171cfcSAugustin Cavalier /* A rate's goodput has to be at least this much larger to be "better". */
166*04171cfcSAugustin Cavalier #define IEEE80211_RA_RATE_THRESHOLD (RA_FP_1 / 64) /* ~ 0.015 */
167*04171cfcSAugustin Cavalier
168*04171cfcSAugustin Cavalier int
ieee80211_ra_next_lower_intra_rate(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)169*04171cfcSAugustin Cavalier ieee80211_ra_next_lower_intra_rate(struct ieee80211_ra_node *rn,
170*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
171*04171cfcSAugustin Cavalier {
172*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
173*04171cfcSAugustin Cavalier int i, next;
174*04171cfcSAugustin Cavalier
175*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
176*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
177*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs)
178*04171cfcSAugustin Cavalier return rs->min_mcs;
179*04171cfcSAugustin Cavalier
180*04171cfcSAugustin Cavalier next = ni->ni_txmcs;
181*04171cfcSAugustin Cavalier for (i = rs->nrates - 1; i >= 0; i--) {
182*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
183*04171cfcSAugustin Cavalier continue;
184*04171cfcSAugustin Cavalier if (i + rs->min_mcs < ni->ni_txmcs) {
185*04171cfcSAugustin Cavalier next = i + rs->min_mcs;
186*04171cfcSAugustin Cavalier break;
187*04171cfcSAugustin Cavalier }
188*04171cfcSAugustin Cavalier }
189*04171cfcSAugustin Cavalier
190*04171cfcSAugustin Cavalier return next;
191*04171cfcSAugustin Cavalier }
192*04171cfcSAugustin Cavalier
193*04171cfcSAugustin Cavalier int
ieee80211_ra_next_intra_rate(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)194*04171cfcSAugustin Cavalier ieee80211_ra_next_intra_rate(struct ieee80211_ra_node *rn,
195*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
196*04171cfcSAugustin Cavalier {
197*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
198*04171cfcSAugustin Cavalier int i, next;
199*04171cfcSAugustin Cavalier
200*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
201*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
202*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs)
203*04171cfcSAugustin Cavalier return rs->max_mcs;
204*04171cfcSAugustin Cavalier
205*04171cfcSAugustin Cavalier next = ni->ni_txmcs;
206*04171cfcSAugustin Cavalier for (i = 0; i < rs->nrates; i++) {
207*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << (i + rs->min_mcs))) == 0)
208*04171cfcSAugustin Cavalier continue;
209*04171cfcSAugustin Cavalier if (i + rs->min_mcs > ni->ni_txmcs) {
210*04171cfcSAugustin Cavalier next = i + rs->min_mcs;
211*04171cfcSAugustin Cavalier break;
212*04171cfcSAugustin Cavalier }
213*04171cfcSAugustin Cavalier }
214*04171cfcSAugustin Cavalier
215*04171cfcSAugustin Cavalier return next;
216*04171cfcSAugustin Cavalier }
217*04171cfcSAugustin Cavalier
218*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *
ieee80211_ra_next_rateset(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)219*04171cfcSAugustin Cavalier ieee80211_ra_next_rateset(struct ieee80211_ra_node *rn,
220*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
221*04171cfcSAugustin Cavalier {
222*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs, *rsnext;
223*04171cfcSAugustin Cavalier int next;
224*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni);
225*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni);
226*04171cfcSAugustin Cavalier int mcs = ni->ni_txmcs;
227*04171cfcSAugustin Cavalier
228*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(mcs, chan40, sgi);
229*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP) {
230*04171cfcSAugustin Cavalier if (rs->max_mcs == 7) { /* MCS 0-7 */
231*04171cfcSAugustin Cavalier if (chan40)
232*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 :
233*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2_40;
234*04171cfcSAugustin Cavalier else
235*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI :
236*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2;
237*04171cfcSAugustin Cavalier } else if (rs->max_mcs == 15) { /* MCS 8-15 */
238*04171cfcSAugustin Cavalier if (chan40)
239*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 :
240*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3_40;
241*04171cfcSAugustin Cavalier else
242*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI :
243*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3;
244*04171cfcSAugustin Cavalier } else if (rs->max_mcs == 23) { /* MCS 16-23 */
245*04171cfcSAugustin Cavalier if (chan40)
246*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI40 :
247*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO4_40;
248*04171cfcSAugustin Cavalier else
249*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO4_SGI :
250*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO4;
251*04171cfcSAugustin Cavalier } else /* MCS 24-31 */
252*04171cfcSAugustin Cavalier return NULL;
253*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
254*04171cfcSAugustin Cavalier if (rs->min_mcs == 24) { /* MCS 24-31 */
255*04171cfcSAugustin Cavalier if (chan40)
256*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI40 :
257*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3_40;
258*04171cfcSAugustin Cavalier else
259*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO3_SGI :
260*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO3;
261*04171cfcSAugustin Cavalier } else if (rs->min_mcs == 16) { /* MCS 16-23 */
262*04171cfcSAugustin Cavalier if (chan40)
263*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI40 :
264*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2_40;
265*04171cfcSAugustin Cavalier else
266*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_MIMO2_SGI :
267*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_MIMO2;
268*04171cfcSAugustin Cavalier } else if (rs->min_mcs == 8) { /* MCS 8-15 */
269*04171cfcSAugustin Cavalier if (chan40)
270*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_SISO_SGI40 :
271*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_SISO_40;
272*04171cfcSAugustin Cavalier else
273*04171cfcSAugustin Cavalier next = sgi ? IEEE80211_HT_RATESET_SISO_SGI :
274*04171cfcSAugustin Cavalier IEEE80211_HT_RATESET_SISO;
275*04171cfcSAugustin Cavalier } else /* MCS 0-7 */
276*04171cfcSAugustin Cavalier return NULL;
277*04171cfcSAugustin Cavalier } else
278*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing);
279*04171cfcSAugustin Cavalier
280*04171cfcSAugustin Cavalier rsnext = &ieee80211_std_ratesets_11n[next];
281*04171cfcSAugustin Cavalier if ((rsnext->mcs_mask & rn->valid_rates) == 0)
282*04171cfcSAugustin Cavalier return NULL;
283*04171cfcSAugustin Cavalier
284*04171cfcSAugustin Cavalier return rsnext;
285*04171cfcSAugustin Cavalier }
286*04171cfcSAugustin Cavalier
287*04171cfcSAugustin Cavalier int
ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node * rn,const struct ieee80211_ht_rateset * rs)288*04171cfcSAugustin Cavalier ieee80211_ra_best_mcs_in_rateset(struct ieee80211_ra_node *rn,
289*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs)
290*04171cfcSAugustin Cavalier {
291*04171cfcSAugustin Cavalier uint64_t gmax = 0;
292*04171cfcSAugustin Cavalier int i, best_mcs = rs->min_mcs;
293*04171cfcSAugustin Cavalier
294*04171cfcSAugustin Cavalier for (i = 0; i < rs->nrates; i++) {
295*04171cfcSAugustin Cavalier int mcs = rs->min_mcs + i;
296*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[mcs];
297*04171cfcSAugustin Cavalier if (((1 << mcs) & rn->valid_rates) == 0)
298*04171cfcSAugustin Cavalier continue;
299*04171cfcSAugustin Cavalier if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
300*04171cfcSAugustin Cavalier gmax = g->measured;
301*04171cfcSAugustin Cavalier best_mcs = mcs;
302*04171cfcSAugustin Cavalier }
303*04171cfcSAugustin Cavalier }
304*04171cfcSAugustin Cavalier
305*04171cfcSAugustin Cavalier return best_mcs;
306*04171cfcSAugustin Cavalier }
307*04171cfcSAugustin Cavalier
308*04171cfcSAugustin Cavalier void
ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node * rn,struct ieee80211_node * ni,const struct ieee80211_ht_rateset * rsnext)309*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(struct ieee80211_ra_node *rn,
310*04171cfcSAugustin Cavalier struct ieee80211_node *ni, const struct ieee80211_ht_rateset *rsnext)
311*04171cfcSAugustin Cavalier {
312*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
313*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g;
314*04171cfcSAugustin Cavalier int best_mcs, i;
315*04171cfcSAugustin Cavalier
316*04171cfcSAugustin Cavalier /* Find most recently measured best MCS from the current rateset. */
317*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs,
318*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni), ieee80211_ra_use_ht_sgi(ni));
319*04171cfcSAugustin Cavalier best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs);
320*04171cfcSAugustin Cavalier
321*04171cfcSAugustin Cavalier /* Switch to the next rateset. */
322*04171cfcSAugustin Cavalier ni->ni_txmcs = rsnext->min_mcs;
323*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << rsnext->min_mcs)) == 0)
324*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_intra_rate(rn, ni);
325*04171cfcSAugustin Cavalier
326*04171cfcSAugustin Cavalier /* Select the lowest rate from the next rateset with loss-free
327*04171cfcSAugustin Cavalier * goodput close to the current best measurement. */
328*04171cfcSAugustin Cavalier g = &rn->g[best_mcs];
329*04171cfcSAugustin Cavalier for (i = 0; i < rsnext->nrates; i++) {
330*04171cfcSAugustin Cavalier int mcs = rsnext->min_mcs + i;
331*04171cfcSAugustin Cavalier uint64_t txrate = rsnext->rates[i];
332*04171cfcSAugustin Cavalier
333*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << mcs)) == 0)
334*04171cfcSAugustin Cavalier continue;
335*04171cfcSAugustin Cavalier
336*04171cfcSAugustin Cavalier txrate = txrate * 500; /* convert to kbit/s */
337*04171cfcSAugustin Cavalier txrate <<= RA_FP_SHIFT; /* convert to fixed-point */
338*04171cfcSAugustin Cavalier txrate /= 1000; /* convert to mbit/s */
339*04171cfcSAugustin Cavalier
340*04171cfcSAugustin Cavalier if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD) {
341*04171cfcSAugustin Cavalier ni->ni_txmcs = mcs;
342*04171cfcSAugustin Cavalier break;
343*04171cfcSAugustin Cavalier }
344*04171cfcSAugustin Cavalier }
345*04171cfcSAugustin Cavalier /* If all rates are lower the maximum rate is the closest match. */
346*04171cfcSAugustin Cavalier if (i == rsnext->nrates)
347*04171cfcSAugustin Cavalier ni->ni_txmcs = rsnext->max_mcs;
348*04171cfcSAugustin Cavalier
349*04171cfcSAugustin Cavalier /* Add rates from the next rateset as candidates. */
350*04171cfcSAugustin Cavalier rn->candidate_rates |= (1 << ni->ni_txmcs);
351*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP) {
352*04171cfcSAugustin Cavalier rn->candidate_rates |=
353*04171cfcSAugustin Cavalier (1 << ieee80211_ra_next_intra_rate(rn, ni));
354*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
355*04171cfcSAugustin Cavalier rn->candidate_rates |=
356*04171cfcSAugustin Cavalier (1 << ieee80211_ra_next_lower_intra_rate(rn, ni));
357*04171cfcSAugustin Cavalier } else
358*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing);
359*04171cfcSAugustin Cavalier }
360*04171cfcSAugustin Cavalier
361*04171cfcSAugustin Cavalier int
ieee80211_ra_next_mcs(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)362*04171cfcSAugustin Cavalier ieee80211_ra_next_mcs(struct ieee80211_ra_node *rn,
363*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
364*04171cfcSAugustin Cavalier {
365*04171cfcSAugustin Cavalier int next;
366*04171cfcSAugustin Cavalier
367*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_DOWN)
368*04171cfcSAugustin Cavalier next = ieee80211_ra_next_lower_intra_rate(rn, ni);
369*04171cfcSAugustin Cavalier else if (rn->probing & IEEE80211_RA_PROBING_UP)
370*04171cfcSAugustin Cavalier next = ieee80211_ra_next_intra_rate(rn, ni);
371*04171cfcSAugustin Cavalier else
372*04171cfcSAugustin Cavalier panic("%s: invalid probing mode %d", __func__, rn->probing);
373*04171cfcSAugustin Cavalier
374*04171cfcSAugustin Cavalier return next;
375*04171cfcSAugustin Cavalier }
376*04171cfcSAugustin Cavalier
377*04171cfcSAugustin Cavalier void
ieee80211_ra_probe_clear(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)378*04171cfcSAugustin Cavalier ieee80211_ra_probe_clear(struct ieee80211_ra_node *rn,
379*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
380*04171cfcSAugustin Cavalier {
381*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs];
382*04171cfcSAugustin Cavalier
383*04171cfcSAugustin Cavalier g->nprobe_pkts = 0;
384*04171cfcSAugustin Cavalier g->nprobe_fail = 0;
385*04171cfcSAugustin Cavalier }
386*04171cfcSAugustin Cavalier
387*04171cfcSAugustin Cavalier void
ieee80211_ra_probe_done(struct ieee80211_ra_node * rn)388*04171cfcSAugustin Cavalier ieee80211_ra_probe_done(struct ieee80211_ra_node *rn)
389*04171cfcSAugustin Cavalier {
390*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING;
391*04171cfcSAugustin Cavalier rn->probed_rates = 0;
392*04171cfcSAugustin Cavalier rn->valid_probes = 0;
393*04171cfcSAugustin Cavalier rn->candidate_rates = 0;
394*04171cfcSAugustin Cavalier }
395*04171cfcSAugustin Cavalier
396*04171cfcSAugustin Cavalier int
ieee80211_ra_intra_mode_ra_finished(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)397*04171cfcSAugustin Cavalier ieee80211_ra_intra_mode_ra_finished(struct ieee80211_ra_node *rn,
398*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
399*04171cfcSAugustin Cavalier {
400*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs;
401*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs];
402*04171cfcSAugustin Cavalier int next_mcs, best_mcs;
403*04171cfcSAugustin Cavalier uint64_t next_rate;
404*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni);
405*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni);
406*04171cfcSAugustin Cavalier
407*04171cfcSAugustin Cavalier rn->probed_rates = (rn->probed_rates | (1 << ni->ni_txmcs));
408*04171cfcSAugustin Cavalier
409*04171cfcSAugustin Cavalier /* Check if the min/max MCS in this rateset has been probed. */
410*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi);
411*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_DOWN) {
412*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs ||
413*04171cfcSAugustin Cavalier rn->probed_rates & (1 << rs->min_mcs)) {
414*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
415*04171cfcSAugustin Cavalier return 1;
416*04171cfcSAugustin Cavalier }
417*04171cfcSAugustin Cavalier } else if (rn->probing & IEEE80211_RA_PROBING_UP) {
418*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs ||
419*04171cfcSAugustin Cavalier rn->probed_rates & (1 << rs->max_mcs)) {
420*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
421*04171cfcSAugustin Cavalier return 1;
422*04171cfcSAugustin Cavalier }
423*04171cfcSAugustin Cavalier }
424*04171cfcSAugustin Cavalier
425*04171cfcSAugustin Cavalier /*
426*04171cfcSAugustin Cavalier * Check if the measured goodput is loss-free and better than the
427*04171cfcSAugustin Cavalier * loss-free goodput of the candidate rate.
428*04171cfcSAugustin Cavalier */
429*04171cfcSAugustin Cavalier next_mcs = ieee80211_ra_next_mcs(rn, ni);
430*04171cfcSAugustin Cavalier if (next_mcs == ni->ni_txmcs) {
431*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
432*04171cfcSAugustin Cavalier return 1;
433*04171cfcSAugustin Cavalier }
434*04171cfcSAugustin Cavalier next_rate = ieee80211_ra_get_txrate(next_mcs, chan40, sgi);
435*04171cfcSAugustin Cavalier if (g->loss == 0 &&
436*04171cfcSAugustin Cavalier g->measured >= next_rate + IEEE80211_RA_RATE_THRESHOLD) {
437*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
438*04171cfcSAugustin Cavalier return 1;
439*04171cfcSAugustin Cavalier }
440*04171cfcSAugustin Cavalier
441*04171cfcSAugustin Cavalier /* Check if we had a better measurement at a previously probed MCS. */
442*04171cfcSAugustin Cavalier best_mcs = ieee80211_ra_best_mcs_in_rateset(rn, rs);
443*04171cfcSAugustin Cavalier if (best_mcs != ni->ni_txmcs && (rn->probed_rates & (1 << best_mcs))) {
444*04171cfcSAugustin Cavalier if ((rn->probing & IEEE80211_RA_PROBING_UP) &&
445*04171cfcSAugustin Cavalier best_mcs < ni->ni_txmcs) {
446*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
447*04171cfcSAugustin Cavalier return 1;
448*04171cfcSAugustin Cavalier }
449*04171cfcSAugustin Cavalier if ((rn->probing & IEEE80211_RA_PROBING_DOWN) &&
450*04171cfcSAugustin Cavalier best_mcs > ni->ni_txmcs) {
451*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(rn, ni);
452*04171cfcSAugustin Cavalier return 1;
453*04171cfcSAugustin Cavalier }
454*04171cfcSAugustin Cavalier }
455*04171cfcSAugustin Cavalier
456*04171cfcSAugustin Cavalier /* Check if all rates in the set of candidate rates have been probed. */
457*04171cfcSAugustin Cavalier if ((rn->candidate_rates & rn->probed_rates) == rn->candidate_rates) {
458*04171cfcSAugustin Cavalier /* Remain in the current rateset until above checks trigger. */
459*04171cfcSAugustin Cavalier rn->probing &= ~IEEE80211_RA_PROBING_INTER;
460*04171cfcSAugustin Cavalier return 1;
461*04171cfcSAugustin Cavalier }
462*04171cfcSAugustin Cavalier
463*04171cfcSAugustin Cavalier return 0;
464*04171cfcSAugustin Cavalier }
465*04171cfcSAugustin Cavalier
466*04171cfcSAugustin Cavalier void
ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)467*04171cfcSAugustin Cavalier ieee80211_ra_trigger_next_rateset(struct ieee80211_ra_node *rn,
468*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
469*04171cfcSAugustin Cavalier {
470*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rsnext;
471*04171cfcSAugustin Cavalier
472*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni);
473*04171cfcSAugustin Cavalier if (rsnext) {
474*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni, rsnext);
475*04171cfcSAugustin Cavalier rn->probing |= IEEE80211_RA_PROBING_INTER;
476*04171cfcSAugustin Cavalier } else
477*04171cfcSAugustin Cavalier rn->probing &= ~IEEE80211_RA_PROBING_INTER;
478*04171cfcSAugustin Cavalier }
479*04171cfcSAugustin Cavalier
480*04171cfcSAugustin Cavalier int
ieee80211_ra_inter_mode_ra_finished(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)481*04171cfcSAugustin Cavalier ieee80211_ra_inter_mode_ra_finished(struct ieee80211_ra_node *rn,
482*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
483*04171cfcSAugustin Cavalier {
484*04171cfcSAugustin Cavalier return ((rn->probing & IEEE80211_RA_PROBING_INTER) == 0);
485*04171cfcSAugustin Cavalier }
486*04171cfcSAugustin Cavalier
487*04171cfcSAugustin Cavalier int
ieee80211_ra_best_rate(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)488*04171cfcSAugustin Cavalier ieee80211_ra_best_rate(struct ieee80211_ra_node *rn,
489*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
490*04171cfcSAugustin Cavalier {
491*04171cfcSAugustin Cavalier int i, best = rn->best_mcs;
492*04171cfcSAugustin Cavalier uint64_t gmax = rn->g[rn->best_mcs].measured;
493*04171cfcSAugustin Cavalier
494*04171cfcSAugustin Cavalier for (i = 0; i < nitems(rn->g); i++) {
495*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[i];
496*04171cfcSAugustin Cavalier if (((1 << i) & rn->valid_rates) == 0)
497*04171cfcSAugustin Cavalier continue;
498*04171cfcSAugustin Cavalier if (g->measured > gmax + IEEE80211_RA_RATE_THRESHOLD) {
499*04171cfcSAugustin Cavalier gmax = g->measured;
500*04171cfcSAugustin Cavalier best = i;
501*04171cfcSAugustin Cavalier }
502*04171cfcSAugustin Cavalier }
503*04171cfcSAugustin Cavalier
504*04171cfcSAugustin Cavalier #ifdef RA_DEBUG
505*04171cfcSAugustin Cavalier if (rn->best_mcs != best) {
506*04171cfcSAugustin Cavalier DPRINTF(("MCS %d is best; MCS{cur|avg|loss}:", best));
507*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) {
508*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[i];
509*04171cfcSAugustin Cavalier if ((rn->valid_rates & (1 << i)) == 0)
510*04171cfcSAugustin Cavalier continue;
511*04171cfcSAugustin Cavalier DPRINTF((" %d{%s|", i, ra_fp_sprintf(g->measured)));
512*04171cfcSAugustin Cavalier DPRINTF(("%s|", ra_fp_sprintf(g->average)));
513*04171cfcSAugustin Cavalier DPRINTF(("%s%%}", ra_fp_sprintf(g->loss)));
514*04171cfcSAugustin Cavalier }
515*04171cfcSAugustin Cavalier DPRINTF(("\n"));
516*04171cfcSAugustin Cavalier }
517*04171cfcSAugustin Cavalier #endif
518*04171cfcSAugustin Cavalier return best;
519*04171cfcSAugustin Cavalier }
520*04171cfcSAugustin Cavalier
521*04171cfcSAugustin Cavalier void
ieee80211_ra_probe_next_rate(struct ieee80211_ra_node * rn,struct ieee80211_node * ni)522*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rate(struct ieee80211_ra_node *rn,
523*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
524*04171cfcSAugustin Cavalier {
525*04171cfcSAugustin Cavalier /* Select the next rate to probe. */
526*04171cfcSAugustin Cavalier rn->probed_rates |= (1 << ni->ni_txmcs);
527*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni);
528*04171cfcSAugustin Cavalier }
529*04171cfcSAugustin Cavalier
530*04171cfcSAugustin Cavalier int
ieee80211_ra_valid_tx_mcs(struct ieee80211com * ic,int mcs)531*04171cfcSAugustin Cavalier ieee80211_ra_valid_tx_mcs(struct ieee80211com *ic, int mcs)
532*04171cfcSAugustin Cavalier {
533*04171cfcSAugustin Cavalier uint32_t ntxstreams = 1;
534*04171cfcSAugustin Cavalier static const int max_mcs[] = { 7, 15, 23, 31 };
535*04171cfcSAugustin Cavalier
536*04171cfcSAugustin Cavalier if ((ic->ic_tx_mcs_set & IEEE80211_TX_RX_MCS_NOT_EQUAL) == 0)
537*04171cfcSAugustin Cavalier return isset(ic->ic_sup_mcs, mcs);
538*04171cfcSAugustin Cavalier
539*04171cfcSAugustin Cavalier ntxstreams += ((ic->ic_tx_mcs_set & IEEE80211_TX_SPATIAL_STREAMS) >> 2);
540*04171cfcSAugustin Cavalier if (ntxstreams < 1 || ntxstreams > 4)
541*04171cfcSAugustin Cavalier panic("invalid number of Tx streams: %u", ntxstreams);
542*04171cfcSAugustin Cavalier return (mcs <= max_mcs[ntxstreams - 1] && isset(ic->ic_sup_mcs, mcs));
543*04171cfcSAugustin Cavalier }
544*04171cfcSAugustin Cavalier
545*04171cfcSAugustin Cavalier uint32_t
ieee80211_ra_valid_rates(struct ieee80211com * ic,struct ieee80211_node * ni)546*04171cfcSAugustin Cavalier ieee80211_ra_valid_rates(struct ieee80211com *ic, struct ieee80211_node *ni)
547*04171cfcSAugustin Cavalier {
548*04171cfcSAugustin Cavalier uint32_t valid_mcs = 0;
549*04171cfcSAugustin Cavalier int i;
550*04171cfcSAugustin Cavalier
551*04171cfcSAugustin Cavalier for (i = 0; i < IEEE80211_HT_RATESET_NUM_MCS; i++) {
552*04171cfcSAugustin Cavalier if (!isset(ni->ni_rxmcs, i))
553*04171cfcSAugustin Cavalier continue;
554*04171cfcSAugustin Cavalier if (!ieee80211_ra_valid_tx_mcs(ic, i))
555*04171cfcSAugustin Cavalier continue;
556*04171cfcSAugustin Cavalier valid_mcs |= (1 << i);
557*04171cfcSAugustin Cavalier }
558*04171cfcSAugustin Cavalier
559*04171cfcSAugustin Cavalier return valid_mcs;
560*04171cfcSAugustin Cavalier }
561*04171cfcSAugustin Cavalier
562*04171cfcSAugustin Cavalier int
ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats * g)563*04171cfcSAugustin Cavalier ieee80211_ra_probe_valid(struct ieee80211_ra_goodput_stats *g)
564*04171cfcSAugustin Cavalier {
565*04171cfcSAugustin Cavalier /* 128 packets make up a valid probe in any case. */
566*04171cfcSAugustin Cavalier if (g->nprobe_pkts >= 128)
567*04171cfcSAugustin Cavalier return 1;
568*04171cfcSAugustin Cavalier
569*04171cfcSAugustin Cavalier /* 8 packets with > 75% loss make a valid probe, too. */
570*04171cfcSAugustin Cavalier if (g->nprobe_pkts >= 8 &&
571*04171cfcSAugustin Cavalier g->nprobe_pkts - g->nprobe_fail < g->nprobe_pkts / 4)
572*04171cfcSAugustin Cavalier return 1;
573*04171cfcSAugustin Cavalier
574*04171cfcSAugustin Cavalier return 0;
575*04171cfcSAugustin Cavalier }
576*04171cfcSAugustin Cavalier
577*04171cfcSAugustin Cavalier void
ieee80211_ra_add_stats_ht(struct ieee80211_ra_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni,int mcs,uint32_t total,uint32_t fail)578*04171cfcSAugustin Cavalier ieee80211_ra_add_stats_ht(struct ieee80211_ra_node *rn,
579*04171cfcSAugustin Cavalier struct ieee80211com *ic, struct ieee80211_node *ni,
580*04171cfcSAugustin Cavalier int mcs, uint32_t total, uint32_t fail)
581*04171cfcSAugustin Cavalier {
582*04171cfcSAugustin Cavalier static const uint64_t alpha = RA_FP_1 / 8; /* 1/8 = 0.125 */
583*04171cfcSAugustin Cavalier static const uint64_t beta = RA_FP_1 / 4; /* 1/4 = 0.25 */
584*04171cfcSAugustin Cavalier int s;
585*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g;
586*04171cfcSAugustin Cavalier uint64_t sfer, rate, delta;
587*04171cfcSAugustin Cavalier
588*04171cfcSAugustin Cavalier /*
589*04171cfcSAugustin Cavalier * Ignore invalid values. These values may come from hardware
590*04171cfcSAugustin Cavalier * so asserting valid values via panic is not appropriate.
591*04171cfcSAugustin Cavalier */
592*04171cfcSAugustin Cavalier if (mcs < 0 || mcs >= IEEE80211_HT_RATESET_NUM_MCS)
593*04171cfcSAugustin Cavalier return;
594*04171cfcSAugustin Cavalier if (total == 0)
595*04171cfcSAugustin Cavalier return;
596*04171cfcSAugustin Cavalier
597*04171cfcSAugustin Cavalier s = splnet();
598*04171cfcSAugustin Cavalier
599*04171cfcSAugustin Cavalier g = &rn->g[mcs];
600*04171cfcSAugustin Cavalier g->nprobe_pkts += total;
601*04171cfcSAugustin Cavalier g->nprobe_fail += fail;
602*04171cfcSAugustin Cavalier
603*04171cfcSAugustin Cavalier if (!ieee80211_ra_probe_valid(g)) {
604*04171cfcSAugustin Cavalier splx(s);
605*04171cfcSAugustin Cavalier return;
606*04171cfcSAugustin Cavalier }
607*04171cfcSAugustin Cavalier rn->valid_probes |= 1U << mcs;
608*04171cfcSAugustin Cavalier
609*04171cfcSAugustin Cavalier if (g->nprobe_fail > g->nprobe_pkts) {
610*04171cfcSAugustin Cavalier DPRINTF(("%s fail %u > pkts %u\n",
611*04171cfcSAugustin Cavalier ether_sprintf(ni->ni_macaddr),
612*04171cfcSAugustin Cavalier g->nprobe_fail, g->nprobe_pkts));
613*04171cfcSAugustin Cavalier g->nprobe_fail = g->nprobe_pkts;
614*04171cfcSAugustin Cavalier }
615*04171cfcSAugustin Cavalier
616*04171cfcSAugustin Cavalier sfer = g->nprobe_fail << RA_FP_SHIFT;
617*04171cfcSAugustin Cavalier sfer /= g->nprobe_pkts;
618*04171cfcSAugustin Cavalier g->nprobe_fail = 0;
619*04171cfcSAugustin Cavalier g->nprobe_pkts = 0;
620*04171cfcSAugustin Cavalier
621*04171cfcSAugustin Cavalier rate = ieee80211_ra_get_txrate(mcs,
622*04171cfcSAugustin Cavalier ieee80211_node_supports_ht_chan40(ni),
623*04171cfcSAugustin Cavalier ieee80211_ra_use_ht_sgi(ni));
624*04171cfcSAugustin Cavalier
625*04171cfcSAugustin Cavalier g->loss = sfer * 100;
626*04171cfcSAugustin Cavalier g->measured = RA_FP_MUL(RA_FP_1 - sfer, rate);
627*04171cfcSAugustin Cavalier g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average);
628*04171cfcSAugustin Cavalier g->average += RA_FP_MUL(alpha, g->measured);
629*04171cfcSAugustin Cavalier
630*04171cfcSAugustin Cavalier g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation);
631*04171cfcSAugustin Cavalier if (g->average > g->measured)
632*04171cfcSAugustin Cavalier delta = g->average - g->measured;
633*04171cfcSAugustin Cavalier else
634*04171cfcSAugustin Cavalier delta = g->measured - g->average;
635*04171cfcSAugustin Cavalier g->stddeviation += RA_FP_MUL(beta, delta);
636*04171cfcSAugustin Cavalier
637*04171cfcSAugustin Cavalier splx(s);
638*04171cfcSAugustin Cavalier }
639*04171cfcSAugustin Cavalier
640*04171cfcSAugustin Cavalier void
ieee80211_ra_choose(struct ieee80211_ra_node * rn,struct ieee80211com * ic,struct ieee80211_node * ni)641*04171cfcSAugustin Cavalier ieee80211_ra_choose(struct ieee80211_ra_node *rn, struct ieee80211com *ic,
642*04171cfcSAugustin Cavalier struct ieee80211_node *ni)
643*04171cfcSAugustin Cavalier {
644*04171cfcSAugustin Cavalier struct ieee80211_ra_goodput_stats *g = &rn->g[ni->ni_txmcs];
645*04171cfcSAugustin Cavalier int s;
646*04171cfcSAugustin Cavalier int chan40 = ieee80211_node_supports_ht_chan40(ni);
647*04171cfcSAugustin Cavalier int sgi = ieee80211_ra_use_ht_sgi(ni);
648*04171cfcSAugustin Cavalier const struct ieee80211_ht_rateset *rs, *rsnext;
649*04171cfcSAugustin Cavalier
650*04171cfcSAugustin Cavalier s = splnet();
651*04171cfcSAugustin Cavalier
652*04171cfcSAugustin Cavalier if (rn->valid_rates == 0)
653*04171cfcSAugustin Cavalier rn->valid_rates = ieee80211_ra_valid_rates(ic, ni);
654*04171cfcSAugustin Cavalier
655*04171cfcSAugustin Cavalier if (rn->probing) {
656*04171cfcSAugustin Cavalier /* Probe another rate or settle at the best rate. */
657*04171cfcSAugustin Cavalier if (!(rn->valid_probes & (1UL << ni->ni_txmcs))) {
658*04171cfcSAugustin Cavalier splx(s);
659*04171cfcSAugustin Cavalier return;
660*04171cfcSAugustin Cavalier }
661*04171cfcSAugustin Cavalier ieee80211_ra_probe_clear(rn, ni);
662*04171cfcSAugustin Cavalier if (!ieee80211_ra_intra_mode_ra_finished(rn, ni)) {
663*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rate(rn, ni);
664*04171cfcSAugustin Cavalier DPRINTFN(3, ("probing MCS %d\n", ni->ni_txmcs));
665*04171cfcSAugustin Cavalier } else if (ieee80211_ra_inter_mode_ra_finished(rn, ni)) {
666*04171cfcSAugustin Cavalier rn->best_mcs = ieee80211_ra_best_rate(rn, ni);
667*04171cfcSAugustin Cavalier ni->ni_txmcs = rn->best_mcs;
668*04171cfcSAugustin Cavalier ieee80211_ra_probe_done(rn);
669*04171cfcSAugustin Cavalier }
670*04171cfcSAugustin Cavalier
671*04171cfcSAugustin Cavalier splx(s);
672*04171cfcSAugustin Cavalier return;
673*04171cfcSAugustin Cavalier } else {
674*04171cfcSAugustin Cavalier rn->valid_probes = 0;
675*04171cfcSAugustin Cavalier }
676*04171cfcSAugustin Cavalier
677*04171cfcSAugustin Cavalier rs = ieee80211_ra_get_ht_rateset(ni->ni_txmcs, chan40, sgi);
678*04171cfcSAugustin Cavalier if ((g->measured >> RA_FP_SHIFT) == 0LL ||
679*04171cfcSAugustin Cavalier (g->average >= 3 * g->stddeviation &&
680*04171cfcSAugustin Cavalier g->measured < g->average - 3 * g->stddeviation)) {
681*04171cfcSAugustin Cavalier /* Channel becomes bad. Probe downwards. */
682*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_PROBING_DOWN;
683*04171cfcSAugustin Cavalier rn->probed_rates = 0;
684*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->min_mcs) {
685*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni);
686*04171cfcSAugustin Cavalier if (rsnext) {
687*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni,
688*04171cfcSAugustin Cavalier rsnext);
689*04171cfcSAugustin Cavalier } else {
690*04171cfcSAugustin Cavalier /* Cannot probe further down. */
691*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING;
692*04171cfcSAugustin Cavalier }
693*04171cfcSAugustin Cavalier } else {
694*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni);
695*04171cfcSAugustin Cavalier rn->candidate_rates = (1 << ni->ni_txmcs);
696*04171cfcSAugustin Cavalier }
697*04171cfcSAugustin Cavalier } else if (g->loss < 2 * RA_FP_1 ||
698*04171cfcSAugustin Cavalier g->measured > g->average + 3 * g->stddeviation) {
699*04171cfcSAugustin Cavalier /* Channel becomes good. */
700*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_PROBING_UP;
701*04171cfcSAugustin Cavalier rn->probed_rates = 0;
702*04171cfcSAugustin Cavalier if (ni->ni_txmcs == rs->max_mcs) {
703*04171cfcSAugustin Cavalier rsnext = ieee80211_ra_next_rateset(rn, ni);
704*04171cfcSAugustin Cavalier if (rsnext) {
705*04171cfcSAugustin Cavalier ieee80211_ra_probe_next_rateset(rn, ni,
706*04171cfcSAugustin Cavalier rsnext);
707*04171cfcSAugustin Cavalier } else {
708*04171cfcSAugustin Cavalier /* Cannot probe further up. */
709*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING;
710*04171cfcSAugustin Cavalier }
711*04171cfcSAugustin Cavalier } else {
712*04171cfcSAugustin Cavalier ni->ni_txmcs = ieee80211_ra_next_mcs(rn, ni);
713*04171cfcSAugustin Cavalier rn->candidate_rates = (1 << ni->ni_txmcs);
714*04171cfcSAugustin Cavalier }
715*04171cfcSAugustin Cavalier } else {
716*04171cfcSAugustin Cavalier /* Remain at current rate. */
717*04171cfcSAugustin Cavalier rn->probing = IEEE80211_RA_NOT_PROBING;
718*04171cfcSAugustin Cavalier rn->probed_rates = 0;
719*04171cfcSAugustin Cavalier rn->candidate_rates = 0;
720*04171cfcSAugustin Cavalier }
721*04171cfcSAugustin Cavalier
722*04171cfcSAugustin Cavalier splx(s);
723*04171cfcSAugustin Cavalier
724*04171cfcSAugustin Cavalier if (rn->probing) {
725*04171cfcSAugustin Cavalier if (rn->probing & IEEE80211_RA_PROBING_UP)
726*04171cfcSAugustin Cavalier DPRINTFN(2, ("channel becomes good; probe up\n"));
727*04171cfcSAugustin Cavalier else
728*04171cfcSAugustin Cavalier DPRINTFN(2, ("channel becomes bad; probe down\n"));
729*04171cfcSAugustin Cavalier
730*04171cfcSAugustin Cavalier DPRINTFN(3, ("measured: %s Mbit/s\n",
731*04171cfcSAugustin Cavalier ra_fp_sprintf(g->measured)));
732*04171cfcSAugustin Cavalier DPRINTFN(3, ("average: %s Mbit/s\n",
733*04171cfcSAugustin Cavalier ra_fp_sprintf(g->average)));
734*04171cfcSAugustin Cavalier DPRINTFN(3, ("stddeviation: %s\n",
735*04171cfcSAugustin Cavalier ra_fp_sprintf(g->stddeviation)));
736*04171cfcSAugustin Cavalier DPRINTFN(3, ("loss: %s%%\n", ra_fp_sprintf(g->loss)));
737*04171cfcSAugustin Cavalier }
738*04171cfcSAugustin Cavalier }
739*04171cfcSAugustin Cavalier
740*04171cfcSAugustin Cavalier void
ieee80211_ra_node_init(struct ieee80211_ra_node * rn)741*04171cfcSAugustin Cavalier ieee80211_ra_node_init(struct ieee80211_ra_node *rn)
742*04171cfcSAugustin Cavalier {
743*04171cfcSAugustin Cavalier memset(rn, 0, sizeof(*rn));
744*04171cfcSAugustin Cavalier }
745