Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net80211/ieee80211_ht.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*/
27
28
/*
29
* IEEE 802.11n protocol support.
30
*/
31
32
#include "opt_inet.h"
33
#include "opt_wlan.h"
34
35
#include <sys/param.h>
36
#include <sys/kernel.h>
37
#include <sys/malloc.h>
38
#include <sys/systm.h>
39
#include <sys/endian.h>
40
41
#include <sys/socket.h>
42
43
#include <net/if.h>
44
#include <net/if_var.h>
45
#include <net/if_media.h>
46
#include <net/ethernet.h>
47
48
#include <net80211/ieee80211_var.h>
49
#include <net80211/ieee80211_action.h>
50
#include <net80211/ieee80211_input.h>
51
52
const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = {
53
{ 13, 14, 27, 30 }, /* MCS 0 */
54
{ 26, 29, 54, 60 }, /* MCS 1 */
55
{ 39, 43, 81, 90 }, /* MCS 2 */
56
{ 52, 58, 108, 120 }, /* MCS 3 */
57
{ 78, 87, 162, 180 }, /* MCS 4 */
58
{ 104, 116, 216, 240 }, /* MCS 5 */
59
{ 117, 130, 243, 270 }, /* MCS 6 */
60
{ 130, 144, 270, 300 }, /* MCS 7 */
61
{ 26, 29, 54, 60 }, /* MCS 8 */
62
{ 52, 58, 108, 120 }, /* MCS 9 */
63
{ 78, 87, 162, 180 }, /* MCS 10 */
64
{ 104, 116, 216, 240 }, /* MCS 11 */
65
{ 156, 173, 324, 360 }, /* MCS 12 */
66
{ 208, 231, 432, 480 }, /* MCS 13 */
67
{ 234, 260, 486, 540 }, /* MCS 14 */
68
{ 260, 289, 540, 600 }, /* MCS 15 */
69
{ 39, 43, 81, 90 }, /* MCS 16 */
70
{ 78, 87, 162, 180 }, /* MCS 17 */
71
{ 117, 130, 243, 270 }, /* MCS 18 */
72
{ 156, 173, 324, 360 }, /* MCS 19 */
73
{ 234, 260, 486, 540 }, /* MCS 20 */
74
{ 312, 347, 648, 720 }, /* MCS 21 */
75
{ 351, 390, 729, 810 }, /* MCS 22 */
76
{ 390, 433, 810, 900 }, /* MCS 23 */
77
{ 52, 58, 108, 120 }, /* MCS 24 */
78
{ 104, 116, 216, 240 }, /* MCS 25 */
79
{ 156, 173, 324, 360 }, /* MCS 26 */
80
{ 208, 231, 432, 480 }, /* MCS 27 */
81
{ 312, 347, 648, 720 }, /* MCS 28 */
82
{ 416, 462, 864, 960 }, /* MCS 29 */
83
{ 468, 520, 972, 1080 }, /* MCS 30 */
84
{ 520, 578, 1080, 1200 }, /* MCS 31 */
85
{ 0, 0, 12, 13 }, /* MCS 32 */
86
{ 78, 87, 162, 180 }, /* MCS 33 */
87
{ 104, 116, 216, 240 }, /* MCS 34 */
88
{ 130, 144, 270, 300 }, /* MCS 35 */
89
{ 117, 130, 243, 270 }, /* MCS 36 */
90
{ 156, 173, 324, 360 }, /* MCS 37 */
91
{ 195, 217, 405, 450 }, /* MCS 38 */
92
{ 104, 116, 216, 240 }, /* MCS 39 */
93
{ 130, 144, 270, 300 }, /* MCS 40 */
94
{ 130, 144, 270, 300 }, /* MCS 41 */
95
{ 156, 173, 324, 360 }, /* MCS 42 */
96
{ 182, 202, 378, 420 }, /* MCS 43 */
97
{ 182, 202, 378, 420 }, /* MCS 44 */
98
{ 208, 231, 432, 480 }, /* MCS 45 */
99
{ 156, 173, 324, 360 }, /* MCS 46 */
100
{ 195, 217, 405, 450 }, /* MCS 47 */
101
{ 195, 217, 405, 450 }, /* MCS 48 */
102
{ 234, 260, 486, 540 }, /* MCS 49 */
103
{ 273, 303, 567, 630 }, /* MCS 50 */
104
{ 273, 303, 567, 630 }, /* MCS 51 */
105
{ 312, 347, 648, 720 }, /* MCS 52 */
106
{ 130, 144, 270, 300 }, /* MCS 53 */
107
{ 156, 173, 324, 360 }, /* MCS 54 */
108
{ 182, 202, 378, 420 }, /* MCS 55 */
109
{ 156, 173, 324, 360 }, /* MCS 56 */
110
{ 182, 202, 378, 420 }, /* MCS 57 */
111
{ 208, 231, 432, 480 }, /* MCS 58 */
112
{ 234, 260, 486, 540 }, /* MCS 59 */
113
{ 208, 231, 432, 480 }, /* MCS 60 */
114
{ 234, 260, 486, 540 }, /* MCS 61 */
115
{ 260, 289, 540, 600 }, /* MCS 62 */
116
{ 260, 289, 540, 600 }, /* MCS 63 */
117
{ 286, 318, 594, 660 }, /* MCS 64 */
118
{ 195, 217, 405, 450 }, /* MCS 65 */
119
{ 234, 260, 486, 540 }, /* MCS 66 */
120
{ 273, 303, 567, 630 }, /* MCS 67 */
121
{ 234, 260, 486, 540 }, /* MCS 68 */
122
{ 273, 303, 567, 630 }, /* MCS 69 */
123
{ 312, 347, 648, 720 }, /* MCS 70 */
124
{ 351, 390, 729, 810 }, /* MCS 71 */
125
{ 312, 347, 648, 720 }, /* MCS 72 */
126
{ 351, 390, 729, 810 }, /* MCS 73 */
127
{ 390, 433, 810, 900 }, /* MCS 74 */
128
{ 390, 433, 810, 900 }, /* MCS 75 */
129
{ 429, 477, 891, 990 }, /* MCS 76 */
130
};
131
132
static int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */
133
SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age,
134
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
135
&ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I",
136
"AMPDU max reorder age (ms)");
137
138
static int ieee80211_recv_bar_ena = 1;
139
SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena,
140
0, "BAR frame processing (ena/dis)");
141
142
static int ieee80211_addba_timeout = -1;/* timeout for ADDBA response */
143
SYSCTL_PROC(_net_wlan, OID_AUTO, addba_timeout,
144
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
145
&ieee80211_addba_timeout, 0, ieee80211_sysctl_msecs_ticks, "I",
146
"ADDBA request timeout (ms)");
147
static int ieee80211_addba_backoff = -1;/* backoff after max ADDBA requests */
148
SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff,
149
CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
150
&ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I",
151
"ADDBA request backoff (ms)");
152
static int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
153
SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW,
154
&ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
155
156
static int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
157
static int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
158
159
static ieee80211_recv_action_func ht_recv_action_ba_addba_request;
160
static ieee80211_recv_action_func ht_recv_action_ba_addba_response;
161
static ieee80211_recv_action_func ht_recv_action_ba_delba;
162
static ieee80211_recv_action_func ht_recv_action_ht_mimopwrsave;
163
static ieee80211_recv_action_func ht_recv_action_ht_txchwidth;
164
165
static ieee80211_send_action_func ht_send_action_ba_addba;
166
static ieee80211_send_action_func ht_send_action_ba_delba;
167
static ieee80211_send_action_func ht_send_action_ht_txchwidth;
168
169
static void
170
ieee80211_ht_init(void)
171
{
172
/*
173
* Setup HT parameters that depends on the clock frequency.
174
*/
175
ieee80211_ampdu_age = msecs_to_ticks(500);
176
ieee80211_addba_timeout = msecs_to_ticks(250);
177
ieee80211_addba_backoff = msecs_to_ticks(10*1000);
178
ieee80211_bar_timeout = msecs_to_ticks(250);
179
/*
180
* Register action frame handlers.
181
*/
182
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
183
IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_recv_action_ba_addba_request);
184
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
185
IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_recv_action_ba_addba_response);
186
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA,
187
IEEE80211_ACTION_BA_DELBA, ht_recv_action_ba_delba);
188
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
189
IEEE80211_ACTION_HT_MIMOPWRSAVE, ht_recv_action_ht_mimopwrsave);
190
ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT,
191
IEEE80211_ACTION_HT_TXCHWIDTH, ht_recv_action_ht_txchwidth);
192
193
ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
194
IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_send_action_ba_addba);
195
ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
196
IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_send_action_ba_addba);
197
ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA,
198
IEEE80211_ACTION_BA_DELBA, ht_send_action_ba_delba);
199
ieee80211_send_action_register(IEEE80211_ACTION_CAT_HT,
200
IEEE80211_ACTION_HT_TXCHWIDTH, ht_send_action_ht_txchwidth);
201
}
202
SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
203
204
static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
205
struct ieee80211_tx_ampdu *tap);
206
static int ieee80211_addba_request(struct ieee80211_node *ni,
207
struct ieee80211_tx_ampdu *tap,
208
int dialogtoken, int baparamset, int batimeout);
209
static int ieee80211_addba_response(struct ieee80211_node *ni,
210
struct ieee80211_tx_ampdu *tap,
211
int code, int baparamset, int batimeout);
212
static void ieee80211_addba_stop(struct ieee80211_node *ni,
213
struct ieee80211_tx_ampdu *tap);
214
static void null_addba_response_timeout(struct ieee80211_node *ni,
215
struct ieee80211_tx_ampdu *tap);
216
217
static void ieee80211_bar_response(struct ieee80211_node *ni,
218
struct ieee80211_tx_ampdu *tap, int status);
219
static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
220
static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
221
static int ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *,
222
int baparamset, int batimeout, int baseqctl);
223
static void ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *);
224
225
void
226
ieee80211_ht_attach(struct ieee80211com *ic)
227
{
228
/* setup default aggregation policy */
229
ic->ic_recv_action = ieee80211_recv_action;
230
ic->ic_send_action = ieee80211_send_action;
231
ic->ic_ampdu_enable = ieee80211_ampdu_enable;
232
ic->ic_addba_request = ieee80211_addba_request;
233
ic->ic_addba_response = ieee80211_addba_response;
234
ic->ic_addba_response_timeout = null_addba_response_timeout;
235
ic->ic_addba_stop = ieee80211_addba_stop;
236
ic->ic_bar_response = ieee80211_bar_response;
237
ic->ic_ampdu_rx_start = ampdu_rx_start;
238
ic->ic_ampdu_rx_stop = ampdu_rx_stop;
239
240
ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
241
ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
242
}
243
244
void
245
ieee80211_ht_detach(struct ieee80211com *ic)
246
{
247
}
248
249
void
250
ieee80211_ht_vattach(struct ieee80211vap *vap)
251
{
252
253
/* driver can override defaults */
254
vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
255
vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
256
vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
257
vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
258
/* tx aggregation traffic thresholds */
259
vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
260
vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
261
vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
262
vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
263
264
vap->iv_htprotmode = IEEE80211_PROT_RTSCTS;
265
vap->iv_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
266
267
if (vap->iv_htcaps & IEEE80211_HTC_HT) {
268
/*
269
* Device is HT capable; enable all HT-related
270
* facilities by default.
271
* XXX these choices may be too aggressive.
272
*/
273
vap->iv_flags_ht |= IEEE80211_FHT_HT
274
| IEEE80211_FHT_HTCOMPAT
275
;
276
if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
277
vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI20;
278
/* XXX infer from channel list? */
279
if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
280
vap->iv_flags_ht |= IEEE80211_FHT_USEHT40;
281
if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
282
vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI40;
283
}
284
/* enable RIFS if capable */
285
if (vap->iv_htcaps & IEEE80211_HTC_RIFS)
286
vap->iv_flags_ht |= IEEE80211_FHT_RIFS;
287
288
/* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
289
vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_RX;
290
if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
291
vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_TX;
292
vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_RX;
293
if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
294
vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_TX;
295
296
if (vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC)
297
vap->iv_flags_ht |= IEEE80211_FHT_STBC_TX;
298
if (vap->iv_htcaps & IEEE80211_HTCAP_RXSTBC)
299
vap->iv_flags_ht |= IEEE80211_FHT_STBC_RX;
300
301
if (vap->iv_htcaps & IEEE80211_HTCAP_LDPC)
302
vap->iv_flags_ht |= IEEE80211_FHT_LDPC_RX;
303
if (vap->iv_htcaps & IEEE80211_HTC_TXLDPC)
304
vap->iv_flags_ht |= IEEE80211_FHT_LDPC_TX;
305
}
306
/* NB: disable default legacy WDS, too many issues right now */
307
if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
308
vap->iv_flags_ht &= ~IEEE80211_FHT_HT;
309
}
310
311
void
312
ieee80211_ht_vdetach(struct ieee80211vap *vap)
313
{
314
}
315
316
static int
317
ht_getrate(struct ieee80211com *ic, int index, enum ieee80211_phymode mode,
318
int ratetype)
319
{
320
struct ieee80211_node_txrate tr;
321
int mword, rate;
322
323
tr = IEEE80211_NODE_TXRATE_INIT_HT(index);
324
325
mword = ieee80211_rate2media(ic, &tr, mode);
326
if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
327
return (0);
328
switch (ratetype) {
329
case 0:
330
rate = ieee80211_htrates[index].ht20_rate_800ns;
331
break;
332
case 1:
333
rate = ieee80211_htrates[index].ht20_rate_400ns;
334
break;
335
case 2:
336
rate = ieee80211_htrates[index].ht40_rate_800ns;
337
break;
338
default:
339
rate = ieee80211_htrates[index].ht40_rate_400ns;
340
break;
341
}
342
return (rate);
343
}
344
345
static struct printranges {
346
int minmcs;
347
int maxmcs;
348
int txstream;
349
int ratetype;
350
int htcapflags;
351
} ranges[] = {
352
{ 0, 7, 1, 0, 0 },
353
{ 8, 15, 2, 0, 0 },
354
{ 16, 23, 3, 0, 0 },
355
{ 24, 31, 4, 0, 0 },
356
{ 32, 0, 1, 2, IEEE80211_HTC_TXMCS32 },
357
{ 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL },
358
{ 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL },
359
{ 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL },
360
{ 0, 0, 0, 0, 0 },
361
};
362
363
static void
364
ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype)
365
{
366
int minrate, maxrate;
367
struct printranges *range;
368
369
for (range = ranges; range->txstream != 0; range++) {
370
if (ic->ic_txstream < range->txstream)
371
continue;
372
if (range->htcapflags &&
373
(ic->ic_htcaps & range->htcapflags) == 0)
374
continue;
375
if (ratetype < range->ratetype)
376
continue;
377
minrate = ht_getrate(ic, range->minmcs, mode, ratetype);
378
maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype);
379
if (range->maxmcs) {
380
ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n",
381
range->minmcs, range->maxmcs,
382
minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""),
383
maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : ""));
384
} else {
385
ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs,
386
minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""));
387
}
388
}
389
}
390
391
static void
392
ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode)
393
{
394
const char *modestr = ieee80211_phymode_name[mode];
395
396
ic_printf(ic, "%s MCS 20MHz\n", modestr);
397
ht_rateprint(ic, mode, 0);
398
if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) {
399
ic_printf(ic, "%s MCS 20MHz SGI\n", modestr);
400
ht_rateprint(ic, mode, 1);
401
}
402
if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
403
ic_printf(ic, "%s MCS 40MHz:\n", modestr);
404
ht_rateprint(ic, mode, 2);
405
}
406
if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
407
(ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) {
408
ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr);
409
ht_rateprint(ic, mode, 3);
410
}
411
}
412
413
void
414
ieee80211_ht_announce(struct ieee80211com *ic)
415
{
416
417
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
418
isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
419
ic_printf(ic, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream);
420
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
421
ht_announce(ic, IEEE80211_MODE_11NA);
422
if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
423
ht_announce(ic, IEEE80211_MODE_11NG);
424
}
425
426
void
427
ieee80211_init_suphtrates(struct ieee80211com *ic)
428
{
429
#define ADDRATE(x) do { \
430
htrateset->rs_rates[htrateset->rs_nrates] = x; \
431
htrateset->rs_nrates++; \
432
} while (0)
433
struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates;
434
int i;
435
436
memset(htrateset, 0, sizeof(struct ieee80211_htrateset));
437
for (i = 0; i < ic->ic_txstream * 8; i++)
438
ADDRATE(i);
439
if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
440
(ic->ic_htcaps & IEEE80211_HTC_TXMCS32))
441
ADDRATE(32);
442
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
443
if (ic->ic_txstream >= 2) {
444
for (i = 33; i <= 38; i++)
445
ADDRATE(i);
446
}
447
if (ic->ic_txstream >= 3) {
448
for (i = 39; i <= 52; i++)
449
ADDRATE(i);
450
}
451
if (ic->ic_txstream == 4) {
452
for (i = 53; i <= 76; i++)
453
ADDRATE(i);
454
}
455
}
456
#undef ADDRATE
457
}
458
459
/*
460
* Receive processing.
461
*/
462
463
/*
464
* Decap the encapsulated A-MSDU frames and dispatch all but
465
* the last for delivery. The last frame is returned for
466
* delivery via the normal path.
467
*/
468
struct mbuf *
469
ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
470
{
471
struct ieee80211vap *vap = ni->ni_vap;
472
int framelen;
473
struct mbuf *n;
474
475
/* discard 802.3 header inserted by ieee80211_decap */
476
m_adj(m, sizeof(struct ether_header));
477
478
vap->iv_stats.is_amsdu_decap++;
479
480
for (;;) {
481
/*
482
* Decap the first frame, bust it apart from the
483
* remainder and deliver. We leave the last frame
484
* delivery to the caller (for consistency with other
485
* code paths, could also do it here).
486
*/
487
m = ieee80211_decap1(m, &framelen);
488
if (m == NULL) {
489
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
490
ni->ni_macaddr, "a-msdu", "%s", "decap failed");
491
vap->iv_stats.is_amsdu_tooshort++;
492
return NULL;
493
}
494
if (m->m_pkthdr.len == framelen)
495
break;
496
n = m_split(m, framelen, IEEE80211_M_NOWAIT);
497
if (n == NULL) {
498
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
499
ni->ni_macaddr, "a-msdu",
500
"%s", "unable to split encapsulated frames");
501
vap->iv_stats.is_amsdu_split++;
502
m_freem(m); /* NB: must reclaim */
503
return NULL;
504
}
505
vap->iv_deliver_data(vap, ni, m);
506
507
/*
508
* Remove frame contents; each intermediate frame
509
* is required to be aligned to a 4-byte boundary.
510
*/
511
m = n;
512
m_adj(m, roundup2(framelen, 4) - framelen); /* padding */
513
}
514
return m; /* last delivered by caller */
515
}
516
517
static void
518
ampdu_rx_purge_slot(struct ieee80211_rx_ampdu *rap, int i)
519
{
520
struct mbuf *m;
521
522
/* Walk the queue, removing frames as appropriate */
523
for (;;) {
524
m = mbufq_dequeue(&rap->rxa_mq[i]);
525
if (m == NULL)
526
break;
527
rap->rxa_qbytes -= m->m_pkthdr.len;
528
rap->rxa_qframes--;
529
m_freem(m);
530
}
531
}
532
533
/*
534
* Add the given frame to the current RX reorder slot.
535
*
536
* For future offloaded A-MSDU handling where multiple frames with
537
* the same sequence number show up here, this routine will append
538
* those frames as long as they're appropriately tagged.
539
*/
540
static int
541
ampdu_rx_add_slot(struct ieee80211_rx_ampdu *rap, int off, int tid,
542
ieee80211_seq rxseq,
543
struct ieee80211_node *ni,
544
struct mbuf *m,
545
const struct ieee80211_rx_stats *rxs)
546
{
547
const struct ieee80211_rx_stats *rxs_final = NULL;
548
struct ieee80211vap *vap = ni->ni_vap;
549
int toss_dup;
550
#define PROCESS 0 /* caller should process frame */
551
#define CONSUMED 1 /* frame consumed, caller does nothing */
552
553
/*
554
* Figure out if this is a duplicate frame for the given slot.
555
*
556
* We're assuming that the driver will hand us all the frames
557
* for a given AMSDU decap pass and if we get /a/ frame
558
* for an AMSDU decap then we'll get all of them.
559
*
560
* The tricksy bit is that we don't know when the /end/ of
561
* the decap pass is, because we aren't tracking state here
562
* per-slot to know that we've finished receiving the frame list.
563
*
564
* The driver sets RX_F_AMSDU and RX_F_AMSDU_MORE to tell us
565
* what's going on; so ideally we'd just check the frame at the
566
* end of the reassembly slot to see if its F_AMSDU w/ no F_AMSDU_MORE -
567
* that means we've received the whole AMSDU decap pass.
568
*/
569
570
/*
571
* Get the rxs of the final mbuf in the slot, if one exists.
572
*/
573
if (!mbufq_empty(&rap->rxa_mq[off])) {
574
rxs_final = ieee80211_get_rx_params_ptr(mbufq_last(&rap->rxa_mq[off]));
575
}
576
577
/* Default to tossing the duplicate frame */
578
toss_dup = 1;
579
580
/*
581
* Check to see if the final frame has F_AMSDU and F_AMSDU set, AND
582
* this frame has F_AMSDU set (MORE or otherwise.) That's a sign
583
* that more can come.
584
*/
585
586
if ((rxs != NULL) && (rxs_final != NULL) &&
587
ieee80211_check_rxseq_amsdu(rxs) &&
588
ieee80211_check_rxseq_amsdu(rxs_final)) {
589
if (! ieee80211_check_rxseq_amsdu_more(rxs_final)) {
590
/*
591
* amsdu_more() returning 0 means "it's not the
592
* final frame" so we can append more
593
* frames here.
594
*/
595
toss_dup = 0;
596
}
597
}
598
599
/*
600
* If the list is empty OR we have determined we can put more
601
* driver decap'ed AMSDU frames in here, then insert.
602
*/
603
if (mbufq_empty(&rap->rxa_mq[off]) || (toss_dup == 0)) {
604
if (mbufq_enqueue(&rap->rxa_mq[off], m) != 0) {
605
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
606
ni->ni_macaddr,
607
"a-mpdu queue fail",
608
"seqno %u tid %u BA win <%u:%u> off=%d, qlen=%d, maxqlen=%d",
609
rxseq, tid, rap->rxa_start,
610
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
611
off,
612
mbufq_len(&rap->rxa_mq[off]),
613
rap->rxa_mq[off].mq_maxlen);
614
/* XXX error count */
615
m_freem(m);
616
return CONSUMED;
617
}
618
rap->rxa_qframes++;
619
rap->rxa_qbytes += m->m_pkthdr.len;
620
vap->iv_stats.is_ampdu_rx_reorder++;
621
/*
622
* Statistics for AMSDU decap.
623
*/
624
if (rxs != NULL && ieee80211_check_rxseq_amsdu(rxs)) {
625
if (ieee80211_check_rxseq_amsdu_more(rxs)) {
626
/* more=1, AMSDU, end of batch */
627
IEEE80211_NODE_STAT(ni, rx_amsdu_more_end);
628
} else {
629
IEEE80211_NODE_STAT(ni, rx_amsdu_more);
630
}
631
}
632
} else {
633
IEEE80211_DISCARD_MAC(vap,
634
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
635
ni->ni_macaddr, "a-mpdu duplicate",
636
"seqno %u tid %u BA win <%u:%u>",
637
rxseq, tid, rap->rxa_start,
638
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
639
if (rxs != NULL) {
640
IEEE80211_DISCARD_MAC(vap,
641
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
642
ni->ni_macaddr, "a-mpdu duplicate",
643
"seqno %d tid %u pktflags 0x%08x\n",
644
rxseq, tid, rxs->c_pktflags);
645
}
646
if (rxs_final != NULL) {
647
IEEE80211_DISCARD_MAC(vap,
648
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
649
ni->ni_macaddr, "a-mpdu duplicate",
650
"final: pktflags 0x%08x\n",
651
rxs_final->c_pktflags);
652
}
653
vap->iv_stats.is_rx_dup++;
654
IEEE80211_NODE_STAT(ni, rx_dup);
655
m_freem(m);
656
}
657
return CONSUMED;
658
#undef CONSUMED
659
#undef PROCESS
660
}
661
662
/*
663
* Purge all frames in the A-MPDU re-order queue.
664
*/
665
static void
666
ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
667
{
668
int i;
669
670
for (i = 0; i < rap->rxa_wnd; i++) {
671
ampdu_rx_purge_slot(rap, i);
672
if (rap->rxa_qframes == 0)
673
break;
674
}
675
KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
676
("lost %u data, %u frames on ampdu rx q",
677
rap->rxa_qbytes, rap->rxa_qframes));
678
}
679
680
static void
681
ieee80211_ampdu_rx_init_rap(struct ieee80211_node *ni,
682
struct ieee80211_rx_ampdu *rap)
683
{
684
int i;
685
686
/* XXX TODO: ensure the queues are empty */
687
memset(rap, 0, sizeof(*rap));
688
for (i = 0; i < IEEE80211_AGGR_BAWMAX; i++)
689
mbufq_init(&rap->rxa_mq[i], 256);
690
}
691
692
/*
693
* Start A-MPDU rx/re-order processing for the specified TID.
694
*/
695
static int
696
ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,
697
int baparamset, int batimeout, int baseqctl)
698
{
699
struct ieee80211vap *vap = ni->ni_vap;
700
int bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
701
702
if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
703
/*
704
* AMPDU previously setup and not terminated with a DELBA,
705
* flush the reorder q's in case anything remains.
706
*/
707
ampdu_rx_purge(rap);
708
}
709
ieee80211_ampdu_rx_init_rap(ni, rap);
710
rap->rxa_wnd = (bufsiz == 0) ?
711
IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
712
rap->rxa_start = _IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_START);
713
rap->rxa_flags |= IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
714
715
/* XXX this should be a configuration flag */
716
if ((vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU) &&
717
(_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))
718
rap->rxa_flags |= IEEE80211_AGGR_AMSDU;
719
else
720
rap->rxa_flags &= ~IEEE80211_AGGR_AMSDU;
721
722
return 0;
723
}
724
725
/*
726
* Public function; manually setup the RX ampdu state.
727
*/
728
int
729
ieee80211_ampdu_rx_start_ext(struct ieee80211_node *ni, int tid, int seq, int baw)
730
{
731
struct ieee80211_rx_ampdu *rap;
732
733
/* XXX TODO: sanity check tid, seq, baw */
734
735
rap = &ni->ni_rx_ampdu[tid];
736
737
if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
738
/*
739
* AMPDU previously setup and not terminated with a DELBA,
740
* flush the reorder q's in case anything remains.
741
*/
742
ampdu_rx_purge(rap);
743
}
744
745
ieee80211_ampdu_rx_init_rap(ni, rap);
746
747
rap->rxa_wnd = (baw== 0) ?
748
IEEE80211_AGGR_BAWMAX : min(baw, IEEE80211_AGGR_BAWMAX);
749
if (seq == -1) {
750
/* Wait for the first RX frame, use that as BAW */
751
rap->rxa_start = 0;
752
rap->rxa_flags |= IEEE80211_AGGR_WAITRX;
753
} else {
754
rap->rxa_start = seq;
755
}
756
rap->rxa_flags |= IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
757
758
/* XXX TODO: no amsdu flag */
759
760
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
761
"%s: tid=%d, start=%d, wnd=%d, flags=0x%08x",
762
__func__,
763
tid,
764
seq,
765
rap->rxa_wnd,
766
rap->rxa_flags);
767
768
return 0;
769
}
770
771
/*
772
* Public function; manually stop the RX AMPDU state.
773
*/
774
void
775
ieee80211_ampdu_rx_stop_ext(struct ieee80211_node *ni, int tid)
776
{
777
struct ieee80211_rx_ampdu *rap;
778
779
/* XXX TODO: sanity check tid, seq, baw */
780
rap = &ni->ni_rx_ampdu[tid];
781
ampdu_rx_stop(ni, rap);
782
}
783
784
/*
785
* Stop A-MPDU rx processing for the specified TID.
786
*/
787
static void
788
ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
789
{
790
791
ampdu_rx_purge(rap);
792
rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING
793
| IEEE80211_AGGR_XCHGPEND
794
| IEEE80211_AGGR_WAITRX);
795
}
796
797
/*
798
* Dispatch a frame from the A-MPDU reorder queue. The
799
* frame is fed back into ieee80211_input marked with an
800
* M_AMPDU_MPDU flag so it doesn't come back to us (it also
801
* permits ieee80211_input to optimize re-processing).
802
*/
803
static __inline void
804
ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
805
{
806
m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */
807
/* NB: rssi and noise are ignored w/ M_AMPDU_MPDU set */
808
(void) ieee80211_input(ni, m, 0, 0);
809
}
810
811
static int
812
ampdu_dispatch_slot(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni,
813
int i)
814
{
815
struct mbuf *m;
816
int n = 0;
817
818
for (;;) {
819
m = mbufq_dequeue(&rap->rxa_mq[i]);
820
if (m == NULL)
821
break;
822
n++;
823
824
rap->rxa_qbytes -= m->m_pkthdr.len;
825
rap->rxa_qframes--;
826
827
ampdu_dispatch(ni, m);
828
}
829
return (n);
830
}
831
832
static void
833
ampdu_rx_moveup(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni,
834
int i, int winstart)
835
{
836
struct ieee80211vap *vap = ni->ni_vap;
837
838
/*
839
* If frames remain, copy the mbuf pointers down so
840
* they correspond to the offsets in the new window.
841
*/
842
if (rap->rxa_qframes != 0) {
843
int n = rap->rxa_qframes, j;
844
for (j = i+1; j < rap->rxa_wnd; j++) {
845
/*
846
* Concat the list contents over, which will
847
* blank the source list for us.
848
*/
849
if (mbufq_len(&rap->rxa_mq[j]) != 0) {
850
n = n - mbufq_len(&rap->rxa_mq[j]);
851
mbufq_concat(&rap->rxa_mq[j-i], &rap->rxa_mq[j]);
852
KASSERT(n >= 0, ("%s: n < 0 (%d)", __func__, n));
853
if (n == 0)
854
break;
855
}
856
}
857
KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
858
"BA win <%d:%d> winstart %d",
859
__func__, n, rap->rxa_qframes, i, rap->rxa_start,
860
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
861
winstart));
862
vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
863
}
864
}
865
866
/*
867
* Dispatch as many frames as possible from the re-order queue.
868
* Frames will always be "at the front"; we process all frames
869
* up to the first empty slot in the window. On completion we
870
* cleanup state if there are still pending frames in the current
871
* BA window. We assume the frame at slot 0 is already handled
872
* by the caller; we always start at slot 1.
873
*/
874
static void
875
ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
876
{
877
struct ieee80211vap *vap = ni->ni_vap;
878
int i, r, r2;
879
880
/* flush run of frames */
881
r2 = 0;
882
for (i = 1; i < rap->rxa_wnd; i++) {
883
r = ampdu_dispatch_slot(rap, ni, i);
884
if (r == 0)
885
break;
886
r2 += r;
887
}
888
889
/* move up frames */
890
ampdu_rx_moveup(rap, ni, i, -1);
891
892
/*
893
* Adjust the start of the BA window to
894
* reflect the frames just dispatched.
895
*/
896
rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
897
vap->iv_stats.is_ampdu_rx_oor += r2;
898
899
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
900
"%s: moved slot up %d slots to start at %d (%d frames)",
901
__func__,
902
i,
903
rap->rxa_start,
904
r2);
905
}
906
907
/*
908
* Dispatch all frames in the A-MPDU re-order queue.
909
*/
910
static void
911
ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
912
{
913
int i, r;
914
915
for (i = 0; i < rap->rxa_wnd; i++) {
916
r = ampdu_dispatch_slot(rap, ni, i);
917
if (r == 0)
918
continue;
919
ni->ni_vap->iv_stats.is_ampdu_rx_oor += r;
920
921
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
922
"%s: moved slot up %d slots to start at %d (%d frames)",
923
__func__,
924
1,
925
rap->rxa_start,
926
r);
927
928
if (rap->rxa_qframes == 0)
929
break;
930
}
931
}
932
933
/*
934
* Dispatch all frames in the A-MPDU re-order queue
935
* preceding the specified sequence number. This logic
936
* handles window moves due to a received MSDU or BAR.
937
*/
938
static void
939
ampdu_rx_flush_upto(struct ieee80211_node *ni,
940
struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
941
{
942
struct ieee80211vap *vap = ni->ni_vap;
943
ieee80211_seq seqno;
944
int i, r;
945
946
/*
947
* Flush any complete MSDU's with a sequence number lower
948
* than winstart. Gaps may exist. Note that we may actually
949
* dispatch frames past winstart if a run continues; this is
950
* an optimization that avoids having to do a separate pass
951
* to dispatch frames after moving the BA window start.
952
*/
953
seqno = rap->rxa_start;
954
for (i = 0; i < rap->rxa_wnd; i++) {
955
if ((r = mbufq_len(&rap->rxa_mq[i])) != 0) {
956
(void) ampdu_dispatch_slot(rap, ni, i);
957
} else {
958
if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
959
break;
960
}
961
vap->iv_stats.is_ampdu_rx_oor += r;
962
seqno = IEEE80211_SEQ_INC(seqno);
963
964
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
965
"%s: moved slot up %d slots to start at %d (%d frames)",
966
__func__,
967
1,
968
seqno,
969
r);
970
}
971
972
/*
973
* If frames remain, copy the mbuf pointers down so
974
* they correspond to the offsets in the new window.
975
*/
976
ampdu_rx_moveup(rap, ni, i, winstart);
977
978
/*
979
* Move the start of the BA window; we use the
980
* sequence number of the last MSDU that was
981
* passed up the stack+1 or winstart if stopped on
982
* a gap in the reorder buffer.
983
*/
984
rap->rxa_start = seqno;
985
}
986
987
/*
988
* Process a received QoS data frame for an HT station. Handle
989
* A-MPDU reordering: if this frame is received out of order
990
* and falls within the BA window hold onto it. Otherwise if
991
* this frame completes a run, flush any pending frames. We
992
* return 1 if the frame is consumed. A 0 is returned if
993
* the frame should be processed normally by the caller.
994
*
995
* A-MSDU: handle hardware decap'ed A-MSDU frames that are
996
* pretending to be MPDU's. They're dispatched directly if
997
* able; or attempted to put into the receive reordering slot.
998
*/
999
int
1000
ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m,
1001
const struct ieee80211_rx_stats *rxs)
1002
{
1003
#define PROCESS 0 /* caller should process frame */
1004
#define CONSUMED 1 /* frame consumed, caller does nothing */
1005
struct ieee80211vap *vap = ni->ni_vap;
1006
struct ieee80211_qosframe *wh;
1007
struct ieee80211_rx_ampdu *rap;
1008
ieee80211_seq rxseq;
1009
uint8_t tid;
1010
int off;
1011
int amsdu = ieee80211_check_rxseq_amsdu(rxs);
1012
int amsdu_end = ieee80211_check_rxseq_amsdu_more(rxs);
1013
1014
KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
1015
("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
1016
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
1017
1018
/* NB: m_len known to be sufficient */
1019
wh = mtod(m, struct ieee80211_qosframe *);
1020
if (!IEEE80211_IS_QOSDATA(wh)) {
1021
/*
1022
* Not QoS data, shouldn't get here but just
1023
* return it to the caller for processing.
1024
*/
1025
return PROCESS;
1026
}
1027
1028
/*
1029
* 802.11-2012 9.3.2.10 - Duplicate detection and recovery.
1030
*
1031
* Multicast QoS data frames are checked against a different
1032
* counter, not the per-TID counter.
1033
*/
1034
if (IEEE80211_IS_MULTICAST(wh->i_addr1))
1035
return PROCESS;
1036
1037
tid = ieee80211_getqos(wh)[0];
1038
tid &= IEEE80211_QOS_TID;
1039
rap = &ni->ni_rx_ampdu[tid];
1040
if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1041
/*
1042
* No ADDBA request yet, don't touch.
1043
*/
1044
return PROCESS;
1045
}
1046
rxseq = le16toh(*(uint16_t *)wh->i_seq);
1047
if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
1048
/*
1049
* Fragments are not allowed; toss.
1050
*/
1051
IEEE80211_DISCARD_MAC(vap,
1052
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1053
"A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
1054
wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1055
vap->iv_stats.is_ampdu_rx_drop++;
1056
IEEE80211_NODE_STAT(ni, rx_drop);
1057
m_freem(m);
1058
return CONSUMED;
1059
}
1060
rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
1061
rap->rxa_nframes++;
1062
1063
/*
1064
* Handle waiting for the first frame to define the BAW.
1065
* Some firmware doesn't provide the RX of the starting point
1066
* of the BAW and we have to cope.
1067
*/
1068
if (rap->rxa_flags & IEEE80211_AGGR_WAITRX) {
1069
rap->rxa_flags &= ~IEEE80211_AGGR_WAITRX;
1070
rap->rxa_start = rxseq;
1071
}
1072
again:
1073
if (rxseq == rap->rxa_start) {
1074
/*
1075
* First frame in window.
1076
*/
1077
if (rap->rxa_qframes != 0) {
1078
/*
1079
* Dispatch as many packets as we can.
1080
*/
1081
KASSERT(mbufq_empty(&rap->rxa_mq[0]), ("unexpected dup"));
1082
ampdu_dispatch(ni, m);
1083
ampdu_rx_dispatch(rap, ni);
1084
return CONSUMED;
1085
} else {
1086
/*
1087
* In order; advance window if needed and notify
1088
* caller to dispatch directly.
1089
*/
1090
if (amsdu) {
1091
if (amsdu_end) {
1092
rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
1093
IEEE80211_NODE_STAT(ni, rx_amsdu_more_end);
1094
} else {
1095
IEEE80211_NODE_STAT(ni, rx_amsdu_more);
1096
}
1097
} else {
1098
rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
1099
}
1100
return PROCESS;
1101
}
1102
}
1103
/*
1104
* Frame is out of order; store if in the BA window.
1105
*/
1106
/* calculate offset in BA window */
1107
off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
1108
if (off < rap->rxa_wnd) {
1109
/*
1110
* Common case (hopefully): in the BA window.
1111
* Sec 9.10.7.6.2 a) (p.137)
1112
*/
1113
1114
/*
1115
* Check for frames sitting too long in the reorder queue.
1116
* This should only ever happen if frames are not delivered
1117
* without the sender otherwise notifying us (e.g. with a
1118
* BAR to move the window). Typically this happens because
1119
* of vendor bugs that cause the sequence number to jump.
1120
* When this happens we get a gap in the reorder queue that
1121
* leaves frame sitting on the queue until they get pushed
1122
* out due to window moves. When the vendor does not send
1123
* BAR this move only happens due to explicit packet sends
1124
*
1125
* NB: we only track the time of the oldest frame in the
1126
* reorder q; this means that if we flush we might push
1127
* frames that still "new"; if this happens then subsequent
1128
* frames will result in BA window moves which cost something
1129
* but is still better than a big throughput dip.
1130
*/
1131
if (rap->rxa_qframes != 0) {
1132
/* XXX honor batimeout? */
1133
if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
1134
/*
1135
* Too long since we received the first
1136
* frame; flush the reorder buffer.
1137
*/
1138
if (rap->rxa_qframes != 0) {
1139
vap->iv_stats.is_ampdu_rx_age +=
1140
rap->rxa_qframes;
1141
ampdu_rx_flush(ni, rap);
1142
}
1143
/*
1144
* Advance the window if needed and notify
1145
* the caller to dispatch directly.
1146
*/
1147
if (amsdu) {
1148
if (amsdu_end) {
1149
rap->rxa_start =
1150
IEEE80211_SEQ_INC(rxseq);
1151
IEEE80211_NODE_STAT(ni,
1152
rx_amsdu_more_end);
1153
} else {
1154
IEEE80211_NODE_STAT(ni,
1155
rx_amsdu_more);
1156
}
1157
} else {
1158
rap->rxa_start =
1159
IEEE80211_SEQ_INC(rxseq);
1160
}
1161
return PROCESS;
1162
}
1163
} else {
1164
/*
1165
* First frame, start aging timer.
1166
*/
1167
rap->rxa_age = ticks;
1168
}
1169
1170
/* save packet - this consumes, no matter what */
1171
ampdu_rx_add_slot(rap, off, tid, rxseq, ni, m, rxs);
1172
return CONSUMED;
1173
}
1174
if (off < IEEE80211_SEQ_BA_RANGE) {
1175
/*
1176
* Outside the BA window, but within range;
1177
* flush the reorder q and move the window.
1178
* Sec 9.10.7.6.2 b) (p.138)
1179
*/
1180
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1181
"move BA win <%u:%u> (%u frames) rxseq %u tid %u",
1182
rap->rxa_start,
1183
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1184
rap->rxa_qframes, rxseq, tid);
1185
vap->iv_stats.is_ampdu_rx_move++;
1186
1187
/*
1188
* The spec says to flush frames up to but not including:
1189
* WinStart_B = rxseq - rap->rxa_wnd + 1
1190
* Then insert the frame or notify the caller to process
1191
* it immediately. We can safely do this by just starting
1192
* over again because we know the frame will now be within
1193
* the BA window.
1194
*/
1195
/* NB: rxa_wnd known to be >0 */
1196
ampdu_rx_flush_upto(ni, rap,
1197
IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
1198
goto again;
1199
} else {
1200
/*
1201
* Outside the BA window and out of range; toss.
1202
* Sec 9.10.7.6.2 c) (p.138)
1203
*/
1204
IEEE80211_DISCARD_MAC(vap,
1205
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1206
"MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
1207
rap->rxa_start,
1208
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1209
rap->rxa_qframes, rxseq, tid,
1210
wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1211
vap->iv_stats.is_ampdu_rx_drop++;
1212
IEEE80211_NODE_STAT(ni, rx_drop);
1213
m_freem(m);
1214
return CONSUMED;
1215
}
1216
#undef CONSUMED
1217
#undef PROCESS
1218
}
1219
1220
/*
1221
* Process a BAR ctl frame. Dispatch all frames up to
1222
* the sequence number of the frame. If this frame is
1223
* out of range it's discarded.
1224
*/
1225
void
1226
ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
1227
{
1228
struct ieee80211vap *vap = ni->ni_vap;
1229
struct ieee80211_frame_bar *wh;
1230
struct ieee80211_rx_ampdu *rap;
1231
ieee80211_seq rxseq;
1232
int tid, off;
1233
1234
if (!ieee80211_recv_bar_ena) {
1235
#if 0
1236
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
1237
ni->ni_macaddr, "BAR", "%s", "processing disabled");
1238
#endif
1239
vap->iv_stats.is_ampdu_bar_bad++;
1240
return;
1241
}
1242
wh = mtod(m0, struct ieee80211_frame_bar *);
1243
/* XXX check basic BAR */
1244
tid = _IEEE80211_MASKSHIFT(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
1245
rap = &ni->ni_rx_ampdu[tid];
1246
if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1247
/*
1248
* No ADDBA request yet, don't touch.
1249
*/
1250
IEEE80211_DISCARD_MAC(vap,
1251
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
1252
ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
1253
vap->iv_stats.is_ampdu_bar_bad++;
1254
return;
1255
}
1256
vap->iv_stats.is_ampdu_bar_rx++;
1257
rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
1258
if (rxseq == rap->rxa_start)
1259
return;
1260
/* calculate offset in BA window */
1261
off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
1262
if (off < IEEE80211_SEQ_BA_RANGE) {
1263
/*
1264
* Flush the reorder q up to rxseq and move the window.
1265
* Sec 9.10.7.6.3 a) (p.138)
1266
*/
1267
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1268
"BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
1269
rap->rxa_start,
1270
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1271
rap->rxa_qframes, rxseq, tid);
1272
vap->iv_stats.is_ampdu_bar_move++;
1273
1274
ampdu_rx_flush_upto(ni, rap, rxseq);
1275
if (off >= rap->rxa_wnd) {
1276
/*
1277
* BAR specifies a window start to the right of BA
1278
* window; we must move it explicitly since
1279
* ampdu_rx_flush_upto will not.
1280
*/
1281
rap->rxa_start = rxseq;
1282
}
1283
} else {
1284
/*
1285
* Out of range; toss.
1286
* Sec 9.10.7.6.3 b) (p.138)
1287
*/
1288
IEEE80211_DISCARD_MAC(vap,
1289
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1290
"BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
1291
rap->rxa_start,
1292
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1293
rap->rxa_qframes, rxseq, tid,
1294
wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1295
vap->iv_stats.is_ampdu_bar_oow++;
1296
IEEE80211_NODE_STAT(ni, rx_drop);
1297
}
1298
}
1299
1300
/*
1301
* Setup HT-specific state in a node. Called only
1302
* when HT use is negotiated so we don't do extra
1303
* work for temporary and/or legacy sta's.
1304
*/
1305
void
1306
ieee80211_ht_node_init(struct ieee80211_node *ni)
1307
{
1308
struct ieee80211_tx_ampdu *tap;
1309
int tid;
1310
1311
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1312
ni,
1313
"%s: called (%p)",
1314
__func__,
1315
ni);
1316
1317
if (ni->ni_flags & IEEE80211_NODE_HT) {
1318
/*
1319
* Clean AMPDU state on re-associate. This handles the case
1320
* where a station leaves w/o notifying us and then returns
1321
* before node is reaped for inactivity.
1322
*/
1323
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1324
ni,
1325
"%s: calling cleanup (%p)",
1326
__func__, ni);
1327
ieee80211_ht_node_cleanup(ni);
1328
}
1329
for (tid = 0; tid < WME_NUM_TID; tid++) {
1330
tap = &ni->ni_tx_ampdu[tid];
1331
tap->txa_tid = tid;
1332
tap->txa_ni = ni;
1333
ieee80211_txampdu_init_pps(tap);
1334
/* NB: further initialization deferred */
1335
ieee80211_ampdu_rx_init_rap(ni, &ni->ni_rx_ampdu[tid]);
1336
}
1337
ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
1338
IEEE80211_NODE_AMSDU;
1339
}
1340
1341
/*
1342
* Cleanup HT-specific state in a node. Called only
1343
* when HT use has been marked.
1344
*/
1345
void
1346
ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
1347
{
1348
struct ieee80211com *ic = ni->ni_ic;
1349
int i;
1350
1351
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1352
ni,
1353
"%s: called (%p)",
1354
__func__, ni);
1355
1356
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
1357
1358
/* XXX optimize this */
1359
for (i = 0; i < WME_NUM_TID; i++) {
1360
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
1361
if (tap->txa_flags & IEEE80211_AGGR_SETUP)
1362
ampdu_tx_stop(tap);
1363
}
1364
for (i = 0; i < WME_NUM_TID; i++)
1365
ic->ic_ampdu_rx_stop(ni, &ni->ni_rx_ampdu[i]);
1366
1367
ni->ni_htcap = 0;
1368
ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
1369
}
1370
1371
/*
1372
* Age out HT resources for a station.
1373
*/
1374
void
1375
ieee80211_ht_node_age(struct ieee80211_node *ni)
1376
{
1377
struct ieee80211vap *vap = ni->ni_vap;
1378
uint8_t tid;
1379
1380
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
1381
1382
for (tid = 0; tid < WME_NUM_TID; tid++) {
1383
struct ieee80211_rx_ampdu *rap;
1384
1385
rap = &ni->ni_rx_ampdu[tid];
1386
if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
1387
continue;
1388
if (rap->rxa_qframes == 0)
1389
continue;
1390
/*
1391
* Check for frames sitting too long in the reorder queue.
1392
* See above for more details on what's happening here.
1393
*/
1394
/* XXX honor batimeout? */
1395
if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
1396
/*
1397
* Too long since we received the first
1398
* frame; flush the reorder buffer.
1399
*/
1400
vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
1401
ampdu_rx_flush(ni, rap);
1402
}
1403
}
1404
}
1405
1406
static struct ieee80211_channel *
1407
findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
1408
{
1409
return ieee80211_find_channel(ic, c->ic_freq,
1410
(c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
1411
}
1412
1413
/*
1414
* Adjust a channel to be HT/non-HT according to the vap's configuration.
1415
*/
1416
struct ieee80211_channel *
1417
ieee80211_ht_adjust_channel(struct ieee80211com *ic,
1418
struct ieee80211_channel *chan, int flags)
1419
{
1420
struct ieee80211_channel *c;
1421
1422
if (flags & IEEE80211_FHT_HT) {
1423
/* promote to HT if possible */
1424
if (flags & IEEE80211_FHT_USEHT40) {
1425
if (!IEEE80211_IS_CHAN_HT40(chan)) {
1426
/* NB: arbitrarily pick ht40+ over ht40- */
1427
c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
1428
if (c == NULL)
1429
c = findhtchan(ic, chan,
1430
IEEE80211_CHAN_HT40D);
1431
if (c == NULL)
1432
c = findhtchan(ic, chan,
1433
IEEE80211_CHAN_HT20);
1434
if (c != NULL)
1435
chan = c;
1436
}
1437
} else if (!IEEE80211_IS_CHAN_HT20(chan)) {
1438
c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
1439
if (c != NULL)
1440
chan = c;
1441
}
1442
} else if (IEEE80211_IS_CHAN_HT(chan)) {
1443
/* demote to legacy, HT use is disabled */
1444
c = ieee80211_find_channel(ic, chan->ic_freq,
1445
chan->ic_flags &~ IEEE80211_CHAN_HT);
1446
if (c != NULL)
1447
chan = c;
1448
}
1449
return chan;
1450
}
1451
1452
/*
1453
* Setup HT-specific state for a legacy WDS peer.
1454
*/
1455
void
1456
ieee80211_ht_wds_init(struct ieee80211_node *ni)
1457
{
1458
struct ieee80211vap *vap = ni->ni_vap;
1459
struct ieee80211_tx_ampdu *tap;
1460
int tid;
1461
1462
KASSERT(vap->iv_flags_ht & IEEE80211_FHT_HT, ("no HT requested"));
1463
1464
/* XXX check scan cache in case peer has an ap and we have info */
1465
/*
1466
* If setup with a legacy channel; locate an HT channel.
1467
* Otherwise if the inherited channel (from a companion
1468
* AP) is suitable use it so we use the same location
1469
* for the extension channel).
1470
*/
1471
ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
1472
ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
1473
1474
ni->ni_htcap = 0;
1475
if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
1476
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
1477
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
1478
ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
1479
ni->ni_chw = NET80211_STA_RX_BW_40;
1480
if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
1481
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
1482
else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
1483
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
1484
if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
1485
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
1486
} else {
1487
ni->ni_chw = NET80211_STA_RX_BW_20;
1488
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
1489
}
1490
ni->ni_htctlchan = ni->ni_chan->ic_ieee;
1491
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
1492
ni->ni_flags |= IEEE80211_NODE_RIFS;
1493
/* XXX does it make sense to enable SMPS? */
1494
1495
ni->ni_htopmode = 0; /* XXX need protection state */
1496
ni->ni_htstbc = 0; /* XXX need info */
1497
1498
for (tid = 0; tid < WME_NUM_TID; tid++) {
1499
tap = &ni->ni_tx_ampdu[tid];
1500
tap->txa_tid = tid;
1501
ieee80211_txampdu_init_pps(tap);
1502
}
1503
/* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
1504
ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
1505
IEEE80211_NODE_AMSDU;
1506
}
1507
1508
/*
1509
* Notify a VAP of a change in the HTINFO ie if it's a hostap VAP.
1510
*
1511
* This is to be called from the deferred HT protection update
1512
* task once the flags are updated.
1513
*/
1514
void
1515
ieee80211_htinfo_notify(struct ieee80211vap *vap)
1516
{
1517
1518
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1519
1520
if (vap->iv_opmode != IEEE80211_M_HOSTAP)
1521
return;
1522
if (vap->iv_state != IEEE80211_S_RUN ||
1523
!IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
1524
return;
1525
1526
IEEE80211_NOTE(vap,
1527
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1528
vap->iv_bss,
1529
"HT bss occupancy change: %d sta, %d ht, "
1530
"%d ht40%s, HT protmode now 0x%x"
1531
, vap->iv_sta_assoc
1532
, vap->iv_ht_sta_assoc
1533
, vap->iv_ht40_sta_assoc
1534
, (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) ?
1535
", non-HT sta present" : ""
1536
, vap->iv_curhtprotmode);
1537
1538
ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
1539
}
1540
1541
/*
1542
* Calculate HT protection mode from current
1543
* state and handle updates.
1544
*/
1545
static void
1546
htinfo_update(struct ieee80211vap *vap)
1547
{
1548
struct ieee80211com *ic = vap->iv_ic;
1549
uint8_t protmode;
1550
1551
if (vap->iv_sta_assoc != vap->iv_ht_sta_assoc) {
1552
protmode = IEEE80211_HTINFO_OPMODE_MIXED
1553
| IEEE80211_HTINFO_NONHT_PRESENT;
1554
} else if (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) {
1555
protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
1556
| IEEE80211_HTINFO_NONHT_PRESENT;
1557
} else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
1558
IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
1559
vap->iv_sta_assoc != vap->iv_ht40_sta_assoc) {
1560
protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
1561
} else {
1562
protmode = IEEE80211_HTINFO_OPMODE_PURE;
1563
}
1564
if (protmode != vap->iv_curhtprotmode) {
1565
vap->iv_curhtprotmode = protmode;
1566
/* Update VAP with new protection mode */
1567
ieee80211_vap_update_ht_protmode(vap);
1568
}
1569
}
1570
1571
/*
1572
* Handle an HT station joining a BSS.
1573
*/
1574
void
1575
ieee80211_ht_node_join(struct ieee80211_node *ni)
1576
{
1577
struct ieee80211vap *vap = ni->ni_vap;
1578
1579
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1580
1581
if (ni->ni_flags & IEEE80211_NODE_HT) {
1582
vap->iv_ht_sta_assoc++;
1583
if (ni->ni_chw == NET80211_STA_RX_BW_40)
1584
vap->iv_ht40_sta_assoc++;
1585
}
1586
htinfo_update(vap);
1587
}
1588
1589
/*
1590
* Handle an HT station leaving a BSS.
1591
*/
1592
void
1593
ieee80211_ht_node_leave(struct ieee80211_node *ni)
1594
{
1595
struct ieee80211vap *vap = ni->ni_vap;
1596
1597
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1598
1599
if (ni->ni_flags & IEEE80211_NODE_HT) {
1600
vap->iv_ht_sta_assoc--;
1601
if (ni->ni_chw == NET80211_STA_RX_BW_40)
1602
vap->iv_ht40_sta_assoc--;
1603
}
1604
htinfo_update(vap);
1605
}
1606
1607
/*
1608
* Public version of htinfo_update; used for processing
1609
* beacon frames from overlapping bss.
1610
*
1611
* Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
1612
* (on receipt of a beacon that advertises MIXED) or
1613
* IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
1614
* from an overlapping legacy bss). We treat MIXED with
1615
* a higher precedence than PROTOPT (i.e. we will not change
1616
* change PROTOPT -> MIXED; only MIXED -> PROTOPT). This
1617
* corresponds to how we handle things in htinfo_update.
1618
*
1619
*/
1620
void
1621
ieee80211_htprot_update(struct ieee80211vap *vap, int protmode)
1622
{
1623
struct ieee80211com *ic = vap->iv_ic;
1624
#define OPMODE(x) _IEEE80211_SHIFTMASK(x, IEEE80211_HTINFO_OPMODE)
1625
IEEE80211_LOCK(ic);
1626
1627
/* track non-HT station presence */
1628
KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
1629
("protmode 0x%x", protmode));
1630
vap->iv_flags_ht |= IEEE80211_FHT_NONHT_PR;
1631
vap->iv_lastnonht = ticks;
1632
1633
if (protmode != vap->iv_curhtprotmode &&
1634
(OPMODE(vap->iv_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
1635
OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
1636
vap->iv_curhtprotmode = protmode;
1637
/* Update VAP with new protection mode */
1638
ieee80211_vap_update_ht_protmode(vap);
1639
}
1640
IEEE80211_UNLOCK(ic);
1641
#undef OPMODE
1642
}
1643
1644
/*
1645
* Time out presence of an overlapping bss with non-HT
1646
* stations. When operating in hostap mode we listen for
1647
* beacons from other stations and if we identify a non-HT
1648
* station is present we update the opmode field of the
1649
* HTINFO ie. To identify when all non-HT stations are
1650
* gone we time out this condition.
1651
*/
1652
void
1653
ieee80211_ht_timeout(struct ieee80211vap *vap)
1654
{
1655
1656
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1657
1658
if ((vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) &&
1659
ieee80211_time_after(ticks, vap->iv_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
1660
IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
1661
"%s", "time out non-HT STA present on channel");
1662
vap->iv_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
1663
htinfo_update(vap);
1664
}
1665
}
1666
1667
/*
1668
* Process an 802.11n HT capabilities ie.
1669
*/
1670
void
1671
ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1672
{
1673
if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1674
/*
1675
* Station used Vendor OUI ie to associate;
1676
* mark the node so when we respond we'll use
1677
* the Vendor OUI's and not the standard ie's.
1678
*/
1679
ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1680
ie += 4;
1681
} else
1682
ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1683
1684
ni->ni_htcap = le16dec(ie +
1685
__offsetof(struct ieee80211_ie_htcap, hc_cap));
1686
ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1687
}
1688
1689
static void
1690
htinfo_parse(struct ieee80211_node *ni,
1691
const struct ieee80211_ie_htinfo *htinfo)
1692
{
1693
uint16_t w;
1694
1695
ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1696
ni->ni_ht2ndchan = _IEEE80211_SHIFTMASK(htinfo->hi_byte1,
1697
IEEE80211_HTINFO_2NDCHAN);
1698
w = le16dec(&htinfo->hi_byte2);
1699
ni->ni_htopmode = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_OPMODE);
1700
w = le16dec(&htinfo->hi_byte45);
1701
ni->ni_htstbc = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1702
}
1703
1704
/*
1705
* Parse an 802.11n HT info ie and save useful information
1706
* to the node state. Note this does not effect any state
1707
* changes such as for channel width change.
1708
*/
1709
void
1710
ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1711
{
1712
if (ie[0] == IEEE80211_ELEMID_VENDOR)
1713
ie += 4;
1714
htinfo_parse(ni, (const struct ieee80211_ie_htinfo *) ie);
1715
}
1716
1717
/*
1718
* Handle 11n/11ac channel switch.
1719
*
1720
* Use the received HT/VHT ie's to identify the right channel to use.
1721
* If we cannot locate it in the channel table then fallback to
1722
* legacy operation.
1723
*
1724
* Note that we use this information to identify the node's
1725
* channel only; the caller is responsible for insuring any
1726
* required channel change is done (e.g. in sta mode when
1727
* parsing the contents of a beacon frame).
1728
*/
1729
static int
1730
htinfo_update_chw(struct ieee80211_node *ni, int htflags, int vhtflags)
1731
{
1732
struct ieee80211com *ic = ni->ni_ic;
1733
struct ieee80211_channel *c;
1734
int chanflags;
1735
int ret = 0;
1736
1737
/*
1738
* First step - do HT/VHT only channel lookup based on operating mode
1739
* flags. This involves masking out the VHT flags as well.
1740
* Otherwise we end up doing the full channel walk each time
1741
* we trigger this, which is expensive.
1742
*/
1743
chanflags = (ni->ni_chan->ic_flags &~
1744
(IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags | vhtflags;
1745
1746
if (chanflags == ni->ni_chan->ic_flags)
1747
goto done;
1748
1749
/*
1750
* If HT /or/ VHT flags have changed then check both.
1751
* We need to start by picking a HT channel anyway.
1752
*/
1753
1754
c = NULL;
1755
chanflags = (ni->ni_chan->ic_flags &~
1756
(IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags;
1757
/* XXX not right for ht40- */
1758
c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1759
if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
1760
/*
1761
* No HT40 channel entry in our table; fall back
1762
* to HT20 operation. This should not happen.
1763
*/
1764
c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1765
#if 0
1766
IEEE80211_NOTE(ni->ni_vap,
1767
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1768
"no HT40 channel (freq %u), falling back to HT20",
1769
ni->ni_chan->ic_freq);
1770
#endif
1771
/* XXX stat */
1772
}
1773
1774
/* Nothing found - leave it alone; move onto VHT */
1775
if (c == NULL)
1776
c = ni->ni_chan;
1777
1778
/*
1779
* If it's non-HT, then bail out now.
1780
*/
1781
if (! IEEE80211_IS_CHAN_HT(c)) {
1782
IEEE80211_NOTE(ni->ni_vap,
1783
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1784
"not HT; skipping VHT check (%u/0x%x)",
1785
c->ic_freq, c->ic_flags);
1786
goto done;
1787
}
1788
1789
/*
1790
* Next step - look at the current VHT flags and determine
1791
* if we need to upgrade. Mask out the VHT and HT flags since
1792
* the vhtflags field will already have the correct HT
1793
* flags to use.
1794
*/
1795
if (IEEE80211_CONF_VHT(ic) && ni->ni_vhtcap != 0 && vhtflags != 0) {
1796
chanflags = (c->ic_flags
1797
&~ (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT))
1798
| vhtflags;
1799
IEEE80211_NOTE(ni->ni_vap,
1800
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1801
ni,
1802
"%s: VHT; chanwidth=0x%02x; vhtflags=0x%08x",
1803
__func__, ni->ni_vht_chanwidth, vhtflags);
1804
1805
IEEE80211_NOTE(ni->ni_vap,
1806
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1807
ni,
1808
"%s: VHT; trying lookup for %d/0x%08x",
1809
__func__, c->ic_freq, chanflags);
1810
c = ieee80211_find_channel(ic, c->ic_freq, chanflags);
1811
}
1812
1813
/* Finally, if it's changed */
1814
if (c != NULL && c != ni->ni_chan) {
1815
IEEE80211_NOTE(ni->ni_vap,
1816
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1817
"switch station to %s%d channel %u/0x%x",
1818
IEEE80211_IS_CHAN_VHT(c) ? "VHT" : "HT",
1819
IEEE80211_IS_CHAN_VHT80(c) ? 80 :
1820
(IEEE80211_IS_CHAN_HT40(c) ? 40 : 20),
1821
c->ic_freq, c->ic_flags);
1822
ni->ni_chan = c;
1823
ret = 1;
1824
}
1825
/* NB: caller responsible for forcing any channel change */
1826
1827
done:
1828
/* update node's (11n) tx channel width */
1829
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
1830
NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
1831
return (ret);
1832
}
1833
1834
/*
1835
* Update 11n MIMO PS state according to received htcap.
1836
*/
1837
static __inline int
1838
htcap_update_mimo_ps(struct ieee80211_node *ni)
1839
{
1840
uint16_t oflags = ni->ni_flags;
1841
1842
switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) {
1843
case IEEE80211_HTCAP_SMPS_DYNAMIC:
1844
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1845
ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
1846
break;
1847
case IEEE80211_HTCAP_SMPS_ENA:
1848
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1849
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1850
break;
1851
case IEEE80211_HTCAP_SMPS_OFF:
1852
default: /* disable on rx of reserved value */
1853
ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
1854
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1855
break;
1856
}
1857
return (oflags ^ ni->ni_flags);
1858
}
1859
1860
/*
1861
* Update short GI state according to received htcap
1862
* and local settings.
1863
*/
1864
static __inline void
1865
htcap_update_shortgi(struct ieee80211_node *ni)
1866
{
1867
struct ieee80211vap *vap = ni->ni_vap;
1868
1869
ni->ni_flags &= ~(IEEE80211_NODE_SGI20|IEEE80211_NODE_SGI40);
1870
if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
1871
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20))
1872
ni->ni_flags |= IEEE80211_NODE_SGI20;
1873
if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
1874
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
1875
ni->ni_flags |= IEEE80211_NODE_SGI40;
1876
}
1877
1878
/*
1879
* Update LDPC state according to received htcap
1880
* and local settings.
1881
*/
1882
static __inline void
1883
htcap_update_ldpc(struct ieee80211_node *ni)
1884
{
1885
struct ieee80211vap *vap = ni->ni_vap;
1886
1887
if ((ni->ni_htcap & IEEE80211_HTCAP_LDPC) &&
1888
(vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX))
1889
ni->ni_flags |= IEEE80211_NODE_LDPC;
1890
}
1891
1892
/*
1893
* Parse and update HT-related state extracted from
1894
* the HT cap and info ie's.
1895
*
1896
* This is called from the STA management path and
1897
* the ieee80211_node_join() path. It will take into
1898
* account the IEs discovered during scanning and
1899
* adjust things accordingly.
1900
*/
1901
void
1902
ieee80211_ht_updateparams(struct ieee80211_node *ni,
1903
const uint8_t *htcapie, const uint8_t *htinfoie)
1904
{
1905
struct ieee80211vap *vap = ni->ni_vap;
1906
const struct ieee80211_ie_htinfo *htinfo;
1907
1908
ieee80211_parse_htcap(ni, htcapie);
1909
if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
1910
htcap_update_mimo_ps(ni);
1911
htcap_update_shortgi(ni);
1912
htcap_update_ldpc(ni);
1913
1914
if (htinfoie[0] == IEEE80211_ELEMID_VENDOR)
1915
htinfoie += 4;
1916
htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
1917
htinfo_parse(ni, htinfo);
1918
1919
/*
1920
* Defer the node channel change; we need to now
1921
* update VHT parameters before we do it.
1922
*/
1923
1924
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
1925
(vap->iv_flags_ht & IEEE80211_FHT_RIFS))
1926
ni->ni_flags |= IEEE80211_NODE_RIFS;
1927
else
1928
ni->ni_flags &= ~IEEE80211_NODE_RIFS;
1929
}
1930
1931
static uint32_t
1932
ieee80211_vht_get_vhtflags(struct ieee80211_node *ni, uint32_t htflags)
1933
{
1934
#define _RETURN_CHAN_BITS(_cb) \
1935
do { \
1936
if (0) IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, \
1937
"%s:%d: selected %b", __func__, __LINE__, \
1938
(_cb), IEEE80211_CHAN_BITS); \
1939
return (_cb); \
1940
} while(0)
1941
struct ieee80211vap *vap;
1942
const struct ieee80211_ie_htinfo *htinfo;
1943
uint32_t vhtflags;
1944
bool can_vht160, can_vht80p80, can_vht80;
1945
bool ht40;
1946
1947
vap = ni->ni_vap;
1948
1949
/* If we do not support VHT or VHT is disabled just return. */
1950
if ((ni->ni_flags & IEEE80211_NODE_VHT) == 0 ||
1951
(vap->iv_vht_flags & IEEE80211_FVHT_VHT) == 0)
1952
_RETURN_CHAN_BITS(0);
1953
1954
/*
1955
* TODO: should we bail out if there's no htinfo?
1956
* Or just treat it as if we can't do the HT20/HT40 check?
1957
*/
1958
1959
/*
1960
* The original code was based on
1961
* 802.11ac-2013, Table 8-183x-VHT Operation Information subfields.
1962
* 802.11-2020, Table 9-274-VHT Operation Information subfields
1963
* has IEEE80211_VHT_CHANWIDTH_160MHZ and
1964
* IEEE80211_VHT_CHANWIDTH_80P80MHZ deprecated.
1965
* For current logic see
1966
* 802.11-2020, 11.38.1 Basic VHT BSS functionality.
1967
*/
1968
1969
htinfo = (const struct ieee80211_ie_htinfo *)ni->ni_ies.htinfo_ie;
1970
if (htinfo != NULL)
1971
ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
1972
IEEE80211_HTINFO_TXWIDTH_2040);
1973
else
1974
ht40 = false;
1975
1976
can_vht160 = can_vht80p80 = can_vht80 = false;
1977
1978
/* 20 Mhz */
1979
if (!ht40) {
1980
/* Check for the full valid combination -- other fields be 0. */
1981
if (ni->ni_vht_chanwidth != IEEE80211_VHT_CHANWIDTH_USE_HT ||
1982
ni->ni_vht_chan2 != 0)
1983
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
1984
"%s: invalid VHT BSS bandwidth 0/%d/%d/%d",
1985
__func__, ni->ni_vht_chanwidth,
1986
ni->ni_vht_chan1, ni->ni_vht_chan2);
1987
1988
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
1989
}
1990
1991
vhtflags = 0;
1992
1993
/* We know we can at least do 40Mhz, so mirror the HT40 flags. */
1994
if (htflags == IEEE80211_CHAN_HT40U)
1995
vhtflags |= IEEE80211_CHAN_HT40U;
1996
else if (htflags == IEEE80211_CHAN_HT40D)
1997
vhtflags |= IEEE80211_CHAN_HT40D;
1998
1999
/* 40 MHz */
2000
if (ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_USE_HT) {
2001
if (ni->ni_vht_chan2 != 0)
2002
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
2003
"%s: invalid VHT BSS bandwidth 1/%d/%d/%d",
2004
__func__, ni->ni_vht_chanwidth,
2005
ni->ni_vht_chan1, ni->ni_vht_chan2);
2006
2007
if ((vap->iv_vht_flags & IEEE80211_FVHT_USEVHT40) != 0) {
2008
if (htflags == IEEE80211_CHAN_HT40U)
2009
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40U | vhtflags);
2010
if (htflags == IEEE80211_CHAN_HT40D)
2011
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40D | vhtflags);
2012
}
2013
2014
/* If we get here VHT40 is not supported or disabled. */
2015
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
2016
}
2017
2018
/* Deprecated check for 160. */
2019
if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_160MHZ) &&
2020
IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(vap->iv_vht_cap.vht_cap_info) &&
2021
(vap->iv_vht_flags & IEEE80211_FVHT_USEVHT160) != 0)
2022
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT160 | vhtflags);
2023
2024
/* Deprecated check for 80P80. */
2025
if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_80P80MHZ) &&
2026
IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(vap->iv_vht_cap.vht_cap_info) &&
2027
(vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80P80) != 0)
2028
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80P80 | vhtflags);
2029
2030
if (ni->ni_vht_chanwidth != IEEE80211_VHT_CHANWIDTH_80MHZ) {
2031
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
2032
"%s: invalid VHT BSS bandwidth %d/%d/%d", __func__,
2033
ni->ni_vht_chanwidth, ni->ni_vht_chan2);
2034
2035
_RETURN_CHAN_BITS(0);
2036
}
2037
2038
/* CCFS1 > 0 and | CCFS1 - CCFS0 | = 8 */
2039
if (ni->ni_vht_chan2 > 0 && (ni->ni_vht_chan2 - ni->ni_vht_chan1) == 8)
2040
can_vht160 = can_vht80 = true;
2041
2042
/* CCFS1 > 0 and | CCFS1 - CCFS0 | > 16 */
2043
if (ni->ni_vht_chan2 > 0 && (ni->ni_vht_chan2 - ni->ni_vht_chan1) > 16)
2044
can_vht80p80 = can_vht80 = true;
2045
2046
/* CFFS1 == 0 */
2047
if (ni->ni_vht_chan2 == 0)
2048
can_vht80 = true;
2049
2050
if (can_vht160 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT160) != 0)
2051
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT160 | vhtflags);
2052
2053
if (can_vht80p80 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80P80) != 0)
2054
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80P80 | vhtflags);
2055
2056
if (can_vht80 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80) != 0)
2057
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80 | vhtflags);
2058
2059
if (ht40 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT40) != 0) {
2060
if (htflags == IEEE80211_CHAN_HT40U)
2061
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40U | vhtflags);
2062
if (htflags == IEEE80211_CHAN_HT40D)
2063
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40D | vhtflags);
2064
}
2065
2066
/* Either we disabled support or got an invalid setting. */
2067
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
2068
#undef _RETURN_CHAN_BITS
2069
}
2070
2071
/*
2072
* Final part of updating the HT parameters.
2073
*
2074
* This is called from the STA management path and
2075
* the ieee80211_node_join() path. It will take into
2076
* account the IEs discovered during scanning and
2077
* adjust things accordingly.
2078
*
2079
* This is done after a call to ieee80211_ht_updateparams()
2080
* because it (and the upcoming VHT version of updateparams)
2081
* needs to ensure everything is parsed before htinfo_update_chw()
2082
* is called - which will change the channel config for the
2083
* node for us.
2084
*/
2085
int
2086
ieee80211_ht_updateparams_final(struct ieee80211_node *ni,
2087
const uint8_t *htcapie, const uint8_t *htinfoie)
2088
{
2089
struct ieee80211vap *vap = ni->ni_vap;
2090
const struct ieee80211_ie_htinfo *htinfo;
2091
int htflags, vhtflags;
2092
int ret = 0;
2093
2094
htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
2095
2096
htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
2097
IEEE80211_CHAN_HT20 : 0;
2098
2099
/* NB: honor operating mode constraint */
2100
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
2101
(vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
2102
if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
2103
htflags = IEEE80211_CHAN_HT40U;
2104
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
2105
htflags = IEEE80211_CHAN_HT40D;
2106
}
2107
2108
/*
2109
* VHT flags - do much the same; check whether VHT is available
2110
* and if so, what our ideal channel use would be based on our
2111
* capabilities and the (pre-parsed) VHT info IE.
2112
*/
2113
vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
2114
2115
if (htinfo_update_chw(ni, htflags, vhtflags))
2116
ret = 1;
2117
2118
return (ret);
2119
}
2120
2121
/*
2122
* Parse and update HT-related state extracted from the HT cap ie
2123
* for a station joining an HT BSS.
2124
*
2125
* This is called from the hostap path for each station.
2126
*/
2127
void
2128
ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
2129
{
2130
struct ieee80211vap *vap = ni->ni_vap;
2131
2132
ieee80211_parse_htcap(ni, htcapie);
2133
if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
2134
htcap_update_mimo_ps(ni);
2135
htcap_update_shortgi(ni);
2136
htcap_update_ldpc(ni);
2137
}
2138
2139
/*
2140
* Called once HT and VHT capabilities are parsed in hostap mode -
2141
* this will adjust the channel configuration of the given node
2142
* based on the configuration and capabilities.
2143
*/
2144
void
2145
ieee80211_ht_updatehtcap_final(struct ieee80211_node *ni)
2146
{
2147
struct ieee80211vap *vap = ni->ni_vap;
2148
int htflags;
2149
int vhtflags;
2150
2151
/* NB: honor operating mode constraint */
2152
/* XXX 40 MHz intolerant */
2153
htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
2154
IEEE80211_CHAN_HT20 : 0;
2155
if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
2156
(vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
2157
if (IEEE80211_IS_CHAN_HT40U(vap->iv_bss->ni_chan))
2158
htflags = IEEE80211_CHAN_HT40U;
2159
else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
2160
htflags = IEEE80211_CHAN_HT40D;
2161
}
2162
/*
2163
* VHT flags - do much the same; check whether VHT is available
2164
* and if so, what our ideal channel use would be based on our
2165
* capabilities and the (pre-parsed) VHT info IE.
2166
*/
2167
vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
2168
2169
(void) htinfo_update_chw(ni, htflags, vhtflags);
2170
}
2171
2172
/*
2173
* Install received HT rate set by parsing the HT cap ie.
2174
*/
2175
int
2176
ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
2177
{
2178
struct ieee80211com *ic = ni->ni_ic;
2179
struct ieee80211vap *vap = ni->ni_vap;
2180
const struct ieee80211_ie_htcap *htcap;
2181
struct ieee80211_htrateset *rs;
2182
int i, maxequalmcs, maxunequalmcs;
2183
2184
maxequalmcs = ic->ic_txstream * 8 - 1;
2185
maxunequalmcs = 0;
2186
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
2187
if (ic->ic_txstream >= 2)
2188
maxunequalmcs = 38;
2189
if (ic->ic_txstream >= 3)
2190
maxunequalmcs = 52;
2191
if (ic->ic_txstream >= 4)
2192
maxunequalmcs = 76;
2193
}
2194
2195
rs = &ni->ni_htrates;
2196
memset(rs, 0, sizeof(*rs));
2197
if (ie != NULL) {
2198
if (ie[0] == IEEE80211_ELEMID_VENDOR)
2199
ie += 4;
2200
htcap = (const struct ieee80211_ie_htcap *) ie;
2201
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
2202
if (isclr(htcap->hc_mcsset, i))
2203
continue;
2204
if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
2205
IEEE80211_NOTE(vap,
2206
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
2207
"WARNING, HT rate set too large; only "
2208
"using %u rates", IEEE80211_HTRATE_MAXSIZE);
2209
vap->iv_stats.is_rx_rstoobig++;
2210
break;
2211
}
2212
if (i <= 31 && i > maxequalmcs)
2213
continue;
2214
if (i == 32 &&
2215
(ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
2216
continue;
2217
if (i > 32 && i > maxunequalmcs)
2218
continue;
2219
rs->rs_rates[rs->rs_nrates++] = i;
2220
}
2221
}
2222
return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
2223
}
2224
2225
/*
2226
* Mark rates in a node's HT rate set as basic according
2227
* to the information in the supplied HT info ie.
2228
*/
2229
void
2230
ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
2231
{
2232
const struct ieee80211_ie_htinfo *htinfo;
2233
struct ieee80211_htrateset *rs;
2234
int i, j;
2235
2236
if (ie[0] == IEEE80211_ELEMID_VENDOR)
2237
ie += 4;
2238
htinfo = (const struct ieee80211_ie_htinfo *) ie;
2239
rs = &ni->ni_htrates;
2240
if (rs->rs_nrates == 0) {
2241
IEEE80211_NOTE(ni->ni_vap,
2242
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
2243
"%s", "WARNING, empty HT rate set");
2244
return;
2245
}
2246
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
2247
if (isclr(htinfo->hi_basicmcsset, i))
2248
continue;
2249
for (j = 0; j < rs->rs_nrates; j++)
2250
if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
2251
rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
2252
}
2253
}
2254
2255
static void
2256
ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
2257
{
2258
callout_init(&tap->txa_timer, 1);
2259
tap->txa_flags |= IEEE80211_AGGR_SETUP;
2260
tap->txa_lastsample = ticks;
2261
}
2262
2263
static void
2264
ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
2265
{
2266
struct ieee80211_node *ni = tap->txa_ni;
2267
struct ieee80211com *ic = ni->ni_ic;
2268
2269
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2270
tap->txa_ni,
2271
"%s: called",
2272
__func__);
2273
2274
KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
2275
("txa_flags 0x%x tid %d ac %d", tap->txa_flags, tap->txa_tid,
2276
TID_TO_WME_AC(tap->txa_tid)));
2277
2278
/*
2279
* Stop BA stream if setup so driver has a chance
2280
* to reclaim any resources it might have allocated.
2281
*/
2282
ic->ic_addba_stop(ni, tap);
2283
/*
2284
* Stop any pending BAR transmit.
2285
*/
2286
bar_stop_timer(tap);
2287
2288
/*
2289
* Reset packet estimate.
2290
*/
2291
ieee80211_txampdu_init_pps(tap);
2292
2293
/* NB: clearing NAK means we may re-send ADDBA */
2294
tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
2295
}
2296
2297
/*
2298
* ADDBA response timeout.
2299
*
2300
* If software aggregation and per-TID queue management was done here,
2301
* that queue would be unpaused after the ADDBA timeout occurs.
2302
*/
2303
static void
2304
addba_timeout(void *arg)
2305
{
2306
struct ieee80211_tx_ampdu *tap = arg;
2307
struct ieee80211_node *ni = tap->txa_ni;
2308
struct ieee80211com *ic = ni->ni_ic;
2309
2310
/* XXX ? */
2311
tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
2312
tap->txa_attempts++;
2313
ic->ic_addba_response_timeout(ni, tap);
2314
}
2315
2316
static void
2317
addba_start_timeout(struct ieee80211_tx_ampdu *tap)
2318
{
2319
/* XXX use CALLOUT_PENDING instead? */
2320
callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
2321
addba_timeout, tap);
2322
tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
2323
tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
2324
}
2325
2326
static void
2327
addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
2328
{
2329
/* XXX use CALLOUT_PENDING instead? */
2330
if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
2331
callout_stop(&tap->txa_timer);
2332
tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
2333
}
2334
}
2335
2336
static void
2337
null_addba_response_timeout(struct ieee80211_node *ni,
2338
struct ieee80211_tx_ampdu *tap)
2339
{
2340
}
2341
2342
/*
2343
* Default method for requesting A-MPDU tx aggregation.
2344
* We setup the specified state block and start a timer
2345
* to wait for an ADDBA response frame.
2346
*/
2347
static int
2348
ieee80211_addba_request(struct ieee80211_node *ni,
2349
struct ieee80211_tx_ampdu *tap,
2350
int dialogtoken, int baparamset, int batimeout)
2351
{
2352
int bufsiz;
2353
2354
/* XXX locking */
2355
tap->txa_token = dialogtoken;
2356
tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
2357
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2358
tap->txa_wnd = (bufsiz == 0) ?
2359
IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
2360
addba_start_timeout(tap);
2361
return 1;
2362
}
2363
2364
/*
2365
* Called by drivers that wish to request an ADDBA session be
2366
* setup. This brings it up and starts the request timer.
2367
*/
2368
int
2369
ieee80211_ampdu_tx_request_ext(struct ieee80211_node *ni, int tid)
2370
{
2371
struct ieee80211_tx_ampdu *tap;
2372
2373
if (tid < 0 || tid > 15)
2374
return (0);
2375
tap = &ni->ni_tx_ampdu[tid];
2376
2377
/* XXX locking */
2378
if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
2379
/* do deferred setup of state */
2380
ampdu_tx_setup(tap);
2381
}
2382
/* XXX hack for not doing proper locking */
2383
tap->txa_flags &= ~IEEE80211_AGGR_NAK;
2384
addba_start_timeout(tap);
2385
return (1);
2386
}
2387
2388
/*
2389
* Called by drivers that have marked a session as active.
2390
*/
2391
int
2392
ieee80211_ampdu_tx_request_active_ext(struct ieee80211_node *ni, int tid,
2393
int status)
2394
{
2395
struct ieee80211_tx_ampdu *tap;
2396
2397
if (tid < 0 || tid > 15)
2398
return (0);
2399
tap = &ni->ni_tx_ampdu[tid];
2400
2401
/* XXX locking */
2402
addba_stop_timeout(tap);
2403
if (status == 1) {
2404
tap->txa_flags |= IEEE80211_AGGR_RUNNING;
2405
tap->txa_attempts = 0;
2406
} else {
2407
/* mark tid so we don't try again */
2408
tap->txa_flags |= IEEE80211_AGGR_NAK;
2409
}
2410
return (1);
2411
}
2412
2413
/*
2414
* Default method for processing an A-MPDU tx aggregation
2415
* response. We shutdown any pending timer and update the
2416
* state block according to the reply.
2417
*/
2418
static int
2419
ieee80211_addba_response(struct ieee80211_node *ni,
2420
struct ieee80211_tx_ampdu *tap,
2421
int status, int baparamset, int batimeout)
2422
{
2423
struct ieee80211vap *vap = ni->ni_vap;
2424
int bufsiz;
2425
2426
/* XXX locking */
2427
addba_stop_timeout(tap);
2428
if (status == IEEE80211_STATUS_SUCCESS) {
2429
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2430
/* XXX override our request? */
2431
tap->txa_wnd = (bufsiz == 0) ?
2432
IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
2433
#ifdef __notyet__
2434
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2435
#endif
2436
tap->txa_flags |= IEEE80211_AGGR_RUNNING;
2437
tap->txa_attempts = 0;
2438
/* TODO: this should be a vap flag */
2439
if ((vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU) &&
2440
(ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
2441
(_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))
2442
tap->txa_flags |= IEEE80211_AGGR_AMSDU;
2443
else
2444
tap->txa_flags &= ~IEEE80211_AGGR_AMSDU;
2445
} else {
2446
/* mark tid so we don't try again */
2447
tap->txa_flags |= IEEE80211_AGGR_NAK;
2448
}
2449
return 1;
2450
}
2451
2452
/*
2453
* Default method for stopping A-MPDU tx aggregation.
2454
* Any timer is cleared and we drain any pending frames.
2455
*/
2456
static void
2457
ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
2458
{
2459
/* XXX locking */
2460
addba_stop_timeout(tap);
2461
if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
2462
/* XXX clear aggregation queue */
2463
tap->txa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU);
2464
}
2465
tap->txa_attempts = 0;
2466
}
2467
2468
/*
2469
* Process a received action frame using the default aggregation
2470
* policy. We intercept ADDBA-related frames and use them to
2471
* update our aggregation state. All other frames are passed up
2472
* for processing by ieee80211_recv_action.
2473
*/
2474
static int
2475
ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
2476
const struct ieee80211_frame *wh,
2477
const uint8_t *frm, const uint8_t *efrm)
2478
{
2479
struct ieee80211com *ic = ni->ni_ic;
2480
struct ieee80211vap *vap = ni->ni_vap;
2481
struct ieee80211_rx_ampdu *rap;
2482
uint8_t dialogtoken;
2483
uint16_t baparamset, batimeout, baseqctl;
2484
uint16_t args[5];
2485
int tid;
2486
2487
dialogtoken = frm[2];
2488
baparamset = le16dec(frm+3);
2489
batimeout = le16dec(frm+5);
2490
baseqctl = le16dec(frm+7);
2491
2492
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2493
2494
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2495
"recv ADDBA request: dialogtoken %u baparamset 0x%x "
2496
"(tid %d bufsiz %d) batimeout %d baseqctl %d:%d amsdu %d",
2497
dialogtoken, baparamset,
2498
tid, _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ),
2499
batimeout,
2500
_IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_START),
2501
_IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_FRAG),
2502
_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU));
2503
2504
rap = &ni->ni_rx_ampdu[tid];
2505
2506
/* Send ADDBA response */
2507
args[0] = dialogtoken;
2508
/*
2509
* NB: We ack only if the sta associated with HT and
2510
* the ap is configured to do AMPDU rx (the latter
2511
* violates the 11n spec and is mostly for testing).
2512
*/
2513
if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
2514
(vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
2515
/* XXX TODO: handle ampdu_rx_start failure */
2516
ic->ic_ampdu_rx_start(ni, rap,
2517
baparamset, batimeout, baseqctl);
2518
2519
args[1] = IEEE80211_STATUS_SUCCESS;
2520
} else {
2521
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2522
ni, "reject ADDBA request: %s",
2523
ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
2524
"administratively disabled" :
2525
"not negotiated for station");
2526
vap->iv_stats.is_addba_reject++;
2527
args[1] = IEEE80211_STATUS_UNSPECIFIED;
2528
}
2529
/* XXX honor rap flags? */
2530
args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
2531
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
2532
| _IEEE80211_SHIFTMASK(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
2533
;
2534
2535
/*
2536
* TODO: we're out of iv_flags_ht fields; once
2537
* this is extended we should make this configurable.
2538
*/
2539
if ((baparamset & IEEE80211_BAPS_AMSDU) &&
2540
(ni->ni_flags & IEEE80211_NODE_AMSDU_RX) &&
2541
(vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU))
2542
args[2] |= IEEE80211_BAPS_AMSDU;
2543
2544
args[3] = 0;
2545
args[4] = 0;
2546
ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2547
IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
2548
return 0;
2549
}
2550
2551
static int
2552
ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
2553
const struct ieee80211_frame *wh,
2554
const uint8_t *frm, const uint8_t *efrm)
2555
{
2556
struct ieee80211com *ic = ni->ni_ic;
2557
struct ieee80211vap *vap = ni->ni_vap;
2558
struct ieee80211_tx_ampdu *tap;
2559
uint8_t dialogtoken, policy;
2560
uint16_t baparamset, batimeout, code;
2561
int tid;
2562
#ifdef IEEE80211_DEBUG
2563
int amsdu, bufsiz;
2564
#endif
2565
2566
dialogtoken = frm[2];
2567
code = le16dec(frm+3);
2568
baparamset = le16dec(frm+5);
2569
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2570
#ifdef IEEE80211_DEBUG
2571
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2572
amsdu = !! _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU);
2573
#endif
2574
policy = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_POLICY);
2575
batimeout = le16dec(frm+7);
2576
2577
tap = &ni->ni_tx_ampdu[tid];
2578
if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
2579
IEEE80211_DISCARD_MAC(vap,
2580
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2581
ni->ni_macaddr, "ADDBA response",
2582
"no pending ADDBA, tid %d dialogtoken %u "
2583
"code %d", tid, dialogtoken, code);
2584
vap->iv_stats.is_addba_norequest++;
2585
return 0;
2586
}
2587
if (dialogtoken != tap->txa_token) {
2588
IEEE80211_DISCARD_MAC(vap,
2589
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2590
ni->ni_macaddr, "ADDBA response",
2591
"dialogtoken mismatch: waiting for %d, "
2592
"received %d, tid %d code %d",
2593
tap->txa_token, dialogtoken, tid, code);
2594
vap->iv_stats.is_addba_badtoken++;
2595
return 0;
2596
}
2597
/* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
2598
if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
2599
IEEE80211_DISCARD_MAC(vap,
2600
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2601
ni->ni_macaddr, "ADDBA response",
2602
"policy mismatch: expecting %s, "
2603
"received %s, tid %d code %d",
2604
tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
2605
policy, tid, code);
2606
vap->iv_stats.is_addba_badpolicy++;
2607
return 0;
2608
}
2609
#if 0
2610
/* XXX we take MIN in ieee80211_addba_response */
2611
if (bufsiz > IEEE80211_AGGR_BAWMAX) {
2612
IEEE80211_DISCARD_MAC(vap,
2613
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2614
ni->ni_macaddr, "ADDBA response",
2615
"BA window too large: max %d, "
2616
"received %d, tid %d code %d",
2617
bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
2618
vap->iv_stats.is_addba_badbawinsize++;
2619
return 0;
2620
}
2621
#endif
2622
2623
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2624
"recv ADDBA response: dialogtoken %u code %d "
2625
"baparamset 0x%x (tid %d bufsiz %d amsdu %d) batimeout %d",
2626
dialogtoken, code, baparamset, tid,
2627
bufsiz,
2628
amsdu,
2629
batimeout);
2630
ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
2631
return 0;
2632
}
2633
2634
static int
2635
ht_recv_action_ba_delba(struct ieee80211_node *ni,
2636
const struct ieee80211_frame *wh,
2637
const uint8_t *frm, const uint8_t *efrm)
2638
{
2639
struct ieee80211com *ic = ni->ni_ic;
2640
struct ieee80211_rx_ampdu *rap;
2641
struct ieee80211_tx_ampdu *tap;
2642
uint16_t baparamset;
2643
#ifdef IEEE80211_DEBUG
2644
uint16_t code;
2645
#endif
2646
int tid;
2647
2648
baparamset = le16dec(frm+2);
2649
#ifdef IEEE80211_DEBUG
2650
code = le16dec(frm+4);
2651
#endif
2652
2653
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_TID);
2654
2655
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2656
"recv DELBA: baparamset 0x%x (tid %d initiator %d) "
2657
"code %d", baparamset, tid,
2658
_IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_INIT), code);
2659
2660
if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
2661
tap = &ni->ni_tx_ampdu[tid];
2662
ic->ic_addba_stop(ni, tap);
2663
} else {
2664
rap = &ni->ni_rx_ampdu[tid];
2665
ic->ic_ampdu_rx_stop(ni, rap);
2666
}
2667
return 0;
2668
}
2669
2670
/*
2671
* Handle the HT channel width action frame.
2672
*
2673
* 802.11-2020 9.6.11.2 (Notify Channel Width frame format).
2674
*/
2675
static int
2676
ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
2677
const struct ieee80211_frame *wh __unused,
2678
const uint8_t *frm, const uint8_t *efrm __unused)
2679
{
2680
int chw;
2681
2682
/* If 20/40 is not supported the chw cannot change. */
2683
if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) == 0)
2684
return (0);
2685
2686
/*
2687
* The supported values are either 0 (any supported width)
2688
* or 1 (HT20). 80, 160, etc MHz widths are not represented
2689
* here.
2690
*/
2691
chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ?
2692
NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
2693
2694
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2695
"%s: HT txchwidth, width %d%s (%s)", __func__,
2696
chw, ni->ni_chw != chw ? "*" : "", net80211_ni_chw_to_str(chw));
2697
if (chw != ni->ni_chw) {
2698
/* XXX does this need to change the ht40 station count? */
2699
ni->ni_chw = chw;
2700
/* XXX notify on change */
2701
}
2702
return 0;
2703
}
2704
2705
static int
2706
ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
2707
const struct ieee80211_frame *wh,
2708
const uint8_t *frm, const uint8_t *efrm)
2709
{
2710
const struct ieee80211_action_ht_mimopowersave *mps =
2711
(const struct ieee80211_action_ht_mimopowersave *) frm;
2712
2713
/* XXX check iv_htcaps */
2714
if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
2715
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
2716
else
2717
ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
2718
if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
2719
ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
2720
else
2721
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
2722
/* XXX notify on change */
2723
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2724
"%s: HT MIMO PS (%s%s)", __func__,
2725
(ni->ni_flags & IEEE80211_NODE_MIMO_PS) ? "on" : "off",
2726
(ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ? "+rts" : ""
2727
);
2728
return 0;
2729
}
2730
2731
/*
2732
* Transmit processing.
2733
*/
2734
2735
/*
2736
* Check if A-MPDU should be requested/enabled for a stream.
2737
* We require a traffic rate above a per-AC threshold and we
2738
* also handle backoff from previous failed attempts.
2739
*
2740
* Drivers may override this method to bring in information
2741
* such as link state conditions in making the decision.
2742
*/
2743
static int
2744
ieee80211_ampdu_enable(struct ieee80211_node *ni,
2745
struct ieee80211_tx_ampdu *tap)
2746
{
2747
struct ieee80211vap *vap = ni->ni_vap;
2748
2749
if (tap->txa_avgpps <
2750
vap->iv_ampdu_mintraffic[TID_TO_WME_AC(tap->txa_tid)])
2751
return 0;
2752
/* XXX check rssi? */
2753
if (tap->txa_attempts >= ieee80211_addba_maxtries &&
2754
ieee80211_time_after(ticks, tap->txa_nextrequest)) {
2755
/*
2756
* Don't retry too often; txa_nextrequest is set
2757
* to the minimum interval we'll retry after
2758
* ieee80211_addba_maxtries failed attempts are made.
2759
*/
2760
return 0;
2761
}
2762
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
2763
"enable AMPDU on tid %d (%s), avgpps %d pkts %d attempt %d",
2764
tap->txa_tid, ieee80211_wme_acnames[TID_TO_WME_AC(tap->txa_tid)],
2765
tap->txa_avgpps, tap->txa_pkts, tap->txa_attempts);
2766
return 1;
2767
}
2768
2769
/*
2770
* Request A-MPDU tx aggregation. Setup local state and
2771
* issue an ADDBA request. BA use will only happen after
2772
* the other end replies with ADDBA response.
2773
*/
2774
int
2775
ieee80211_ampdu_request(struct ieee80211_node *ni,
2776
struct ieee80211_tx_ampdu *tap)
2777
{
2778
struct ieee80211com *ic = ni->ni_ic;
2779
uint16_t args[5];
2780
int tid, dialogtoken;
2781
static int tokens = 0; /* XXX */
2782
2783
/* XXX locking */
2784
if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
2785
/* do deferred setup of state */
2786
ampdu_tx_setup(tap);
2787
}
2788
/* XXX hack for not doing proper locking */
2789
tap->txa_flags &= ~IEEE80211_AGGR_NAK;
2790
2791
dialogtoken = (tokens+1) % 63; /* XXX */
2792
tid = tap->txa_tid;
2793
2794
/*
2795
* XXX TODO: This is racy with any other parallel TX going on. :(
2796
*/
2797
tap->txa_start = ni->ni_txseqs[tid];
2798
2799
args[0] = dialogtoken;
2800
args[1] = 0; /* NB: status code not used */
2801
args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
2802
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
2803
| _IEEE80211_SHIFTMASK(IEEE80211_AGGR_BAWMAX,
2804
IEEE80211_BAPS_BUFSIZ)
2805
;
2806
2807
/* XXX TODO: this should be a flag, not iv_htcaps */
2808
if ((ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
2809
(ni->ni_vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU))
2810
args[2] |= IEEE80211_BAPS_AMSDU;
2811
2812
args[3] = 0; /* batimeout */
2813
/* NB: do first so there's no race against reply */
2814
if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
2815
/* unable to setup state, don't make request */
2816
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2817
ni, "%s: could not setup BA stream for TID %d AC %d",
2818
__func__, tap->txa_tid, TID_TO_WME_AC(tap->txa_tid));
2819
/* defer next try so we don't slam the driver with requests */
2820
tap->txa_attempts = ieee80211_addba_maxtries;
2821
/* NB: check in case driver wants to override */
2822
if (tap->txa_nextrequest <= ticks)
2823
tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
2824
return 0;
2825
}
2826
tokens = dialogtoken; /* allocate token */
2827
/* NB: after calling ic_addba_request so driver can set txa_start */
2828
args[4] = _IEEE80211_SHIFTMASK(tap->txa_start, IEEE80211_BASEQ_START)
2829
| _IEEE80211_SHIFTMASK(0, IEEE80211_BASEQ_FRAG)
2830
;
2831
return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2832
IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
2833
}
2834
2835
/*
2836
* Terminate an AMPDU tx stream. State is reclaimed
2837
* and the peer notified with a DelBA Action frame.
2838
*/
2839
void
2840
ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
2841
int reason)
2842
{
2843
struct ieee80211com *ic = ni->ni_ic;
2844
struct ieee80211vap *vap = ni->ni_vap;
2845
uint16_t args[4];
2846
2847
/* XXX locking */
2848
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2849
if (IEEE80211_AMPDU_RUNNING(tap)) {
2850
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2851
ni, "%s: stop BA stream for TID %d (reason: %d (%s))",
2852
__func__, tap->txa_tid, reason,
2853
ieee80211_reason_to_string(reason));
2854
vap->iv_stats.is_ampdu_stop++;
2855
2856
ic->ic_addba_stop(ni, tap);
2857
args[0] = tap->txa_tid;
2858
args[1] = IEEE80211_DELBAPS_INIT;
2859
args[2] = reason; /* XXX reason code */
2860
ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2861
IEEE80211_ACTION_BA_DELBA, args);
2862
} else {
2863
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2864
ni, "%s: BA stream for TID %d not running "
2865
"(reason: %d (%s))", __func__, tap->txa_tid, reason,
2866
ieee80211_reason_to_string(reason));
2867
vap->iv_stats.is_ampdu_stop_failed++;
2868
}
2869
}
2870
2871
/* XXX */
2872
static void bar_start_timer(struct ieee80211_tx_ampdu *tap);
2873
2874
static void
2875
bar_timeout(void *arg)
2876
{
2877
struct ieee80211_tx_ampdu *tap = arg;
2878
struct ieee80211_node *ni = tap->txa_ni;
2879
2880
KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
2881
("bar/addba collision, flags 0x%x", tap->txa_flags));
2882
2883
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2884
ni, "%s: tid %u flags 0x%x attempts %d", __func__,
2885
tap->txa_tid, tap->txa_flags, tap->txa_attempts);
2886
2887
/* guard against race with bar_tx_complete */
2888
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
2889
return;
2890
/* XXX ? */
2891
if (tap->txa_attempts >= ieee80211_bar_maxtries) {
2892
struct ieee80211com *ic = ni->ni_ic;
2893
2894
ni->ni_vap->iv_stats.is_ampdu_bar_tx_fail++;
2895
/*
2896
* If (at least) the last BAR TX timeout was due to
2897
* an ieee80211_send_bar() failures, then we need
2898
* to make sure we notify the driver that a BAR
2899
* TX did occur and fail. This gives the driver
2900
* a chance to undo any queue pause that may
2901
* have occurred.
2902
*/
2903
ic->ic_bar_response(ni, tap, 1);
2904
ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
2905
} else {
2906
ni->ni_vap->iv_stats.is_ampdu_bar_tx_retry++;
2907
if (ieee80211_send_bar(ni, tap, tap->txa_seqpending) != 0) {
2908
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2909
ni, "%s: failed to TX, starting timer\n",
2910
__func__);
2911
/*
2912
* If ieee80211_send_bar() fails here, the
2913
* timer may have stopped and/or the pending
2914
* flag may be clear. Because of this,
2915
* fake the BARPEND and reset the timer.
2916
* A retransmission attempt will then occur
2917
* during the next timeout.
2918
*/
2919
/* XXX locking */
2920
tap->txa_flags |= IEEE80211_AGGR_BARPEND;
2921
bar_start_timer(tap);
2922
}
2923
}
2924
}
2925
2926
static void
2927
bar_start_timer(struct ieee80211_tx_ampdu *tap)
2928
{
2929
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2930
tap->txa_ni,
2931
"%s: called",
2932
__func__);
2933
callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
2934
}
2935
2936
static void
2937
bar_stop_timer(struct ieee80211_tx_ampdu *tap)
2938
{
2939
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2940
tap->txa_ni,
2941
"%s: called",
2942
__func__);
2943
callout_stop(&tap->txa_timer);
2944
}
2945
2946
static void
2947
bar_tx_complete(struct ieee80211_node *ni, void *arg, int status)
2948
{
2949
struct ieee80211_tx_ampdu *tap = arg;
2950
2951
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2952
ni, "%s: tid %u flags 0x%x pending %d status %d",
2953
__func__, tap->txa_tid, tap->txa_flags,
2954
callout_pending(&tap->txa_timer), status);
2955
2956
ni->ni_vap->iv_stats.is_ampdu_bar_tx++;
2957
/* XXX locking */
2958
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
2959
callout_pending(&tap->txa_timer)) {
2960
struct ieee80211com *ic = ni->ni_ic;
2961
2962
if (status == 0) /* ACK'd */
2963
bar_stop_timer(tap);
2964
ic->ic_bar_response(ni, tap, status);
2965
/* NB: just let timer expire so we pace requests */
2966
}
2967
}
2968
2969
static void
2970
ieee80211_bar_response(struct ieee80211_node *ni,
2971
struct ieee80211_tx_ampdu *tap, int status)
2972
{
2973
2974
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2975
tap->txa_ni,
2976
"%s: called",
2977
__func__);
2978
if (status == 0) { /* got ACK */
2979
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2980
ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
2981
tap->txa_start,
2982
IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
2983
tap->txa_qframes, tap->txa_seqpending,
2984
tap->txa_tid);
2985
2986
/* NB: timer already stopped in bar_tx_complete */
2987
tap->txa_start = tap->txa_seqpending;
2988
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2989
}
2990
}
2991
2992
/*
2993
* Transmit a BAR frame to the specified node. The
2994
* BAR contents are drawn from the supplied aggregation
2995
* state associated with the node.
2996
*
2997
* NB: we only handle immediate ACK w/ compressed bitmap.
2998
*/
2999
int
3000
ieee80211_send_bar(struct ieee80211_node *ni,
3001
struct ieee80211_tx_ampdu *tap, ieee80211_seq seq)
3002
{
3003
#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
3004
struct ieee80211vap *vap = ni->ni_vap;
3005
struct ieee80211com *ic = ni->ni_ic;
3006
struct ieee80211_frame_bar *bar;
3007
struct mbuf *m;
3008
uint16_t barctl, barseqctl;
3009
uint8_t *frm;
3010
int tid, ret;
3011
3012
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
3013
tap->txa_ni,
3014
"%s: called",
3015
__func__);
3016
3017
if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
3018
/* no ADDBA response, should not happen */
3019
/* XXX stat+msg */
3020
return EINVAL;
3021
}
3022
/* XXX locking */
3023
bar_stop_timer(tap);
3024
3025
ieee80211_ref_node(ni);
3026
3027
m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
3028
if (m == NULL)
3029
senderr(ENOMEM, is_tx_nobuf);
3030
3031
if (!ieee80211_add_callback(m, bar_tx_complete, tap)) {
3032
m_freem(m);
3033
senderr(ENOMEM, is_tx_nobuf); /* XXX */
3034
/* NOTREACHED */
3035
}
3036
3037
bar = mtod(m, struct ieee80211_frame_bar *);
3038
bar->i_fc[0] = IEEE80211_FC0_VERSION_0 |
3039
IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
3040
bar->i_fc[1] = 0;
3041
IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
3042
IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
3043
3044
tid = tap->txa_tid;
3045
barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
3046
0 : IEEE80211_BAR_NOACK)
3047
| IEEE80211_BAR_COMP
3048
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAR_TID)
3049
;
3050
barseqctl = _IEEE80211_SHIFTMASK(seq, IEEE80211_BAR_SEQ_START);
3051
/* NB: known to have proper alignment */
3052
bar->i_ctl = htole16(barctl);
3053
bar->i_seq = htole16(barseqctl);
3054
m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
3055
3056
M_WME_SETAC(m, WME_AC_VO);
3057
3058
IEEE80211_NODE_STAT(ni, tx_mgmt); /* XXX tx_ctl? */
3059
3060
/* XXX locking */
3061
/* init/bump attempts counter */
3062
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
3063
tap->txa_attempts = 1;
3064
else
3065
tap->txa_attempts++;
3066
tap->txa_seqpending = seq;
3067
tap->txa_flags |= IEEE80211_AGGR_BARPEND;
3068
3069
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
3070
ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)",
3071
tid, barctl, seq, tap->txa_attempts);
3072
3073
/*
3074
* ic_raw_xmit will free the node reference
3075
* regardless of queue/TX success or failure.
3076
*/
3077
IEEE80211_TX_LOCK(ic);
3078
ret = ieee80211_raw_output(vap, ni, m, NULL);
3079
IEEE80211_TX_UNLOCK(ic);
3080
if (ret != 0) {
3081
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
3082
ni, "send BAR: failed: (ret = %d)\n",
3083
ret);
3084
/* xmit failed, clear state flag */
3085
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
3086
vap->iv_stats.is_ampdu_bar_tx_fail++;
3087
return ret;
3088
}
3089
/* XXX hack against tx complete happening before timer is started */
3090
if (tap->txa_flags & IEEE80211_AGGR_BARPEND)
3091
bar_start_timer(tap);
3092
return 0;
3093
bad:
3094
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
3095
tap->txa_ni,
3096
"%s: bad! ret=%d",
3097
__func__, ret);
3098
vap->iv_stats.is_ampdu_bar_tx_fail++;
3099
ieee80211_free_node(ni);
3100
return ret;
3101
#undef senderr
3102
}
3103
3104
static int
3105
ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
3106
{
3107
struct ieee80211_bpf_params params;
3108
3109
memset(&params, 0, sizeof(params));
3110
params.ibp_pri = WME_AC_VO;
3111
params.ibp_rate0 = ni->ni_txparms->mgmtrate;
3112
/* NB: we know all frames are unicast */
3113
params.ibp_try0 = ni->ni_txparms->maxretry;
3114
params.ibp_power = ni->ni_txpower;
3115
return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
3116
&params);
3117
}
3118
3119
#define ADDSHORT(frm, v) do { \
3120
frm[0] = (v) & 0xff; \
3121
frm[1] = (v) >> 8; \
3122
frm += 2; \
3123
} while (0)
3124
3125
/*
3126
* Send an action management frame. The arguments are stuff
3127
* into a frame without inspection; the caller is assumed to
3128
* prepare them carefully (e.g. based on the aggregation state).
3129
*/
3130
static int
3131
ht_send_action_ba_addba(struct ieee80211_node *ni,
3132
int category, int action, void *arg0)
3133
{
3134
struct ieee80211vap *vap = ni->ni_vap;
3135
struct ieee80211com *ic = ni->ni_ic;
3136
uint16_t *args = arg0;
3137
struct mbuf *m;
3138
uint8_t *frm;
3139
3140
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3141
"send ADDBA %s: dialogtoken %d status %d "
3142
"baparamset 0x%x (tid %d amsdu %d) batimeout 0x%x baseqctl 0x%x",
3143
(action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
3144
"request" : "response", args[0], args[1], args[2],
3145
_IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_TID),
3146
_IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_AMSDU),
3147
args[3], args[4]);
3148
3149
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3150
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3151
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3152
ieee80211_ref_node(ni);
3153
3154
m = ieee80211_getmgtframe(&frm,
3155
ic->ic_headroom + sizeof(struct ieee80211_frame),
3156
sizeof(uint16_t) /* action+category */
3157
/* XXX may action payload */
3158
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3159
);
3160
if (m != NULL) {
3161
*frm++ = category;
3162
*frm++ = action;
3163
*frm++ = args[0]; /* dialog token */
3164
if (action == IEEE80211_ACTION_BA_ADDBA_RESPONSE)
3165
ADDSHORT(frm, args[1]); /* status code */
3166
ADDSHORT(frm, args[2]); /* baparamset */
3167
ADDSHORT(frm, args[3]); /* batimeout */
3168
if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
3169
ADDSHORT(frm, args[4]); /* baseqctl */
3170
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3171
return ht_action_output(ni, m);
3172
} else {
3173
vap->iv_stats.is_tx_nobuf++;
3174
ieee80211_free_node(ni);
3175
return ENOMEM;
3176
}
3177
}
3178
3179
static int
3180
ht_send_action_ba_delba(struct ieee80211_node *ni,
3181
int category, int action, void *arg0)
3182
{
3183
struct ieee80211vap *vap = ni->ni_vap;
3184
struct ieee80211com *ic = ni->ni_ic;
3185
uint16_t *args = arg0;
3186
struct mbuf *m;
3187
uint16_t baparamset;
3188
uint8_t *frm;
3189
3190
baparamset = _IEEE80211_SHIFTMASK(args[0], IEEE80211_DELBAPS_TID)
3191
| args[1]
3192
;
3193
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3194
"send DELBA action: tid %d, initiator %d reason %d (%s)",
3195
args[0], args[1], args[2], ieee80211_reason_to_string(args[2]));
3196
3197
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3198
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3199
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3200
ieee80211_ref_node(ni);
3201
3202
m = ieee80211_getmgtframe(&frm,
3203
ic->ic_headroom + sizeof(struct ieee80211_frame),
3204
sizeof(uint16_t) /* action+category */
3205
/* XXX may action payload */
3206
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3207
);
3208
if (m != NULL) {
3209
*frm++ = category;
3210
*frm++ = action;
3211
ADDSHORT(frm, baparamset);
3212
ADDSHORT(frm, args[2]); /* reason code */
3213
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3214
return ht_action_output(ni, m);
3215
} else {
3216
vap->iv_stats.is_tx_nobuf++;
3217
ieee80211_free_node(ni);
3218
return ENOMEM;
3219
}
3220
}
3221
3222
static int
3223
ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
3224
int category, int action, void *arg0)
3225
{
3226
struct ieee80211vap *vap = ni->ni_vap;
3227
struct ieee80211com *ic = ni->ni_ic;
3228
struct mbuf *m;
3229
uint8_t *frm;
3230
3231
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3232
"send HT txchwidth: width %d",
3233
IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
3234
3235
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3236
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3237
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3238
ieee80211_ref_node(ni);
3239
3240
m = ieee80211_getmgtframe(&frm,
3241
ic->ic_headroom + sizeof(struct ieee80211_frame),
3242
sizeof(uint16_t) /* action+category */
3243
/* XXX may action payload */
3244
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3245
);
3246
if (m != NULL) {
3247
*frm++ = category;
3248
*frm++ = action;
3249
*frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
3250
IEEE80211_A_HT_TXCHWIDTH_2040 :
3251
IEEE80211_A_HT_TXCHWIDTH_20;
3252
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3253
return ht_action_output(ni, m);
3254
} else {
3255
vap->iv_stats.is_tx_nobuf++;
3256
ieee80211_free_node(ni);
3257
return ENOMEM;
3258
}
3259
}
3260
#undef ADDSHORT
3261
3262
/*
3263
* Construct the MCS bit mask for inclusion in an HT capabilities
3264
* information element.
3265
*/
3266
static void
3267
ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm)
3268
{
3269
int i;
3270
uint8_t txparams;
3271
3272
KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4),
3273
("ic_rxstream %d out of range", ic->ic_rxstream));
3274
KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4),
3275
("ic_txstream %d out of range", ic->ic_txstream));
3276
3277
for (i = 0; i < ic->ic_rxstream * 8; i++)
3278
setbit(frm, i);
3279
if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
3280
(ic->ic_htcaps & IEEE80211_HTC_RXMCS32))
3281
setbit(frm, 32);
3282
if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) {
3283
if (ic->ic_rxstream >= 2) {
3284
for (i = 33; i <= 38; i++)
3285
setbit(frm, i);
3286
}
3287
if (ic->ic_rxstream >= 3) {
3288
for (i = 39; i <= 52; i++)
3289
setbit(frm, i);
3290
}
3291
if (ic->ic_rxstream >= 4) {
3292
for (i = 53; i <= 76; i++)
3293
setbit(frm, i);
3294
}
3295
}
3296
3297
txparams = 0x1; /* TX MCS set defined */
3298
if (ic->ic_rxstream != ic->ic_txstream) {
3299
txparams |= 0x2; /* TX RX MCS not equal */
3300
txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */
3301
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL)
3302
txparams |= 0x16; /* TX unequal modulation sup */
3303
}
3304
3305
frm[12] = txparams;
3306
}
3307
3308
/*
3309
* Add body of an HTCAP information element.
3310
*/
3311
static uint8_t *
3312
ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
3313
{
3314
#define ADDSHORT(frm, v) do { \
3315
frm[0] = (v) & 0xff; \
3316
frm[1] = (v) >> 8; \
3317
frm += 2; \
3318
} while (0)
3319
struct ieee80211com *ic = ni->ni_ic;
3320
struct ieee80211vap *vap = ni->ni_vap;
3321
uint16_t caps, extcaps;
3322
int rxmax, density;
3323
3324
/* HT capabilities */
3325
caps = vap->iv_htcaps & 0xffff;
3326
/*
3327
* Note channel width depends on whether we are operating as
3328
* a sta or not. When operating as a sta we are generating
3329
* a request based on our desired configuration. Otherwise
3330
* we are operational and the channel attributes identify
3331
* how we've been setup (which might be different if a fixed
3332
* channel is specified).
3333
*/
3334
if (vap->iv_opmode == IEEE80211_M_STA) {
3335
/* override 20/40 use based on config */
3336
if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
3337
caps |= IEEE80211_HTCAP_CHWIDTH40;
3338
else
3339
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3340
3341
/* Start by using the advertised settings */
3342
rxmax = _IEEE80211_MASKSHIFT(ni->ni_htparam,
3343
IEEE80211_HTCAP_MAXRXAMPDU);
3344
density = _IEEE80211_MASKSHIFT(ni->ni_htparam,
3345
IEEE80211_HTCAP_MPDUDENSITY);
3346
3347
IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
3348
"%s: advertised rxmax=%d, density=%d, vap rxmax=%d, density=%d\n",
3349
__func__,
3350
rxmax,
3351
density,
3352
vap->iv_ampdu_rxmax,
3353
vap->iv_ampdu_density);
3354
3355
/* Cap at VAP rxmax */
3356
if (rxmax > vap->iv_ampdu_rxmax)
3357
rxmax = vap->iv_ampdu_rxmax;
3358
3359
/*
3360
* If the VAP ampdu density value greater, use that.
3361
*
3362
* (Larger density value == larger minimum gap between A-MPDU
3363
* subframes.)
3364
*/
3365
if (vap->iv_ampdu_density > density)
3366
density = vap->iv_ampdu_density;
3367
3368
/*
3369
* NB: Hardware might support HT40 on some but not all
3370
* channels. We can't determine this earlier because only
3371
* after association the channel is upgraded to HT based
3372
* on the negotiated capabilities.
3373
*/
3374
if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
3375
findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL &&
3376
findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL)
3377
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3378
} else {
3379
/* override 20/40 use based on current channel */
3380
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
3381
caps |= IEEE80211_HTCAP_CHWIDTH40;
3382
else
3383
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3384
3385
/* XXX TODO should it start by using advertised settings? */
3386
rxmax = vap->iv_ampdu_rxmax;
3387
density = vap->iv_ampdu_density;
3388
}
3389
3390
/* adjust short GI based on channel and config */
3391
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
3392
caps &= ~IEEE80211_HTCAP_SHORTGI20;
3393
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
3394
(caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
3395
caps &= ~IEEE80211_HTCAP_SHORTGI40;
3396
3397
/* adjust STBC based on receive capabilities */
3398
if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) == 0)
3399
caps &= ~IEEE80211_HTCAP_RXSTBC;
3400
3401
/* adjust LDPC based on receive capabilites */
3402
if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_RX) == 0)
3403
caps &= ~IEEE80211_HTCAP_LDPC;
3404
3405
ADDSHORT(frm, caps);
3406
3407
/* HT parameters */
3408
*frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
3409
| _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
3410
;
3411
frm++;
3412
3413
/* pre-zero remainder of ie */
3414
memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
3415
__offsetof(struct ieee80211_ie_htcap, hc_mcsset));
3416
3417
/* supported MCS set */
3418
/*
3419
* XXX: For sta mode the rate set should be restricted based
3420
* on the AP's capabilities, but ni_htrates isn't setup when
3421
* we're called to form an AssocReq frame so for now we're
3422
* restricted to the device capabilities.
3423
*/
3424
ieee80211_set_mcsset(ni->ni_ic, frm);
3425
3426
frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
3427
__offsetof(struct ieee80211_ie_htcap, hc_mcsset);
3428
3429
/* HT extended capabilities */
3430
extcaps = vap->iv_htextcaps & 0xffff;
3431
3432
ADDSHORT(frm, extcaps);
3433
3434
frm += sizeof(struct ieee80211_ie_htcap) -
3435
__offsetof(struct ieee80211_ie_htcap, hc_txbf);
3436
3437
return frm;
3438
#undef ADDSHORT
3439
}
3440
3441
/*
3442
* Add 802.11n HT capabilities information element
3443
*/
3444
uint8_t *
3445
ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
3446
{
3447
frm[0] = IEEE80211_ELEMID_HTCAP;
3448
frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
3449
return ieee80211_add_htcap_body(frm + 2, ni);
3450
}
3451
3452
/*
3453
* Non-associated probe request - add HT capabilities based on
3454
* the current channel configuration.
3455
*/
3456
static uint8_t *
3457
ieee80211_add_htcap_body_ch(uint8_t *frm, struct ieee80211vap *vap,
3458
struct ieee80211_channel *c)
3459
{
3460
#define ADDSHORT(frm, v) do { \
3461
frm[0] = (v) & 0xff; \
3462
frm[1] = (v) >> 8; \
3463
frm += 2; \
3464
} while (0)
3465
struct ieee80211com *ic = vap->iv_ic;
3466
uint16_t caps, extcaps;
3467
int rxmax, density;
3468
3469
/* HT capabilities */
3470
caps = vap->iv_htcaps & 0xffff;
3471
3472
/*
3473
* We don't use this in STA mode; only in IBSS mode.
3474
* So in IBSS mode we base our HTCAP flags on the
3475
* given channel.
3476
*/
3477
3478
/* override 20/40 use based on current channel */
3479
if (IEEE80211_IS_CHAN_HT40(c))
3480
caps |= IEEE80211_HTCAP_CHWIDTH40;
3481
else
3482
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3483
3484
/* Use the currently configured values */
3485
rxmax = vap->iv_ampdu_rxmax;
3486
density = vap->iv_ampdu_density;
3487
3488
/* adjust short GI based on channel and config */
3489
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
3490
caps &= ~IEEE80211_HTCAP_SHORTGI20;
3491
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
3492
(caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
3493
caps &= ~IEEE80211_HTCAP_SHORTGI40;
3494
ADDSHORT(frm, caps);
3495
3496
/* HT parameters */
3497
*frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
3498
| _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
3499
;
3500
frm++;
3501
3502
/* pre-zero remainder of ie */
3503
memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
3504
__offsetof(struct ieee80211_ie_htcap, hc_mcsset));
3505
3506
/* supported MCS set */
3507
/*
3508
* XXX: For sta mode the rate set should be restricted based
3509
* on the AP's capabilities, but ni_htrates isn't setup when
3510
* we're called to form an AssocReq frame so for now we're
3511
* restricted to the device capabilities.
3512
*/
3513
ieee80211_set_mcsset(ic, frm);
3514
3515
frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
3516
__offsetof(struct ieee80211_ie_htcap, hc_mcsset);
3517
3518
/* HT extended capabilities */
3519
extcaps = vap->iv_htextcaps & 0xffff;
3520
3521
ADDSHORT(frm, extcaps);
3522
3523
frm += sizeof(struct ieee80211_ie_htcap) -
3524
__offsetof(struct ieee80211_ie_htcap, hc_txbf);
3525
3526
return frm;
3527
#undef ADDSHORT
3528
}
3529
3530
/*
3531
* Add 802.11n HT capabilities information element
3532
*/
3533
uint8_t *
3534
ieee80211_add_htcap_ch(uint8_t *frm, struct ieee80211vap *vap,
3535
struct ieee80211_channel *c)
3536
{
3537
frm[0] = IEEE80211_ELEMID_HTCAP;
3538
frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
3539
return ieee80211_add_htcap_body_ch(frm + 2, vap, c);
3540
}
3541
3542
/*
3543
* Add Broadcom OUI wrapped standard HTCAP ie; this is
3544
* used for compatibility w/ pre-draft implementations.
3545
*/
3546
uint8_t *
3547
ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
3548
{
3549
frm[0] = IEEE80211_ELEMID_VENDOR;
3550
frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
3551
frm[2] = (BCM_OUI >> 0) & 0xff;
3552
frm[3] = (BCM_OUI >> 8) & 0xff;
3553
frm[4] = (BCM_OUI >> 16) & 0xff;
3554
frm[5] = BCM_OUI_HTCAP;
3555
return ieee80211_add_htcap_body(frm + 6, ni);
3556
}
3557
3558
/*
3559
* Construct the MCS bit mask of basic rates
3560
* for inclusion in an HT information element.
3561
*/
3562
static void
3563
ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
3564
{
3565
int i;
3566
3567
for (i = 0; i < rs->rs_nrates; i++) {
3568
int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
3569
if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
3570
r < IEEE80211_HTRATE_MAXSIZE) {
3571
/* NB: this assumes a particular implementation */
3572
setbit(frm, r);
3573
}
3574
}
3575
}
3576
3577
/*
3578
* Update the HTINFO ie for a beacon frame.
3579
*/
3580
void
3581
ieee80211_ht_update_beacon(struct ieee80211vap *vap,
3582
struct ieee80211_beacon_offsets *bo)
3583
{
3584
#define PROTMODE (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
3585
struct ieee80211_node *ni;
3586
const struct ieee80211_channel *bsschan;
3587
struct ieee80211com *ic = vap->iv_ic;
3588
struct ieee80211_ie_htinfo *ht =
3589
(struct ieee80211_ie_htinfo *) bo->bo_htinfo;
3590
3591
ni = ieee80211_ref_node(vap->iv_bss);
3592
bsschan = ni->ni_chan;
3593
3594
/* XXX only update on channel change */
3595
ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
3596
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
3597
ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PERM;
3598
else
3599
ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
3600
if (IEEE80211_IS_CHAN_HT40U(bsschan))
3601
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
3602
else if (IEEE80211_IS_CHAN_HT40D(bsschan))
3603
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
3604
else
3605
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
3606
if (IEEE80211_IS_CHAN_HT40(bsschan))
3607
ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
3608
3609
/* protection mode */
3610
/*
3611
* XXX TODO: this uses the global flag, not the per-VAP flag.
3612
* Eventually (once the protection modes are done per-channel
3613
* rather than per-VAP) we can flip this over to be per-VAP but
3614
* using the channel protection mode.
3615
*/
3616
ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
3617
3618
ieee80211_free_node(ni);
3619
3620
/* XXX propagate to vendor ie's */
3621
#undef PROTMODE
3622
}
3623
3624
/*
3625
* Add body of an HTINFO information element.
3626
*
3627
* NB: We don't use struct ieee80211_ie_htinfo because we can
3628
* be called to fillin both a standard ie and a compat ie that
3629
* has a vendor OUI at the front.
3630
*/
3631
static uint8_t *
3632
ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
3633
{
3634
struct ieee80211vap *vap = ni->ni_vap;
3635
struct ieee80211com *ic = ni->ni_ic;
3636
3637
/* pre-zero remainder of ie */
3638
memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
3639
3640
/* primary/control channel center */
3641
*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
3642
3643
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
3644
frm[0] = IEEE80211_HTINFO_RIFSMODE_PERM;
3645
else
3646
frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
3647
if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
3648
frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
3649
else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
3650
frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
3651
else
3652
frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
3653
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
3654
frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
3655
3656
/*
3657
* Add current protection mode. Unlike for beacons,
3658
* this will respect the per-VAP flags.
3659
*/
3660
frm[1] = vap->iv_curhtprotmode;
3661
3662
frm += 5;
3663
3664
/* basic MCS set */
3665
ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
3666
frm += sizeof(struct ieee80211_ie_htinfo) -
3667
__offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
3668
return frm;
3669
}
3670
3671
/*
3672
* Add 802.11n HT information element.
3673
*/
3674
uint8_t *
3675
ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
3676
{
3677
frm[0] = IEEE80211_ELEMID_HTINFO;
3678
frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
3679
return ieee80211_add_htinfo_body(frm + 2, ni);
3680
}
3681
3682
/*
3683
* Add Broadcom OUI wrapped standard HTINFO ie; this is
3684
* used for compatibility w/ pre-draft implementations.
3685
*/
3686
uint8_t *
3687
ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
3688
{
3689
frm[0] = IEEE80211_ELEMID_VENDOR;
3690
frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
3691
frm[2] = (BCM_OUI >> 0) & 0xff;
3692
frm[3] = (BCM_OUI >> 8) & 0xff;
3693
frm[4] = (BCM_OUI >> 16) & 0xff;
3694
frm[5] = BCM_OUI_HTINFO;
3695
return ieee80211_add_htinfo_body(frm + 6, ni);
3696
}
3697
3698
/*
3699
* Get the HT density for the given 802.11n node.
3700
*
3701
* Take into account the density advertised from the peer.
3702
* Larger values are longer A-MPDU density spacing values, and
3703
* we want to obey them per station if we get them.
3704
*/
3705
int
3706
ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni)
3707
{
3708
struct ieee80211vap *vap;
3709
int peer_mpdudensity;
3710
3711
vap = ni->ni_vap;
3712
peer_mpdudensity =
3713
_IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
3714
if (vap->iv_ampdu_density > peer_mpdudensity)
3715
peer_mpdudensity = vap->iv_ampdu_density;
3716
return (peer_mpdudensity);
3717
}
3718
3719
/*
3720
* Get the transmit A-MPDU limit for the given 802.11n node.
3721
*
3722
* Take into account the limit advertised from the peer.
3723
* Smaller values indicate smaller maximum A-MPDU sizes, and
3724
* should be used when forming an A-MPDU to the given peer.
3725
*/
3726
int
3727
ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni)
3728
{
3729
struct ieee80211vap *vap;
3730
int peer_mpdulimit;
3731
3732
vap = ni->ni_vap;
3733
peer_mpdulimit =
3734
_IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
3735
3736
return (MIN(vap->iv_ampdu_limit, peer_mpdulimit));
3737
}
3738
3739
/*
3740
* Return true if short-GI is available when transmitting to
3741
* the given node at 20MHz.
3742
*
3743
* Ensure it's configured and available in the VAP / driver as
3744
* well as the node.
3745
*/
3746
bool
3747
ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni)
3748
{
3749
const struct ieee80211vap *vap;
3750
const struct ieee80211com *ic;
3751
3752
if (! ieee80211_ht_check_tx_ht(ni))
3753
return (false);
3754
3755
vap = ni->ni_vap;
3756
ic = ni->ni_ic;
3757
3758
return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) &&
3759
(ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
3760
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20));
3761
}
3762
3763
/*
3764
* Return true if short-GI is available when transmitting to
3765
* the given node at 40MHz.
3766
*
3767
* Ensure it's configured and available in the VAP / driver as
3768
* well as the node and BSS.
3769
*/
3770
bool
3771
ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni)
3772
{
3773
const struct ieee80211vap *vap;
3774
const struct ieee80211com *ic;
3775
3776
if (! ieee80211_ht_check_tx_ht40(ni))
3777
return (false);
3778
3779
vap = ni->ni_vap;
3780
ic = ni->ni_ic;
3781
3782
return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40) &&
3783
(ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
3784
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40));
3785
}
3786
3787
/*
3788
* Return true if HT rates can be used for the given node.
3789
*
3790
* There are some situations seen in the wild, wild past where
3791
* HT APs would announce HT but no HT rates.
3792
*/
3793
bool
3794
ieee80211_ht_check_tx_ht(const struct ieee80211_node *ni)
3795
{
3796
const struct ieee80211vap *vap;
3797
const struct ieee80211_channel *bss_chan;
3798
3799
if (ni == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC ||
3800
ni->ni_vap == NULL || ni->ni_vap->iv_bss == NULL)
3801
return (false);
3802
3803
vap = ni->ni_vap;
3804
bss_chan = vap->iv_bss->ni_chan;
3805
3806
if (bss_chan == IEEE80211_CHAN_ANYC)
3807
return (false);
3808
3809
if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
3810
ni->ni_htrates.rs_nrates == 0)
3811
return (false);
3812
return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
3813
}
3814
3815
/*
3816
* Return true if HT40 rates can be transmitted to the given node.
3817
*
3818
* This verifies that the BSS is HT40 capable and the current
3819
* node channel width is 40MHz.
3820
*/
3821
bool
3822
ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni)
3823
{
3824
struct ieee80211vap *vap;
3825
struct ieee80211_channel *bss_chan;
3826
3827
if (! ieee80211_ht_check_tx_ht(ni))
3828
return (false);
3829
3830
vap = ni->ni_vap;
3831
bss_chan = vap->iv_bss->ni_chan;
3832
3833
return (IEEE80211_IS_CHAN_HT40(bss_chan) &&
3834
IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
3835
(ni->ni_chw == NET80211_STA_RX_BW_40));
3836
}
3837
3838