Bug Summary

File:net80211/ieee80211_ra_vht.c
Warning:line 690, column 2
Value stored to 'rs' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ieee80211_ra_vht.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -target-feature +retpoline-external-thunk -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/legacy-dpm -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu13 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/inc -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/inc/pmfw_if -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D SUSPEND -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /home/ben/Projects/scan/2024-01-11-110808-61670-1 -x c /usr/src/sys/net80211/ieee80211_ra_vht.c
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_SHIFT21 21
61#define RA_FP_INT(x)(xULL << 21) (x ## ULL << RA_FP_SHIFT21) /* the integer x */
62#define RA_FP_1(1ULL << 21) RA_FP_INT(1)(1ULL << 21)
63
64/* Multiply two fixed point numbers. */
65#define RA_FP_MUL(a, b)(((a) * (b)) >> 21) \
66 (((a) * (b)) >> RA_FP_SHIFT21)
67
68/* Divide two fixed point numbers. */
69#define RA_FP_DIV(a, b)(b == 0 ? (uint64_t)-1 : (((a) << 21) / (b))) \
70 (b == 0 ? (uint64_t)-1 : (((a) << RA_FP_SHIFT21) / (b)))
71
72#ifdef RA_DEBUG
73#define DPRINTF(x)do { ; } while (0) do { if (ra_vht_debug > 0) printf x; } while (0)
74#define DPRINTFN(n, x)do { ; } while (0) do { if (ra_vht_debug >= (n)) printf x; } while (0)
75int ra_vht_debug = 0;
76#else
77#define DPRINTF(x)do { ; } while (0) do { ; } while (0)
78#define DPRINTFN(n, x)do { ; } while (0) 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_SHIFT21);
89
90 /* fractional part */
91 tmp = (fp & ((uint64_t)-1 >> (64 - RA_FP_SHIFT21)));
92 tmp *= 100;
93 *f = (uint32_t)(tmp >> RA_FP_SHIFT21);
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_RATESETS12; 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_160MHZ0x00000002) &&
133 ieee80211_node_supports_vht_chan160(ni)) {
134 if (ni->ni_flags & IEEE80211_NODE_VHT_SGI1600x100000)
135 return 1;
136 }
137
138 if ((ni->ni_chan->ic_xflags & IEEE80211_CHANX_80MHZ0x00000001) &&
139 ieee80211_node_supports_vht_chan80(ni)) {
140 if (ni->ni_flags & IEEE80211_NODE_VHT_SGI800x80000)
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_SHIFT21; /* 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((1ULL << 21) / 64) (RA_FP_1(1ULL << 21) / 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)(0x3 << (2*((nss)-1)))) >>
187 IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss)(2*((nss)-1));
188 int max_mcs = -1;
189
190 switch (supp_mcs) {
191 case IEEE80211_VHT_MCS_SS_NOT_SUPP3:
192 break;
193 case IEEE80211_VHT_MCS_0_70:
194 max_mcs = 7;
195 break;
196 case IEEE80211_VHT_MCS_0_81:
197 max_mcs = 8;
198 break;
199 case IEEE80211_VHT_MCS_0_92:
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_UP0x2) {
247 switch (rs->idx) {
248 case IEEE80211_VHT_RATESET_SISO_808:
249 next = IEEE80211_VHT_RATESET_MIMO2_8010;
250 break;
251 case IEEE80211_VHT_RATESET_SISO_80_SGI9:
252 next = IEEE80211_VHT_RATESET_MIMO2_80_SGI11;
253 break;
254 default:
255 return NULL((void *)0);
256 }
257 } else if (rn->probing & IEEE80211_RA_PROBING_DOWN0x1) {
258 switch (rs->idx) {
259 case IEEE80211_VHT_RATESET_MIMO2_8010:
260 next = IEEE80211_VHT_RATESET_SISO_808;
261 break;
262 case IEEE80211_VHT_RATESET_MIMO2_80_SGI11:
263 next = IEEE80211_VHT_RATESET_SISO_80_SGI9;
264 break;
265 default:
266 return NULL((void *)0);
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((void *)0);
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((1ULL << 21) / 64)) {
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_SHIFT21; /* convert to fixed-point */
326 txrate /= 1000; /* convert to mbit/s */
327
328 if (txrate > g->measured + IEEE80211_RA_RATE_THRESHOLD((1ULL << 21) / 64)) {
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_UP0x2) {
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_DOWN0x1) {
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_DOWN0x1)
356 next = ieee80211_ra_vht_next_lower_intra_rate(rn, ni);
357 else if (rn->probing & IEEE80211_RA_PROBING_UP0x2)
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_PROBING0x0;
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_DOWN0x1) {
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_UP0x2) {
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((1ULL << 21) / 64)) {
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_UP0x2) &&
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_DOWN0x1) &&
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_INTER0x4;
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_INTER0x4;
464 } else
465 rn->probing &= ~IEEE80211_RA_PROBING_INTER0x4;
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_INTER0x4) == 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_RATESETS12; i++) {
488 rs = &ieee80211_std_ratesets_11ac[i];
489 for (j = 0; j < IEEE80211_VHT_RATESET_MAX_NRATES10; 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((1ULL << 21) / 64)) {
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}:",do { ; } while (0)
504 best_mcs, best_nss))do { ; } while (0);
505 for (i = 0; i < IEEE80211_VHT_NUM_RATESETS12; 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_NRATES10; 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,do { ; } while (0)
517 ra_vht_fp_sprintf(g->measured)))do { ; } while (0);
518 DPRINTF(("%s|", ra_vht_fp_sprintf(g->average)))do { ; } while (0);
519 DPRINTF(("%s%%}", ra_vht_fp_sprintf(g->loss)))do { ; } while (0);
520 }
521 }
522 DPRINTF(("\n"))do { ; } while (0);
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))__builtin_memset((rn->max_mcs), (0), (sizeof(rn->max_mcs
)))
;
545 memset(rn->valid_rates, 0, sizeof(rn->valid_rates))__builtin_memset((rn->valid_rates), (0), (sizeof(rn->valid_rates
)))
;
546
547 for (nss = 1; nss <= IEEE80211_VHT_NUM_SS8; 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)(((ic->ic_bss->ni_chan)->ic_flags & 0x8000) != 0
)
);
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)(((ic_max_mcs)<(ni_max_mcs))?(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(1ULL << 21) / 8; /* 1/8 = 0.125 */
583 static const uint64_t beta = RA_FP_1(1ULL << 21) / 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_NRATES10)
594 return;
595 if (nss <= 0 || nss > IEEE80211_VHT_NUM_SS8)
596 return;
597 if (total == 0)
598 return;
599
600 s = splnet()splraise(0x4);
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)spllower(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",do { ; } while (0)
616 ether_sprintf(ni->ni_macaddr),do { ; } while (0)
617 g->nprobe_fail, g->nprobe_pkts))do { ; } while (0);
618 g->nprobe_fail = g->nprobe_pkts;
619 }
620
621 sfer = g->nprobe_fail << RA_FP_SHIFT21;
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)((((1ULL << 21) - sfer) * (rate)) >> 21);
631 g->average = RA_FP_MUL(RA_FP_1 - alpha, g->average)((((1ULL << 21) - alpha) * (g->average)) >> 21
)
;
632 g->average += RA_FP_MUL(alpha, g->measured)(((alpha) * (g->measured)) >> 21);
633
634 g->stddeviation = RA_FP_MUL(RA_FP_1 - beta, g->stddeviation)((((1ULL << 21) - beta) * (g->stddeviation)) >>
21)
;
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)(((beta) * (delta)) >> 21);
640
641 splx(s)spllower(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()splraise(0x4);
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)spllower(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",do { ; } while (0)
675 ni->ni_txmcs, ni->ni_vht_ss))do { ; } while (0);
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)spllower(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);
Value stored to 'rs' is never read
691 if ((g->measured >> RA_FP_SHIFT21) == 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_DOWN0x1;
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_PROBING0x0;
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(1ULL << 21) ||
711 g->measured > g->average + 3 * g->stddeviation) {
712 /* Channel becomes good. */
713 rn->probing = IEEE80211_RA_PROBING_UP0x2;
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_PROBING0x0;
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_PROBING0x0;
731 rn->probed_rates[nss - 1] = 0;
732 rn->candidate_rates[nss - 1] = 0;
733 }
734
735 splx(s)spllower(s);
736
737 if (rn->probing) {
738 if (rn->probing & IEEE80211_RA_PROBING_UP0x2)
739 DPRINTFN(2, ("channel becomes good; probe up\n"))do { ; } while (0);
740 else
741 DPRINTFN(2, ("channel becomes bad; probe down\n"))do { ; } while (0);
742
743 DPRINTFN(3, ("measured: %s Mbit/s\n",do { ; } while (0)
744 ra_vht_fp_sprintf(g->measured)))do { ; } while (0);
745 DPRINTFN(3, ("average: %s Mbit/s\n",do { ; } while (0)
746 ra_vht_fp_sprintf(g->average)))do { ; } while (0);
747 DPRINTFN(3, ("stddeviation: %s\n",do { ; } while (0)
748 ra_vht_fp_sprintf(g->stddeviation)))do { ; } while (0);
749 DPRINTFN(3, ("loss: %s%%\n", ra_vht_fp_sprintf(g->loss)))do { ; } while (0);
750 }
751}
752
753void
754ieee80211_ra_vht_node_init(struct ieee80211_ra_vht_node *rn)
755{
756 memset(rn, 0, sizeof(*rn))__builtin_memset((rn), (0), (sizeof(*rn)));
757 rn->best_nss = 1;
758}