Bug Summary

File:net80211/ieee80211_ra_vht.c
Warning:line 534, column 44
The result of the left shift is undefined because the right operand is negative

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

/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));
18
Calling 'ieee80211_node_supports_ht_chan40'
21
Returning from 'ieee80211_node_supports_ht_chan40'
222 if (max_mcs
21.1
'max_mcs' is not equal to 7
21.1
'max_mcs' is not equal to 7
!= 7 && max_mcs
21.2
'max_mcs' is equal to 8
21.2
'max_mcs' is equal to 8
!= 8 && max_mcs != 9)
223 panic("ni->ni_vht_ss invalid: %u", ni->ni_vht_ss);
224
225 if (ni->ni_txmcs >= max_mcs)
22
Assuming 'max_mcs' is > field 'ni_txmcs'
23
Taking false branch
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)
15
Taking false branch
356 next = ieee80211_ra_vht_next_lower_intra_rate(rn, ni);
357 else if (rn->probing & IEEE80211_RA_PROBING_UP0x2)
16
Taking true branch
358 next = ieee80211_ra_vht_next_intra_rate(rn, ni);
17
Calling 'ieee80211_ra_vht_next_intra_rate'
24
Returning from 'ieee80211_ra_vht_next_intra_rate'
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) {
8
Assuming the condition is false
9
Taking false branch
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) {
10
Assuming the condition is true
404 if (ni->ni_txmcs == rn->max_mcs[nss - 1] ||
11
Assuming the condition is false
13
Taking false branch
405 rn->probed_rates[nss - 1] & (1 << rn->max_mcs[nss - 1])) {
12
Assuming the condition is false
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);
14
Calling 'ieee80211_ra_vht_next_mcs'
25
Returning from 'ieee80211_ra_vht_next_mcs'
416 if (next_mcs == ni->ni_txmcs) {
26
Assuming 'next_mcs' is not equal to field 'ni_txmcs'
27
Taking false branch
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 &&
28
Assuming field 'loss' is not equal to 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
28.1
'best_mcs' is not equal to field 'ni_txmcs'
28.1
'best_mcs' is not equal to field 'ni_txmcs'
!= ni->ni_txmcs) {
431 if ((rn->probing & IEEE80211_RA_PROBING_UP0x2) &&
432 best_mcs
28.2
'best_mcs' is >= field 'ni_txmcs'
28.2
'best_mcs' is >= field 'ni_txmcs'
< 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]) ==
29
Assuming the condition is false
30
Taking false branch
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);
34
The result of the left shift is undefined because the right operand is negative
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) {
1
Assuming the condition is false
2
Taking false branch
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) {
3
Assuming field 'probing' is not equal to 0
4
Taking true branch
666 /* Probe another rate or settle at the best rate. */
667 if (!(rn->valid_probes[nss - 1] & (1UL << ni->ni_txmcs))) {
5
Assuming the condition is false
6
Taking false branch
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)) {
7
Calling 'ieee80211_ra_vht_intra_mode_ra_finished'
31
Returning from 'ieee80211_ra_vht_intra_mode_ra_finished'
32
Taking true branch
673 ieee80211_ra_vht_probe_next_rate(rn, ni);
33
Calling 'ieee80211_ra_vht_probe_next_rate'
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);
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}

/usr/src/sys/net80211/ieee80211_node.h

