Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net80211/ieee80211_ht.c
106126 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 *dummy __unused)
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 (ieee80211_time_after(ticks - rap->rxa_age,
1134
ieee80211_ampdu_age)) {
1135
/*
1136
* Too long since we received the first
1137
* frame; flush the reorder buffer.
1138
*/
1139
if (rap->rxa_qframes != 0) {
1140
vap->iv_stats.is_ampdu_rx_age +=
1141
rap->rxa_qframes;
1142
ampdu_rx_flush(ni, rap);
1143
}
1144
/*
1145
* Advance the window if needed and notify
1146
* the caller to dispatch directly.
1147
*/
1148
if (amsdu) {
1149
if (amsdu_end) {
1150
rap->rxa_start =
1151
IEEE80211_SEQ_INC(rxseq);
1152
IEEE80211_NODE_STAT(ni,
1153
rx_amsdu_more_end);
1154
} else {
1155
IEEE80211_NODE_STAT(ni,
1156
rx_amsdu_more);
1157
}
1158
} else {
1159
rap->rxa_start =
1160
IEEE80211_SEQ_INC(rxseq);
1161
}
1162
return PROCESS;
1163
}
1164
} else {
1165
/*
1166
* First frame, start aging timer.
1167
*/
1168
rap->rxa_age = ticks;
1169
}
1170
1171
/* save packet - this consumes, no matter what */
1172
ampdu_rx_add_slot(rap, off, tid, rxseq, ni, m, rxs);
1173
return CONSUMED;
1174
}
1175
if (off < IEEE80211_SEQ_BA_RANGE) {
1176
/*
1177
* Outside the BA window, but within range;
1178
* flush the reorder q and move the window.
1179
* Sec 9.10.7.6.2 b) (p.138)
1180
*/
1181
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1182
"move BA win <%u:%u> (%u frames) rxseq %u tid %u",
1183
rap->rxa_start,
1184
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1185
rap->rxa_qframes, rxseq, tid);
1186
vap->iv_stats.is_ampdu_rx_move++;
1187
1188
/*
1189
* The spec says to flush frames up to but not including:
1190
* WinStart_B = rxseq - rap->rxa_wnd + 1
1191
* Then insert the frame or notify the caller to process
1192
* it immediately. We can safely do this by just starting
1193
* over again because we know the frame will now be within
1194
* the BA window.
1195
*/
1196
/* NB: rxa_wnd known to be >0 */
1197
ampdu_rx_flush_upto(ni, rap,
1198
IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
1199
goto again;
1200
} else {
1201
/*
1202
* Outside the BA window and out of range; toss.
1203
* Sec 9.10.7.6.2 c) (p.138)
1204
*/
1205
IEEE80211_DISCARD_MAC(vap,
1206
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1207
"MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
1208
rap->rxa_start,
1209
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1210
rap->rxa_qframes, rxseq, tid,
1211
wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1212
vap->iv_stats.is_ampdu_rx_drop++;
1213
IEEE80211_NODE_STAT(ni, rx_drop);
1214
m_freem(m);
1215
return CONSUMED;
1216
}
1217
#undef CONSUMED
1218
#undef PROCESS
1219
}
1220
1221
/*
1222
* Process a BAR ctl frame. Dispatch all frames up to
1223
* the sequence number of the frame. If this frame is
1224
* out of range it's discarded.
1225
*/
1226
void
1227
ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
1228
{
1229
struct ieee80211vap *vap = ni->ni_vap;
1230
struct ieee80211_frame_bar *wh;
1231
struct ieee80211_rx_ampdu *rap;
1232
ieee80211_seq rxseq;
1233
int tid, off;
1234
1235
if (!ieee80211_recv_bar_ena) {
1236
#if 0
1237
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
1238
ni->ni_macaddr, "BAR", "%s", "processing disabled");
1239
#endif
1240
vap->iv_stats.is_ampdu_bar_bad++;
1241
return;
1242
}
1243
wh = mtod(m0, struct ieee80211_frame_bar *);
1244
/* XXX check basic BAR */
1245
tid = _IEEE80211_MASKSHIFT(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
1246
rap = &ni->ni_rx_ampdu[tid];
1247
if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1248
/*
1249
* No ADDBA request yet, don't touch.
1250
*/
1251
IEEE80211_DISCARD_MAC(vap,
1252
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
1253
ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
1254
vap->iv_stats.is_ampdu_bar_bad++;
1255
return;
1256
}
1257
vap->iv_stats.is_ampdu_bar_rx++;
1258
rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
1259
if (rxseq == rap->rxa_start)
1260
return;
1261
/* calculate offset in BA window */
1262
off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
1263
if (off < IEEE80211_SEQ_BA_RANGE) {
1264
/*
1265
* Flush the reorder q up to rxseq and move the window.
1266
* Sec 9.10.7.6.3 a) (p.138)
1267
*/
1268
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1269
"BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
1270
rap->rxa_start,
1271
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1272
rap->rxa_qframes, rxseq, tid);
1273
vap->iv_stats.is_ampdu_bar_move++;
1274
1275
ampdu_rx_flush_upto(ni, rap, rxseq);
1276
if (off >= rap->rxa_wnd) {
1277
/*
1278
* BAR specifies a window start to the right of BA
1279
* window; we must move it explicitly since
1280
* ampdu_rx_flush_upto will not.
1281
*/
1282
rap->rxa_start = rxseq;
1283
}
1284
} else {
1285
/*
1286
* Out of range; toss.
1287
* Sec 9.10.7.6.3 b) (p.138)
1288
*/
1289
IEEE80211_DISCARD_MAC(vap,
1290
IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1291
"BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
1292
rap->rxa_start,
1293
IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1294
rap->rxa_qframes, rxseq, tid,
1295
wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1296
vap->iv_stats.is_ampdu_bar_oow++;
1297
IEEE80211_NODE_STAT(ni, rx_drop);
1298
}
1299
}
1300
1301
/*
1302
* Setup HT-specific state in a node. Called only
1303
* when HT use is negotiated so we don't do extra
1304
* work for temporary and/or legacy sta's.
1305
*/
1306
void
1307
ieee80211_ht_node_init(struct ieee80211_node *ni)
1308
{
1309
struct ieee80211_tx_ampdu *tap;
1310
int tid;
1311
1312
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1313
ni,
1314
"%s: called (%p)",
1315
__func__,
1316
ni);
1317
1318
if (ni->ni_flags & IEEE80211_NODE_HT) {
1319
/*
1320
* Clean AMPDU state on re-associate. This handles the case
1321
* where a station leaves w/o notifying us and then returns
1322
* before node is reaped for inactivity.
1323
*/
1324
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1325
ni,
1326
"%s: calling cleanup (%p)",
1327
__func__, ni);
1328
ieee80211_ht_node_cleanup(ni);
1329
}
1330
for (tid = 0; tid < WME_NUM_TID; tid++) {
1331
tap = &ni->ni_tx_ampdu[tid];
1332
tap->txa_tid = tid;
1333
tap->txa_ni = ni;
1334
ieee80211_txampdu_init_pps(tap);
1335
/* NB: further initialization deferred */
1336
ieee80211_ampdu_rx_init_rap(ni, &ni->ni_rx_ampdu[tid]);
1337
}
1338
ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
1339
IEEE80211_NODE_AMSDU;
1340
}
1341
1342
/*
1343
* Cleanup HT-specific state in a node. Called only
1344
* when HT use has been marked.
1345
*/
1346
void
1347
ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
1348
{
1349
struct ieee80211com *ic = ni->ni_ic;
1350
int i;
1351
1352
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1353
ni,
1354
"%s: called (%p)",
1355
__func__, ni);
1356
1357
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
1358
1359
/* XXX optimize this */
1360
for (i = 0; i < WME_NUM_TID; i++) {
1361
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
1362
if (tap->txa_flags & IEEE80211_AGGR_SETUP)
1363
ampdu_tx_stop(tap);
1364
}
1365
for (i = 0; i < WME_NUM_TID; i++)
1366
ic->ic_ampdu_rx_stop(ni, &ni->ni_rx_ampdu[i]);
1367
1368
ni->ni_htcap = 0;
1369
ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
1370
}
1371
1372
/*
1373
* Age out HT resources for a station.
1374
*/
1375
void
1376
ieee80211_ht_node_age(struct ieee80211_node *ni)
1377
{
1378
struct ieee80211vap *vap = ni->ni_vap;
1379
uint8_t tid;
1380
1381
KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
1382
1383
for (tid = 0; tid < WME_NUM_TID; tid++) {
1384
struct ieee80211_rx_ampdu *rap;
1385
1386
rap = &ni->ni_rx_ampdu[tid];
1387
if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
1388
continue;
1389
if (rap->rxa_qframes == 0)
1390
continue;
1391
/*
1392
* Check for frames sitting too long in the reorder queue.
1393
* See above for more details on what's happening here.
1394
*/
1395
/* XXX honor batimeout? */
1396
if (ieee80211_time_after(ticks - rap->rxa_age,
1397
ieee80211_ampdu_age)) {
1398
/*
1399
* Too long since we received the first
1400
* frame; flush the reorder buffer.
1401
*/
1402
vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
1403
ampdu_rx_flush(ni, rap);
1404
}
1405
}
1406
}
1407
1408
static struct ieee80211_channel *
1409
findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
1410
{
1411
return ieee80211_find_channel(ic, c->ic_freq,
1412
(c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
1413
}
1414
1415
/*
1416
* Adjust a channel to be HT/non-HT according to the vap's configuration.
1417
*/
1418
struct ieee80211_channel *
1419
ieee80211_ht_adjust_channel(struct ieee80211com *ic,
1420
struct ieee80211_channel *chan, int flags)
1421
{
1422
struct ieee80211_channel *c;
1423
1424
if (flags & IEEE80211_FHT_HT) {
1425
/* promote to HT if possible */
1426
if (flags & IEEE80211_FHT_USEHT40) {
1427
if (!IEEE80211_IS_CHAN_HT40(chan)) {
1428
/* NB: arbitrarily pick ht40+ over ht40- */
1429
c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
1430
if (c == NULL)
1431
c = findhtchan(ic, chan,
1432
IEEE80211_CHAN_HT40D);
1433
if (c == NULL)
1434
c = findhtchan(ic, chan,
1435
IEEE80211_CHAN_HT20);
1436
if (c != NULL)
1437
chan = c;
1438
}
1439
} else if (!IEEE80211_IS_CHAN_HT20(chan)) {
1440
c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
1441
if (c != NULL)
1442
chan = c;
1443
}
1444
} else if (IEEE80211_IS_CHAN_HT(chan)) {
1445
/* demote to legacy, HT use is disabled */
1446
c = ieee80211_find_channel(ic, chan->ic_freq,
1447
chan->ic_flags &~ IEEE80211_CHAN_HT);
1448
if (c != NULL)
1449
chan = c;
1450
}
1451
return chan;
1452
}
1453
1454
/*
1455
* Setup HT-specific state for a legacy WDS peer.
1456
*/
1457
void
1458
ieee80211_ht_wds_init(struct ieee80211_node *ni)
1459
{
1460
struct ieee80211vap *vap = ni->ni_vap;
1461
struct ieee80211_tx_ampdu *tap;
1462
int tid;
1463
1464
KASSERT(vap->iv_flags_ht & IEEE80211_FHT_HT, ("no HT requested"));
1465
1466
/* XXX check scan cache in case peer has an ap and we have info */
1467
/*
1468
* If setup with a legacy channel; locate an HT channel.
1469
* Otherwise if the inherited channel (from a companion
1470
* AP) is suitable use it so we use the same location
1471
* for the extension channel).
1472
*/
1473
ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
1474
ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
1475
1476
ni->ni_htcap = 0;
1477
if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
1478
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
1479
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
1480
ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
1481
ni->ni_chw = NET80211_STA_RX_BW_40;
1482
if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
1483
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
1484
else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
1485
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
1486
if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
1487
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
1488
} else {
1489
ni->ni_chw = NET80211_STA_RX_BW_20;
1490
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
1491
}
1492
ni->ni_htctlchan = ni->ni_chan->ic_ieee;
1493
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
1494
ni->ni_flags |= IEEE80211_NODE_RIFS;
1495
/* XXX does it make sense to enable SMPS? */
1496
1497
ni->ni_htopmode = 0; /* XXX need protection state */
1498
ni->ni_htstbc = 0; /* XXX need info */
1499
1500
for (tid = 0; tid < WME_NUM_TID; tid++) {
1501
tap = &ni->ni_tx_ampdu[tid];
1502
tap->txa_tid = tid;
1503
ieee80211_txampdu_init_pps(tap);
1504
}
1505
/* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
1506
ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
1507
IEEE80211_NODE_AMSDU;
1508
}
1509
1510
/*
1511
* Notify a VAP of a change in the HTINFO ie if it's a hostap VAP.
1512
*
1513
* This is to be called from the deferred HT protection update
1514
* task once the flags are updated.
1515
*/
1516
void
1517
ieee80211_htinfo_notify(struct ieee80211vap *vap)
1518
{
1519
1520
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1521
1522
if (vap->iv_opmode != IEEE80211_M_HOSTAP)
1523
return;
1524
if (vap->iv_state != IEEE80211_S_RUN ||
1525
!IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
1526
return;
1527
1528
IEEE80211_NOTE(vap,
1529
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1530
vap->iv_bss,
1531
"HT bss occupancy change: %d sta, %d ht, "
1532
"%d ht40%s, HT protmode now 0x%x"
1533
, vap->iv_sta_assoc
1534
, vap->iv_ht_sta_assoc
1535
, vap->iv_ht40_sta_assoc
1536
, (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) ?
1537
", non-HT sta present" : ""
1538
, vap->iv_curhtprotmode);
1539
1540
ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
1541
}
1542
1543
/*
1544
* Calculate HT protection mode from current
1545
* state and handle updates.
1546
*/
1547
static void
1548
htinfo_update(struct ieee80211vap *vap)
1549
{
1550
struct ieee80211com *ic = vap->iv_ic;
1551
uint8_t protmode;
1552
1553
if (vap->iv_sta_assoc != vap->iv_ht_sta_assoc) {
1554
protmode = IEEE80211_HTINFO_OPMODE_MIXED
1555
| IEEE80211_HTINFO_NONHT_PRESENT;
1556
} else if (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) {
1557
protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
1558
| IEEE80211_HTINFO_NONHT_PRESENT;
1559
} else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
1560
IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
1561
vap->iv_sta_assoc != vap->iv_ht40_sta_assoc) {
1562
protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
1563
} else {
1564
protmode = IEEE80211_HTINFO_OPMODE_PURE;
1565
}
1566
if (protmode != vap->iv_curhtprotmode) {
1567
vap->iv_curhtprotmode = protmode;
1568
/* Update VAP with new protection mode */
1569
ieee80211_vap_update_ht_protmode(vap);
1570
}
1571
}
1572
1573
/*
1574
* Handle an HT station joining a BSS.
1575
*/
1576
void
1577
ieee80211_ht_node_join(struct ieee80211_node *ni)
1578
{
1579
struct ieee80211vap *vap = ni->ni_vap;
1580
1581
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1582
1583
if (ni->ni_flags & IEEE80211_NODE_HT) {
1584
vap->iv_ht_sta_assoc++;
1585
if (ni->ni_chw == NET80211_STA_RX_BW_40)
1586
vap->iv_ht40_sta_assoc++;
1587
}
1588
htinfo_update(vap);
1589
}
1590
1591
/*
1592
* Handle an HT station leaving a BSS.
1593
*/
1594
void
1595
ieee80211_ht_node_leave(struct ieee80211_node *ni)
1596
{
1597
struct ieee80211vap *vap = ni->ni_vap;
1598
1599
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1600
1601
if (ni->ni_flags & IEEE80211_NODE_HT) {
1602
vap->iv_ht_sta_assoc--;
1603
if (ni->ni_chw == NET80211_STA_RX_BW_40)
1604
vap->iv_ht40_sta_assoc--;
1605
}
1606
htinfo_update(vap);
1607
}
1608
1609
/*
1610
* Public version of htinfo_update; used for processing
1611
* beacon frames from overlapping bss.
1612
*
1613
* Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
1614
* (on receipt of a beacon that advertises MIXED) or
1615
* IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
1616
* from an overlapping legacy bss). We treat MIXED with
1617
* a higher precedence than PROTOPT (i.e. we will not change
1618
* change PROTOPT -> MIXED; only MIXED -> PROTOPT). This
1619
* corresponds to how we handle things in htinfo_update.
1620
*
1621
*/
1622
void
1623
ieee80211_htprot_update(struct ieee80211vap *vap, int protmode)
1624
{
1625
struct ieee80211com *ic = vap->iv_ic;
1626
#define OPMODE(x) _IEEE80211_SHIFTMASK(x, IEEE80211_HTINFO_OPMODE)
1627
IEEE80211_LOCK(ic);
1628
1629
/* track non-HT station presence */
1630
KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
1631
("protmode 0x%x", protmode));
1632
vap->iv_flags_ht |= IEEE80211_FHT_NONHT_PR;
1633
vap->iv_lastnonht = ticks;
1634
1635
if (protmode != vap->iv_curhtprotmode &&
1636
(OPMODE(vap->iv_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
1637
OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
1638
vap->iv_curhtprotmode = protmode;
1639
/* Update VAP with new protection mode */
1640
ieee80211_vap_update_ht_protmode(vap);
1641
}
1642
IEEE80211_UNLOCK(ic);
1643
#undef OPMODE
1644
}
1645
1646
/*
1647
* Time out presence of an overlapping bss with non-HT
1648
* stations. When operating in hostap mode we listen for
1649
* beacons from other stations and if we identify a non-HT
1650
* station is present we update the opmode field of the
1651
* HTINFO ie. To identify when all non-HT stations are
1652
* gone we time out this condition.
1653
*/
1654
void
1655
ieee80211_ht_timeout(struct ieee80211vap *vap)
1656
{
1657
1658
IEEE80211_LOCK_ASSERT(vap->iv_ic);
1659
1660
if ((vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) &&
1661
ieee80211_time_after(ticks, vap->iv_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
1662
IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
1663
"%s", "time out non-HT STA present on channel");
1664
vap->iv_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
1665
htinfo_update(vap);
1666
}
1667
}
1668
1669
/*
1670
* Process an 802.11n HT capabilities ie.
1671
*/
1672
void
1673
ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1674
{
1675
if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1676
/*
1677
* Station used Vendor OUI ie to associate;
1678
* mark the node so when we respond we'll use
1679
* the Vendor OUI's and not the standard ie's.
1680
*/
1681
ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1682
ie += 4;
1683
} else
1684
ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1685
1686
ni->ni_htcap = le16dec(ie +
1687
__offsetof(struct ieee80211_ie_htcap, hc_cap));
1688
ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1689
}
1690
1691
static void
1692
htinfo_parse(struct ieee80211_node *ni,
1693
const struct ieee80211_ie_htinfo *htinfo)
1694
{
1695
uint16_t w;
1696
1697
ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1698
ni->ni_ht2ndchan = _IEEE80211_SHIFTMASK(htinfo->hi_byte1,
1699
IEEE80211_HTINFO_2NDCHAN);
1700
w = le16dec(&htinfo->hi_byte2);
1701
ni->ni_htopmode = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_OPMODE);
1702
w = le16dec(&htinfo->hi_byte45);
1703
ni->ni_htstbc = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1704
}
1705
1706
/*
1707
* Parse an 802.11n HT info ie and save useful information
1708
* to the node state. Note this does not effect any state
1709
* changes such as for channel width change.
1710
*/
1711
void
1712
ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1713
{
1714
if (ie[0] == IEEE80211_ELEMID_VENDOR)
1715
ie += 4;
1716
htinfo_parse(ni, (const struct ieee80211_ie_htinfo *) ie);
1717
}
1718
1719
/*
1720
* Handle 11n/11ac channel switch.
1721
*
1722
* Use the received HT/VHT ie's to identify the right channel to use.
1723
* If we cannot locate it in the channel table then fallback to
1724
* legacy operation.
1725
*
1726
* Note that we use this information to identify the node's
1727
* channel only; the caller is responsible for insuring any
1728
* required channel change is done (e.g. in sta mode when
1729
* parsing the contents of a beacon frame).
1730
*/
1731
static int
1732
htinfo_update_chw(struct ieee80211_node *ni, int htflags, int vhtflags)
1733
{
1734
struct ieee80211com *ic = ni->ni_ic;
1735
struct ieee80211_channel *c;
1736
int chanflags;
1737
int ret = 0;
1738
1739
/*
1740
* First step - do HT/VHT only channel lookup based on operating mode
1741
* flags. This involves masking out the VHT flags as well.
1742
* Otherwise we end up doing the full channel walk each time
1743
* we trigger this, which is expensive.
1744
*/
1745
chanflags = (ni->ni_chan->ic_flags &~
1746
(IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags | vhtflags;
1747
1748
if (chanflags == ni->ni_chan->ic_flags)
1749
goto done;
1750
1751
/*
1752
* If HT /or/ VHT flags have changed then check both.
1753
* We need to start by picking a HT channel anyway.
1754
*/
1755
1756
c = NULL;
1757
chanflags = (ni->ni_chan->ic_flags &~
1758
(IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags;
1759
/* XXX not right for ht40- */
1760
c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1761
if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
1762
/*
1763
* No HT40 channel entry in our table; fall back
1764
* to HT20 operation. This should not happen.
1765
*/
1766
c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1767
#if 0
1768
IEEE80211_NOTE(ni->ni_vap,
1769
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1770
"no HT40 channel (freq %u), falling back to HT20",
1771
ni->ni_chan->ic_freq);
1772
#endif
1773
/* XXX stat */
1774
}
1775
1776
/* Nothing found - leave it alone; move onto VHT */
1777
if (c == NULL)
1778
c = ni->ni_chan;
1779
1780
/*
1781
* If it's non-HT, then bail out now.
1782
*/
1783
if (! IEEE80211_IS_CHAN_HT(c)) {
1784
IEEE80211_NOTE(ni->ni_vap,
1785
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1786
"not HT; skipping VHT check (%u/0x%x)",
1787
c->ic_freq, c->ic_flags);
1788
goto done;
1789
}
1790
1791
/*
1792
* Next step - look at the current VHT flags and determine
1793
* if we need to upgrade. Mask out the VHT and HT flags since
1794
* the vhtflags field will already have the correct HT
1795
* flags to use.
1796
*/
1797
if (IEEE80211_CONF_VHT(ic) && ni->ni_vhtcap != 0 && vhtflags != 0) {
1798
chanflags = (c->ic_flags
1799
&~ (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT))
1800
| vhtflags;
1801
IEEE80211_NOTE(ni->ni_vap,
1802
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1803
ni,
1804
"%s: VHT; chanwidth=0x%02x; vhtflags=0x%08x",
1805
__func__, ni->ni_vht_chanwidth, vhtflags);
1806
1807
IEEE80211_NOTE(ni->ni_vap,
1808
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1809
ni,
1810
"%s: VHT; trying lookup for %d/0x%08x",
1811
__func__, c->ic_freq, chanflags);
1812
c = ieee80211_find_channel(ic, c->ic_freq, chanflags);
1813
}
1814
1815
/* Finally, if it's changed */
1816
if (c != NULL && c != ni->ni_chan) {
1817
IEEE80211_NOTE(ni->ni_vap,
1818
IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1819
"switch station to %s%d channel %u/0x%x",
1820
IEEE80211_IS_CHAN_VHT(c) ? "VHT" : "HT",
1821
IEEE80211_IS_CHAN_VHT80(c) ? 80 :
1822
(IEEE80211_IS_CHAN_HT40(c) ? 40 : 20),
1823
c->ic_freq, c->ic_flags);
1824
ni->ni_chan = c;
1825
ret = 1;
1826
}
1827
/* NB: caller responsible for forcing any channel change */
1828
1829
done:
1830
/* update node's (11n) tx channel width */
1831
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
1832
NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
1833
return (ret);
1834
}
1835
1836
/*
1837
* Update 11n MIMO PS state according to received htcap.
1838
*/
1839
static __inline int
1840
htcap_update_mimo_ps(struct ieee80211_node *ni)
1841
{
1842
uint16_t oflags = ni->ni_flags;
1843
1844
switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) {
1845
case IEEE80211_HTCAP_SMPS_DYNAMIC:
1846
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1847
ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
1848
break;
1849
case IEEE80211_HTCAP_SMPS_ENA:
1850
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1851
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1852
break;
1853
case IEEE80211_HTCAP_SMPS_OFF:
1854
default: /* disable on rx of reserved value */
1855
ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
1856
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1857
break;
1858
}
1859
return (oflags ^ ni->ni_flags);
1860
}
1861
1862
/*
1863
* Update short GI state according to received htcap
1864
* and local settings.
1865
*/
1866
static __inline void
1867
htcap_update_shortgi(struct ieee80211_node *ni)
1868
{
1869
struct ieee80211vap *vap = ni->ni_vap;
1870
1871
ni->ni_flags &= ~(IEEE80211_NODE_SGI20|IEEE80211_NODE_SGI40);
1872
if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
1873
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20))
1874
ni->ni_flags |= IEEE80211_NODE_SGI20;
1875
if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
1876
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
1877
ni->ni_flags |= IEEE80211_NODE_SGI40;
1878
}
1879
1880
/*
1881
* Update LDPC state according to received htcap
1882
* and local settings.
1883
*/
1884
static __inline void
1885
htcap_update_ldpc(struct ieee80211_node *ni)
1886
{
1887
struct ieee80211vap *vap = ni->ni_vap;
1888
1889
if ((ni->ni_htcap & IEEE80211_HTCAP_LDPC) &&
1890
(vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX))
1891
ni->ni_flags |= IEEE80211_NODE_LDPC;
1892
}
1893
1894
/*
1895
* Parse and update HT-related state extracted from
1896
* the HT cap and info ie's.
1897
*
1898
* This is called from the STA management path and
1899
* the ieee80211_node_join() path. It will take into
1900
* account the IEs discovered during scanning and
1901
* adjust things accordingly.
1902
*/
1903
void
1904
ieee80211_ht_updateparams(struct ieee80211_node *ni,
1905
const uint8_t *htcapie, const uint8_t *htinfoie)
1906
{
1907
struct ieee80211vap *vap = ni->ni_vap;
1908
const struct ieee80211_ie_htinfo *htinfo;
1909
1910
ieee80211_parse_htcap(ni, htcapie);
1911
if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
1912
htcap_update_mimo_ps(ni);
1913
htcap_update_shortgi(ni);
1914
htcap_update_ldpc(ni);
1915
1916
if (htinfoie[0] == IEEE80211_ELEMID_VENDOR)
1917
htinfoie += 4;
1918
htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
1919
htinfo_parse(ni, htinfo);
1920
1921
/*
1922
* Defer the node channel change; we need to now
1923
* update VHT parameters before we do it.
1924
*/
1925
1926
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
1927
(vap->iv_flags_ht & IEEE80211_FHT_RIFS))
1928
ni->ni_flags |= IEEE80211_NODE_RIFS;
1929
else
1930
ni->ni_flags &= ~IEEE80211_NODE_RIFS;
1931
}
1932
1933
static uint32_t
1934
ieee80211_vht_get_vhtflags(struct ieee80211_node *ni, uint32_t htflags)
1935
{
1936
#define _RETURN_CHAN_BITS(_cb) \
1937
do { \
1938
if (0) IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni, \
1939
"%s:%d: selected %b", __func__, __LINE__, \
1940
(_cb), IEEE80211_CHAN_BITS); \
1941
return (_cb); \
1942
} while(0)
1943
struct ieee80211vap *vap;
1944
const struct ieee80211_ie_htinfo *htinfo;
1945
uint32_t vhtflags;
1946
bool can_vht160, can_vht80p80, can_vht80;
1947
bool ht40;
1948
1949
vap = ni->ni_vap;
1950
1951
/* If we do not support VHT or VHT is disabled just return. */
1952
if ((ni->ni_flags & IEEE80211_NODE_VHT) == 0 ||
1953
(vap->iv_vht_flags & IEEE80211_FVHT_VHT) == 0)
1954
_RETURN_CHAN_BITS(0);
1955
1956
/*
1957
* TODO: should we bail out if there's no htinfo?
1958
* Or just treat it as if we can't do the HT20/HT40 check?
1959
*/
1960
1961
/*
1962
* The original code was based on
1963
* 802.11ac-2013, Table 8-183x-VHT Operation Information subfields.
1964
* 802.11-2020, Table 9-274-VHT Operation Information subfields
1965
* has IEEE80211_VHT_CHANWIDTH_160MHZ and
1966
* IEEE80211_VHT_CHANWIDTH_80P80MHZ deprecated.
1967
* For current logic see
1968
* 802.11-2020, 11.38.1 Basic VHT BSS functionality.
1969
*/
1970
1971
htinfo = (const struct ieee80211_ie_htinfo *)ni->ni_ies.htinfo_ie;
1972
if (htinfo != NULL)
1973
ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
1974
IEEE80211_HTINFO_TXWIDTH_2040);
1975
else
1976
ht40 = false;
1977
1978
can_vht160 = can_vht80p80 = can_vht80 = false;
1979
1980
/* 20 Mhz */
1981
if (!ht40) {
1982
/* Check for the full valid combination -- other fields be 0. */
1983
if (ni->ni_vht_chanwidth != IEEE80211_VHT_CHANWIDTH_USE_HT ||
1984
ni->ni_vht_chan2 != 0)
1985
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
1986
"%s: invalid VHT BSS bandwidth 0/%d/%d/%d",
1987
__func__, ni->ni_vht_chanwidth,
1988
ni->ni_vht_chan1, ni->ni_vht_chan2);
1989
1990
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
1991
}
1992
1993
vhtflags = 0;
1994
1995
/* We know we can at least do 40Mhz, so mirror the HT40 flags. */
1996
if (htflags == IEEE80211_CHAN_HT40U)
1997
vhtflags |= IEEE80211_CHAN_HT40U;
1998
else if (htflags == IEEE80211_CHAN_HT40D)
1999
vhtflags |= IEEE80211_CHAN_HT40D;
2000
2001
/* 40 MHz */
2002
if (ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_USE_HT) {
2003
if (ni->ni_vht_chan2 != 0)
2004
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
2005
"%s: invalid VHT BSS bandwidth 1/%d/%d/%d",
2006
__func__, ni->ni_vht_chanwidth,
2007
ni->ni_vht_chan1, ni->ni_vht_chan2);
2008
2009
if ((vap->iv_vht_flags & IEEE80211_FVHT_USEVHT40) != 0) {
2010
if (htflags == IEEE80211_CHAN_HT40U)
2011
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40U | vhtflags);
2012
if (htflags == IEEE80211_CHAN_HT40D)
2013
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40D | vhtflags);
2014
}
2015
2016
/* If we get here VHT40 is not supported or disabled. */
2017
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
2018
}
2019
2020
/* Deprecated check for 160. */
2021
if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_160MHZ) &&
2022
IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160MHZ(vap->iv_vht_cap.vht_cap_info) &&
2023
(vap->iv_vht_flags & IEEE80211_FVHT_USEVHT160) != 0)
2024
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT160 | vhtflags);
2025
2026
/* Deprecated check for 80P80. */
2027
if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_80P80MHZ) &&
2028
IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_IS_160_80P80MHZ(vap->iv_vht_cap.vht_cap_info) &&
2029
(vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80P80) != 0)
2030
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80P80 | vhtflags);
2031
2032
if (ni->ni_vht_chanwidth != IEEE80211_VHT_CHANWIDTH_80MHZ) {
2033
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
2034
"%s: invalid VHT BSS bandwidth %d/%d/%d", __func__,
2035
ni->ni_vht_chanwidth, ni->ni_vht_chan2);
2036
2037
_RETURN_CHAN_BITS(0);
2038
}
2039
2040
/* CCFS1 > 0 and | CCFS1 - CCFS0 | = 8 */
2041
if (ni->ni_vht_chan2 > 0 && (ni->ni_vht_chan2 - ni->ni_vht_chan1) == 8)
2042
can_vht160 = can_vht80 = true;
2043
2044
/* CCFS1 > 0 and | CCFS1 - CCFS0 | > 16 */
2045
if (ni->ni_vht_chan2 > 0 && (ni->ni_vht_chan2 - ni->ni_vht_chan1) > 16)
2046
can_vht80p80 = can_vht80 = true;
2047
2048
/* CFFS1 == 0 */
2049
if (ni->ni_vht_chan2 == 0)
2050
can_vht80 = true;
2051
2052
if (can_vht160 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT160) != 0)
2053
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT160 | vhtflags);
2054
2055
if (can_vht80p80 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80P80) != 0)
2056
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80P80 | vhtflags);
2057
2058
if (can_vht80 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT80) != 0)
2059
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT80 | vhtflags);
2060
2061
if (ht40 && (vap->iv_vht_flags & IEEE80211_FVHT_USEVHT40) != 0) {
2062
if (htflags == IEEE80211_CHAN_HT40U)
2063
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40U | vhtflags);
2064
if (htflags == IEEE80211_CHAN_HT40D)
2065
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT40D | vhtflags);
2066
}
2067
2068
/* Either we disabled support or got an invalid setting. */
2069
_RETURN_CHAN_BITS(IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_HT20);
2070
#undef _RETURN_CHAN_BITS
2071
}
2072
2073
/*
2074
* Final part of updating the HT parameters.
2075
*
2076
* This is called from the STA management path and
2077
* the ieee80211_node_join() path. It will take into
2078
* account the IEs discovered during scanning and
2079
* adjust things accordingly.
2080
*
2081
* This is done after a call to ieee80211_ht_updateparams()
2082
* because it (and the upcoming VHT version of updateparams)
2083
* needs to ensure everything is parsed before htinfo_update_chw()
2084
* is called - which will change the channel config for the
2085
* node for us.
2086
*/
2087
int
2088
ieee80211_ht_updateparams_final(struct ieee80211_node *ni,
2089
const uint8_t *htcapie, const uint8_t *htinfoie)
2090
{
2091
struct ieee80211vap *vap = ni->ni_vap;
2092
const struct ieee80211_ie_htinfo *htinfo;
2093
int htflags, vhtflags;
2094
int ret = 0;
2095
2096
htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
2097
2098
htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
2099
IEEE80211_CHAN_HT20 : 0;
2100
2101
/* NB: honor operating mode constraint */
2102
if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
2103
(vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
2104
if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
2105
htflags = IEEE80211_CHAN_HT40U;
2106
else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
2107
htflags = IEEE80211_CHAN_HT40D;
2108
}
2109
2110
/*
2111
* VHT flags - do much the same; check whether VHT is available
2112
* and if so, what our ideal channel use would be based on our
2113
* capabilities and the (pre-parsed) VHT info IE.
2114
*/
2115
vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
2116
2117
if (htinfo_update_chw(ni, htflags, vhtflags))
2118
ret = 1;
2119
2120
return (ret);
2121
}
2122
2123
/*
2124
* Parse and update HT-related state extracted from the HT cap ie
2125
* for a station joining an HT BSS.
2126
*
2127
* This is called from the hostap path for each station.
2128
*/
2129
void
2130
ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
2131
{
2132
struct ieee80211vap *vap = ni->ni_vap;
2133
2134
ieee80211_parse_htcap(ni, htcapie);
2135
if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
2136
htcap_update_mimo_ps(ni);
2137
htcap_update_shortgi(ni);
2138
htcap_update_ldpc(ni);
2139
}
2140
2141
/*
2142
* Called once HT and VHT capabilities are parsed in hostap mode -
2143
* this will adjust the channel configuration of the given node
2144
* based on the configuration and capabilities.
2145
*/
2146
void
2147
ieee80211_ht_updatehtcap_final(struct ieee80211_node *ni)
2148
{
2149
struct ieee80211vap *vap = ni->ni_vap;
2150
int htflags;
2151
int vhtflags;
2152
2153
/* NB: honor operating mode constraint */
2154
/* XXX 40 MHz intolerant */
2155
htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
2156
IEEE80211_CHAN_HT20 : 0;
2157
if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
2158
(vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
2159
if (IEEE80211_IS_CHAN_HT40U(vap->iv_bss->ni_chan))
2160
htflags = IEEE80211_CHAN_HT40U;
2161
else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
2162
htflags = IEEE80211_CHAN_HT40D;
2163
}
2164
/*
2165
* VHT flags - do much the same; check whether VHT is available
2166
* and if so, what our ideal channel use would be based on our
2167
* capabilities and the (pre-parsed) VHT info IE.
2168
*/
2169
vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
2170
2171
(void) htinfo_update_chw(ni, htflags, vhtflags);
2172
}
2173
2174
/*
2175
* Install received HT rate set by parsing the HT cap ie.
2176
*/
2177
int
2178
ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
2179
{
2180
struct ieee80211com *ic = ni->ni_ic;
2181
struct ieee80211vap *vap = ni->ni_vap;
2182
const struct ieee80211_ie_htcap *htcap;
2183
struct ieee80211_htrateset *rs;
2184
int i, maxequalmcs, maxunequalmcs;
2185
2186
maxequalmcs = ic->ic_txstream * 8 - 1;
2187
maxunequalmcs = 0;
2188
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
2189
if (ic->ic_txstream >= 2)
2190
maxunequalmcs = 38;
2191
if (ic->ic_txstream >= 3)
2192
maxunequalmcs = 52;
2193
if (ic->ic_txstream >= 4)
2194
maxunequalmcs = 76;
2195
}
2196
2197
rs = &ni->ni_htrates;
2198
memset(rs, 0, sizeof(*rs));
2199
if (ie != NULL) {
2200
if (ie[0] == IEEE80211_ELEMID_VENDOR)
2201
ie += 4;
2202
htcap = (const struct ieee80211_ie_htcap *) ie;
2203
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
2204
if (isclr(htcap->hc_mcsset, i))
2205
continue;
2206
if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
2207
IEEE80211_NOTE(vap,
2208
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
2209
"WARNING, HT rate set too large; only "
2210
"using %u rates", IEEE80211_HTRATE_MAXSIZE);
2211
vap->iv_stats.is_rx_rstoobig++;
2212
break;
2213
}
2214
if (i <= 31 && i > maxequalmcs)
2215
continue;
2216
if (i == 32 &&
2217
(ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
2218
continue;
2219
if (i > 32 && i > maxunequalmcs)
2220
continue;
2221
rs->rs_rates[rs->rs_nrates++] = i;
2222
}
2223
}
2224
return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
2225
}
2226
2227
/*
2228
* Mark rates in a node's HT rate set as basic according
2229
* to the information in the supplied HT info ie.
2230
*/
2231
void
2232
ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
2233
{
2234
const struct ieee80211_ie_htinfo *htinfo;
2235
struct ieee80211_htrateset *rs;
2236
int i, j;
2237
2238
if (ie[0] == IEEE80211_ELEMID_VENDOR)
2239
ie += 4;
2240
htinfo = (const struct ieee80211_ie_htinfo *) ie;
2241
rs = &ni->ni_htrates;
2242
if (rs->rs_nrates == 0) {
2243
IEEE80211_NOTE(ni->ni_vap,
2244
IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
2245
"%s", "WARNING, empty HT rate set");
2246
return;
2247
}
2248
for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
2249
if (isclr(htinfo->hi_basicmcsset, i))
2250
continue;
2251
for (j = 0; j < rs->rs_nrates; j++)
2252
if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
2253
rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
2254
}
2255
}
2256
2257
static void
2258
ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
2259
{
2260
callout_init(&tap->txa_timer, 1);
2261
tap->txa_flags |= IEEE80211_AGGR_SETUP;
2262
tap->txa_lastsample = ticks;
2263
}
2264
2265
static void
2266
ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
2267
{
2268
struct ieee80211_node *ni = tap->txa_ni;
2269
struct ieee80211com *ic = ni->ni_ic;
2270
2271
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2272
tap->txa_ni,
2273
"%s: called",
2274
__func__);
2275
2276
KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
2277
("txa_flags 0x%x tid %d ac %d", tap->txa_flags, tap->txa_tid,
2278
TID_TO_WME_AC(tap->txa_tid)));
2279
2280
/*
2281
* Stop BA stream if setup so driver has a chance
2282
* to reclaim any resources it might have allocated.
2283
*/
2284
ic->ic_addba_stop(ni, tap);
2285
/*
2286
* Stop any pending BAR transmit.
2287
*/
2288
bar_stop_timer(tap);
2289
2290
/*
2291
* Reset packet estimate.
2292
*/
2293
ieee80211_txampdu_init_pps(tap);
2294
2295
/* NB: clearing NAK means we may re-send ADDBA */
2296
tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
2297
}
2298
2299
/*
2300
* ADDBA response timeout.
2301
*
2302
* If software aggregation and per-TID queue management was done here,
2303
* that queue would be unpaused after the ADDBA timeout occurs.
2304
*/
2305
static void
2306
addba_timeout(void *arg)
2307
{
2308
struct ieee80211_tx_ampdu *tap = arg;
2309
struct ieee80211_node *ni = tap->txa_ni;
2310
struct ieee80211com *ic = ni->ni_ic;
2311
2312
/* XXX ? */
2313
tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
2314
tap->txa_attempts++;
2315
ic->ic_addba_response_timeout(ni, tap);
2316
}
2317
2318
static void
2319
addba_start_timeout(struct ieee80211_tx_ampdu *tap)
2320
{
2321
/* XXX use CALLOUT_PENDING instead? */
2322
callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
2323
addba_timeout, tap);
2324
tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
2325
tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
2326
}
2327
2328
static void
2329
addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
2330
{
2331
/* XXX use CALLOUT_PENDING instead? */
2332
if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
2333
callout_stop(&tap->txa_timer);
2334
tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
2335
}
2336
}
2337
2338
static void
2339
null_addba_response_timeout(struct ieee80211_node *ni,
2340
struct ieee80211_tx_ampdu *tap)
2341
{
2342
}
2343
2344
/*
2345
* Default method for requesting A-MPDU tx aggregation.
2346
* We setup the specified state block and start a timer
2347
* to wait for an ADDBA response frame.
2348
*/
2349
static int
2350
ieee80211_addba_request(struct ieee80211_node *ni,
2351
struct ieee80211_tx_ampdu *tap,
2352
int dialogtoken, int baparamset, int batimeout)
2353
{
2354
int bufsiz;
2355
2356
/* XXX locking */
2357
tap->txa_token = dialogtoken;
2358
tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
2359
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2360
tap->txa_wnd = (bufsiz == 0) ?
2361
IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
2362
addba_start_timeout(tap);
2363
return 1;
2364
}
2365
2366
/*
2367
* Called by drivers that wish to request an ADDBA session be
2368
* setup. This brings it up and starts the request timer.
2369
*/
2370
int
2371
ieee80211_ampdu_tx_request_ext(struct ieee80211_node *ni, int tid)
2372
{
2373
struct ieee80211_tx_ampdu *tap;
2374
2375
if (tid < 0 || tid > 15)
2376
return (0);
2377
tap = &ni->ni_tx_ampdu[tid];
2378
2379
/* XXX locking */
2380
if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
2381
/* do deferred setup of state */
2382
ampdu_tx_setup(tap);
2383
}
2384
/* XXX hack for not doing proper locking */
2385
tap->txa_flags &= ~IEEE80211_AGGR_NAK;
2386
addba_start_timeout(tap);
2387
return (1);
2388
}
2389
2390
/*
2391
* Called by drivers that have marked a session as active.
2392
*/
2393
int
2394
ieee80211_ampdu_tx_request_active_ext(struct ieee80211_node *ni, int tid,
2395
int status)
2396
{
2397
struct ieee80211_tx_ampdu *tap;
2398
2399
if (tid < 0 || tid > 15)
2400
return (0);
2401
tap = &ni->ni_tx_ampdu[tid];
2402
2403
/* XXX locking */
2404
addba_stop_timeout(tap);
2405
if (status == 1) {
2406
tap->txa_flags |= IEEE80211_AGGR_RUNNING;
2407
tap->txa_attempts = 0;
2408
} else {
2409
/* mark tid so we don't try again */
2410
tap->txa_flags |= IEEE80211_AGGR_NAK;
2411
}
2412
return (1);
2413
}
2414
2415
/*
2416
* Default method for processing an A-MPDU tx aggregation
2417
* response. We shutdown any pending timer and update the
2418
* state block according to the reply.
2419
*/
2420
static int
2421
ieee80211_addba_response(struct ieee80211_node *ni,
2422
struct ieee80211_tx_ampdu *tap,
2423
int status, int baparamset, int batimeout)
2424
{
2425
struct ieee80211vap *vap = ni->ni_vap;
2426
int bufsiz;
2427
2428
/* XXX locking */
2429
addba_stop_timeout(tap);
2430
if (status == IEEE80211_STATUS_SUCCESS) {
2431
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2432
/* XXX override our request? */
2433
tap->txa_wnd = (bufsiz == 0) ?
2434
IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
2435
#ifdef __notyet__
2436
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2437
#endif
2438
tap->txa_flags |= IEEE80211_AGGR_RUNNING;
2439
tap->txa_attempts = 0;
2440
/* TODO: this should be a vap flag */
2441
if ((vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU) &&
2442
(ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
2443
(_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))
2444
tap->txa_flags |= IEEE80211_AGGR_AMSDU;
2445
else
2446
tap->txa_flags &= ~IEEE80211_AGGR_AMSDU;
2447
} else {
2448
/* mark tid so we don't try again */
2449
tap->txa_flags |= IEEE80211_AGGR_NAK;
2450
}
2451
return 1;
2452
}
2453
2454
/*
2455
* Default method for stopping A-MPDU tx aggregation.
2456
* Any timer is cleared and we drain any pending frames.
2457
*/
2458
static void
2459
ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
2460
{
2461
/* XXX locking */
2462
addba_stop_timeout(tap);
2463
if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
2464
/* XXX clear aggregation queue */
2465
tap->txa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU);
2466
}
2467
tap->txa_attempts = 0;
2468
}
2469
2470
/*
2471
* Process a received action frame using the default aggregation
2472
* policy. We intercept ADDBA-related frames and use them to
2473
* update our aggregation state. All other frames are passed up
2474
* for processing by ieee80211_recv_action.
2475
*/
2476
static int
2477
ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
2478
const struct ieee80211_frame *wh,
2479
const uint8_t *frm, const uint8_t *efrm)
2480
{
2481
struct ieee80211com *ic = ni->ni_ic;
2482
struct ieee80211vap *vap = ni->ni_vap;
2483
struct ieee80211_rx_ampdu *rap;
2484
uint8_t dialogtoken;
2485
uint16_t baparamset, batimeout, baseqctl;
2486
uint16_t args[5];
2487
int tid;
2488
2489
dialogtoken = frm[2];
2490
baparamset = le16dec(frm+3);
2491
batimeout = le16dec(frm+5);
2492
baseqctl = le16dec(frm+7);
2493
2494
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2495
2496
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2497
"recv ADDBA request: dialogtoken %u baparamset 0x%x "
2498
"(tid %d bufsiz %d) batimeout %d baseqctl %d:%d amsdu %d",
2499
dialogtoken, baparamset,
2500
tid, _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ),
2501
batimeout,
2502
_IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_START),
2503
_IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_FRAG),
2504
_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU));
2505
2506
rap = &ni->ni_rx_ampdu[tid];
2507
2508
/* Send ADDBA response */
2509
args[0] = dialogtoken;
2510
/*
2511
* NB: We ack only if the sta associated with HT and
2512
* the ap is configured to do AMPDU rx (the latter
2513
* violates the 11n spec and is mostly for testing).
2514
*/
2515
if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
2516
(vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
2517
/* XXX TODO: handle ampdu_rx_start failure */
2518
ic->ic_ampdu_rx_start(ni, rap,
2519
baparamset, batimeout, baseqctl);
2520
2521
args[1] = IEEE80211_STATUS_SUCCESS;
2522
} else {
2523
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2524
ni, "reject ADDBA request: %s",
2525
ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
2526
"administratively disabled" :
2527
"not negotiated for station");
2528
vap->iv_stats.is_addba_reject++;
2529
args[1] = IEEE80211_STATUS_UNSPECIFIED;
2530
}
2531
/* XXX honor rap flags? */
2532
args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
2533
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
2534
| _IEEE80211_SHIFTMASK(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
2535
;
2536
2537
/*
2538
* TODO: we're out of iv_flags_ht fields; once
2539
* this is extended we should make this configurable.
2540
*/
2541
if ((baparamset & IEEE80211_BAPS_AMSDU) &&
2542
(ni->ni_flags & IEEE80211_NODE_AMSDU_RX) &&
2543
(vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU))
2544
args[2] |= IEEE80211_BAPS_AMSDU;
2545
2546
args[3] = 0;
2547
args[4] = 0;
2548
ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2549
IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
2550
return 0;
2551
}
2552
2553
static int
2554
ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
2555
const struct ieee80211_frame *wh,
2556
const uint8_t *frm, const uint8_t *efrm)
2557
{
2558
struct ieee80211com *ic = ni->ni_ic;
2559
struct ieee80211vap *vap = ni->ni_vap;
2560
struct ieee80211_tx_ampdu *tap;
2561
uint8_t dialogtoken, policy;
2562
uint16_t baparamset, batimeout, code;
2563
int tid;
2564
#ifdef IEEE80211_DEBUG
2565
int amsdu, bufsiz;
2566
#endif
2567
2568
dialogtoken = frm[2];
2569
code = le16dec(frm+3);
2570
baparamset = le16dec(frm+5);
2571
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
2572
#ifdef IEEE80211_DEBUG
2573
bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
2574
amsdu = !! _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU);
2575
#endif
2576
policy = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_POLICY);
2577
batimeout = le16dec(frm+7);
2578
2579
tap = &ni->ni_tx_ampdu[tid];
2580
if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
2581
IEEE80211_DISCARD_MAC(vap,
2582
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2583
ni->ni_macaddr, "ADDBA response",
2584
"no pending ADDBA, tid %d dialogtoken %u "
2585
"code %d", tid, dialogtoken, code);
2586
vap->iv_stats.is_addba_norequest++;
2587
return 0;
2588
}
2589
if (dialogtoken != tap->txa_token) {
2590
IEEE80211_DISCARD_MAC(vap,
2591
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2592
ni->ni_macaddr, "ADDBA response",
2593
"dialogtoken mismatch: waiting for %d, "
2594
"received %d, tid %d code %d",
2595
tap->txa_token, dialogtoken, tid, code);
2596
vap->iv_stats.is_addba_badtoken++;
2597
return 0;
2598
}
2599
/* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
2600
if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
2601
IEEE80211_DISCARD_MAC(vap,
2602
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2603
ni->ni_macaddr, "ADDBA response",
2604
"policy mismatch: expecting %s, "
2605
"received %s, tid %d code %d",
2606
tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
2607
policy, tid, code);
2608
vap->iv_stats.is_addba_badpolicy++;
2609
return 0;
2610
}
2611
#if 0
2612
/* XXX we take MIN in ieee80211_addba_response */
2613
if (bufsiz > IEEE80211_AGGR_BAWMAX) {
2614
IEEE80211_DISCARD_MAC(vap,
2615
IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2616
ni->ni_macaddr, "ADDBA response",
2617
"BA window too large: max %d, "
2618
"received %d, tid %d code %d",
2619
bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
2620
vap->iv_stats.is_addba_badbawinsize++;
2621
return 0;
2622
}
2623
#endif
2624
2625
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2626
"recv ADDBA response: dialogtoken %u code %d "
2627
"baparamset 0x%x (tid %d bufsiz %d amsdu %d) batimeout %d",
2628
dialogtoken, code, baparamset, tid,
2629
bufsiz,
2630
amsdu,
2631
batimeout);
2632
ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
2633
return 0;
2634
}
2635
2636
static int
2637
ht_recv_action_ba_delba(struct ieee80211_node *ni,
2638
const struct ieee80211_frame *wh,
2639
const uint8_t *frm, const uint8_t *efrm)
2640
{
2641
struct ieee80211com *ic = ni->ni_ic;
2642
struct ieee80211_rx_ampdu *rap;
2643
struct ieee80211_tx_ampdu *tap;
2644
uint16_t baparamset;
2645
#ifdef IEEE80211_DEBUG
2646
uint16_t code;
2647
#endif
2648
int tid;
2649
2650
baparamset = le16dec(frm+2);
2651
#ifdef IEEE80211_DEBUG
2652
code = le16dec(frm+4);
2653
#endif
2654
2655
tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_TID);
2656
2657
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2658
"recv DELBA: baparamset 0x%x (tid %d initiator %d) "
2659
"code %d", baparamset, tid,
2660
_IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_INIT), code);
2661
2662
if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
2663
tap = &ni->ni_tx_ampdu[tid];
2664
ic->ic_addba_stop(ni, tap);
2665
} else {
2666
rap = &ni->ni_rx_ampdu[tid];
2667
ic->ic_ampdu_rx_stop(ni, rap);
2668
}
2669
return 0;
2670
}
2671
2672
/*
2673
* Handle the HT channel width action frame.
2674
*
2675
* 802.11-2020 9.6.11.2 (Notify Channel Width frame format).
2676
*/
2677
static int
2678
ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
2679
const struct ieee80211_frame *wh __unused,
2680
const uint8_t *frm, const uint8_t *efrm __unused)
2681
{
2682
int chw;
2683
2684
/* If 20/40 is not supported the chw cannot change. */
2685
if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) == 0)
2686
return (0);
2687
2688
/*
2689
* The supported values are either 0 (any supported width)
2690
* or 1 (HT20). 80, 160, etc MHz widths are not represented
2691
* here.
2692
*/
2693
chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ?
2694
NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
2695
2696
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2697
"%s: HT txchwidth, width %d%s (%s)", __func__,
2698
chw, ni->ni_chw != chw ? "*" : "", net80211_ni_chw_to_str(chw));
2699
if (chw != ni->ni_chw) {
2700
/* XXX does this need to change the ht40 station count? */
2701
ni->ni_chw = chw;
2702
/* XXX notify on change */
2703
}
2704
return 0;
2705
}
2706
2707
static int
2708
ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
2709
const struct ieee80211_frame *wh,
2710
const uint8_t *frm, const uint8_t *efrm)
2711
{
2712
const struct ieee80211_action_ht_mimopowersave *mps =
2713
(const struct ieee80211_action_ht_mimopowersave *) frm;
2714
2715
/* XXX check iv_htcaps */
2716
if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
2717
ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
2718
else
2719
ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
2720
if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
2721
ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
2722
else
2723
ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
2724
/* XXX notify on change */
2725
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2726
"%s: HT MIMO PS (%s%s)", __func__,
2727
(ni->ni_flags & IEEE80211_NODE_MIMO_PS) ? "on" : "off",
2728
(ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ? "+rts" : ""
2729
);
2730
return 0;
2731
}
2732
2733
/*
2734
* Transmit processing.
2735
*/
2736
2737
/*
2738
* Check if A-MPDU should be requested/enabled for a stream.
2739
* We require a traffic rate above a per-AC threshold and we
2740
* also handle backoff from previous failed attempts.
2741
*
2742
* Drivers may override this method to bring in information
2743
* such as link state conditions in making the decision.
2744
*/
2745
static int
2746
ieee80211_ampdu_enable(struct ieee80211_node *ni,
2747
struct ieee80211_tx_ampdu *tap)
2748
{
2749
struct ieee80211vap *vap = ni->ni_vap;
2750
2751
if (tap->txa_avgpps <
2752
vap->iv_ampdu_mintraffic[TID_TO_WME_AC(tap->txa_tid)])
2753
return 0;
2754
/* XXX check rssi? */
2755
if (tap->txa_attempts >= ieee80211_addba_maxtries &&
2756
ieee80211_time_after(ticks, tap->txa_nextrequest)) {
2757
/*
2758
* Don't retry too often; txa_nextrequest is set
2759
* to the minimum interval we'll retry after
2760
* ieee80211_addba_maxtries failed attempts are made.
2761
*/
2762
return 0;
2763
}
2764
IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
2765
"enable AMPDU on tid %d (%s), avgpps %d pkts %d attempt %d",
2766
tap->txa_tid, ieee80211_wme_acnames[TID_TO_WME_AC(tap->txa_tid)],
2767
tap->txa_avgpps, tap->txa_pkts, tap->txa_attempts);
2768
return 1;
2769
}
2770
2771
/**
2772
* @brief Request A-MPDU tx aggregation.
2773
*
2774
* Setup local state and issue an ADDBA request. BA use will only happen after
2775
* the other end replies with ADDBA response.
2776
*
2777
* @param ni ieee80211_node update
2778
* @param tap tx_ampdu state
2779
* @returns 1 on success and 0 on error
2780
*/
2781
int
2782
ieee80211_ampdu_request(struct ieee80211_node *ni,
2783
struct ieee80211_tx_ampdu *tap)
2784
{
2785
struct ieee80211com *ic = ni->ni_ic;
2786
uint16_t args[5];
2787
int tid, dialogtoken, error;
2788
static int tokens = 0; /* XXX */
2789
2790
/* XXX locking */
2791
if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
2792
/* do deferred setup of state */
2793
ampdu_tx_setup(tap);
2794
}
2795
/* XXX hack for not doing proper locking */
2796
tap->txa_flags &= ~IEEE80211_AGGR_NAK;
2797
2798
dialogtoken = (tokens+1) % 63; /* XXX */
2799
tid = tap->txa_tid;
2800
2801
/*
2802
* XXX TODO: This is racy with any other parallel TX going on. :(
2803
*/
2804
tap->txa_start = ni->ni_txseqs[tid];
2805
2806
args[0] = dialogtoken;
2807
args[1] = 0; /* NB: status code not used */
2808
args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
2809
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
2810
| _IEEE80211_SHIFTMASK(IEEE80211_AGGR_BAWMAX,
2811
IEEE80211_BAPS_BUFSIZ)
2812
;
2813
2814
/* XXX TODO: this should be a flag, not iv_htcaps */
2815
if ((ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
2816
(ni->ni_vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU))
2817
args[2] |= IEEE80211_BAPS_AMSDU;
2818
2819
args[3] = 0; /* batimeout */
2820
/* NB: do first so there's no race against reply */
2821
if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
2822
/* unable to setup state, don't make request */
2823
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2824
ni, "%s: could not setup BA stream for TID %d AC %d",
2825
__func__, tap->txa_tid, TID_TO_WME_AC(tap->txa_tid));
2826
/* defer next try so we don't slam the driver with requests */
2827
tap->txa_attempts = ieee80211_addba_maxtries;
2828
/* NB: check in case driver wants to override */
2829
if (ieee80211_time_before_eq(tap->txa_nextrequest, ticks))
2830
tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
2831
return 0;
2832
}
2833
tokens = dialogtoken; /* allocate token */
2834
/* NB: after calling ic_addba_request so driver can set txa_start */
2835
args[4] = _IEEE80211_SHIFTMASK(tap->txa_start, IEEE80211_BASEQ_START)
2836
| _IEEE80211_SHIFTMASK(0, IEEE80211_BASEQ_FRAG)
2837
;
2838
2839
error = ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2840
IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
2841
/* Silly return of 1 for success here. */
2842
return (error == 0);
2843
}
2844
2845
/*
2846
* Terminate an AMPDU tx stream. State is reclaimed
2847
* and the peer notified with a DelBA Action frame.
2848
*/
2849
void
2850
ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
2851
int reason)
2852
{
2853
struct ieee80211com *ic = ni->ni_ic;
2854
struct ieee80211vap *vap = ni->ni_vap;
2855
uint16_t args[4];
2856
2857
/* XXX locking */
2858
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2859
if (IEEE80211_AMPDU_RUNNING(tap)) {
2860
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2861
ni, "%s: stop BA stream for TID %d (reason: %d (%s))",
2862
__func__, tap->txa_tid, reason,
2863
ieee80211_reason_to_string(reason));
2864
vap->iv_stats.is_ampdu_stop++;
2865
2866
ic->ic_addba_stop(ni, tap);
2867
args[0] = tap->txa_tid;
2868
args[1] = IEEE80211_DELBAPS_INIT;
2869
args[2] = reason; /* XXX reason code */
2870
ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2871
IEEE80211_ACTION_BA_DELBA, args);
2872
} else {
2873
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2874
ni, "%s: BA stream for TID %d not running "
2875
"(reason: %d (%s))", __func__, tap->txa_tid, reason,
2876
ieee80211_reason_to_string(reason));
2877
vap->iv_stats.is_ampdu_stop_failed++;
2878
}
2879
}
2880
2881
/* XXX */
2882
static void bar_start_timer(struct ieee80211_tx_ampdu *tap);
2883
2884
static void
2885
bar_timeout(void *arg)
2886
{
2887
struct ieee80211_tx_ampdu *tap = arg;
2888
struct ieee80211_node *ni = tap->txa_ni;
2889
2890
KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
2891
("bar/addba collision, flags 0x%x", tap->txa_flags));
2892
2893
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2894
ni, "%s: tid %u flags 0x%x attempts %d", __func__,
2895
tap->txa_tid, tap->txa_flags, tap->txa_attempts);
2896
2897
/* guard against race with bar_tx_complete */
2898
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
2899
return;
2900
/* XXX ? */
2901
if (tap->txa_attempts >= ieee80211_bar_maxtries) {
2902
struct ieee80211com *ic = ni->ni_ic;
2903
2904
ni->ni_vap->iv_stats.is_ampdu_bar_tx_fail++;
2905
/*
2906
* If (at least) the last BAR TX timeout was due to
2907
* an ieee80211_send_bar() failures, then we need
2908
* to make sure we notify the driver that a BAR
2909
* TX did occur and fail. This gives the driver
2910
* a chance to undo any queue pause that may
2911
* have occurred.
2912
*/
2913
ic->ic_bar_response(ni, tap, 1);
2914
ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
2915
} else {
2916
ni->ni_vap->iv_stats.is_ampdu_bar_tx_retry++;
2917
if (ieee80211_send_bar(ni, tap, tap->txa_seqpending) != 0) {
2918
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2919
ni, "%s: failed to TX, starting timer\n",
2920
__func__);
2921
/*
2922
* If ieee80211_send_bar() fails here, the
2923
* timer may have stopped and/or the pending
2924
* flag may be clear. Because of this,
2925
* fake the BARPEND and reset the timer.
2926
* A retransmission attempt will then occur
2927
* during the next timeout.
2928
*/
2929
/* XXX locking */
2930
tap->txa_flags |= IEEE80211_AGGR_BARPEND;
2931
bar_start_timer(tap);
2932
}
2933
}
2934
}
2935
2936
static void
2937
bar_start_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_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
2944
}
2945
2946
static void
2947
bar_stop_timer(struct ieee80211_tx_ampdu *tap)
2948
{
2949
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2950
tap->txa_ni,
2951
"%s: called",
2952
__func__);
2953
callout_stop(&tap->txa_timer);
2954
}
2955
2956
static void
2957
bar_tx_complete(struct ieee80211_node *ni, void *arg, int status)
2958
{
2959
struct ieee80211_tx_ampdu *tap = arg;
2960
2961
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2962
ni, "%s: tid %u flags 0x%x pending %d status %d",
2963
__func__, tap->txa_tid, tap->txa_flags,
2964
callout_pending(&tap->txa_timer), status);
2965
2966
ni->ni_vap->iv_stats.is_ampdu_bar_tx++;
2967
/* XXX locking */
2968
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
2969
callout_pending(&tap->txa_timer)) {
2970
struct ieee80211com *ic = ni->ni_ic;
2971
2972
if (status == 0) /* ACK'd */
2973
bar_stop_timer(tap);
2974
ic->ic_bar_response(ni, tap, status);
2975
/* NB: just let timer expire so we pace requests */
2976
}
2977
}
2978
2979
static void
2980
ieee80211_bar_response(struct ieee80211_node *ni,
2981
struct ieee80211_tx_ampdu *tap, int status)
2982
{
2983
2984
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
2985
tap->txa_ni,
2986
"%s: called",
2987
__func__);
2988
if (status == 0) { /* got ACK */
2989
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2990
ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
2991
tap->txa_start,
2992
IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
2993
tap->txa_qframes, tap->txa_seqpending,
2994
tap->txa_tid);
2995
2996
/* NB: timer already stopped in bar_tx_complete */
2997
tap->txa_start = tap->txa_seqpending;
2998
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2999
}
3000
}
3001
3002
/*
3003
* Transmit a BAR frame to the specified node. The
3004
* BAR contents are drawn from the supplied aggregation
3005
* state associated with the node.
3006
*
3007
* NB: we only handle immediate ACK w/ compressed bitmap.
3008
*/
3009
int
3010
ieee80211_send_bar(struct ieee80211_node *ni,
3011
struct ieee80211_tx_ampdu *tap, ieee80211_seq seq)
3012
{
3013
#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
3014
struct ieee80211vap *vap = ni->ni_vap;
3015
struct ieee80211com *ic = ni->ni_ic;
3016
struct ieee80211_frame_bar *bar;
3017
struct mbuf *m;
3018
uint16_t barctl, barseqctl;
3019
uint8_t *frm;
3020
int tid, ret;
3021
3022
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
3023
tap->txa_ni,
3024
"%s: called",
3025
__func__);
3026
3027
if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
3028
/* no ADDBA response, should not happen */
3029
/* XXX stat+msg */
3030
return EINVAL;
3031
}
3032
/* XXX locking */
3033
bar_stop_timer(tap);
3034
3035
ieee80211_ref_node(ni);
3036
3037
m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
3038
if (m == NULL)
3039
senderr(ENOMEM, is_tx_nobuf);
3040
3041
if (!ieee80211_add_callback(m, bar_tx_complete, tap)) {
3042
m_freem(m);
3043
senderr(ENOMEM, is_tx_nobuf); /* XXX */
3044
/* NOTREACHED */
3045
}
3046
3047
bar = mtod(m, struct ieee80211_frame_bar *);
3048
bar->i_fc[0] = IEEE80211_FC0_VERSION_0 |
3049
IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
3050
bar->i_fc[1] = 0;
3051
IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
3052
IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
3053
3054
tid = tap->txa_tid;
3055
barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
3056
0 : IEEE80211_BAR_NOACK)
3057
| IEEE80211_BAR_COMP
3058
| _IEEE80211_SHIFTMASK(tid, IEEE80211_BAR_TID)
3059
;
3060
barseqctl = _IEEE80211_SHIFTMASK(seq, IEEE80211_BAR_SEQ_START);
3061
/* NB: known to have proper alignment */
3062
bar->i_ctl = htole16(barctl);
3063
bar->i_seq = htole16(barseqctl);
3064
m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
3065
3066
M_WME_SETAC(m, WME_AC_VO);
3067
3068
IEEE80211_NODE_STAT(ni, tx_mgmt); /* XXX tx_ctl? */
3069
3070
/* XXX locking */
3071
/* init/bump attempts counter */
3072
if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
3073
tap->txa_attempts = 1;
3074
else
3075
tap->txa_attempts++;
3076
tap->txa_seqpending = seq;
3077
tap->txa_flags |= IEEE80211_AGGR_BARPEND;
3078
3079
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
3080
ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)",
3081
tid, barctl, seq, tap->txa_attempts);
3082
3083
/*
3084
* ic_raw_xmit will free the node reference
3085
* regardless of queue/TX success or failure.
3086
*/
3087
IEEE80211_TX_LOCK(ic);
3088
ret = ieee80211_raw_output(vap, ni, m, NULL);
3089
IEEE80211_TX_UNLOCK(ic);
3090
if (ret != 0) {
3091
IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
3092
ni, "send BAR: failed: (ret = %d)\n",
3093
ret);
3094
/* xmit failed, clear state flag */
3095
tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
3096
vap->iv_stats.is_ampdu_bar_tx_fail++;
3097
return ret;
3098
}
3099
/* XXX hack against tx complete happening before timer is started */
3100
if (tap->txa_flags & IEEE80211_AGGR_BARPEND)
3101
bar_start_timer(tap);
3102
return 0;
3103
bad:
3104
IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
3105
tap->txa_ni,
3106
"%s: bad! ret=%d",
3107
__func__, ret);
3108
vap->iv_stats.is_ampdu_bar_tx_fail++;
3109
ieee80211_free_node(ni);
3110
return ret;
3111
#undef senderr
3112
}
3113
3114
static int
3115
ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
3116
{
3117
struct ieee80211_bpf_params params;
3118
3119
memset(&params, 0, sizeof(params));
3120
params.ibp_pri = WME_AC_VO;
3121
params.ibp_rate0 = ni->ni_txparms->mgmtrate;
3122
/* NB: we know all frames are unicast */
3123
params.ibp_try0 = ni->ni_txparms->maxretry;
3124
params.ibp_power = ni->ni_txpower;
3125
return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
3126
&params);
3127
}
3128
3129
#define ADDSHORT(frm, v) do { \
3130
frm[0] = (v) & 0xff; \
3131
frm[1] = (v) >> 8; \
3132
frm += 2; \
3133
} while (0)
3134
3135
/*
3136
* Send an action management frame. The arguments are stuff
3137
* into a frame without inspection; the caller is assumed to
3138
* prepare them carefully (e.g. based on the aggregation state).
3139
*/
3140
static int
3141
ht_send_action_ba_addba(struct ieee80211_node *ni,
3142
int category, int action, void *arg0)
3143
{
3144
struct ieee80211vap *vap = ni->ni_vap;
3145
struct ieee80211com *ic = ni->ni_ic;
3146
uint16_t *args = arg0;
3147
struct mbuf *m;
3148
uint8_t *frm;
3149
3150
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3151
"send ADDBA %s: dialogtoken %d status %d "
3152
"baparamset 0x%x (tid %d amsdu %d) batimeout 0x%x baseqctl 0x%x",
3153
(action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
3154
"request" : "response", args[0], args[1], args[2],
3155
_IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_TID),
3156
_IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_AMSDU),
3157
args[3], args[4]);
3158
3159
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3160
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3161
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3162
ieee80211_ref_node(ni);
3163
3164
m = ieee80211_getmgtframe(&frm,
3165
ic->ic_headroom + sizeof(struct ieee80211_frame),
3166
sizeof(uint16_t) /* action+category */
3167
/* XXX may action payload */
3168
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3169
);
3170
if (m != NULL) {
3171
*frm++ = category;
3172
*frm++ = action;
3173
*frm++ = args[0]; /* dialog token */
3174
if (action == IEEE80211_ACTION_BA_ADDBA_RESPONSE)
3175
ADDSHORT(frm, args[1]); /* status code */
3176
ADDSHORT(frm, args[2]); /* baparamset */
3177
ADDSHORT(frm, args[3]); /* batimeout */
3178
if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
3179
ADDSHORT(frm, args[4]); /* baseqctl */
3180
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3181
return ht_action_output(ni, m);
3182
} else {
3183
vap->iv_stats.is_tx_nobuf++;
3184
ieee80211_free_node(ni);
3185
return ENOMEM;
3186
}
3187
}
3188
3189
static int
3190
ht_send_action_ba_delba(struct ieee80211_node *ni,
3191
int category, int action, void *arg0)
3192
{
3193
struct ieee80211vap *vap = ni->ni_vap;
3194
struct ieee80211com *ic = ni->ni_ic;
3195
uint16_t *args = arg0;
3196
struct mbuf *m;
3197
uint16_t baparamset;
3198
uint8_t *frm;
3199
3200
baparamset = _IEEE80211_SHIFTMASK(args[0], IEEE80211_DELBAPS_TID)
3201
| args[1]
3202
;
3203
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3204
"send DELBA action: tid %d, initiator %d reason %d (%s)",
3205
args[0], args[1], args[2], ieee80211_reason_to_string(args[2]));
3206
3207
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3208
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3209
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3210
ieee80211_ref_node(ni);
3211
3212
m = ieee80211_getmgtframe(&frm,
3213
ic->ic_headroom + sizeof(struct ieee80211_frame),
3214
sizeof(uint16_t) /* action+category */
3215
/* XXX may action payload */
3216
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3217
);
3218
if (m != NULL) {
3219
*frm++ = category;
3220
*frm++ = action;
3221
ADDSHORT(frm, baparamset);
3222
ADDSHORT(frm, args[2]); /* reason code */
3223
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3224
return ht_action_output(ni, m);
3225
} else {
3226
vap->iv_stats.is_tx_nobuf++;
3227
ieee80211_free_node(ni);
3228
return ENOMEM;
3229
}
3230
}
3231
3232
static int
3233
ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
3234
int category, int action, void *arg0)
3235
{
3236
struct ieee80211vap *vap = ni->ni_vap;
3237
struct ieee80211com *ic = ni->ni_ic;
3238
struct mbuf *m;
3239
uint8_t *frm;
3240
3241
IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
3242
"send HT txchwidth: width %d",
3243
IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
3244
3245
IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
3246
"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
3247
ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
3248
ieee80211_ref_node(ni);
3249
3250
m = ieee80211_getmgtframe(&frm,
3251
ic->ic_headroom + sizeof(struct ieee80211_frame),
3252
sizeof(uint16_t) /* action+category */
3253
/* XXX may action payload */
3254
+ sizeof(struct ieee80211_action_ba_addbaresponse)
3255
);
3256
if (m != NULL) {
3257
*frm++ = category;
3258
*frm++ = action;
3259
*frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
3260
IEEE80211_A_HT_TXCHWIDTH_2040 :
3261
IEEE80211_A_HT_TXCHWIDTH_20;
3262
m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
3263
return ht_action_output(ni, m);
3264
} else {
3265
vap->iv_stats.is_tx_nobuf++;
3266
ieee80211_free_node(ni);
3267
return ENOMEM;
3268
}
3269
}
3270
#undef ADDSHORT
3271
3272
/*
3273
* Construct the MCS bit mask for inclusion in an HT capabilities
3274
* information element.
3275
*/
3276
static void
3277
ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm)
3278
{
3279
int i;
3280
uint8_t txparams;
3281
3282
KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4),
3283
("ic_rxstream %d out of range", ic->ic_rxstream));
3284
KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4),
3285
("ic_txstream %d out of range", ic->ic_txstream));
3286
3287
for (i = 0; i < ic->ic_rxstream * 8; i++)
3288
setbit(frm, i);
3289
if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
3290
(ic->ic_htcaps & IEEE80211_HTC_RXMCS32))
3291
setbit(frm, 32);
3292
if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) {
3293
if (ic->ic_rxstream >= 2) {
3294
for (i = 33; i <= 38; i++)
3295
setbit(frm, i);
3296
}
3297
if (ic->ic_rxstream >= 3) {
3298
for (i = 39; i <= 52; i++)
3299
setbit(frm, i);
3300
}
3301
if (ic->ic_rxstream >= 4) {
3302
for (i = 53; i <= 76; i++)
3303
setbit(frm, i);
3304
}
3305
}
3306
3307
txparams = 0x1; /* TX MCS set defined */
3308
if (ic->ic_rxstream != ic->ic_txstream) {
3309
txparams |= 0x2; /* TX RX MCS not equal */
3310
txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */
3311
if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL)
3312
txparams |= 0x16; /* TX unequal modulation sup */
3313
}
3314
3315
frm[12] = txparams;
3316
}
3317
3318
/*
3319
* Add body of an HTCAP information element.
3320
*/
3321
static uint8_t *
3322
ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
3323
{
3324
#define ADDSHORT(frm, v) do { \
3325
frm[0] = (v) & 0xff; \
3326
frm[1] = (v) >> 8; \
3327
frm += 2; \
3328
} while (0)
3329
struct ieee80211com *ic = ni->ni_ic;
3330
struct ieee80211vap *vap = ni->ni_vap;
3331
uint16_t caps, extcaps;
3332
int rxmax, density;
3333
3334
/* HT capabilities */
3335
caps = vap->iv_htcaps & 0xffff;
3336
/*
3337
* Note channel width depends on whether we are operating as
3338
* a sta or not. When operating as a sta we are generating
3339
* a request based on our desired configuration. Otherwise
3340
* we are operational and the channel attributes identify
3341
* how we've been setup (which might be different if a fixed
3342
* channel is specified).
3343
*/
3344
if (vap->iv_opmode == IEEE80211_M_STA) {
3345
/* override 20/40 use based on config */
3346
if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
3347
caps |= IEEE80211_HTCAP_CHWIDTH40;
3348
else
3349
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3350
3351
/* Start by using the advertised settings */
3352
rxmax = _IEEE80211_MASKSHIFT(ni->ni_htparam,
3353
IEEE80211_HTCAP_MAXRXAMPDU);
3354
density = _IEEE80211_MASKSHIFT(ni->ni_htparam,
3355
IEEE80211_HTCAP_MPDUDENSITY);
3356
3357
IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
3358
"%s: advertised rxmax=%d, density=%d, vap rxmax=%d, density=%d\n",
3359
__func__,
3360
rxmax,
3361
density,
3362
vap->iv_ampdu_rxmax,
3363
vap->iv_ampdu_density);
3364
3365
/* Cap at VAP rxmax */
3366
if (rxmax > vap->iv_ampdu_rxmax)
3367
rxmax = vap->iv_ampdu_rxmax;
3368
3369
/*
3370
* If the VAP ampdu density value greater, use that.
3371
*
3372
* (Larger density value == larger minimum gap between A-MPDU
3373
* subframes.)
3374
*/
3375
if (vap->iv_ampdu_density > density)
3376
density = vap->iv_ampdu_density;
3377
3378
/*
3379
* NB: Hardware might support HT40 on some but not all
3380
* channels. We can't determine this earlier because only
3381
* after association the channel is upgraded to HT based
3382
* on the negotiated capabilities.
3383
*/
3384
if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
3385
findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL &&
3386
findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL)
3387
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3388
} else {
3389
/* override 20/40 use based on current channel */
3390
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
3391
caps |= IEEE80211_HTCAP_CHWIDTH40;
3392
else
3393
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3394
3395
/* XXX TODO should it start by using advertised settings? */
3396
rxmax = vap->iv_ampdu_rxmax;
3397
density = vap->iv_ampdu_density;
3398
}
3399
3400
/* adjust short GI based on channel and config */
3401
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
3402
caps &= ~IEEE80211_HTCAP_SHORTGI20;
3403
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
3404
(caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
3405
caps &= ~IEEE80211_HTCAP_SHORTGI40;
3406
3407
/* adjust STBC based on receive capabilities */
3408
if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) == 0)
3409
caps &= ~IEEE80211_HTCAP_RXSTBC;
3410
3411
/* adjust LDPC based on receive capabilites */
3412
if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_RX) == 0)
3413
caps &= ~IEEE80211_HTCAP_LDPC;
3414
3415
ADDSHORT(frm, caps);
3416
3417
/* HT parameters */
3418
*frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
3419
| _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
3420
;
3421
frm++;
3422
3423
/* pre-zero remainder of ie */
3424
memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
3425
__offsetof(struct ieee80211_ie_htcap, hc_mcsset));
3426
3427
/* supported MCS set */
3428
/*
3429
* XXX: For sta mode the rate set should be restricted based
3430
* on the AP's capabilities, but ni_htrates isn't setup when
3431
* we're called to form an AssocReq frame so for now we're
3432
* restricted to the device capabilities.
3433
*/
3434
ieee80211_set_mcsset(ni->ni_ic, frm);
3435
3436
frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
3437
__offsetof(struct ieee80211_ie_htcap, hc_mcsset);
3438
3439
/* HT extended capabilities */
3440
extcaps = vap->iv_htextcaps & 0xffff;
3441
3442
ADDSHORT(frm, extcaps);
3443
3444
frm += sizeof(struct ieee80211_ie_htcap) -
3445
__offsetof(struct ieee80211_ie_htcap, hc_txbf);
3446
3447
return frm;
3448
#undef ADDSHORT
3449
}
3450
3451
/*
3452
* Add 802.11n HT capabilities information element
3453
*/
3454
uint8_t *
3455
ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
3456
{
3457
frm[0] = IEEE80211_ELEMID_HTCAP;
3458
frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
3459
return ieee80211_add_htcap_body(frm + 2, ni);
3460
}
3461
3462
/*
3463
* Non-associated probe request - add HT capabilities based on
3464
* the current channel configuration.
3465
*/
3466
static uint8_t *
3467
ieee80211_add_htcap_body_ch(uint8_t *frm, struct ieee80211vap *vap,
3468
struct ieee80211_channel *c)
3469
{
3470
#define ADDSHORT(frm, v) do { \
3471
frm[0] = (v) & 0xff; \
3472
frm[1] = (v) >> 8; \
3473
frm += 2; \
3474
} while (0)
3475
struct ieee80211com *ic = vap->iv_ic;
3476
uint16_t caps, extcaps;
3477
int rxmax, density;
3478
3479
/* HT capabilities */
3480
caps = vap->iv_htcaps & 0xffff;
3481
3482
/*
3483
* We don't use this in STA mode; only in IBSS mode.
3484
* So in IBSS mode we base our HTCAP flags on the
3485
* given channel.
3486
*/
3487
3488
/* override 20/40 use based on current channel */
3489
if (IEEE80211_IS_CHAN_HT40(c))
3490
caps |= IEEE80211_HTCAP_CHWIDTH40;
3491
else
3492
caps &= ~IEEE80211_HTCAP_CHWIDTH40;
3493
3494
/* Use the currently configured values */
3495
rxmax = vap->iv_ampdu_rxmax;
3496
density = vap->iv_ampdu_density;
3497
3498
/* adjust short GI based on channel and config */
3499
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
3500
caps &= ~IEEE80211_HTCAP_SHORTGI20;
3501
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
3502
(caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
3503
caps &= ~IEEE80211_HTCAP_SHORTGI40;
3504
ADDSHORT(frm, caps);
3505
3506
/* HT parameters */
3507
*frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
3508
| _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
3509
;
3510
frm++;
3511
3512
/* pre-zero remainder of ie */
3513
memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
3514
__offsetof(struct ieee80211_ie_htcap, hc_mcsset));
3515
3516
/* supported MCS set */
3517
/*
3518
* XXX: For sta mode the rate set should be restricted based
3519
* on the AP's capabilities, but ni_htrates isn't setup when
3520
* we're called to form an AssocReq frame so for now we're
3521
* restricted to the device capabilities.
3522
*/
3523
ieee80211_set_mcsset(ic, frm);
3524
3525
frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
3526
__offsetof(struct ieee80211_ie_htcap, hc_mcsset);
3527
3528
/* HT extended capabilities */
3529
extcaps = vap->iv_htextcaps & 0xffff;
3530
3531
ADDSHORT(frm, extcaps);
3532
3533
frm += sizeof(struct ieee80211_ie_htcap) -
3534
__offsetof(struct ieee80211_ie_htcap, hc_txbf);
3535
3536
return frm;
3537
#undef ADDSHORT
3538
}
3539
3540
/*
3541
* Add 802.11n HT capabilities information element
3542
*/
3543
uint8_t *
3544
ieee80211_add_htcap_ch(uint8_t *frm, struct ieee80211vap *vap,
3545
struct ieee80211_channel *c)
3546
{
3547
frm[0] = IEEE80211_ELEMID_HTCAP;
3548
frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
3549
return ieee80211_add_htcap_body_ch(frm + 2, vap, c);
3550
}
3551
3552
/*
3553
* Add Broadcom OUI wrapped standard HTCAP ie; this is
3554
* used for compatibility w/ pre-draft implementations.
3555
*/
3556
uint8_t *
3557
ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
3558
{
3559
frm[0] = IEEE80211_ELEMID_VENDOR;
3560
frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
3561
frm[2] = (BCM_OUI >> 0) & 0xff;
3562
frm[3] = (BCM_OUI >> 8) & 0xff;
3563
frm[4] = (BCM_OUI >> 16) & 0xff;
3564
frm[5] = BCM_OUI_HTCAP;
3565
return ieee80211_add_htcap_body(frm + 6, ni);
3566
}
3567
3568
/*
3569
* Construct the MCS bit mask of basic rates
3570
* for inclusion in an HT information element.
3571
*/
3572
static void
3573
ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
3574
{
3575
int i;
3576
3577
for (i = 0; i < rs->rs_nrates; i++) {
3578
int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
3579
if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
3580
r < IEEE80211_HTRATE_MAXSIZE) {
3581
/* NB: this assumes a particular implementation */
3582
setbit(frm, r);
3583
}
3584
}
3585
}
3586
3587
/*
3588
* Update the HTINFO ie for a beacon frame.
3589
*/
3590
void
3591
ieee80211_ht_update_beacon(struct ieee80211vap *vap,
3592
struct ieee80211_beacon_offsets *bo)
3593
{
3594
#define PROTMODE (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
3595
struct ieee80211_node *ni;
3596
const struct ieee80211_channel *bsschan;
3597
struct ieee80211com *ic = vap->iv_ic;
3598
struct ieee80211_ie_htinfo *ht =
3599
(struct ieee80211_ie_htinfo *) bo->bo_htinfo;
3600
3601
ni = ieee80211_ref_node(vap->iv_bss);
3602
bsschan = ni->ni_chan;
3603
3604
/* XXX only update on channel change */
3605
ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
3606
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
3607
ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PERM;
3608
else
3609
ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
3610
if (IEEE80211_IS_CHAN_HT40U(bsschan))
3611
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
3612
else if (IEEE80211_IS_CHAN_HT40D(bsschan))
3613
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
3614
else
3615
ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
3616
if (IEEE80211_IS_CHAN_HT40(bsschan))
3617
ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
3618
3619
/* protection mode */
3620
/*
3621
* XXX TODO: this uses the global flag, not the per-VAP flag.
3622
* Eventually (once the protection modes are done per-channel
3623
* rather than per-VAP) we can flip this over to be per-VAP but
3624
* using the channel protection mode.
3625
*/
3626
ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
3627
3628
ieee80211_free_node(ni);
3629
3630
/* XXX propagate to vendor ie's */
3631
#undef PROTMODE
3632
}
3633
3634
/*
3635
* Add body of an HTINFO information element.
3636
*
3637
* NB: We don't use struct ieee80211_ie_htinfo because we can
3638
* be called to fillin both a standard ie and a compat ie that
3639
* has a vendor OUI at the front.
3640
*/
3641
static uint8_t *
3642
ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
3643
{
3644
struct ieee80211vap *vap = ni->ni_vap;
3645
struct ieee80211com *ic = ni->ni_ic;
3646
3647
/* pre-zero remainder of ie */
3648
memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
3649
3650
/* primary/control channel center */
3651
*frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
3652
3653
if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
3654
frm[0] = IEEE80211_HTINFO_RIFSMODE_PERM;
3655
else
3656
frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
3657
if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
3658
frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
3659
else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
3660
frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
3661
else
3662
frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
3663
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
3664
frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
3665
3666
/*
3667
* Add current protection mode. Unlike for beacons,
3668
* this will respect the per-VAP flags.
3669
*/
3670
frm[1] = vap->iv_curhtprotmode;
3671
3672
frm += 5;
3673
3674
/* basic MCS set */
3675
ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
3676
frm += sizeof(struct ieee80211_ie_htinfo) -
3677
__offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
3678
return frm;
3679
}
3680
3681
/*
3682
* Add 802.11n HT information element.
3683
*/
3684
uint8_t *
3685
ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
3686
{
3687
frm[0] = IEEE80211_ELEMID_HTINFO;
3688
frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
3689
return ieee80211_add_htinfo_body(frm + 2, ni);
3690
}
3691
3692
/*
3693
* Add Broadcom OUI wrapped standard HTINFO ie; this is
3694
* used for compatibility w/ pre-draft implementations.
3695
*/
3696
uint8_t *
3697
ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
3698
{
3699
frm[0] = IEEE80211_ELEMID_VENDOR;
3700
frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
3701
frm[2] = (BCM_OUI >> 0) & 0xff;
3702
frm[3] = (BCM_OUI >> 8) & 0xff;
3703
frm[4] = (BCM_OUI >> 16) & 0xff;
3704
frm[5] = BCM_OUI_HTINFO;
3705
return ieee80211_add_htinfo_body(frm + 6, ni);
3706
}
3707
3708
/*
3709
* Get the HT density for the given 802.11n node.
3710
*
3711
* Take into account the density advertised from the peer.
3712
* Larger values are longer A-MPDU density spacing values, and
3713
* we want to obey them per station if we get them.
3714
*/
3715
int
3716
ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni)
3717
{
3718
struct ieee80211vap *vap;
3719
int peer_mpdudensity;
3720
3721
vap = ni->ni_vap;
3722
peer_mpdudensity =
3723
_IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
3724
if (vap->iv_ampdu_density > peer_mpdudensity)
3725
peer_mpdudensity = vap->iv_ampdu_density;
3726
return (peer_mpdudensity);
3727
}
3728
3729
/*
3730
* Get the transmit A-MPDU limit for the given 802.11n node.
3731
*
3732
* Take into account the limit advertised from the peer.
3733
* Smaller values indicate smaller maximum A-MPDU sizes, and
3734
* should be used when forming an A-MPDU to the given peer.
3735
*/
3736
int
3737
ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni)
3738
{
3739
struct ieee80211vap *vap;
3740
int peer_mpdulimit;
3741
3742
vap = ni->ni_vap;
3743
peer_mpdulimit =
3744
_IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
3745
3746
return (MIN(vap->iv_ampdu_limit, peer_mpdulimit));
3747
}
3748
3749
/*
3750
* Return true if short-GI is available when transmitting to
3751
* the given node at 20MHz.
3752
*
3753
* Ensure it's configured and available in the VAP / driver as
3754
* well as the node.
3755
*/
3756
bool
3757
ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni)
3758
{
3759
const struct ieee80211vap *vap;
3760
const struct ieee80211com *ic;
3761
3762
if (! ieee80211_ht_check_tx_ht(ni))
3763
return (false);
3764
3765
vap = ni->ni_vap;
3766
ic = ni->ni_ic;
3767
3768
return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) &&
3769
(ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
3770
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20));
3771
}
3772
3773
/*
3774
* Return true if short-GI is available when transmitting to
3775
* the given node at 40MHz.
3776
*
3777
* Ensure it's configured and available in the VAP / driver as
3778
* well as the node and BSS.
3779
*/
3780
bool
3781
ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni)
3782
{
3783
const struct ieee80211vap *vap;
3784
const struct ieee80211com *ic;
3785
3786
if (! ieee80211_ht_check_tx_ht40(ni))
3787
return (false);
3788
3789
vap = ni->ni_vap;
3790
ic = ni->ni_ic;
3791
3792
return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40) &&
3793
(ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
3794
(vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40));
3795
}
3796
3797
/*
3798
* Return true if HT rates can be used for the given node.
3799
*
3800
* There are some situations seen in the wild, wild past where
3801
* HT APs would announce HT but no HT rates.
3802
*/
3803
bool
3804
ieee80211_ht_check_tx_ht(const struct ieee80211_node *ni)
3805
{
3806
const struct ieee80211vap *vap;
3807
const struct ieee80211_channel *bss_chan;
3808
3809
if (ni == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC ||
3810
ni->ni_vap == NULL || ni->ni_vap->iv_bss == NULL)
3811
return (false);
3812
3813
vap = ni->ni_vap;
3814
bss_chan = vap->iv_bss->ni_chan;
3815
3816
if (bss_chan == IEEE80211_CHAN_ANYC)
3817
return (false);
3818
3819
if (IEEE80211_IS_CHAN_HT(ni->ni_chan) &&
3820
ni->ni_htrates.rs_nrates == 0)
3821
return (false);
3822
return (IEEE80211_IS_CHAN_HT(ni->ni_chan));
3823
}
3824
3825
/*
3826
* Return true if HT40 rates can be transmitted to the given node.
3827
*
3828
* This verifies that the BSS is HT40 capable and the current
3829
* node channel width is 40MHz.
3830
*/
3831
bool
3832
ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni)
3833
{
3834
struct ieee80211vap *vap;
3835
struct ieee80211_channel *bss_chan;
3836
3837
if (! ieee80211_ht_check_tx_ht(ni))
3838
return (false);
3839
3840
vap = ni->ni_vap;
3841
bss_chan = vap->iv_bss->ni_chan;
3842
3843
return (IEEE80211_IS_CHAN_HT40(bss_chan) &&
3844
IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
3845
(ni->ni_chw == NET80211_STA_RX_BW_40));
3846
}
3847
3848