1/* $OpenBSD: ieee80211_node.h,v 1.94 2022/03/20 12:01:58 stsp Exp $ */
2/* $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $ */
3
4/*-
5 * Copyright (c) 2001 Atsushi Onoe
6 * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * $FreeBSD: src/sys/net80211/ieee80211_node.h,v 1.10 2004/04/05 22:10:26 sam Exp $
32 */
33#ifndef _NET80211_IEEE80211_NODE_H_
34#define _NET80211_IEEE80211_NODE_H_
35
36#include <sys/tree.h>
37
38#define IEEE80211_PSCAN_WAIT5 5 /* passive scan wait */
39#define IEEE80211_TRANS_WAIT5 5 /* transition wait */
40#define IEEE80211_INACT_WAIT5 5 /* inactivity timer interval */
41#define IEEE80211_INACT_MAX(300/5) (300/IEEE80211_INACT_WAIT5)
42#define IEEE80211_CACHE_SIZE512 512
43#define IEEE80211_CACHE_WAIT30 30
44#define IEEE80211_INACT_SCAN10 10 /* for station mode */
45
46struct ieee80211_rateset {
47 u_int8_t rs_nrates;
48 u_int8_t rs_rates[IEEE80211_RATE_MAXSIZE15];
49};
50
51extern const struct ieee80211_rateset ieee80211_std_rateset_11a;
52extern const struct ieee80211_rateset ieee80211_std_rateset_11b;
53extern const struct ieee80211_rateset ieee80211_std_rateset_11g;
54
55/* Index into ieee80211_std_rateset_11n[] array. */
56#define IEEE80211_HT_RATESET_SISO0 0
57#define IEEE80211_HT_RATESET_SISO_SGI1 1
58#define IEEE80211_HT_RATESET_MIMO22 2
59#define IEEE80211_HT_RATESET_MIMO2_SGI3 3
60#define IEEE80211_HT_RATESET_MIMO34 4
61#define IEEE80211_HT_RATESET_MIMO3_SGI5 5
62#define IEEE80211_HT_RATESET_MIMO46 6
63#define IEEE80211_HT_RATESET_MIMO4_SGI7 7
64#define IEEE80211_HT_RATESET_SISO_408 8
65#define IEEE80211_HT_RATESET_SISO_SGI409 9
66#define IEEE80211_HT_RATESET_MIMO2_4010 10
67#define IEEE80211_HT_RATESET_MIMO2_SGI4011 11
68#define IEEE80211_HT_RATESET_MIMO3_4012 12
69#define IEEE80211_HT_RATESET_MIMO3_SGI4013 13
70#define IEEE80211_HT_RATESET_MIMO4_4014 14
71#define IEEE80211_HT_RATESET_MIMO4_SGI4015 15
72#define IEEE80211_HT_NUM_RATESETS16 16
73
74/* Maximum number of rates in a HT rateset. */
75#define IEEE80211_HT_RATESET_MAX_NRATES8 8
76
77/* Number of MCS indices represented by struct ieee80211_ht_rateset. */
78#define IEEE80211_HT_RATESET_NUM_MCS32 32
79
80struct ieee80211_ht_rateset {
81 uint32_t nrates;
82 uint32_t rates[IEEE80211_HT_RATESET_MAX_NRATES8]; /* 500 kbit/s units */
83
84 /*
85 * This bitmask can only express MCS 0 - MCS 31.
86 * IEEE 802.11 defined 77 HT MCS in total but common hardware
87 * implementations tend to support MCS index 0 through 31 only.
88 */
89 uint32_t mcs_mask;
90
91 /* Range of MCS indices represented in this rateset. */
92 int min_mcs;
93 int max_mcs;
94
95 int chan40;
96 int sgi;
97};
98
99extern const struct ieee80211_ht_rateset ieee80211_std_ratesets_11n[];
100
101/* Index into ieee80211_std_rateset_11ac[] array. */
102#define IEEE80211_VHT_RATESET_SISO0 0
103#define IEEE80211_VHT_RATESET_SISO_SGI1 1
104#define IEEE80211_VHT_RATESET_MIMO22 2
105#define IEEE80211_VHT_RATESET_MIMO2_SGI3 3
106#define IEEE80211_VHT_RATESET_SISO_404 4
107#define IEEE80211_VHT_RATESET_SISO_40_SGI5 5
108#define IEEE80211_VHT_RATESET_MIMO2_406 6
109#define IEEE80211_VHT_RATESET_MIMO2_40_SGI7 7
110#define IEEE80211_VHT_RATESET_SISO_808 8
111#define IEEE80211_VHT_RATESET_SISO_80_SGI9 9
112#define IEEE80211_VHT_RATESET_MIMO2_8010 10
113#define IEEE80211_VHT_RATESET_MIMO2_80_SGI11 11
114#define IEEE80211_VHT_NUM_RATESETS12 12
115
116/* Maximum number of rates in a VHT rateset. */
117#define IEEE80211_VHT_RATESET_MAX_NRATES10 10
118
119struct ieee80211_vht_rateset {
120 int idx; /* This rateset's index in ieee80211_std_rateset_11ac[]. */
121
122 uint32_t nrates;
123 uint32_t rates[IEEE80211_VHT_RATESET_MAX_NRATES10]; /* 500 kbit/s units */
124
125 /* Number of spatial streams used by rates in this rateset. */
126 int num_ss;
127
128 int chan40;
129 int chan80;
130 int sgi;
131};
132
133extern const struct ieee80211_vht_rateset ieee80211_std_ratesets_11ac[];
134
135enum ieee80211_node_state {
136 IEEE80211_STA_CACHE, /* cached node */
137 IEEE80211_STA_BSS, /* ic->ic_bss, the network we joined */
138 IEEE80211_STA_AUTH, /* successfully authenticated */
139 IEEE80211_STA_ASSOC, /* successfully associated */
140 IEEE80211_STA_COLLECT /* This node remains in the cache while
141 * the driver sends a de-auth message;
142 * afterward it should be freed to make room
143 * for a new node.
144 */
145};
146
147#define ieee80211_node_newstate(__ni, __state)do { (__ni)->ni_state = (__state); } while (0) \
148 do { \
149 (__ni)->ni_state = (__state); \
150 } while (0)
151
152enum ieee80211_node_psstate {
153 IEEE80211_PS_AWAKE,
154 IEEE80211_PS_DOZE
155};
156
157#define IEEE80211_PS_MAX_QUEUE50 50 /* maximum saved packets */
158
159/* Authenticator state machine: 4-Way Handshake (see 8.5.6.1.1) */
160enum {
161 RSNA_INITIALIZE,
162 RSNA_AUTHENTICATION,
163 RSNA_AUTHENTICATION_2,
164 RSNA_INITPMK,
165 RSNA_INITPSK,
166 RSNA_PTKSTART,
167 RSNA_PTKCALCNEGOTIATING,
168 RSNA_PTKCALCNEGOTIATING_2,
169 RSNA_PTKINITNEGOTIATING,
170 RSNA_PTKINITDONE,
171 RSNA_DISCONNECT,
172 RSNA_DISCONNECTED
173};
174
175/* Authenticator state machine: Group Key Handshake (see 8.5.6.1.2) */
176enum {
177 RSNA_IDLE,
178 RSNA_REKEYNEGOTIATING,
179 RSNA_REKEYESTABLISHED,
180 RSNA_KEYERROR
181};
182
183/* Supplicant state machine: 4-Way Handshake (not documented in standard) */
184enum {
185 RSNA_SUPP_INITIALIZE, /* not expecting any messages */
186 RSNA_SUPP_PTKSTART, /* awaiting handshake message 1 */
187 RSNA_SUPP_PTKNEGOTIATING, /* got message 1 and derived PTK */
188 RSNA_SUPP_PTKDONE /* got message 3 and authenticated AP */
189};
190
191struct ieee80211_rxinfo {
192 u_int32_t rxi_flags;
193 u_int32_t rxi_tstamp;
194 int rxi_rssi;
195 uint8_t rxi_chan;
196};
197#define IEEE80211_RXI_HWDEC0x00000001 0x00000001
198#define IEEE80211_RXI_AMPDU_DONE0x00000002 0x00000002
199#define IEEE80211_RXI_HWDEC_SAME_PN0x00000004 0x00000004
200#define IEEE80211_RXI_SAME_SEQ0x00000008 0x00000008
201
202/* Block Acknowledgement Record */
203struct ieee80211_tx_ba {
204 struct ieee80211_node *ba_ni; /* backpointer for callbacks */
205 struct timeout ba_to;
206 int ba_timeout_val;
207 int ba_state;
208#define IEEE80211_BA_INIT0 0
209#define IEEE80211_BA_REQUESTED1 1
210#define IEEE80211_BA_AGREED2 2
211
212 /* ADDBA parameter set field for this BA agreement. */
213 u_int16_t ba_params;
214
215 /* These values are IEEE802.11 frame sequence numbers (0x0-0xfff) */
216 u_int16_t ba_winstart;
217 u_int16_t ba_winend;
218
219 /* Number of A-MPDU subframes in reorder buffer. */
220 u_int16_t ba_winsize;
221#define IEEE80211_BA_MAX_WINSZ64 64 /* corresponds to maximum ADDBA BUFSZ */
222
223 u_int8_t ba_token;
224
225 /* Bitmap for ACK'd frames in the current BA window. */
226 uint64_t ba_bitmap;
227};
228
229struct ieee80211_rx_ba {
230 struct ieee80211_node *ba_ni; /* backpointer for callbacks */
231 struct {
232 struct mbuf *m;
233 struct ieee80211_rxinfo rxi;
234 } *ba_buf;
235 struct timeout ba_to;
236 int ba_timeout_val;
237 int ba_state;
238 u_int16_t ba_params;
239 u_int16_t ba_winstart;
240 u_int16_t ba_winend;
241 u_int16_t ba_winsize;
242 u_int16_t ba_head;
243 struct timeout ba_gap_to;
244#define IEEE80211_BA_GAP_TIMEOUT300 300 /* msec */
245
246 /*
247 * Counter for frames forced to wait in the reordering buffer
248 * due to a leading gap caused by one or more missing frames.
249 */
250 int ba_gapwait;
251
252 /* Counter for consecutive frames which missed the BA window. */
253 int ba_winmiss;
254 /* Sequence number of previous frame which missed the BA window. */
255 uint16_t ba_missedsn;
256 /* Window moves forward after this many frames have missed it. */
257#define IEEE80211_BA_MAX_WINMISS8 8
258
259 uint8_t ba_token;
260};
261
262/*
263 * Node specific information. Note that drivers are expected
264 * to derive from this structure to add device-specific per-node
265 * state. This is done by overriding the ic_node_* methods in
266 * the ieee80211com structure.
267 */
268struct ieee80211_node {
269 RBT_ENTRY(ieee80211_node)struct rb_entry ni_node;
270
271 struct ieee80211com *ni_ic; /* back-pointer */
272
273 u_int ni_refcnt;
274 u_int ni_scangen; /* gen# for timeout scan */
275
276 /* hardware */
277 u_int32_t ni_rstamp; /* recv timestamp */
278 u_int8_t ni_rssi; /* recv ssi */
279
280 /* header */
281 u_int8_t ni_macaddr[IEEE80211_ADDR_LEN6];
282 u_int8_t ni_bssid[IEEE80211_ADDR_LEN6];
283
284 /* beacon, probe response */
285 u_int8_t ni_tstamp[8]; /* from last rcv'd beacon */
286 u_int16_t ni_intval; /* beacon interval */
287 u_int16_t ni_capinfo; /* capabilities */
288 u_int8_t ni_esslen;
289 u_int8_t ni_essid[IEEE80211_NWID_LEN32];
290 struct ieee80211_rateset ni_rates; /* negotiated rate set */
291 u_int8_t *ni_country; /* country information XXX */
292 struct ieee80211_channel *ni_chan;
293 u_int8_t ni_erp; /* 11g only */
294
295 /* DTIM and contention free period (CFP) */
296 u_int8_t ni_dtimcount;
297 u_int8_t ni_dtimperiod;
298#ifdef notyet
299 u_int8_t ni_cfpperiod; /* # of DTIMs between CFPs */
300 u_int16_t ni_cfpduremain; /* remaining cfp duration */
301 u_int16_t ni_cfpmaxduration;/* max CFP duration in TU */
302 u_int16_t ni_nextdtim; /* time to next DTIM */
303 u_int16_t ni_timoffset;
304#endif
305
306 /* power saving mode */
307 u_int8_t ni_pwrsave;
308 struct mbuf_queue ni_savedq; /* packets queued for pspoll */
309
310 /* RSN */
311 struct timeout ni_eapol_to;
312 u_int ni_rsn_state;
313 u_int ni_rsn_supp_state;
314 u_int ni_rsn_gstate;
315 u_int ni_rsn_retries;
316 u_int ni_supported_rsnprotos;
317 u_int ni_rsnprotos;
318 u_int ni_supported_rsnakms;
319 u_int ni_rsnakms;
320 u_int ni_rsnciphers;
321 enum ieee80211_cipher ni_rsngroupcipher;
322 enum ieee80211_cipher ni_rsngroupmgmtcipher;
323 u_int16_t ni_rsncaps;
324 enum ieee80211_cipher ni_rsncipher;
325 u_int8_t ni_nonce[EAPOL_KEY_NONCE_LEN32];
326 u_int8_t ni_pmk[IEEE80211_PMK_LEN32];
327 u_int8_t ni_pmkid[IEEE80211_PMKID_LEN16];
328 u_int64_t ni_replaycnt;
329 u_int8_t ni_replaycnt_ok;
330 u_int64_t ni_reqreplaycnt;
331 u_int8_t ni_reqreplaycnt_ok;
332 u_int8_t *ni_rsnie;
333 struct ieee80211_key ni_pairwise_key;
334 struct ieee80211_ptk ni_ptk;
335 u_int8_t ni_key_count;
336 int ni_port_valid;
337
338 /* SA Query */
339 u_int16_t ni_sa_query_trid;
340 struct timeout ni_sa_query_to;
341 int ni_sa_query_count;
342
343 /* HT capabilities */
344 uint16_t ni_htcaps;
345 uint8_t ni_ampdu_param;
346 uint8_t ni_rxmcs[howmany(80,NBBY)(((80) + ((8) - 1)) / (8))];
347 uint16_t ni_max_rxrate; /* in Mb/s, 0 <= rate <= 1023 */
348 uint8_t ni_tx_mcs_set;
349 uint16_t ni_htxcaps;
350 uint32_t ni_txbfcaps;
351 uint8_t ni_aselcaps;
352
353 /* HT operation */
354 uint8_t ni_primary_chan; /* XXX corresponds to ni_chan */
355 uint8_t ni_htop0;
356 uint16_t ni_htop1;
357 uint16_t ni_htop2;
358 uint8_t ni_basic_mcs[howmany(128,NBBY)(((128) + ((8) - 1)) / (8))];
359
360 /* VHT capabilities */
361 uint32_t ni_vhtcaps;
362 uint16_t ni_vht_rxmcs;
363 uint16_t ni_vht_rx_max_lgi_mbit_s;
364 uint16_t ni_vht_txmcs;
365 uint16_t ni_vht_tx_max_lgi_mbit_s;
366
367 /* VHT operation */
368 uint8_t ni_vht_chan_width;
369 uint8_t ni_vht_chan_center_freq_idx0;
370 uint8_t ni_vht_chan_center_freq_idx1;
371 uint16_t ni_vht_basic_mcs;
372
373 /* Timeout handlers which trigger Tx Block Ack negotiation. */
374 struct timeout ni_addba_req_to[IEEE80211_NUM_TID16];
375 int ni_addba_req_intval[IEEE80211_NUM_TID16];
376#define IEEE80211_ADDBA_REQ_INTVAL_MAX30 30 /* in seconds */
377
378 /* Block Ack records */
379 struct ieee80211_tx_ba ni_tx_ba[IEEE80211_NUM_TID16];
380 struct ieee80211_rx_ba ni_rx_ba[IEEE80211_NUM_TID16];
381
382 int ni_txmcs; /* current MCS used for TX */
383 int ni_vht_ss; /* VHT # spatial streams */
384
385 /* others */
386 u_int16_t ni_associd; /* assoc response */
387 u_int16_t ni_txseq; /* seq to be transmitted */
388 u_int16_t ni_rxseq; /* seq previous received */
389 u_int16_t ni_qos_txseqs[IEEE80211_NUM_TID16];
390 u_int16_t ni_qos_rxseqs[IEEE80211_NUM_TID16];
391 int ni_fails; /* failure count to associate */
392 uint32_t ni_assoc_fail; /* assoc failure reasons */
393#define IEEE80211_NODE_ASSOCFAIL_CHAN0x01 0x01
394#define IEEE80211_NODE_ASSOCFAIL_IBSS0x02 0x02
395#define IEEE80211_NODE_ASSOCFAIL_PRIVACY0x04 0x04
396#define IEEE80211_NODE_ASSOCFAIL_BASIC_RATE0x08 0x08
397#define IEEE80211_NODE_ASSOCFAIL_ESSID0x10 0x10
398#define IEEE80211_NODE_ASSOCFAIL_BSSID0x20 0x20
399#define IEEE80211_NODE_ASSOCFAIL_WPA_PROTO0x40 0x40
400#define IEEE80211_NODE_ASSOCFAIL_WPA_KEY0x80 0x80
401
402 int ni_inact; /* inactivity mark count */
403 int ni_txrate; /* index to ni_rates[] */
404 int ni_state;
405
406 u_int32_t ni_flags; /* special-purpose state */
407#define IEEE80211_NODE_ERP0x0001 0x0001
408#define IEEE80211_NODE_QOS0x0002 0x0002
409#define IEEE80211_NODE_REKEY0x0004 0x0004 /* GTK rekeying in progress */
410#define IEEE80211_NODE_RXPROT0x0008 0x0008 /* RX protection ON */
411#define IEEE80211_NODE_TXPROT0x0010 0x0010 /* TX protection ON */
412#define IEEE80211_NODE_TXRXPROT(0x0010 | 0x0008) \
413 (IEEE80211_NODE_TXPROT0x0010 | IEEE80211_NODE_RXPROT0x0008)
414#define IEEE80211_NODE_RXMGMTPROT0x0020 0x0020 /* RX MMPDU protection ON */
415#define IEEE80211_NODE_TXMGMTPROT0x0040 0x0040 /* TX MMPDU protection ON */
416#define IEEE80211_NODE_MFP0x0080 0x0080 /* MFP negotiated */
417#define IEEE80211_NODE_PMK0x0100 0x0100 /* ni_pmk set */
418#define IEEE80211_NODE_PMKID0x0200 0x0200 /* ni_pmkid set */
419#define IEEE80211_NODE_HT0x0400 0x0400 /* HT negotiated */
420#define IEEE80211_NODE_SA_QUERY0x0800 0x0800 /* SA Query in progress */
421#define IEEE80211_NODE_SA_QUERY_FAILED0x1000 0x1000 /* last SA Query failed */
422#define IEEE80211_NODE_RSN_NEW_PTK0x2000 0x2000 /* expecting a new PTK */
423#define IEEE80211_NODE_HT_SGI200x4000 0x4000 /* SGI on 20 MHz negotiated */
424#define IEEE80211_NODE_HT_SGI400x8000 0x8000 /* SGI on 40 MHz negotiated */
425#define IEEE80211_NODE_VHT0x10000 0x10000 /* VHT negotiated */
426#define IEEE80211_NODE_HTCAP0x20000 0x20000 /* claims to support HT */
427#define IEEE80211_NODE_VHTCAP0x40000 0x40000 /* claims to support VHT */
428#define IEEE80211_NODE_VHT_SGI800x80000 0x80000 /* SGI on 80 MHz negotiated */
429#define IEEE80211_NODE_VHT_SGI1600x100000 0x100000 /* SGI on 160 MHz negotiated */
430
431 /* If not NULL, this function gets called when ni_refcnt hits zero. */
432 void (*ni_unref_cb)(struct ieee80211com *,
433 struct ieee80211_node *);
434 void * ni_unref_arg;
435 size_t ni_unref_arg_size;
436};
437
438RBT_HEAD(ieee80211_tree, ieee80211_node)struct ieee80211_tree { struct rb_tree rbh_root; };
439
440struct ieee80211_ess_rbt {
441 RBT_ENTRY(ieee80211_ess_rbt)struct rb_entry ess_rbt;
442 u_int8_t esslen;
443 u_int8_t essid[IEEE80211_NWID_LEN32];
444 struct ieee80211_node *ni2;
445 struct ieee80211_node *ni5;
446 struct ieee80211_node *ni;
447};
448
449RBT_HEAD(ieee80211_ess_tree, ieee80211_ess_rbt)struct ieee80211_ess_tree { struct rb_tree rbh_root; };
450
451static inline void
452ieee80211_node_incref(struct ieee80211_node *ni)
453{
454 int s;
455
456 s = splnet()splraise(0x4);
457 ni->ni_refcnt++;
458 splx(s)spllower(s);
459}
460
461static inline u_int
462ieee80211_node_decref(struct ieee80211_node *ni)
463{
464 u_int refcnt;
465 int s;
466
467 s = splnet()splraise(0x4);
468 refcnt = --ni->ni_refcnt;
469 splx(s)spllower(s);
470 return refcnt;
471}
472
473static inline struct ieee80211_node *
474ieee80211_ref_node(struct ieee80211_node *ni)
475{
476 ieee80211_node_incref(ni);
477 return ni;
478}
479
480static inline void
481ieee80211_unref_node(struct ieee80211_node **ni)
482{
483 ieee80211_node_decref(*ni);
484 *ni = NULL((void *)0); /* guard against use */
485}
486
487/*
488 * Check if the peer supports HT.
489 * Require a HT capabilities IE and at least one of the mandatory MCS.
490 * MCS 0-7 are mandatory but some APs have particular MCS disabled.
491 */
492static inline int
493ieee80211_node_supports_ht(struct ieee80211_node *ni)
494{
495 return ((ni->ni_flags & IEEE80211_NODE_HTCAP0x20000) &&
496 ni->ni_rxmcs[0] & 0xff);
497}
498
499/* Check if the peer supports HT short guard interval (SGI) on 20 MHz. */
500static inline int
501ieee80211_node_supports_ht_sgi20(struct ieee80211_node *ni)
502{
503 return ieee80211_node_supports_ht(ni) &&
504 (ni->ni_htcaps & IEEE80211_HTCAP_SGI200x00000020);
505}
506
507/* Check if the peer supports HT short guard interval (SGI) on 40 MHz. */
508static inline int
509ieee80211_node_supports_ht_sgi40(struct ieee80211_node *ni)
510{
511 return ieee80211_node_supports_ht(ni) &&
512 (ni->ni_htcaps & IEEE80211_HTCAP_SGI400x00000040);
513}
514
515/* Check if the peer can receive frames sent on a 40 MHz channel. */
516static inline int
517ieee80211_node_supports_ht_chan40(struct ieee80211_node *ni)
518{
519 return (ieee80211_node_supports_ht(ni) &&
19
Value assigned to field 'ni_txmcs'
20
Assuming the condition is false
520 (ni->ni_htcaps & IEEE80211_HTCAP_CBW20_400x00000002) &&
521 (ni->ni_htop0 & IEEE80211_HTOP0_CHW0x04));
522}
523
524/*
525 * Check if the peer supports VHT.
526 * Require a VHT capabilities IE and support for VHT MCS with a single
527 * spatial stream.
528 */
529static inline int
530ieee80211_node_supports_vht(struct ieee80211_node *ni)
531{
532 uint16_t rx_mcs;
533
534 rx_mcs = (ni->ni_vht_rxmcs & IEEE80211_VHT_MCS_FOR_SS_MASK(1)(0x3 << (2*((1)-1)))) >>
535 IEEE80211_VHT_MCS_FOR_SS_SHIFT(1)(2*((1)-1));
536
537 return ((ni->ni_flags & IEEE80211_NODE_VHTCAP0x40000) &&
538 rx_mcs != IEEE80211_VHT_MCS_SS_NOT_SUPP3);
539}
540
541/* Check if the peer supports VHT short guard interval (SGI) on 80 MHz. */
542static inline int
543ieee80211_node_supports_vht_sgi80(struct ieee80211_node *ni)
544{
545 return ieee80211_node_supports_vht(ni) &&
546 (ni->ni_vhtcaps & IEEE80211_VHTCAP_SGI800x00000020);
547}
548
549/* Check if the peer supports VHT short guard interval (SGI) on 160 MHz. */
550static inline int
551ieee80211_node_supports_vht_sgi160(struct ieee80211_node *ni)
552{
553 return ieee80211_node_supports_vht(ni) &&
554 (ni->ni_vhtcaps & IEEE80211_VHTCAP_SGI1600x00000040);
555}
556
557/* Check if the peer can receive frames sent on an 80 MHz channel. */
558static inline int
559ieee80211_node_supports_vht_chan80(struct ieee80211_node *ni)
560{
561 uint8_t cap_chan_width, op_chan_width;
562
563 if (!ieee80211_node_supports_vht(ni))
564 return 0;
565
566 cap_chan_width = (ni->ni_vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK0x0c) >>
567 IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT2;
568 if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_800 &&
569 cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_1601 &&
570 cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160_80802)
571 return 0;
572
573 op_chan_width = (ni->ni_vht_chan_width &
574 IEEE80211_VHTOP0_CHAN_WIDTH_MASK0x03) >>
575 IEEE80211_VHTOP0_CHAN_WIDTH_SHIFT0;
576
577 return (op_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_801 ||
578 op_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_1602 ||
579 op_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80803);
580}
581
582/* Check if the peer can receive frames sent on a 160 MHz channel. */
583static inline int
584ieee80211_node_supports_vht_chan160(struct ieee80211_node *ni)
585{
586 uint8_t cap_chan_width, op_chan_width;
587
588 if (!ieee80211_node_supports_vht(ni))
589 return 0;
590
591 cap_chan_width = (ni->ni_vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK0x0c) >>
592 IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT2;
593 if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_1601)
594 return 0;
595
596 op_chan_width = (ni->ni_vht_chan_width &
597 IEEE80211_VHTOP0_CHAN_WIDTH_MASK0x03) >>
598 IEEE80211_VHTOP0_CHAN_WIDTH_SHIFT0;
599
600 return (op_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_1602);
601}
602
603struct ieee80211com;
604
605typedef void ieee80211_iter_func(void *, struct ieee80211_node *);
606
607void ieee80211_node_attach(struct ifnet *);
608void ieee80211_node_lateattach(struct ifnet *);
609void ieee80211_node_detach(struct ifnet *);
610
611void ieee80211_begin_scan(struct ifnet *);
612void ieee80211_next_scan(struct ifnet *);
613void ieee80211_end_scan(struct ifnet *);
614void ieee80211_reset_scan(struct ifnet *);
615struct ieee80211_node *ieee80211_alloc_node(struct ieee80211com *,
616 const u_int8_t *);
617struct ieee80211_node *ieee80211_dup_bss(struct ieee80211com *,
618 const u_int8_t *);
619struct ieee80211_node *ieee80211_find_node(struct ieee80211com *,
620 const u_int8_t *);
621void ieee80211_node_tx_ba_clear(struct ieee80211_node *, int);
622void ieee80211_ba_del(struct ieee80211_node *);
623struct ieee80211_node *ieee80211_find_rxnode(struct ieee80211com *,
624 const struct ieee80211_frame *);
625struct ieee80211_node *ieee80211_find_txnode(struct ieee80211com *,
626 const u_int8_t *);
627void ieee80211_release_node(struct ieee80211com *,
628 struct ieee80211_node *);
629void ieee80211_node_cleanup(struct ieee80211com *, struct ieee80211_node *);
630void ieee80211_free_allnodes(struct ieee80211com *, int);
631void ieee80211_iterate_nodes(struct ieee80211com *,
632 ieee80211_iter_func *, void *);
633void ieee80211_clean_cached(struct ieee80211com *);
634void ieee80211_clean_nodes(struct ieee80211com *, int);
635void ieee80211_setup_htcaps(struct ieee80211_node *, const uint8_t *,
636 uint8_t);
637void ieee80211_clear_htcaps(struct ieee80211_node *);
638int ieee80211_setup_htop(struct ieee80211_node *, const uint8_t *,
639 uint8_t, int);
640void ieee80211_setup_vhtcaps(struct ieee80211_node *, const uint8_t *,
641 uint8_t);
642void ieee80211_clear_vhtcaps(struct ieee80211_node *);
643int ieee80211_setup_vhtop(struct ieee80211_node *, const uint8_t *,
644 uint8_t, int);
645int ieee80211_setup_rates(struct ieee80211com *,
646 struct ieee80211_node *, const u_int8_t *, const u_int8_t *, int);
647void ieee80211_node_trigger_addba_req(struct ieee80211_node *, int);
648int ieee80211_iserp_sta(const struct ieee80211_node *);
649void ieee80211_count_longslotsta(void *, struct ieee80211_node *);
650void ieee80211_count_nonerpsta(void *, struct ieee80211_node *);
651void ieee80211_count_pssta(void *, struct ieee80211_node *);
652void ieee80211_count_rekeysta(void *, struct ieee80211_node *);
653void ieee80211_node_join(struct ieee80211com *,
654 struct ieee80211_node *, int);
655void ieee80211_node_leave(struct ieee80211com *,
656 struct ieee80211_node *);
657int ieee80211_match_bss(struct ieee80211com *, struct ieee80211_node *, int);
658void ieee80211_node_tx_stopped(struct ieee80211com *, struct ieee80211_node *);
659struct ieee80211_node *ieee80211_node_choose_bss(struct ieee80211com *, int,
660 struct ieee80211_node **);
661void ieee80211_node_join_bss(struct ieee80211com *, struct ieee80211_node *);
662void ieee80211_create_ibss(struct ieee80211com* ,
663 struct ieee80211_channel *);
664void ieee80211_notify_dtim(struct ieee80211com *);
665void ieee80211_set_tim(struct ieee80211com *, int, int);
666void ieee80211_free_node(struct ieee80211com *, struct ieee80211_node *);
667
668int ieee80211_node_cmp(const struct ieee80211_node *,
669 const struct ieee80211_node *);
670int ieee80211_ess_cmp(const struct ieee80211_ess_rbt *,
671 const struct ieee80211_ess_rbt *);
672RBT_PROTOTYPE(ieee80211_tree, ieee80211_node, ni_node, ieee80211_node_cmp)extern const struct rb_type *const ieee80211_tree_RBT_TYPE; __attribute__
((__unused__)) static inline void ieee80211_tree_RBT_INIT(struct
ieee80211_tree *head) { _rb_init(&head->rbh_root); } __attribute__
((__unused__)) static inline struct ieee80211_node * ieee80211_tree_RBT_INSERT
(struct ieee80211_tree *head, struct ieee80211_node *elm) { return
_rb_insert(ieee80211_tree_RBT_TYPE, &head->rbh_root, elm
); } __attribute__((__unused__)) static inline struct ieee80211_node
* ieee80211_tree_RBT_REMOVE(struct ieee80211_tree *head, struct
ieee80211_node *elm) { return _rb_remove(ieee80211_tree_RBT_TYPE
, &head->rbh_root, elm); } __attribute__((__unused__))
static inline struct ieee80211_node * ieee80211_tree_RBT_FIND
(struct ieee80211_tree *head, const struct ieee80211_node *key
) { return _rb_find(ieee80211_tree_RBT_TYPE, &head->rbh_root
, key); } __attribute__((__unused__)) static inline struct ieee80211_node
* ieee80211_tree_RBT_NFIND(struct ieee80211_tree *head, const
struct ieee80211_node *key) { return _rb_nfind(ieee80211_tree_RBT_TYPE
, &head->rbh_root, key); } __attribute__((__unused__))
static inline struct ieee80211_node * ieee80211_tree_RBT_ROOT
(struct ieee80211_tree *head) { return _rb_root(ieee80211_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline int ieee80211_tree_RBT_EMPTY(struct ieee80211_tree *head
) { return _rb_empty(&head->rbh_root); } __attribute__
((__unused__)) static inline struct ieee80211_node * ieee80211_tree_RBT_MIN
(struct ieee80211_tree *head) { return _rb_min(ieee80211_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline struct ieee80211_node * ieee80211_tree_RBT_MAX(struct
ieee80211_tree *head) { return _rb_max(ieee80211_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline struct ieee80211_node * ieee80211_tree_RBT_NEXT(struct
ieee80211_node *elm) { return _rb_next(ieee80211_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline struct ieee80211_node
* ieee80211_tree_RBT_PREV(struct ieee80211_node *elm) { return
_rb_prev(ieee80211_tree_RBT_TYPE, elm); } __attribute__((__unused__
)) static inline struct ieee80211_node * ieee80211_tree_RBT_LEFT
(struct ieee80211_node *elm) { return _rb_left(ieee80211_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline struct ieee80211_node
* ieee80211_tree_RBT_RIGHT(struct ieee80211_node *elm) { return
_rb_right(ieee80211_tree_RBT_TYPE, elm); } __attribute__((__unused__
)) static inline struct ieee80211_node * ieee80211_tree_RBT_PARENT
(struct ieee80211_node *elm) { return _rb_parent(ieee80211_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline void ieee80211_tree_RBT_SET_LEFT
(struct ieee80211_node *elm, struct ieee80211_node *left) { _rb_set_left
(ieee80211_tree_RBT_TYPE, elm, left); } __attribute__((__unused__
)) static inline void ieee80211_tree_RBT_SET_RIGHT(struct ieee80211_node
*elm, struct ieee80211_node *right) { _rb_set_right(ieee80211_tree_RBT_TYPE
, elm, right); } __attribute__((__unused__)) static inline void
ieee80211_tree_RBT_SET_PARENT(struct ieee80211_node *elm, struct
ieee80211_node *parent) { _rb_set_parent(ieee80211_tree_RBT_TYPE
, elm, parent); } __attribute__((__unused__)) static inline void
ieee80211_tree_RBT_POISON(struct ieee80211_node *elm, unsigned
long poison) { _rb_poison(ieee80211_tree_RBT_TYPE, elm, poison
); } __attribute__((__unused__)) static inline int ieee80211_tree_RBT_CHECK
(struct ieee80211_node *elm, unsigned long poison) { return _rb_check
(ieee80211_tree_RBT_TYPE, elm, poison); }
;
673RBT_PROTOTYPE(ieee80211_ess_tree, ieee80211_ess_rbt, ess_rbt, ieee80211_ess_cmp)extern const struct rb_type *const ieee80211_ess_tree_RBT_TYPE
; __attribute__((__unused__)) static inline void ieee80211_ess_tree_RBT_INIT
(struct ieee80211_ess_tree *head) { _rb_init(&head->rbh_root
); } __attribute__((__unused__)) static inline struct ieee80211_ess_rbt
* ieee80211_ess_tree_RBT_INSERT(struct ieee80211_ess_tree *head
, struct ieee80211_ess_rbt *elm) { return _rb_insert(ieee80211_ess_tree_RBT_TYPE
, &head->rbh_root, elm); } __attribute__((__unused__))
static inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_REMOVE
(struct ieee80211_ess_tree *head, struct ieee80211_ess_rbt *elm
) { return _rb_remove(ieee80211_ess_tree_RBT_TYPE, &head->
rbh_root, elm); } __attribute__((__unused__)) static inline struct
ieee80211_ess_rbt * ieee80211_ess_tree_RBT_FIND(struct ieee80211_ess_tree
*head, const struct ieee80211_ess_rbt *key) { return _rb_find
(ieee80211_ess_tree_RBT_TYPE, &head->rbh_root, key); }
__attribute__((__unused__)) static inline struct ieee80211_ess_rbt
* ieee80211_ess_tree_RBT_NFIND(struct ieee80211_ess_tree *head
, const struct ieee80211_ess_rbt *key) { return _rb_nfind(ieee80211_ess_tree_RBT_TYPE
, &head->rbh_root, key); } __attribute__((__unused__))
static inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_ROOT
(struct ieee80211_ess_tree *head) { return _rb_root(ieee80211_ess_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline int ieee80211_ess_tree_RBT_EMPTY(struct ieee80211_ess_tree
*head) { return _rb_empty(&head->rbh_root); } __attribute__
((__unused__)) static inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_MIN
(struct ieee80211_ess_tree *head) { return _rb_min(ieee80211_ess_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_MAX
(struct ieee80211_ess_tree *head) { return _rb_max(ieee80211_ess_tree_RBT_TYPE
, &head->rbh_root); } __attribute__((__unused__)) static
inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_NEXT
(struct ieee80211_ess_rbt *elm) { return _rb_next(ieee80211_ess_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline struct ieee80211_ess_rbt
* ieee80211_ess_tree_RBT_PREV(struct ieee80211_ess_rbt *elm)
{ return _rb_prev(ieee80211_ess_tree_RBT_TYPE, elm); } __attribute__
((__unused__)) static inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_LEFT
(struct ieee80211_ess_rbt *elm) { return _rb_left(ieee80211_ess_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline struct ieee80211_ess_rbt
* ieee80211_ess_tree_RBT_RIGHT(struct ieee80211_ess_rbt *elm
) { return _rb_right(ieee80211_ess_tree_RBT_TYPE, elm); } __attribute__
((__unused__)) static inline struct ieee80211_ess_rbt * ieee80211_ess_tree_RBT_PARENT
(struct ieee80211_ess_rbt *elm) { return _rb_parent(ieee80211_ess_tree_RBT_TYPE
, elm); } __attribute__((__unused__)) static inline void ieee80211_ess_tree_RBT_SET_LEFT
(struct ieee80211_ess_rbt *elm, struct ieee80211_ess_rbt *left
) { _rb_set_left(ieee80211_ess_tree_RBT_TYPE, elm, left); } __attribute__
((__unused__)) static inline void ieee80211_ess_tree_RBT_SET_RIGHT
(struct ieee80211_ess_rbt *elm, struct ieee80211_ess_rbt *right
) { _rb_set_right(ieee80211_ess_tree_RBT_TYPE, elm, right); }
__attribute__((__unused__)) static inline void ieee80211_ess_tree_RBT_SET_PARENT
(struct ieee80211_ess_rbt *elm, struct ieee80211_ess_rbt *parent
) { _rb_set_parent(ieee80211_ess_tree_RBT_TYPE, elm, parent);
} __attribute__((__unused__)) static inline void ieee80211_ess_tree_RBT_POISON
(struct ieee80211_ess_rbt *elm, unsigned long poison) { _rb_poison
(ieee80211_ess_tree_RBT_TYPE, elm, poison); } __attribute__((
__unused__)) static inline int ieee80211_ess_tree_RBT_CHECK(struct
ieee80211_ess_rbt *elm, unsigned long poison) { return _rb_check
(ieee80211_ess_tree_RBT_TYPE, elm, poison); }
;
674
675#endif /* _NET80211_IEEE80211_NODE_H_ */