Deleted Added
full compact
ieee80211_ht.c (183249) ieee80211_ht.c (183250)
1/*-
2 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27#ifdef __FreeBSD__
1/*-
2 * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27#ifdef __FreeBSD__
28__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ht.c 183249 2008-09-21 23:18:36Z sam $");
28__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ht.c 183250 2008-09-21 23:20:04Z sam $");
29#endif
30
31/*
32 * IEEE 802.11n protocol support.
33 */
34
35#include "opt_inet.h"
36#include "opt_wlan.h"
37
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/systm.h>
41#include <sys/endian.h>
42
43#include <sys/socket.h>
44
45#include <net/if.h>
46#include <net/if_media.h>
47#include <net/ethernet.h>
48
49#include <net80211/ieee80211_var.h>
50#include <net80211/ieee80211_input.h>
51
52/* define here, used throughout file */
53#define MS(_v, _f) (((_v) & _f) >> _f##_S)
54#define SM(_v, _f) (((_v) << _f##_S) & _f)
55
56const struct ieee80211_mcs_rates ieee80211_htrates[16] = {
57 { 13, 14, 27, 30 }, /* MCS 0 */
58 { 26, 29, 54, 60 }, /* MCS 1 */
59 { 39, 43, 81, 90 }, /* MCS 2 */
60 { 52, 58, 108, 120 }, /* MCS 3 */
61 { 78, 87, 162, 180 }, /* MCS 4 */
62 { 104, 116, 216, 240 }, /* MCS 5 */
63 { 117, 130, 243, 270 }, /* MCS 6 */
64 { 130, 144, 270, 300 }, /* MCS 7 */
65 { 26, 29, 54, 60 }, /* MCS 8 */
66 { 52, 58, 108, 120 }, /* MCS 9 */
67 { 78, 87, 162, 180 }, /* MCS 10 */
68 { 104, 116, 216, 240 }, /* MCS 11 */
69 { 156, 173, 324, 360 }, /* MCS 12 */
70 { 208, 231, 432, 480 }, /* MCS 13 */
71 { 234, 260, 486, 540 }, /* MCS 14 */
72 { 260, 289, 540, 600 } /* MCS 15 */
73};
74
75static const struct ieee80211_htrateset ieee80211_rateset_11n =
76 { 16, {
77 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
78 10, 11, 12, 13, 14, 15 }
79 };
80
81#ifdef IEEE80211_AMPDU_AGE
82/* XXX public for sysctl hookup */
83int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */
84#endif
85int ieee80211_recv_bar_ena = 1;
86int ieee80211_addba_timeout = -1; /* timeout waiting for ADDBA response */
87int ieee80211_addba_backoff = -1; /* backoff after max ADDBA requests */
88int ieee80211_addba_maxtries = 3; /* max ADDBA requests before backoff */
89
90/*
91 * Setup HT parameters that depends on the clock frequency.
92 */
93static void
94ieee80211_ht_setup(void)
95{
96#ifdef IEEE80211_AMPDU_AGE
97 ieee80211_ampdu_age = msecs_to_ticks(500);
98#endif
99 ieee80211_addba_timeout = msecs_to_ticks(250);
100 ieee80211_addba_backoff = msecs_to_ticks(10*1000);
101}
102SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
103
104static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
105 struct ieee80211_tx_ampdu *tap);
106static int ieee80211_addba_request(struct ieee80211_node *ni,
107 struct ieee80211_tx_ampdu *tap,
108 int dialogtoken, int baparamset, int batimeout);
109static int ieee80211_addba_response(struct ieee80211_node *ni,
110 struct ieee80211_tx_ampdu *tap,
111 int code, int baparamset, int batimeout);
112static void ieee80211_addba_stop(struct ieee80211_node *ni,
113 struct ieee80211_tx_ampdu *tap);
114static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
115 const uint8_t *frm, const uint8_t *efrm);
116
117void
118ieee80211_ht_attach(struct ieee80211com *ic)
119{
120 /* setup default aggregation policy */
121 ic->ic_recv_action = ieee80211_aggr_recv_action;
122 ic->ic_send_action = ieee80211_send_action;
123 ic->ic_ampdu_enable = ieee80211_ampdu_enable;
124 ic->ic_addba_request = ieee80211_addba_request;
125 ic->ic_addba_response = ieee80211_addba_response;
126 ic->ic_addba_stop = ieee80211_addba_stop;
127
128 ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
129 ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
130}
131
132void
133ieee80211_ht_detach(struct ieee80211com *ic)
134{
135}
136
137void
138ieee80211_ht_vattach(struct ieee80211vap *vap)
139{
140
141 /* driver can override defaults */
142 vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
143 vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
144 vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
145 vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
146 /* tx aggregation traffic thresholds */
147 vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
148 vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
149 vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
150 vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
151
152 if (vap->iv_htcaps & IEEE80211_HTC_HT) {
153 /*
154 * Device is HT capable; enable all HT-related
155 * facilities by default.
156 * XXX these choices may be too aggressive.
157 */
158 vap->iv_flags_ext |= IEEE80211_FEXT_HT
159 | IEEE80211_FEXT_HTCOMPAT
160 ;
161 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
162 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI20;
163 /* XXX infer from channel list? */
164 if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
165 vap->iv_flags_ext |= IEEE80211_FEXT_USEHT40;
166 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
167 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI40;
168 }
169 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
170 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
171 if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
172 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
173 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
174 if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
175 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
176 }
177 /* NB: disable default legacy WDS, too many issues right now */
178 if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
179 vap->iv_flags_ext &= ~IEEE80211_FEXT_HT;
180}
181
182void
183ieee80211_ht_vdetach(struct ieee80211vap *vap)
184{
185}
186
187static void
188ht_announce(struct ieee80211com *ic, int mode,
189 const struct ieee80211_htrateset *rs)
190{
191 struct ifnet *ifp = ic->ic_ifp;
192 int i, rate, mword;
193
194 if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]);
195 for (i = 0; i < rs->rs_nrates; i++) {
196 mword = ieee80211_rate2media(ic,
197 rs->rs_rates[i] | IEEE80211_RATE_MCS, mode);
198 if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
199 continue;
200 rate = ieee80211_htrates[rs->rs_rates[i]].ht40_rate_400ns;
201 printf("%s%d%sMbps", (i != 0 ? " " : ""),
202 rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
203 }
204 printf("\n");
205}
206
207void
208ieee80211_ht_announce(struct ieee80211com *ic)
209{
210 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
211 ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n);
212 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
213 ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n);
214}
215
216const struct ieee80211_htrateset *
217ieee80211_get_suphtrates(struct ieee80211com *ic,
218 const struct ieee80211_channel *c)
219{
220 return &ieee80211_rateset_11n;
221}
222
223/*
224 * Receive processing.
225 */
226
227/*
228 * Decap the encapsulated A-MSDU frames and dispatch all but
229 * the last for delivery. The last frame is returned for
230 * delivery via the normal path.
231 */
232struct mbuf *
233ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
234{
235 struct ieee80211vap *vap = ni->ni_vap;
236 int framelen;
237 struct mbuf *n;
238
239 /* discard 802.3 header inserted by ieee80211_decap */
240 m_adj(m, sizeof(struct ether_header));
241
242 vap->iv_stats.is_amsdu_decap++;
243
244 for (;;) {
245 /*
246 * Decap the first frame, bust it apart from the
247 * remainder and deliver. We leave the last frame
248 * delivery to the caller (for consistency with other
249 * code paths, could also do it here).
250 */
251 m = ieee80211_decap1(m, &framelen);
252 if (m == NULL) {
253 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
254 ni->ni_macaddr, "a-msdu", "%s", "decap failed");
255 vap->iv_stats.is_amsdu_tooshort++;
256 return NULL;
257 }
258 if (m->m_pkthdr.len == framelen)
259 break;
260 n = m_split(m, framelen, M_NOWAIT);
261 if (n == NULL) {
262 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
263 ni->ni_macaddr, "a-msdu",
264 "%s", "unable to split encapsulated frames");
265 vap->iv_stats.is_amsdu_split++;
266 m_freem(m); /* NB: must reclaim */
267 return NULL;
268 }
269 vap->iv_deliver_data(vap, ni, m);
270
271 /*
272 * Remove frame contents; each intermediate frame
273 * is required to be aligned to a 4-byte boundary.
274 */
275 m = n;
276 m_adj(m, roundup2(framelen, 4) - framelen); /* padding */
277 }
278 return m; /* last delivered by caller */
279}
280
281/*
282 * Purge all frames in the A-MPDU re-order queue.
283 */
284static void
285ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
286{
287 struct mbuf *m;
288 int i;
289
290 for (i = 0; i < rap->rxa_wnd; i++) {
291 m = rap->rxa_m[i];
292 if (m != NULL) {
293 rap->rxa_m[i] = NULL;
294 rap->rxa_qbytes -= m->m_pkthdr.len;
295 m_freem(m);
296 if (--rap->rxa_qframes == 0)
297 break;
298 }
299 }
300 KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
301 ("lost %u data, %u frames on ampdu rx q",
302 rap->rxa_qbytes, rap->rxa_qframes));
303}
304
305/*
306 * Start A-MPDU rx/re-order processing for the specified TID.
307 */
308static void
309ampdu_rx_start(struct ieee80211_rx_ampdu *rap, int bufsiz, int start)
310{
311 if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
312 /*
313 * AMPDU previously setup and not terminated with a DELBA,
314 * flush the reorder q's in case anything remains.
315 */
316 ampdu_rx_purge(rap);
317 }
318 memset(rap, 0, sizeof(*rap));
319 rap->rxa_wnd = (bufsiz == 0) ?
320 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
321 rap->rxa_start = start;
322 rap->rxa_flags |= IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
323}
324
325/*
326 * Stop A-MPDU rx processing for the specified TID.
327 */
328static void
329ampdu_rx_stop(struct ieee80211_rx_ampdu *rap)
330{
331 ampdu_rx_purge(rap);
332 rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND);
333}
334
335/*
336 * Dispatch a frame from the A-MPDU reorder queue. The
337 * frame is fed back into ieee80211_input marked with an
338 * M_AMPDU_MPDU flag so it doesn't come back to us (it also
339 * permits ieee80211_input to optimize re-processing).
340 */
341static __inline void
342ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
343{
344 m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */
345 /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU_MPDU set */
346 (void) ieee80211_input(ni, m, 0, 0, 0);
347}
348
349/*
350 * Dispatch as many frames as possible from the re-order queue.
351 * Frames will always be "at the front"; we process all frames
352 * up to the first empty slot in the window. On completion we
353 * cleanup state if there are still pending frames in the current
354 * BA window. We assume the frame at slot 0 is already handled
355 * by the caller; we always start at slot 1.
356 */
357static void
358ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
359{
360 struct ieee80211vap *vap = ni->ni_vap;
361 struct mbuf *m;
362 int i;
363
364 /* flush run of frames */
365 for (i = 1; i < rap->rxa_wnd; i++) {
366 m = rap->rxa_m[i];
367 if (m == NULL)
368 break;
369 rap->rxa_m[i] = NULL;
370 rap->rxa_qbytes -= m->m_pkthdr.len;
371 rap->rxa_qframes--;
372
373 ampdu_dispatch(ni, m);
374 }
375 /*
376 * If frames remain, copy the mbuf pointers down so
377 * they correspond to the offsets in the new window.
378 */
379 if (rap->rxa_qframes != 0) {
380 int n = rap->rxa_qframes, j;
381 for (j = i+1; j < rap->rxa_wnd; j++) {
382 if (rap->rxa_m[j] != NULL) {
383 rap->rxa_m[j-i] = rap->rxa_m[j];
384 rap->rxa_m[j] = NULL;
385 if (--n == 0)
386 break;
387 }
388 }
389 KASSERT(n == 0, ("lost %d frames", n));
390 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
391 }
392 /*
393 * Adjust the start of the BA window to
394 * reflect the frames just dispatched.
395 */
396 rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
397 vap->iv_stats.is_ampdu_rx_oor += i;
398}
399
400#ifdef IEEE80211_AMPDU_AGE
401/*
402 * Dispatch all frames in the A-MPDU re-order queue.
403 */
404static void
405ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
406{
407 struct ieee80211vap *vap = ni->ni_vap;
408 struct mbuf *m;
409 int i;
410
411 for (i = 0; i < rap->rxa_wnd; i++) {
412 m = rap->rxa_m[i];
413 if (m == NULL)
414 continue;
415 rap->rxa_m[i] = NULL;
416 rap->rxa_qbytes -= m->m_pkthdr.len;
417 rap->rxa_qframes--;
418 vap->iv_stats.is_ampdu_rx_oor++;
419
420 ampdu_dispatch(ni, m);
421 if (rap->rxa_qframes == 0)
422 break;
423 }
424}
425#endif /* IEEE80211_AMPDU_AGE */
426
427/*
428 * Dispatch all frames in the A-MPDU re-order queue
429 * preceding the specified sequence number. This logic
430 * handles window moves due to a received MSDU or BAR.
431 */
432static void
433ampdu_rx_flush_upto(struct ieee80211_node *ni,
434 struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
435{
436 struct ieee80211vap *vap = ni->ni_vap;
437 struct mbuf *m;
438 ieee80211_seq seqno;
439 int i;
440
441 /*
442 * Flush any complete MSDU's with a sequence number lower
443 * than winstart. Gaps may exist. Note that we may actually
444 * dispatch frames past winstart if a run continues; this is
445 * an optimization that avoids having to do a separate pass
446 * to dispatch frames after moving the BA window start.
447 */
448 seqno = rap->rxa_start;
449 for (i = 0; i < rap->rxa_wnd; i++) {
450 m = rap->rxa_m[i];
451 if (m != NULL) {
452 rap->rxa_m[i] = NULL;
453 rap->rxa_qbytes -= m->m_pkthdr.len;
454 rap->rxa_qframes--;
455 vap->iv_stats.is_ampdu_rx_oor++;
456
457 ampdu_dispatch(ni, m);
458 } else {
459 if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
460 break;
461 }
462 seqno = IEEE80211_SEQ_INC(seqno);
463 }
464 /*
465 * If frames remain, copy the mbuf pointers down so
466 * they correspond to the offsets in the new window.
467 */
468 if (rap->rxa_qframes != 0) {
469 int n = rap->rxa_qframes, j;
470
471 /* NB: this loop assumes i > 0 and/or rxa_m[0] is NULL */
472 KASSERT(rap->rxa_m[0] == NULL,
473 ("%s: BA window slot 0 occupied", __func__));
474 for (j = i+1; j < rap->rxa_wnd; j++) {
475 if (rap->rxa_m[j] != NULL) {
476 rap->rxa_m[j-i] = rap->rxa_m[j];
477 rap->rxa_m[j] = NULL;
478 if (--n == 0)
479 break;
480 }
481 }
482 KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
483 "BA win <%d:%d> winstart %d",
484 __func__, n, rap->rxa_qframes, i, rap->rxa_start,
485 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
486 winstart));
487 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
488 }
489 /*
490 * Move the start of the BA window; we use the
491 * sequence number of the last MSDU that was
492 * passed up the stack+1 or winstart if stopped on
493 * a gap in the reorder buffer.
494 */
495 rap->rxa_start = seqno;
496}
497
498/*
499 * Process a received QoS data frame for an HT station. Handle
500 * A-MPDU reordering: if this frame is received out of order
501 * and falls within the BA window hold onto it. Otherwise if
502 * this frame completes a run, flush any pending frames. We
503 * return 1 if the frame is consumed. A 0 is returned if
504 * the frame should be processed normally by the caller.
505 */
506int
507ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
508{
509#define IEEE80211_FC0_QOSDATA \
510 (IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
511#define PROCESS 0 /* caller should process frame */
512#define CONSUMED 1 /* frame consumed, caller does nothing */
513 struct ieee80211vap *vap = ni->ni_vap;
514 struct ieee80211_qosframe *wh;
515 struct ieee80211_rx_ampdu *rap;
516 ieee80211_seq rxseq;
517 uint8_t tid;
518 int off;
519
520 KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
521 ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
522 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
523
524 /* NB: m_len known to be sufficient */
525 wh = mtod(m, struct ieee80211_qosframe *);
526 if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) {
527 /*
528 * Not QoS data, shouldn't get here but just
529 * return it to the caller for processing.
530 */
531 return PROCESS;
532 }
533
534 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
535 tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
536 else
537 tid = wh->i_qos[0];
538 tid &= IEEE80211_QOS_TID;
539 rap = &ni->ni_rx_ampdu[tid];
540 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
541 /*
542 * No ADDBA request yet, don't touch.
543 */
544 return PROCESS;
545 }
546 rxseq = le16toh(*(uint16_t *)wh->i_seq);
547 if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
548 /*
549 * Fragments are not allowed; toss.
550 */
551 IEEE80211_DISCARD_MAC(vap,
552 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
553 "A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
554 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
555 vap->iv_stats.is_ampdu_rx_drop++;
556 IEEE80211_NODE_STAT(ni, rx_drop);
557 m_freem(m);
558 return CONSUMED;
559 }
560 rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
561 rap->rxa_nframes++;
562again:
563 if (rxseq == rap->rxa_start) {
564 /*
565 * First frame in window.
566 */
567 if (rap->rxa_qframes != 0) {
568 /*
569 * Dispatch as many packets as we can.
570 */
571 KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
572 ampdu_dispatch(ni, m);
573 ampdu_rx_dispatch(rap, ni);
574 return CONSUMED;
575 } else {
576 /*
577 * In order; advance window and notify
578 * caller to dispatch directly.
579 */
580 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
581 return PROCESS;
582 }
583 }
584 /*
585 * Frame is out of order; store if in the BA window.
586 */
587 /* calculate offset in BA window */
588 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
589 if (off < rap->rxa_wnd) {
590 /*
591 * Common case (hopefully): in the BA window.
592 * Sec 9.10.7.6 a) (D2.04 p.118 line 47)
593 */
594#ifdef IEEE80211_AMPDU_AGE
595 /*
596 * Check for frames sitting too long in the reorder queue.
597 * This should only ever happen if frames are not delivered
598 * without the sender otherwise notifying us (e.g. with a
599 * BAR to move the window). Typically this happens because
600 * of vendor bugs that cause the sequence number to jump.
601 * When this happens we get a gap in the reorder queue that
602 * leaves frame sitting on the queue until they get pushed
603 * out due to window moves. When the vendor does not send
604 * BAR this move only happens due to explicit packet sends
605 *
606 * NB: we only track the time of the oldest frame in the
607 * reorder q; this means that if we flush we might push
608 * frames that still "new"; if this happens then subsequent
609 * frames will result in BA window moves which cost something
610 * but is still better than a big throughput dip.
611 */
612 if (rap->rxa_qframes != 0) {
613 /* XXX honor batimeout? */
614 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
615 /*
616 * Too long since we received the first
617 * frame; flush the reorder buffer.
618 */
619 if (rap->rxa_qframes != 0) {
620 vap->iv_stats.is_ampdu_rx_age +=
621 rap->rxa_qframes;
622 ampdu_rx_flush(ni, rap);
623 }
624 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
625 return PROCESS;
626 }
627 } else {
628 /*
629 * First frame, start aging timer.
630 */
631 rap->rxa_age = ticks;
632 }
633#endif /* IEEE80211_AMPDU_AGE */
634 /* save packet */
635 if (rap->rxa_m[off] == NULL) {
636 rap->rxa_m[off] = m;
637 rap->rxa_qframes++;
638 rap->rxa_qbytes += m->m_pkthdr.len;
639 vap->iv_stats.is_ampdu_rx_reorder++;
640 } else {
641 IEEE80211_DISCARD_MAC(vap,
642 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
643 ni->ni_macaddr, "a-mpdu duplicate",
644 "seqno %u tid %u BA win <%u:%u>",
645 rxseq, tid, rap->rxa_start,
646 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
647 vap->iv_stats.is_rx_dup++;
648 IEEE80211_NODE_STAT(ni, rx_dup);
649 m_freem(m);
650 }
651 return CONSUMED;
652 }
653 if (off < IEEE80211_SEQ_BA_RANGE) {
654 /*
655 * Outside the BA window, but within range;
656 * flush the reorder q and move the window.
657 * Sec 9.10.7.6 b) (D2.04 p.118 line 60)
658 */
659 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
660 "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
661 rap->rxa_start,
662 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
663 rap->rxa_qframes, rxseq, tid);
664 vap->iv_stats.is_ampdu_rx_move++;
665
666 /*
667 * The spec says to flush frames up to but not including:
668 * WinStart_B = rxseq - rap->rxa_wnd + 1
669 * Then insert the frame or notify the caller to process
670 * it immediately. We can safely do this by just starting
671 * over again because we know the frame will now be within
672 * the BA window.
673 */
674 /* NB: rxa_wnd known to be >0 */
675 ampdu_rx_flush_upto(ni, rap,
676 IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
677 goto again;
678 } else {
679 /*
680 * Outside the BA window and out of range; toss.
681 * Sec 9.10.7.6 c) (D2.04 p.119 line 16)
682 */
683 IEEE80211_DISCARD_MAC(vap,
684 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
685 "MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
686 rap->rxa_start,
687 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
688 rap->rxa_qframes, rxseq, tid,
689 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
690 vap->iv_stats.is_ampdu_rx_drop++;
691 IEEE80211_NODE_STAT(ni, rx_drop);
692 m_freem(m);
693 return CONSUMED;
694 }
695#undef CONSUMED
696#undef PROCESS
697#undef IEEE80211_FC0_QOSDATA
698}
699
700/*
701 * Process a BAR ctl frame. Dispatch all frames up to
702 * the sequence number of the frame. If this frame is
703 * out of range it's discarded.
704 */
705void
706ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
707{
708 struct ieee80211vap *vap = ni->ni_vap;
709 struct ieee80211_frame_bar *wh;
710 struct ieee80211_rx_ampdu *rap;
711 ieee80211_seq rxseq;
712 int tid, off;
713
714 if (!ieee80211_recv_bar_ena) {
715#if 0
716 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
717 ni->ni_macaddr, "BAR", "%s", "processing disabled");
718#endif
719 vap->iv_stats.is_ampdu_bar_bad++;
720 return;
721 }
722 wh = mtod(m0, struct ieee80211_frame_bar *);
723 /* XXX check basic BAR */
724 tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
725 rap = &ni->ni_rx_ampdu[tid];
726 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
727 /*
728 * No ADDBA request yet, don't touch.
729 */
730 IEEE80211_DISCARD_MAC(vap,
731 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
732 ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
733 vap->iv_stats.is_ampdu_bar_bad++;
734 return;
735 }
736 vap->iv_stats.is_ampdu_bar_rx++;
737 rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
738 if (rxseq == rap->rxa_start)
739 return;
740 /* calculate offset in BA window */
741 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
742 if (off < IEEE80211_SEQ_BA_RANGE) {
743 /*
744 * Flush the reorder q up to rxseq and move the window.
745 * Sec 9.10.7.6 a) (D2.04 p.119 line 22)
746 */
747 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
748 "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
749 rap->rxa_start,
750 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
751 rap->rxa_qframes, rxseq, tid);
752 vap->iv_stats.is_ampdu_bar_move++;
753
754 ampdu_rx_flush_upto(ni, rap, rxseq);
755 if (off >= rap->rxa_wnd) {
756 /*
757 * BAR specifies a window start to the right of BA
758 * window; we must move it explicitly since
759 * ampdu_rx_flush_upto will not.
760 */
761 rap->rxa_start = rxseq;
762 }
763 } else {
764 /*
765 * Out of range; toss.
766 * Sec 9.10.7.6 b) (D2.04 p.119 line 41)
767 */
768 IEEE80211_DISCARD_MAC(vap,
769 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
770 "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
771 rap->rxa_start,
772 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
773 rap->rxa_qframes, rxseq, tid,
774 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
775 vap->iv_stats.is_ampdu_bar_oow++;
776 IEEE80211_NODE_STAT(ni, rx_drop);
777 }
778}
779
780/*
781 * Setup HT-specific state in a node. Called only
782 * when HT use is negotiated so we don't do extra
783 * work for temporary and/or legacy sta's.
784 */
785void
786ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
787{
788 struct ieee80211_tx_ampdu *tap;
789 int ac;
790
791 if (ni->ni_flags & IEEE80211_NODE_HT) {
792 /*
793 * Clean AMPDU state on re-associate. This handles the case
794 * where a station leaves w/o notifying us and then returns
795 * before node is reaped for inactivity.
796 */
797 ieee80211_ht_node_cleanup(ni);
798 }
799 ieee80211_parse_htcap(ni, htcap);
800 for (ac = 0; ac < WME_NUM_AC; ac++) {
801 tap = &ni->ni_tx_ampdu[ac];
802 tap->txa_ac = ac;
803 /* NB: further initialization deferred */
804 }
805 ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
806}
807
808/*
809 * Cleanup HT-specific state in a node. Called only
810 * when HT use has been marked.
811 */
812void
813ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
814{
815 struct ieee80211com *ic = ni->ni_ic;
816 int i;
817
818 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
819
820 /* XXX optimize this */
821 for (i = 0; i < WME_NUM_AC; i++) {
822 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
823 if (tap->txa_flags & IEEE80211_AGGR_SETUP) {
824 /*
825 * Stop BA stream if setup so driver has a chance
826 * to reclaim any resources it might have allocated.
827 */
828 ic->ic_addba_stop(ni, &ni->ni_tx_ampdu[i]);
829 tap->txa_lastsample = 0;
830 tap->txa_avgpps = 0;
831 /* NB: clearing NAK means we may re-send ADDBA */
832 tap->txa_flags &=
833 ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
834 }
835 }
836 for (i = 0; i < WME_NUM_TID; i++)
837 ampdu_rx_stop(&ni->ni_rx_ampdu[i]);
838
839 ni->ni_htcap = 0;
840 ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
841}
842
843/*
844 * Age out HT resources for a station.
845 */
846void
847ieee80211_ht_node_age(struct ieee80211_node *ni)
848{
849#ifdef IEEE80211_AMPDU_AGE
850 struct ieee80211vap *vap = ni->ni_vap;
851 uint8_t tid;
852#endif
853
854 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
855
856#ifdef IEEE80211_AMPDU_AGE
857 for (tid = 0; tid < WME_NUM_TID; tid++) {
858 struct ieee80211_rx_ampdu *rap;
859
860 rap = &ni->ni_rx_ampdu[tid];
861 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
862 continue;
863 if (rap->rxa_qframes == 0)
864 continue;
865 /*
866 * Check for frames sitting too long in the reorder queue.
867 * See above for more details on what's happening here.
868 */
869 /* XXX honor batimeout? */
870 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
871 /*
872 * Too long since we received the first
873 * frame; flush the reorder buffer.
874 */
875 vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
876 ampdu_rx_flush(ni, rap);
877 }
878 }
879#endif /* IEEE80211_AMPDU_AGE */
880}
881
882static struct ieee80211_channel *
883findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
884{
885 return ieee80211_find_channel(ic, c->ic_freq,
886 (c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
887}
888
889/*
890 * Adjust a channel to be HT/non-HT according to the vap's configuration.
891 */
892struct ieee80211_channel *
893ieee80211_ht_adjust_channel(struct ieee80211com *ic,
894 struct ieee80211_channel *chan, int flags)
895{
896 struct ieee80211_channel *c;
897
898 if (flags & IEEE80211_FEXT_HT) {
899 /* promote to HT if possible */
900 if (flags & IEEE80211_FEXT_USEHT40) {
901 if (!IEEE80211_IS_CHAN_HT40(chan)) {
902 /* NB: arbitrarily pick ht40+ over ht40- */
903 c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
904 if (c == NULL)
905 c = findhtchan(ic, chan,
906 IEEE80211_CHAN_HT40D);
907 if (c == NULL)
908 c = findhtchan(ic, chan,
909 IEEE80211_CHAN_HT20);
910 if (c != NULL)
911 chan = c;
912 }
913 } else if (!IEEE80211_IS_CHAN_HT20(chan)) {
914 c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
915 if (c != NULL)
916 chan = c;
917 }
918 } else if (IEEE80211_IS_CHAN_HT(chan)) {
919 /* demote to legacy, HT use is disabled */
920 c = ieee80211_find_channel(ic, chan->ic_freq,
921 chan->ic_flags &~ IEEE80211_CHAN_HT);
922 if (c != NULL)
923 chan = c;
924 }
925 return chan;
926}
927
928/*
929 * Setup HT-specific state for a legacy WDS peer.
930 */
931void
932ieee80211_ht_wds_init(struct ieee80211_node *ni)
933{
934 struct ieee80211vap *vap = ni->ni_vap;
935 struct ieee80211_tx_ampdu *tap;
936 int ac;
937
938 KASSERT(vap->iv_flags_ext & IEEE80211_FEXT_HT, ("no HT requested"));
939
940 /* XXX check scan cache in case peer has an ap and we have info */
941 /*
942 * If setup with a legacy channel; locate an HT channel.
943 * Otherwise if the inherited channel (from a companion
944 * AP) is suitable use it so we use the same location
945 * for the extension channel).
946 */
947 ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
948 ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
949
950 ni->ni_htcap = 0;
951 if (vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI20)
952 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
953 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
954 ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
955 ni->ni_chw = 40;
956 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
957 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
958 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
959 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
960 if (vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI40)
961 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
962 } else {
963 ni->ni_chw = 20;
964 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
965 }
966 ni->ni_htctlchan = ni->ni_chan->ic_ieee;
967
968 ni->ni_htopmode = 0; /* XXX need protection state */
969 ni->ni_htstbc = 0; /* XXX need info */
970
971 for (ac = 0; ac < WME_NUM_AC; ac++) {
972 tap = &ni->ni_tx_ampdu[ac];
973 tap->txa_ac = ac;
974 }
975 /* NB: AMPDU tx/rx governed by IEEE80211_FEXT_AMPDU_{TX,RX} */
976 ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
977}
978
979/*
980 * Notify hostap vaps of a change in the HTINFO ie.
981 */
982static void
983htinfo_notify(struct ieee80211com *ic)
984{
985 struct ieee80211vap *vap;
986 int first = 1;
987
988 IEEE80211_LOCK_ASSERT(ic);
989
990 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
991 if (vap->iv_opmode != IEEE80211_M_HOSTAP)
992 continue;
993 if (first) {
994 IEEE80211_NOTE(vap,
995 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
996 vap->iv_bss,
997 "HT bss occupancy change: %d sta, %d ht, "
998 "%d ht40%s, HT protmode now 0x%x"
999 , ic->ic_sta_assoc
1000 , ic->ic_ht_sta_assoc
1001 , ic->ic_ht40_sta_assoc
1002 , (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) ?
1003 ", non-HT sta present" : ""
1004 , ic->ic_curhtprotmode);
1005 first = 0;
1006 }
1007 ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
1008 }
1009}
1010
1011/*
1012 * Calculate HT protection mode from current
1013 * state and handle updates.
1014 */
1015static void
1016htinfo_update(struct ieee80211com *ic)
1017{
1018 uint8_t protmode;
1019
1020 if (ic->ic_sta_assoc != ic->ic_ht_sta_assoc) {
1021 protmode = IEEE80211_HTINFO_OPMODE_MIXED
1022 | IEEE80211_HTINFO_NONHT_PRESENT;
1023 } else if (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) {
1024 protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
1025 | IEEE80211_HTINFO_NONHT_PRESENT;
1026 } else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
1027 IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
1028 ic->ic_sta_assoc != ic->ic_ht40_sta_assoc) {
1029 protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
1030 } else {
1031 protmode = IEEE80211_HTINFO_OPMODE_PURE;
1032 }
1033 if (protmode != ic->ic_curhtprotmode) {
1034 ic->ic_curhtprotmode = protmode;
1035 htinfo_notify(ic);
1036 }
1037}
1038
1039/*
1040 * Handle an HT station joining a BSS.
1041 */
1042void
1043ieee80211_ht_node_join(struct ieee80211_node *ni)
1044{
1045 struct ieee80211com *ic = ni->ni_ic;
1046
1047 IEEE80211_LOCK_ASSERT(ic);
1048
1049 if (ni->ni_flags & IEEE80211_NODE_HT) {
1050 ic->ic_ht_sta_assoc++;
1051 if (ni->ni_chw == 40)
1052 ic->ic_ht40_sta_assoc++;
1053 }
1054 htinfo_update(ic);
1055}
1056
1057/*
1058 * Handle an HT station leaving a BSS.
1059 */
1060void
1061ieee80211_ht_node_leave(struct ieee80211_node *ni)
1062{
1063 struct ieee80211com *ic = ni->ni_ic;
1064
1065 IEEE80211_LOCK_ASSERT(ic);
1066
1067 if (ni->ni_flags & IEEE80211_NODE_HT) {
1068 ic->ic_ht_sta_assoc--;
1069 if (ni->ni_chw == 40)
1070 ic->ic_ht40_sta_assoc--;
1071 }
1072 htinfo_update(ic);
1073}
1074
1075/*
1076 * Public version of htinfo_update; used for processing
1077 * beacon frames from overlapping bss.
1078 *
1079 * Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
1080 * (on receipt of a beacon that advertises MIXED) or
1081 * IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
1082 * from an overlapping legacy bss). We treat MIXED with
1083 * a higher precedence than PROTOPT (i.e. we will not change
1084 * change PROTOPT -> MIXED; only MIXED -> PROTOPT). This
1085 * corresponds to how we handle things in htinfo_update.
1086 */
1087void
1088ieee80211_htprot_update(struct ieee80211com *ic, int protmode)
1089{
1090#define OPMODE(x) SM(x, IEEE80211_HTINFO_OPMODE)
1091 IEEE80211_LOCK(ic);
1092
1093 /* track non-HT station presence */
1094 KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
1095 ("protmode 0x%x", protmode));
1096 ic->ic_flags_ext |= IEEE80211_FEXT_NONHT_PR;
1097 ic->ic_lastnonht = ticks;
1098
1099 if (protmode != ic->ic_curhtprotmode &&
1100 (OPMODE(ic->ic_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
1101 OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
1102 /* push beacon update */
1103 ic->ic_curhtprotmode = protmode;
1104 htinfo_notify(ic);
1105 }
1106 IEEE80211_UNLOCK(ic);
1107#undef OPMODE
1108}
1109
1110/*
1111 * Time out presence of an overlapping bss with non-HT
1112 * stations. When operating in hostap mode we listen for
1113 * beacons from other stations and if we identify a non-HT
1114 * station is present we update the opmode field of the
1115 * HTINFO ie. To identify when all non-HT stations are
1116 * gone we time out this condition.
1117 */
1118void
1119ieee80211_ht_timeout(struct ieee80211com *ic)
1120{
1121 IEEE80211_LOCK_ASSERT(ic);
1122
1123 if ((ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) &&
1124 time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
1125#if 0
1126 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1127 "%s", "time out non-HT STA present on channel");
1128#endif
1129 ic->ic_flags_ext &= ~IEEE80211_FEXT_NONHT_PR;
1130 htinfo_update(ic);
1131 }
1132}
1133
1134/* unalligned little endian access */
1135#define LE_READ_2(p) \
1136 ((uint16_t) \
1137 ((((const uint8_t *)(p))[0] ) | \
1138 (((const uint8_t *)(p))[1] << 8)))
1139
1140/*
1141 * Process an 802.11n HT capabilities ie.
1142 */
1143void
1144ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1145{
1146 struct ieee80211vap *vap = ni->ni_vap;
1147
1148 if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1149 /*
1150 * Station used Vendor OUI ie to associate;
1151 * mark the node so when we respond we'll use
1152 * the Vendor OUI's and not the standard ie's.
1153 */
1154 ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1155 ie += 4;
1156 } else
1157 ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1158
1159 ni->ni_htcap = LE_READ_2(ie +
1160 __offsetof(struct ieee80211_ie_htcap, hc_cap));
1161 ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1162 /* XXX needed or will ieee80211_parse_htinfo always be called? */
1163 ni->ni_chw = (ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
1164 (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40) ? 40 : 20;
1165}
1166
1167/*
1168 * Process an 802.11n HT info ie and update the node state.
1169 * Note that we handle use this information to identify the
1170 * correct channel (HT20, HT40+, HT40-, legacy). The caller
1171 * is responsible for insuring any required channel change is
1172 * done (e.g. in sta mode when parsing the contents of a
1173 * beacon frame).
1174 */
1175void
1176ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1177{
1178 struct ieee80211com *ic = ni->ni_ic;
1179 struct ieee80211vap *vap = ni->ni_vap;
1180 const struct ieee80211_ie_htinfo *htinfo;
1181 struct ieee80211_channel *c;
1182 uint16_t w;
1183 int htflags, chanflags;
1184
1185 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1186 ie += 4;
1187 htinfo = (const struct ieee80211_ie_htinfo *) ie;
1188 ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1189 ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
1190 w = LE_READ_2(&htinfo->hi_byte2);
1191 ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
1192 w = LE_READ_2(&htinfo->hi_byte45);
1193 ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1194 /*
1195 * Handle 11n channel switch. Use the received HT ie's to
1196 * identify the right channel to use. If we cannot locate it
1197 * in the channel table then fallback to legacy operation.
1198 */
1199 /* NB: honor operating mode constraint */
1200 htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
1201 IEEE80211_CHAN_HT20 : 0;
1202 if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
1203 (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
1204 if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
1205 htflags = IEEE80211_CHAN_HT40U;
1206 else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
1207 htflags = IEEE80211_CHAN_HT40D;
1208 }
1209 chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
1210 if (chanflags != ni->ni_chan->ic_flags) {
1211 c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1212 if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
1213 /*
1214 * No HT40 channel entry in our table; fall back
1215 * to HT20 operation. This should not happen.
1216 */
1217 c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1218 IEEE80211_NOTE(vap,
1219 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1220 "no HT40 channel (freq %u), falling back to HT20",
1221 ni->ni_chan->ic_freq);
1222 /* XXX stat */
1223 }
1224 if (c != NULL && c != ni->ni_chan) {
1225 IEEE80211_NOTE(vap,
1226 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1227 "switch station to HT%d channel %u/0x%x",
1228 IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
1229 c->ic_freq, c->ic_flags);
1230 ni->ni_chan = c;
1231 }
1232 /* NB: caller responsible for forcing any channel change */
1233 }
1234 /* update node's tx channel width */
1235 ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
1236}
1237
1238/*
1239 * Install received HT rate set by parsing the HT cap ie.
1240 */
1241int
1242ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
1243{
1244 struct ieee80211vap *vap = ni->ni_vap;
1245 const struct ieee80211_ie_htcap *htcap;
1246 struct ieee80211_htrateset *rs;
1247 int i;
1248
1249 rs = &ni->ni_htrates;
1250 memset(rs, 0, sizeof(*rs));
1251 if (ie != NULL) {
1252 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1253 ie += 4;
1254 htcap = (const struct ieee80211_ie_htcap *) ie;
1255 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1256 if (isclr(htcap->hc_mcsset, i))
1257 continue;
1258 if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
1259 IEEE80211_NOTE(vap,
1260 IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1261 "WARNING, HT rate set too large; only "
1262 "using %u rates", IEEE80211_HTRATE_MAXSIZE);
1263 vap->iv_stats.is_rx_rstoobig++;
1264 break;
1265 }
1266 rs->rs_rates[rs->rs_nrates++] = i;
1267 }
1268 }
1269 return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
1270}
1271
1272/*
1273 * Mark rates in a node's HT rate set as basic according
1274 * to the information in the supplied HT info ie.
1275 */
1276void
1277ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
1278{
1279 const struct ieee80211_ie_htinfo *htinfo;
1280 struct ieee80211_htrateset *rs;
1281 int i, j;
1282
1283 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1284 ie += 4;
1285 htinfo = (const struct ieee80211_ie_htinfo *) ie;
1286 rs = &ni->ni_htrates;
1287 if (rs->rs_nrates == 0) {
1288 IEEE80211_NOTE(ni->ni_vap,
1289 IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1290 "%s", "WARNING, empty HT rate set");
1291 return;
1292 }
1293 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1294 if (isclr(htinfo->hi_basicmcsset, i))
1295 continue;
1296 for (j = 0; j < rs->rs_nrates; j++)
1297 if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
1298 rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
1299 }
1300}
1301
1302static void
1303addba_timeout(void *arg)
1304{
1305 struct ieee80211_tx_ampdu *tap = arg;
1306
1307 /* XXX ? */
1308 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1309 tap->txa_attempts++;
1310}
1311
1312static void
1313addba_start_timeout(struct ieee80211_tx_ampdu *tap)
1314{
1315 /* XXX use CALLOUT_PENDING instead? */
1316 callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
1317 addba_timeout, tap);
1318 tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
1319 tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
1320}
1321
1322static void
1323addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
1324{
1325 /* XXX use CALLOUT_PENDING instead? */
1326 if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
1327 callout_stop(&tap->txa_timer);
1328 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1329 }
1330}
1331
1332/*
1333 * Default method for requesting A-MPDU tx aggregation.
1334 * We setup the specified state block and start a timer
1335 * to wait for an ADDBA response frame.
1336 */
1337static int
1338ieee80211_addba_request(struct ieee80211_node *ni,
1339 struct ieee80211_tx_ampdu *tap,
1340 int dialogtoken, int baparamset, int batimeout)
1341{
1342 int bufsiz;
1343
1344 /* XXX locking */
1345 tap->txa_token = dialogtoken;
1346 tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
1347 tap->txa_start = 0;
1348 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1349 tap->txa_wnd = (bufsiz == 0) ?
1350 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1351 addba_start_timeout(tap);
1352 return 1;
1353}
1354
1355/*
1356 * Default method for processing an A-MPDU tx aggregation
1357 * response. We shutdown any pending timer and update the
1358 * state block according to the reply.
1359 */
1360static int
1361ieee80211_addba_response(struct ieee80211_node *ni,
1362 struct ieee80211_tx_ampdu *tap,
1363 int status, int baparamset, int batimeout)
1364{
1365 int bufsiz;
1366
1367 /* XXX locking */
1368 addba_stop_timeout(tap);
1369 if (status == IEEE80211_STATUS_SUCCESS) {
1370 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1371 /* XXX override our request? */
1372 tap->txa_wnd = (bufsiz == 0) ?
1373 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1374 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
1375 } else {
1376 /* mark tid so we don't try again */
1377 tap->txa_flags |= IEEE80211_AGGR_NAK;
1378 }
1379 return 1;
1380}
1381
1382/*
1383 * Default method for stopping A-MPDU tx aggregation.
1384 * Any timer is cleared and we drain any pending frames.
1385 */
1386static void
1387ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1388{
1389 /* XXX locking */
1390 addba_stop_timeout(tap);
1391 if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
1392 /* XXX clear aggregation queue */
1393 tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
1394 }
1395 tap->txa_attempts = 0;
1396}
1397
1398/*
1399 * Process a received action frame using the default aggregation
1400 * policy. We intercept ADDBA-related frames and use them to
1401 * update our aggregation state. All other frames are passed up
1402 * for processing by ieee80211_recv_action.
1403 */
1404static void
1405ieee80211_aggr_recv_action(struct ieee80211_node *ni,
1406 const uint8_t *frm, const uint8_t *efrm)
1407{
1408 struct ieee80211com *ic = ni->ni_ic;
1409 struct ieee80211vap *vap = ni->ni_vap;
1410 const struct ieee80211_action *ia;
1411 struct ieee80211_rx_ampdu *rap;
1412 struct ieee80211_tx_ampdu *tap;
1413 uint8_t dialogtoken, policy;
1414 uint16_t baparamset, batimeout, baseqctl, code;
1415 uint16_t args[4];
1416 int tid, ac, bufsiz;
1417
1418 ia = (const struct ieee80211_action *) frm;
1419 switch (ia->ia_category) {
1420 case IEEE80211_ACTION_CAT_BA:
1421 switch (ia->ia_action) {
1422 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1423 dialogtoken = frm[2];
1424 baparamset = LE_READ_2(frm+3);
1425 batimeout = LE_READ_2(frm+5);
1426 baseqctl = LE_READ_2(frm+7);
1427
1428 tid = MS(baparamset, IEEE80211_BAPS_TID);
1429 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1430
1431 IEEE80211_NOTE(vap,
1432 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1433 "recv ADDBA request: dialogtoken %u "
1434 "baparamset 0x%x (tid %d bufsiz %d) batimeout %d "
1435 "baseqctl %d:%d",
1436 dialogtoken, baparamset, tid, bufsiz, batimeout,
1437 MS(baseqctl, IEEE80211_BASEQ_START),
1438 MS(baseqctl, IEEE80211_BASEQ_FRAG));
1439
1440 rap = &ni->ni_rx_ampdu[tid];
1441
1442 /* Send ADDBA response */
1443 args[0] = dialogtoken;
1444 /*
1445 * NB: We ack only if the sta associated with HT and
1446 * the ap is configured to do AMPDU rx (the latter
1447 * violates the 11n spec and is mostly for testing).
1448 */
1449 if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
1450 (vap->iv_flags_ext & IEEE80211_FEXT_AMPDU_RX)) {
1451 ampdu_rx_start(rap, bufsiz,
1452 MS(baseqctl, IEEE80211_BASEQ_START));
1453
1454 args[1] = IEEE80211_STATUS_SUCCESS;
1455 } else {
1456 IEEE80211_NOTE(vap,
1457 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1458 ni, "reject ADDBA request: %s",
1459 ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
1460 "administratively disabled" :
1461 "not negotiated for station");
1462 vap->iv_stats.is_addba_reject++;
1463 args[1] = IEEE80211_STATUS_UNSPECIFIED;
1464 }
1465 /* XXX honor rap flags? */
1466 args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
1467 | SM(tid, IEEE80211_BAPS_TID)
1468 | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
1469 ;
1470 args[3] = 0;
1471 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1472 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
1473 return;
1474
1475 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1476 dialogtoken = frm[2];
1477 code = LE_READ_2(frm+3);
1478 baparamset = LE_READ_2(frm+5);
1479 tid = MS(baparamset, IEEE80211_BAPS_TID);
1480 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1481 policy = MS(baparamset, IEEE80211_BAPS_POLICY);
1482 batimeout = LE_READ_2(frm+7);
1483
1484 ac = TID_TO_WME_AC(tid);
1485 tap = &ni->ni_tx_ampdu[ac];
1486 if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1487 IEEE80211_DISCARD_MAC(vap,
1488 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1489 ni->ni_macaddr, "ADDBA response",
1490 "no pending ADDBA, tid %d dialogtoken %u "
1491 "code %d", tid, dialogtoken, code);
1492 vap->iv_stats.is_addba_norequest++;
1493 return;
1494 }
1495 if (dialogtoken != tap->txa_token) {
1496 IEEE80211_DISCARD_MAC(vap,
1497 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1498 ni->ni_macaddr, "ADDBA response",
1499 "dialogtoken mismatch: waiting for %d, "
1500 "received %d, tid %d code %d",
1501 tap->txa_token, dialogtoken, tid, code);
1502 vap->iv_stats.is_addba_badtoken++;
1503 return;
1504 }
1505 /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
1506 if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
1507 IEEE80211_DISCARD_MAC(vap,
1508 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1509 ni->ni_macaddr, "ADDBA response",
1510 "policy mismatch: expecting %s, "
1511 "received %s, tid %d code %d",
1512 tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
1513 policy, tid, code);
1514 vap->iv_stats.is_addba_badpolicy++;
1515 return;
1516 }
1517#if 0
1518 /* XXX we take MIN in ieee80211_addba_response */
1519 if (bufsiz > IEEE80211_AGGR_BAWMAX) {
1520 IEEE80211_DISCARD_MAC(vap,
1521 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1522 ni->ni_macaddr, "ADDBA response",
1523 "BA window too large: max %d, "
1524 "received %d, tid %d code %d",
1525 bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
1526 vap->iv_stats.is_addba_badbawinsize++;
1527 return;
1528 }
1529#endif
1530
1531 IEEE80211_NOTE(vap,
1532 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1533 "recv ADDBA response: dialogtoken %u code %d "
1534 "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
1535 dialogtoken, code, baparamset, tid, bufsiz,
1536 batimeout);
1537 ic->ic_addba_response(ni, tap,
1538 code, baparamset, batimeout);
1539 return;
1540
1541 case IEEE80211_ACTION_BA_DELBA:
1542 baparamset = LE_READ_2(frm+2);
1543 code = LE_READ_2(frm+4);
1544
1545 tid = MS(baparamset, IEEE80211_DELBAPS_TID);
1546
1547 IEEE80211_NOTE(vap,
1548 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1549 "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
1550 "code %d", baparamset, tid,
1551 MS(baparamset, IEEE80211_DELBAPS_INIT), code);
1552
1553 if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
1554 ac = TID_TO_WME_AC(tid);
1555 tap = &ni->ni_tx_ampdu[ac];
1556 ic->ic_addba_stop(ni, tap);
1557 } else {
1558 rap = &ni->ni_rx_ampdu[tid];
1559 ampdu_rx_stop(rap);
1560 }
1561 return;
1562 }
1563 break;
1564 }
1565 ieee80211_recv_action(ni, frm, efrm);
1566}
1567
1568/*
1569 * Process a received 802.11n action frame.
1570 * Aggregation-related frames are assumed to be handled
1571 * already; we handle any other frames we can, otherwise
1572 * complain about being unsupported (with debugging).
1573 */
1574void
1575ieee80211_recv_action(struct ieee80211_node *ni,
1576 const uint8_t *frm, const uint8_t *efrm)
1577{
1578 struct ieee80211vap *vap = ni->ni_vap;
1579 const struct ieee80211_action *ia;
1580 int chw;
1581
1582 ia = (const struct ieee80211_action *) frm;
1583 switch (ia->ia_category) {
1584 case IEEE80211_ACTION_CAT_BA:
1585 IEEE80211_NOTE(vap,
1586 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1587 "%s: BA action %d not implemented", __func__,
1588 ia->ia_action);
1589 vap->iv_stats.is_rx_mgtdiscard++;
1590 break;
1591 case IEEE80211_ACTION_CAT_HT:
1592 switch (ia->ia_action) {
1593 case IEEE80211_ACTION_HT_TXCHWIDTH:
1594 chw = frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040 ? 40 : 20;
1595 IEEE80211_NOTE(vap,
1596 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1597 "%s: HT txchwidth, width %d%s",
1598 __func__, chw, ni->ni_chw != chw ? "*" : "");
1599 if (chw != ni->ni_chw) {
1600 ni->ni_chw = chw;
1601 /* XXX notify on change */
1602 }
1603 break;
1604 case IEEE80211_ACTION_HT_MIMOPWRSAVE:
1605 IEEE80211_NOTE(vap,
1606 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1607 "%s: HT MIMO PS", __func__);
1608 break;
1609 default:
1610 IEEE80211_NOTE(vap,
1611 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1612 "%s: HT action %d not implemented", __func__,
1613 ia->ia_action);
1614 vap->iv_stats.is_rx_mgtdiscard++;
1615 break;
1616 }
1617 break;
1618 default:
1619 IEEE80211_NOTE(vap,
1620 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1621 "%s: category %d not implemented", __func__,
1622 ia->ia_category);
1623 vap->iv_stats.is_rx_mgtdiscard++;
1624 break;
1625 }
1626}
1627
1628/*
1629 * Transmit processing.
1630 */
1631
1632/*
1633 * Check if A-MPDU should be requested/enabled for a stream.
1634 * We require a traffic rate above a per-AC threshold and we
1635 * also handle backoff from previous failed attempts.
1636 *
1637 * Drivers may override this method to bring in information
1638 * such as link state conditions in making the decision.
1639 */
1640static int
1641ieee80211_ampdu_enable(struct ieee80211_node *ni,
1642 struct ieee80211_tx_ampdu *tap)
1643{
1644 struct ieee80211vap *vap = ni->ni_vap;
1645
1646 if (tap->txa_avgpps < vap->iv_ampdu_mintraffic[tap->txa_ac])
1647 return 0;
1648 /* XXX check rssi? */
1649 if (tap->txa_attempts >= ieee80211_addba_maxtries &&
1650 ticks < tap->txa_nextrequest) {
1651 /*
1652 * Don't retry too often; txa_nextrequest is set
1653 * to the minimum interval we'll retry after
1654 * ieee80211_addba_maxtries failed attempts are made.
1655 */
1656 return 0;
1657 }
1658 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1659 "enable AMPDU on %s, avgpps %d pkts %d",
1660 ieee80211_wme_acnames[tap->txa_ac], tap->txa_avgpps, tap->txa_pkts);
1661 return 1;
1662}
1663
1664/*
1665 * Request A-MPDU tx aggregation. Setup local state and
1666 * issue an ADDBA request. BA use will only happen after
1667 * the other end replies with ADDBA response.
1668 */
1669int
1670ieee80211_ampdu_request(struct ieee80211_node *ni,
1671 struct ieee80211_tx_ampdu *tap)
1672{
1673 struct ieee80211com *ic = ni->ni_ic;
1674 uint16_t args[4];
1675 int tid, dialogtoken;
1676 static int tokens = 0; /* XXX */
1677
1678 /* XXX locking */
1679 if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
1680 /* do deferred setup of state */
1681 callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
1682 tap->txa_flags |= IEEE80211_AGGR_SETUP;
1683 }
1684 /* XXX hack for not doing proper locking */
1685 tap->txa_flags &= ~IEEE80211_AGGR_NAK;
1686
1687 dialogtoken = (tokens+1) % 63; /* XXX */
1688 tid = WME_AC_TO_TID(tap->txa_ac);
1689 tap->txa_start = ni->ni_txseqs[tid];
1690
1691 tid = WME_AC_TO_TID(tap->txa_ac);
1692 args[0] = dialogtoken;
1693 args[1] = IEEE80211_BAPS_POLICY_IMMEDIATE
1694 | SM(tid, IEEE80211_BAPS_TID)
1695 | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
1696 ;
1697 args[2] = 0; /* batimeout */
1698 /* NB: do first so there's no race against reply */
1699 if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) {
1700 /* unable to setup state, don't make request */
1701 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1702 ni, "%s: could not setup BA stream for AC %d",
1703 __func__, tap->txa_ac);
1704 /* defer next try so we don't slam the driver with requests */
1705 tap->txa_attempts = ieee80211_addba_maxtries;
1706 /* NB: check in case driver wants to override */
1707 if (tap->txa_nextrequest <= ticks)
1708 tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
1709 return 0;
1710 }
1711 tokens = dialogtoken; /* allocate token */
1712 /* NB: after calling ic_addba_request so driver can set txa_start */
1713 args[3] = SM(tap->txa_start, IEEE80211_BASEQ_START)
1714 | SM(0, IEEE80211_BASEQ_FRAG)
1715 ;
1716 return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1717 IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
1718}
1719
1720/*
1721 * Terminate an AMPDU tx stream. State is reclaimed
1722 * and the peer notified with a DelBA Action frame.
1723 */
1724void
29#endif
30
31/*
32 * IEEE 802.11n protocol support.
33 */
34
35#include "opt_inet.h"
36#include "opt_wlan.h"
37
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/systm.h>
41#include <sys/endian.h>
42
43#include <sys/socket.h>
44
45#include <net/if.h>
46#include <net/if_media.h>
47#include <net/ethernet.h>
48
49#include <net80211/ieee80211_var.h>
50#include <net80211/ieee80211_input.h>
51
52/* define here, used throughout file */
53#define MS(_v, _f) (((_v) & _f) >> _f##_S)
54#define SM(_v, _f) (((_v) << _f##_S) & _f)
55
56const struct ieee80211_mcs_rates ieee80211_htrates[16] = {
57 { 13, 14, 27, 30 }, /* MCS 0 */
58 { 26, 29, 54, 60 }, /* MCS 1 */
59 { 39, 43, 81, 90 }, /* MCS 2 */
60 { 52, 58, 108, 120 }, /* MCS 3 */
61 { 78, 87, 162, 180 }, /* MCS 4 */
62 { 104, 116, 216, 240 }, /* MCS 5 */
63 { 117, 130, 243, 270 }, /* MCS 6 */
64 { 130, 144, 270, 300 }, /* MCS 7 */
65 { 26, 29, 54, 60 }, /* MCS 8 */
66 { 52, 58, 108, 120 }, /* MCS 9 */
67 { 78, 87, 162, 180 }, /* MCS 10 */
68 { 104, 116, 216, 240 }, /* MCS 11 */
69 { 156, 173, 324, 360 }, /* MCS 12 */
70 { 208, 231, 432, 480 }, /* MCS 13 */
71 { 234, 260, 486, 540 }, /* MCS 14 */
72 { 260, 289, 540, 600 } /* MCS 15 */
73};
74
75static const struct ieee80211_htrateset ieee80211_rateset_11n =
76 { 16, {
77 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
78 10, 11, 12, 13, 14, 15 }
79 };
80
81#ifdef IEEE80211_AMPDU_AGE
82/* XXX public for sysctl hookup */
83int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */
84#endif
85int ieee80211_recv_bar_ena = 1;
86int ieee80211_addba_timeout = -1; /* timeout waiting for ADDBA response */
87int ieee80211_addba_backoff = -1; /* backoff after max ADDBA requests */
88int ieee80211_addba_maxtries = 3; /* max ADDBA requests before backoff */
89
90/*
91 * Setup HT parameters that depends on the clock frequency.
92 */
93static void
94ieee80211_ht_setup(void)
95{
96#ifdef IEEE80211_AMPDU_AGE
97 ieee80211_ampdu_age = msecs_to_ticks(500);
98#endif
99 ieee80211_addba_timeout = msecs_to_ticks(250);
100 ieee80211_addba_backoff = msecs_to_ticks(10*1000);
101}
102SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
103
104static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
105 struct ieee80211_tx_ampdu *tap);
106static int ieee80211_addba_request(struct ieee80211_node *ni,
107 struct ieee80211_tx_ampdu *tap,
108 int dialogtoken, int baparamset, int batimeout);
109static int ieee80211_addba_response(struct ieee80211_node *ni,
110 struct ieee80211_tx_ampdu *tap,
111 int code, int baparamset, int batimeout);
112static void ieee80211_addba_stop(struct ieee80211_node *ni,
113 struct ieee80211_tx_ampdu *tap);
114static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
115 const uint8_t *frm, const uint8_t *efrm);
116
117void
118ieee80211_ht_attach(struct ieee80211com *ic)
119{
120 /* setup default aggregation policy */
121 ic->ic_recv_action = ieee80211_aggr_recv_action;
122 ic->ic_send_action = ieee80211_send_action;
123 ic->ic_ampdu_enable = ieee80211_ampdu_enable;
124 ic->ic_addba_request = ieee80211_addba_request;
125 ic->ic_addba_response = ieee80211_addba_response;
126 ic->ic_addba_stop = ieee80211_addba_stop;
127
128 ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
129 ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
130}
131
132void
133ieee80211_ht_detach(struct ieee80211com *ic)
134{
135}
136
137void
138ieee80211_ht_vattach(struct ieee80211vap *vap)
139{
140
141 /* driver can override defaults */
142 vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
143 vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
144 vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
145 vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
146 /* tx aggregation traffic thresholds */
147 vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
148 vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
149 vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
150 vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
151
152 if (vap->iv_htcaps & IEEE80211_HTC_HT) {
153 /*
154 * Device is HT capable; enable all HT-related
155 * facilities by default.
156 * XXX these choices may be too aggressive.
157 */
158 vap->iv_flags_ext |= IEEE80211_FEXT_HT
159 | IEEE80211_FEXT_HTCOMPAT
160 ;
161 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
162 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI20;
163 /* XXX infer from channel list? */
164 if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
165 vap->iv_flags_ext |= IEEE80211_FEXT_USEHT40;
166 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
167 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI40;
168 }
169 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
170 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
171 if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
172 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
173 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
174 if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
175 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
176 }
177 /* NB: disable default legacy WDS, too many issues right now */
178 if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
179 vap->iv_flags_ext &= ~IEEE80211_FEXT_HT;
180}
181
182void
183ieee80211_ht_vdetach(struct ieee80211vap *vap)
184{
185}
186
187static void
188ht_announce(struct ieee80211com *ic, int mode,
189 const struct ieee80211_htrateset *rs)
190{
191 struct ifnet *ifp = ic->ic_ifp;
192 int i, rate, mword;
193
194 if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]);
195 for (i = 0; i < rs->rs_nrates; i++) {
196 mword = ieee80211_rate2media(ic,
197 rs->rs_rates[i] | IEEE80211_RATE_MCS, mode);
198 if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
199 continue;
200 rate = ieee80211_htrates[rs->rs_rates[i]].ht40_rate_400ns;
201 printf("%s%d%sMbps", (i != 0 ? " " : ""),
202 rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
203 }
204 printf("\n");
205}
206
207void
208ieee80211_ht_announce(struct ieee80211com *ic)
209{
210 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
211 ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n);
212 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
213 ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n);
214}
215
216const struct ieee80211_htrateset *
217ieee80211_get_suphtrates(struct ieee80211com *ic,
218 const struct ieee80211_channel *c)
219{
220 return &ieee80211_rateset_11n;
221}
222
223/*
224 * Receive processing.
225 */
226
227/*
228 * Decap the encapsulated A-MSDU frames and dispatch all but
229 * the last for delivery. The last frame is returned for
230 * delivery via the normal path.
231 */
232struct mbuf *
233ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
234{
235 struct ieee80211vap *vap = ni->ni_vap;
236 int framelen;
237 struct mbuf *n;
238
239 /* discard 802.3 header inserted by ieee80211_decap */
240 m_adj(m, sizeof(struct ether_header));
241
242 vap->iv_stats.is_amsdu_decap++;
243
244 for (;;) {
245 /*
246 * Decap the first frame, bust it apart from the
247 * remainder and deliver. We leave the last frame
248 * delivery to the caller (for consistency with other
249 * code paths, could also do it here).
250 */
251 m = ieee80211_decap1(m, &framelen);
252 if (m == NULL) {
253 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
254 ni->ni_macaddr, "a-msdu", "%s", "decap failed");
255 vap->iv_stats.is_amsdu_tooshort++;
256 return NULL;
257 }
258 if (m->m_pkthdr.len == framelen)
259 break;
260 n = m_split(m, framelen, M_NOWAIT);
261 if (n == NULL) {
262 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
263 ni->ni_macaddr, "a-msdu",
264 "%s", "unable to split encapsulated frames");
265 vap->iv_stats.is_amsdu_split++;
266 m_freem(m); /* NB: must reclaim */
267 return NULL;
268 }
269 vap->iv_deliver_data(vap, ni, m);
270
271 /*
272 * Remove frame contents; each intermediate frame
273 * is required to be aligned to a 4-byte boundary.
274 */
275 m = n;
276 m_adj(m, roundup2(framelen, 4) - framelen); /* padding */
277 }
278 return m; /* last delivered by caller */
279}
280
281/*
282 * Purge all frames in the A-MPDU re-order queue.
283 */
284static void
285ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
286{
287 struct mbuf *m;
288 int i;
289
290 for (i = 0; i < rap->rxa_wnd; i++) {
291 m = rap->rxa_m[i];
292 if (m != NULL) {
293 rap->rxa_m[i] = NULL;
294 rap->rxa_qbytes -= m->m_pkthdr.len;
295 m_freem(m);
296 if (--rap->rxa_qframes == 0)
297 break;
298 }
299 }
300 KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
301 ("lost %u data, %u frames on ampdu rx q",
302 rap->rxa_qbytes, rap->rxa_qframes));
303}
304
305/*
306 * Start A-MPDU rx/re-order processing for the specified TID.
307 */
308static void
309ampdu_rx_start(struct ieee80211_rx_ampdu *rap, int bufsiz, int start)
310{
311 if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
312 /*
313 * AMPDU previously setup and not terminated with a DELBA,
314 * flush the reorder q's in case anything remains.
315 */
316 ampdu_rx_purge(rap);
317 }
318 memset(rap, 0, sizeof(*rap));
319 rap->rxa_wnd = (bufsiz == 0) ?
320 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
321 rap->rxa_start = start;
322 rap->rxa_flags |= IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
323}
324
325/*
326 * Stop A-MPDU rx processing for the specified TID.
327 */
328static void
329ampdu_rx_stop(struct ieee80211_rx_ampdu *rap)
330{
331 ampdu_rx_purge(rap);
332 rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND);
333}
334
335/*
336 * Dispatch a frame from the A-MPDU reorder queue. The
337 * frame is fed back into ieee80211_input marked with an
338 * M_AMPDU_MPDU flag so it doesn't come back to us (it also
339 * permits ieee80211_input to optimize re-processing).
340 */
341static __inline void
342ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
343{
344 m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */
345 /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU_MPDU set */
346 (void) ieee80211_input(ni, m, 0, 0, 0);
347}
348
349/*
350 * Dispatch as many frames as possible from the re-order queue.
351 * Frames will always be "at the front"; we process all frames
352 * up to the first empty slot in the window. On completion we
353 * cleanup state if there are still pending frames in the current
354 * BA window. We assume the frame at slot 0 is already handled
355 * by the caller; we always start at slot 1.
356 */
357static void
358ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
359{
360 struct ieee80211vap *vap = ni->ni_vap;
361 struct mbuf *m;
362 int i;
363
364 /* flush run of frames */
365 for (i = 1; i < rap->rxa_wnd; i++) {
366 m = rap->rxa_m[i];
367 if (m == NULL)
368 break;
369 rap->rxa_m[i] = NULL;
370 rap->rxa_qbytes -= m->m_pkthdr.len;
371 rap->rxa_qframes--;
372
373 ampdu_dispatch(ni, m);
374 }
375 /*
376 * If frames remain, copy the mbuf pointers down so
377 * they correspond to the offsets in the new window.
378 */
379 if (rap->rxa_qframes != 0) {
380 int n = rap->rxa_qframes, j;
381 for (j = i+1; j < rap->rxa_wnd; j++) {
382 if (rap->rxa_m[j] != NULL) {
383 rap->rxa_m[j-i] = rap->rxa_m[j];
384 rap->rxa_m[j] = NULL;
385 if (--n == 0)
386 break;
387 }
388 }
389 KASSERT(n == 0, ("lost %d frames", n));
390 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
391 }
392 /*
393 * Adjust the start of the BA window to
394 * reflect the frames just dispatched.
395 */
396 rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
397 vap->iv_stats.is_ampdu_rx_oor += i;
398}
399
400#ifdef IEEE80211_AMPDU_AGE
401/*
402 * Dispatch all frames in the A-MPDU re-order queue.
403 */
404static void
405ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
406{
407 struct ieee80211vap *vap = ni->ni_vap;
408 struct mbuf *m;
409 int i;
410
411 for (i = 0; i < rap->rxa_wnd; i++) {
412 m = rap->rxa_m[i];
413 if (m == NULL)
414 continue;
415 rap->rxa_m[i] = NULL;
416 rap->rxa_qbytes -= m->m_pkthdr.len;
417 rap->rxa_qframes--;
418 vap->iv_stats.is_ampdu_rx_oor++;
419
420 ampdu_dispatch(ni, m);
421 if (rap->rxa_qframes == 0)
422 break;
423 }
424}
425#endif /* IEEE80211_AMPDU_AGE */
426
427/*
428 * Dispatch all frames in the A-MPDU re-order queue
429 * preceding the specified sequence number. This logic
430 * handles window moves due to a received MSDU or BAR.
431 */
432static void
433ampdu_rx_flush_upto(struct ieee80211_node *ni,
434 struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
435{
436 struct ieee80211vap *vap = ni->ni_vap;
437 struct mbuf *m;
438 ieee80211_seq seqno;
439 int i;
440
441 /*
442 * Flush any complete MSDU's with a sequence number lower
443 * than winstart. Gaps may exist. Note that we may actually
444 * dispatch frames past winstart if a run continues; this is
445 * an optimization that avoids having to do a separate pass
446 * to dispatch frames after moving the BA window start.
447 */
448 seqno = rap->rxa_start;
449 for (i = 0; i < rap->rxa_wnd; i++) {
450 m = rap->rxa_m[i];
451 if (m != NULL) {
452 rap->rxa_m[i] = NULL;
453 rap->rxa_qbytes -= m->m_pkthdr.len;
454 rap->rxa_qframes--;
455 vap->iv_stats.is_ampdu_rx_oor++;
456
457 ampdu_dispatch(ni, m);
458 } else {
459 if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
460 break;
461 }
462 seqno = IEEE80211_SEQ_INC(seqno);
463 }
464 /*
465 * If frames remain, copy the mbuf pointers down so
466 * they correspond to the offsets in the new window.
467 */
468 if (rap->rxa_qframes != 0) {
469 int n = rap->rxa_qframes, j;
470
471 /* NB: this loop assumes i > 0 and/or rxa_m[0] is NULL */
472 KASSERT(rap->rxa_m[0] == NULL,
473 ("%s: BA window slot 0 occupied", __func__));
474 for (j = i+1; j < rap->rxa_wnd; j++) {
475 if (rap->rxa_m[j] != NULL) {
476 rap->rxa_m[j-i] = rap->rxa_m[j];
477 rap->rxa_m[j] = NULL;
478 if (--n == 0)
479 break;
480 }
481 }
482 KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
483 "BA win <%d:%d> winstart %d",
484 __func__, n, rap->rxa_qframes, i, rap->rxa_start,
485 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
486 winstart));
487 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
488 }
489 /*
490 * Move the start of the BA window; we use the
491 * sequence number of the last MSDU that was
492 * passed up the stack+1 or winstart if stopped on
493 * a gap in the reorder buffer.
494 */
495 rap->rxa_start = seqno;
496}
497
498/*
499 * Process a received QoS data frame for an HT station. Handle
500 * A-MPDU reordering: if this frame is received out of order
501 * and falls within the BA window hold onto it. Otherwise if
502 * this frame completes a run, flush any pending frames. We
503 * return 1 if the frame is consumed. A 0 is returned if
504 * the frame should be processed normally by the caller.
505 */
506int
507ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
508{
509#define IEEE80211_FC0_QOSDATA \
510 (IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
511#define PROCESS 0 /* caller should process frame */
512#define CONSUMED 1 /* frame consumed, caller does nothing */
513 struct ieee80211vap *vap = ni->ni_vap;
514 struct ieee80211_qosframe *wh;
515 struct ieee80211_rx_ampdu *rap;
516 ieee80211_seq rxseq;
517 uint8_t tid;
518 int off;
519
520 KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
521 ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
522 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
523
524 /* NB: m_len known to be sufficient */
525 wh = mtod(m, struct ieee80211_qosframe *);
526 if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) {
527 /*
528 * Not QoS data, shouldn't get here but just
529 * return it to the caller for processing.
530 */
531 return PROCESS;
532 }
533
534 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
535 tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
536 else
537 tid = wh->i_qos[0];
538 tid &= IEEE80211_QOS_TID;
539 rap = &ni->ni_rx_ampdu[tid];
540 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
541 /*
542 * No ADDBA request yet, don't touch.
543 */
544 return PROCESS;
545 }
546 rxseq = le16toh(*(uint16_t *)wh->i_seq);
547 if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
548 /*
549 * Fragments are not allowed; toss.
550 */
551 IEEE80211_DISCARD_MAC(vap,
552 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
553 "A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
554 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
555 vap->iv_stats.is_ampdu_rx_drop++;
556 IEEE80211_NODE_STAT(ni, rx_drop);
557 m_freem(m);
558 return CONSUMED;
559 }
560 rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
561 rap->rxa_nframes++;
562again:
563 if (rxseq == rap->rxa_start) {
564 /*
565 * First frame in window.
566 */
567 if (rap->rxa_qframes != 0) {
568 /*
569 * Dispatch as many packets as we can.
570 */
571 KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
572 ampdu_dispatch(ni, m);
573 ampdu_rx_dispatch(rap, ni);
574 return CONSUMED;
575 } else {
576 /*
577 * In order; advance window and notify
578 * caller to dispatch directly.
579 */
580 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
581 return PROCESS;
582 }
583 }
584 /*
585 * Frame is out of order; store if in the BA window.
586 */
587 /* calculate offset in BA window */
588 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
589 if (off < rap->rxa_wnd) {
590 /*
591 * Common case (hopefully): in the BA window.
592 * Sec 9.10.7.6 a) (D2.04 p.118 line 47)
593 */
594#ifdef IEEE80211_AMPDU_AGE
595 /*
596 * Check for frames sitting too long in the reorder queue.
597 * This should only ever happen if frames are not delivered
598 * without the sender otherwise notifying us (e.g. with a
599 * BAR to move the window). Typically this happens because
600 * of vendor bugs that cause the sequence number to jump.
601 * When this happens we get a gap in the reorder queue that
602 * leaves frame sitting on the queue until they get pushed
603 * out due to window moves. When the vendor does not send
604 * BAR this move only happens due to explicit packet sends
605 *
606 * NB: we only track the time of the oldest frame in the
607 * reorder q; this means that if we flush we might push
608 * frames that still "new"; if this happens then subsequent
609 * frames will result in BA window moves which cost something
610 * but is still better than a big throughput dip.
611 */
612 if (rap->rxa_qframes != 0) {
613 /* XXX honor batimeout? */
614 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
615 /*
616 * Too long since we received the first
617 * frame; flush the reorder buffer.
618 */
619 if (rap->rxa_qframes != 0) {
620 vap->iv_stats.is_ampdu_rx_age +=
621 rap->rxa_qframes;
622 ampdu_rx_flush(ni, rap);
623 }
624 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
625 return PROCESS;
626 }
627 } else {
628 /*
629 * First frame, start aging timer.
630 */
631 rap->rxa_age = ticks;
632 }
633#endif /* IEEE80211_AMPDU_AGE */
634 /* save packet */
635 if (rap->rxa_m[off] == NULL) {
636 rap->rxa_m[off] = m;
637 rap->rxa_qframes++;
638 rap->rxa_qbytes += m->m_pkthdr.len;
639 vap->iv_stats.is_ampdu_rx_reorder++;
640 } else {
641 IEEE80211_DISCARD_MAC(vap,
642 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
643 ni->ni_macaddr, "a-mpdu duplicate",
644 "seqno %u tid %u BA win <%u:%u>",
645 rxseq, tid, rap->rxa_start,
646 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
647 vap->iv_stats.is_rx_dup++;
648 IEEE80211_NODE_STAT(ni, rx_dup);
649 m_freem(m);
650 }
651 return CONSUMED;
652 }
653 if (off < IEEE80211_SEQ_BA_RANGE) {
654 /*
655 * Outside the BA window, but within range;
656 * flush the reorder q and move the window.
657 * Sec 9.10.7.6 b) (D2.04 p.118 line 60)
658 */
659 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
660 "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
661 rap->rxa_start,
662 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
663 rap->rxa_qframes, rxseq, tid);
664 vap->iv_stats.is_ampdu_rx_move++;
665
666 /*
667 * The spec says to flush frames up to but not including:
668 * WinStart_B = rxseq - rap->rxa_wnd + 1
669 * Then insert the frame or notify the caller to process
670 * it immediately. We can safely do this by just starting
671 * over again because we know the frame will now be within
672 * the BA window.
673 */
674 /* NB: rxa_wnd known to be >0 */
675 ampdu_rx_flush_upto(ni, rap,
676 IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
677 goto again;
678 } else {
679 /*
680 * Outside the BA window and out of range; toss.
681 * Sec 9.10.7.6 c) (D2.04 p.119 line 16)
682 */
683 IEEE80211_DISCARD_MAC(vap,
684 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
685 "MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
686 rap->rxa_start,
687 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
688 rap->rxa_qframes, rxseq, tid,
689 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
690 vap->iv_stats.is_ampdu_rx_drop++;
691 IEEE80211_NODE_STAT(ni, rx_drop);
692 m_freem(m);
693 return CONSUMED;
694 }
695#undef CONSUMED
696#undef PROCESS
697#undef IEEE80211_FC0_QOSDATA
698}
699
700/*
701 * Process a BAR ctl frame. Dispatch all frames up to
702 * the sequence number of the frame. If this frame is
703 * out of range it's discarded.
704 */
705void
706ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
707{
708 struct ieee80211vap *vap = ni->ni_vap;
709 struct ieee80211_frame_bar *wh;
710 struct ieee80211_rx_ampdu *rap;
711 ieee80211_seq rxseq;
712 int tid, off;
713
714 if (!ieee80211_recv_bar_ena) {
715#if 0
716 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
717 ni->ni_macaddr, "BAR", "%s", "processing disabled");
718#endif
719 vap->iv_stats.is_ampdu_bar_bad++;
720 return;
721 }
722 wh = mtod(m0, struct ieee80211_frame_bar *);
723 /* XXX check basic BAR */
724 tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
725 rap = &ni->ni_rx_ampdu[tid];
726 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
727 /*
728 * No ADDBA request yet, don't touch.
729 */
730 IEEE80211_DISCARD_MAC(vap,
731 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
732 ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
733 vap->iv_stats.is_ampdu_bar_bad++;
734 return;
735 }
736 vap->iv_stats.is_ampdu_bar_rx++;
737 rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
738 if (rxseq == rap->rxa_start)
739 return;
740 /* calculate offset in BA window */
741 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
742 if (off < IEEE80211_SEQ_BA_RANGE) {
743 /*
744 * Flush the reorder q up to rxseq and move the window.
745 * Sec 9.10.7.6 a) (D2.04 p.119 line 22)
746 */
747 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
748 "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
749 rap->rxa_start,
750 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
751 rap->rxa_qframes, rxseq, tid);
752 vap->iv_stats.is_ampdu_bar_move++;
753
754 ampdu_rx_flush_upto(ni, rap, rxseq);
755 if (off >= rap->rxa_wnd) {
756 /*
757 * BAR specifies a window start to the right of BA
758 * window; we must move it explicitly since
759 * ampdu_rx_flush_upto will not.
760 */
761 rap->rxa_start = rxseq;
762 }
763 } else {
764 /*
765 * Out of range; toss.
766 * Sec 9.10.7.6 b) (D2.04 p.119 line 41)
767 */
768 IEEE80211_DISCARD_MAC(vap,
769 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
770 "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
771 rap->rxa_start,
772 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
773 rap->rxa_qframes, rxseq, tid,
774 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
775 vap->iv_stats.is_ampdu_bar_oow++;
776 IEEE80211_NODE_STAT(ni, rx_drop);
777 }
778}
779
780/*
781 * Setup HT-specific state in a node. Called only
782 * when HT use is negotiated so we don't do extra
783 * work for temporary and/or legacy sta's.
784 */
785void
786ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
787{
788 struct ieee80211_tx_ampdu *tap;
789 int ac;
790
791 if (ni->ni_flags & IEEE80211_NODE_HT) {
792 /*
793 * Clean AMPDU state on re-associate. This handles the case
794 * where a station leaves w/o notifying us and then returns
795 * before node is reaped for inactivity.
796 */
797 ieee80211_ht_node_cleanup(ni);
798 }
799 ieee80211_parse_htcap(ni, htcap);
800 for (ac = 0; ac < WME_NUM_AC; ac++) {
801 tap = &ni->ni_tx_ampdu[ac];
802 tap->txa_ac = ac;
803 /* NB: further initialization deferred */
804 }
805 ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
806}
807
808/*
809 * Cleanup HT-specific state in a node. Called only
810 * when HT use has been marked.
811 */
812void
813ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
814{
815 struct ieee80211com *ic = ni->ni_ic;
816 int i;
817
818 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
819
820 /* XXX optimize this */
821 for (i = 0; i < WME_NUM_AC; i++) {
822 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
823 if (tap->txa_flags & IEEE80211_AGGR_SETUP) {
824 /*
825 * Stop BA stream if setup so driver has a chance
826 * to reclaim any resources it might have allocated.
827 */
828 ic->ic_addba_stop(ni, &ni->ni_tx_ampdu[i]);
829 tap->txa_lastsample = 0;
830 tap->txa_avgpps = 0;
831 /* NB: clearing NAK means we may re-send ADDBA */
832 tap->txa_flags &=
833 ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
834 }
835 }
836 for (i = 0; i < WME_NUM_TID; i++)
837 ampdu_rx_stop(&ni->ni_rx_ampdu[i]);
838
839 ni->ni_htcap = 0;
840 ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
841}
842
843/*
844 * Age out HT resources for a station.
845 */
846void
847ieee80211_ht_node_age(struct ieee80211_node *ni)
848{
849#ifdef IEEE80211_AMPDU_AGE
850 struct ieee80211vap *vap = ni->ni_vap;
851 uint8_t tid;
852#endif
853
854 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
855
856#ifdef IEEE80211_AMPDU_AGE
857 for (tid = 0; tid < WME_NUM_TID; tid++) {
858 struct ieee80211_rx_ampdu *rap;
859
860 rap = &ni->ni_rx_ampdu[tid];
861 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
862 continue;
863 if (rap->rxa_qframes == 0)
864 continue;
865 /*
866 * Check for frames sitting too long in the reorder queue.
867 * See above for more details on what's happening here.
868 */
869 /* XXX honor batimeout? */
870 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
871 /*
872 * Too long since we received the first
873 * frame; flush the reorder buffer.
874 */
875 vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
876 ampdu_rx_flush(ni, rap);
877 }
878 }
879#endif /* IEEE80211_AMPDU_AGE */
880}
881
882static struct ieee80211_channel *
883findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
884{
885 return ieee80211_find_channel(ic, c->ic_freq,
886 (c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
887}
888
889/*
890 * Adjust a channel to be HT/non-HT according to the vap's configuration.
891 */
892struct ieee80211_channel *
893ieee80211_ht_adjust_channel(struct ieee80211com *ic,
894 struct ieee80211_channel *chan, int flags)
895{
896 struct ieee80211_channel *c;
897
898 if (flags & IEEE80211_FEXT_HT) {
899 /* promote to HT if possible */
900 if (flags & IEEE80211_FEXT_USEHT40) {
901 if (!IEEE80211_IS_CHAN_HT40(chan)) {
902 /* NB: arbitrarily pick ht40+ over ht40- */
903 c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
904 if (c == NULL)
905 c = findhtchan(ic, chan,
906 IEEE80211_CHAN_HT40D);
907 if (c == NULL)
908 c = findhtchan(ic, chan,
909 IEEE80211_CHAN_HT20);
910 if (c != NULL)
911 chan = c;
912 }
913 } else if (!IEEE80211_IS_CHAN_HT20(chan)) {
914 c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
915 if (c != NULL)
916 chan = c;
917 }
918 } else if (IEEE80211_IS_CHAN_HT(chan)) {
919 /* demote to legacy, HT use is disabled */
920 c = ieee80211_find_channel(ic, chan->ic_freq,
921 chan->ic_flags &~ IEEE80211_CHAN_HT);
922 if (c != NULL)
923 chan = c;
924 }
925 return chan;
926}
927
928/*
929 * Setup HT-specific state for a legacy WDS peer.
930 */
931void
932ieee80211_ht_wds_init(struct ieee80211_node *ni)
933{
934 struct ieee80211vap *vap = ni->ni_vap;
935 struct ieee80211_tx_ampdu *tap;
936 int ac;
937
938 KASSERT(vap->iv_flags_ext & IEEE80211_FEXT_HT, ("no HT requested"));
939
940 /* XXX check scan cache in case peer has an ap and we have info */
941 /*
942 * If setup with a legacy channel; locate an HT channel.
943 * Otherwise if the inherited channel (from a companion
944 * AP) is suitable use it so we use the same location
945 * for the extension channel).
946 */
947 ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
948 ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
949
950 ni->ni_htcap = 0;
951 if (vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI20)
952 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
953 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
954 ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
955 ni->ni_chw = 40;
956 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
957 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
958 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
959 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
960 if (vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI40)
961 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
962 } else {
963 ni->ni_chw = 20;
964 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
965 }
966 ni->ni_htctlchan = ni->ni_chan->ic_ieee;
967
968 ni->ni_htopmode = 0; /* XXX need protection state */
969 ni->ni_htstbc = 0; /* XXX need info */
970
971 for (ac = 0; ac < WME_NUM_AC; ac++) {
972 tap = &ni->ni_tx_ampdu[ac];
973 tap->txa_ac = ac;
974 }
975 /* NB: AMPDU tx/rx governed by IEEE80211_FEXT_AMPDU_{TX,RX} */
976 ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
977}
978
979/*
980 * Notify hostap vaps of a change in the HTINFO ie.
981 */
982static void
983htinfo_notify(struct ieee80211com *ic)
984{
985 struct ieee80211vap *vap;
986 int first = 1;
987
988 IEEE80211_LOCK_ASSERT(ic);
989
990 TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
991 if (vap->iv_opmode != IEEE80211_M_HOSTAP)
992 continue;
993 if (first) {
994 IEEE80211_NOTE(vap,
995 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
996 vap->iv_bss,
997 "HT bss occupancy change: %d sta, %d ht, "
998 "%d ht40%s, HT protmode now 0x%x"
999 , ic->ic_sta_assoc
1000 , ic->ic_ht_sta_assoc
1001 , ic->ic_ht40_sta_assoc
1002 , (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) ?
1003 ", non-HT sta present" : ""
1004 , ic->ic_curhtprotmode);
1005 first = 0;
1006 }
1007 ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
1008 }
1009}
1010
1011/*
1012 * Calculate HT protection mode from current
1013 * state and handle updates.
1014 */
1015static void
1016htinfo_update(struct ieee80211com *ic)
1017{
1018 uint8_t protmode;
1019
1020 if (ic->ic_sta_assoc != ic->ic_ht_sta_assoc) {
1021 protmode = IEEE80211_HTINFO_OPMODE_MIXED
1022 | IEEE80211_HTINFO_NONHT_PRESENT;
1023 } else if (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) {
1024 protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
1025 | IEEE80211_HTINFO_NONHT_PRESENT;
1026 } else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
1027 IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
1028 ic->ic_sta_assoc != ic->ic_ht40_sta_assoc) {
1029 protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
1030 } else {
1031 protmode = IEEE80211_HTINFO_OPMODE_PURE;
1032 }
1033 if (protmode != ic->ic_curhtprotmode) {
1034 ic->ic_curhtprotmode = protmode;
1035 htinfo_notify(ic);
1036 }
1037}
1038
1039/*
1040 * Handle an HT station joining a BSS.
1041 */
1042void
1043ieee80211_ht_node_join(struct ieee80211_node *ni)
1044{
1045 struct ieee80211com *ic = ni->ni_ic;
1046
1047 IEEE80211_LOCK_ASSERT(ic);
1048
1049 if (ni->ni_flags & IEEE80211_NODE_HT) {
1050 ic->ic_ht_sta_assoc++;
1051 if (ni->ni_chw == 40)
1052 ic->ic_ht40_sta_assoc++;
1053 }
1054 htinfo_update(ic);
1055}
1056
1057/*
1058 * Handle an HT station leaving a BSS.
1059 */
1060void
1061ieee80211_ht_node_leave(struct ieee80211_node *ni)
1062{
1063 struct ieee80211com *ic = ni->ni_ic;
1064
1065 IEEE80211_LOCK_ASSERT(ic);
1066
1067 if (ni->ni_flags & IEEE80211_NODE_HT) {
1068 ic->ic_ht_sta_assoc--;
1069 if (ni->ni_chw == 40)
1070 ic->ic_ht40_sta_assoc--;
1071 }
1072 htinfo_update(ic);
1073}
1074
1075/*
1076 * Public version of htinfo_update; used for processing
1077 * beacon frames from overlapping bss.
1078 *
1079 * Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
1080 * (on receipt of a beacon that advertises MIXED) or
1081 * IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
1082 * from an overlapping legacy bss). We treat MIXED with
1083 * a higher precedence than PROTOPT (i.e. we will not change
1084 * change PROTOPT -> MIXED; only MIXED -> PROTOPT). This
1085 * corresponds to how we handle things in htinfo_update.
1086 */
1087void
1088ieee80211_htprot_update(struct ieee80211com *ic, int protmode)
1089{
1090#define OPMODE(x) SM(x, IEEE80211_HTINFO_OPMODE)
1091 IEEE80211_LOCK(ic);
1092
1093 /* track non-HT station presence */
1094 KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
1095 ("protmode 0x%x", protmode));
1096 ic->ic_flags_ext |= IEEE80211_FEXT_NONHT_PR;
1097 ic->ic_lastnonht = ticks;
1098
1099 if (protmode != ic->ic_curhtprotmode &&
1100 (OPMODE(ic->ic_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
1101 OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
1102 /* push beacon update */
1103 ic->ic_curhtprotmode = protmode;
1104 htinfo_notify(ic);
1105 }
1106 IEEE80211_UNLOCK(ic);
1107#undef OPMODE
1108}
1109
1110/*
1111 * Time out presence of an overlapping bss with non-HT
1112 * stations. When operating in hostap mode we listen for
1113 * beacons from other stations and if we identify a non-HT
1114 * station is present we update the opmode field of the
1115 * HTINFO ie. To identify when all non-HT stations are
1116 * gone we time out this condition.
1117 */
1118void
1119ieee80211_ht_timeout(struct ieee80211com *ic)
1120{
1121 IEEE80211_LOCK_ASSERT(ic);
1122
1123 if ((ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) &&
1124 time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
1125#if 0
1126 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1127 "%s", "time out non-HT STA present on channel");
1128#endif
1129 ic->ic_flags_ext &= ~IEEE80211_FEXT_NONHT_PR;
1130 htinfo_update(ic);
1131 }
1132}
1133
1134/* unalligned little endian access */
1135#define LE_READ_2(p) \
1136 ((uint16_t) \
1137 ((((const uint8_t *)(p))[0] ) | \
1138 (((const uint8_t *)(p))[1] << 8)))
1139
1140/*
1141 * Process an 802.11n HT capabilities ie.
1142 */
1143void
1144ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1145{
1146 struct ieee80211vap *vap = ni->ni_vap;
1147
1148 if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1149 /*
1150 * Station used Vendor OUI ie to associate;
1151 * mark the node so when we respond we'll use
1152 * the Vendor OUI's and not the standard ie's.
1153 */
1154 ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1155 ie += 4;
1156 } else
1157 ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1158
1159 ni->ni_htcap = LE_READ_2(ie +
1160 __offsetof(struct ieee80211_ie_htcap, hc_cap));
1161 ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1162 /* XXX needed or will ieee80211_parse_htinfo always be called? */
1163 ni->ni_chw = (ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
1164 (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40) ? 40 : 20;
1165}
1166
1167/*
1168 * Process an 802.11n HT info ie and update the node state.
1169 * Note that we handle use this information to identify the
1170 * correct channel (HT20, HT40+, HT40-, legacy). The caller
1171 * is responsible for insuring any required channel change is
1172 * done (e.g. in sta mode when parsing the contents of a
1173 * beacon frame).
1174 */
1175void
1176ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1177{
1178 struct ieee80211com *ic = ni->ni_ic;
1179 struct ieee80211vap *vap = ni->ni_vap;
1180 const struct ieee80211_ie_htinfo *htinfo;
1181 struct ieee80211_channel *c;
1182 uint16_t w;
1183 int htflags, chanflags;
1184
1185 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1186 ie += 4;
1187 htinfo = (const struct ieee80211_ie_htinfo *) ie;
1188 ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1189 ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
1190 w = LE_READ_2(&htinfo->hi_byte2);
1191 ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
1192 w = LE_READ_2(&htinfo->hi_byte45);
1193 ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1194 /*
1195 * Handle 11n channel switch. Use the received HT ie's to
1196 * identify the right channel to use. If we cannot locate it
1197 * in the channel table then fallback to legacy operation.
1198 */
1199 /* NB: honor operating mode constraint */
1200 htflags = (vap->iv_flags_ext & IEEE80211_FEXT_HT) ?
1201 IEEE80211_CHAN_HT20 : 0;
1202 if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
1203 (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)) {
1204 if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
1205 htflags = IEEE80211_CHAN_HT40U;
1206 else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
1207 htflags = IEEE80211_CHAN_HT40D;
1208 }
1209 chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
1210 if (chanflags != ni->ni_chan->ic_flags) {
1211 c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1212 if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
1213 /*
1214 * No HT40 channel entry in our table; fall back
1215 * to HT20 operation. This should not happen.
1216 */
1217 c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1218 IEEE80211_NOTE(vap,
1219 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1220 "no HT40 channel (freq %u), falling back to HT20",
1221 ni->ni_chan->ic_freq);
1222 /* XXX stat */
1223 }
1224 if (c != NULL && c != ni->ni_chan) {
1225 IEEE80211_NOTE(vap,
1226 IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1227 "switch station to HT%d channel %u/0x%x",
1228 IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
1229 c->ic_freq, c->ic_flags);
1230 ni->ni_chan = c;
1231 }
1232 /* NB: caller responsible for forcing any channel change */
1233 }
1234 /* update node's tx channel width */
1235 ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
1236}
1237
1238/*
1239 * Install received HT rate set by parsing the HT cap ie.
1240 */
1241int
1242ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
1243{
1244 struct ieee80211vap *vap = ni->ni_vap;
1245 const struct ieee80211_ie_htcap *htcap;
1246 struct ieee80211_htrateset *rs;
1247 int i;
1248
1249 rs = &ni->ni_htrates;
1250 memset(rs, 0, sizeof(*rs));
1251 if (ie != NULL) {
1252 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1253 ie += 4;
1254 htcap = (const struct ieee80211_ie_htcap *) ie;
1255 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1256 if (isclr(htcap->hc_mcsset, i))
1257 continue;
1258 if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
1259 IEEE80211_NOTE(vap,
1260 IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1261 "WARNING, HT rate set too large; only "
1262 "using %u rates", IEEE80211_HTRATE_MAXSIZE);
1263 vap->iv_stats.is_rx_rstoobig++;
1264 break;
1265 }
1266 rs->rs_rates[rs->rs_nrates++] = i;
1267 }
1268 }
1269 return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
1270}
1271
1272/*
1273 * Mark rates in a node's HT rate set as basic according
1274 * to the information in the supplied HT info ie.
1275 */
1276void
1277ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
1278{
1279 const struct ieee80211_ie_htinfo *htinfo;
1280 struct ieee80211_htrateset *rs;
1281 int i, j;
1282
1283 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1284 ie += 4;
1285 htinfo = (const struct ieee80211_ie_htinfo *) ie;
1286 rs = &ni->ni_htrates;
1287 if (rs->rs_nrates == 0) {
1288 IEEE80211_NOTE(ni->ni_vap,
1289 IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1290 "%s", "WARNING, empty HT rate set");
1291 return;
1292 }
1293 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1294 if (isclr(htinfo->hi_basicmcsset, i))
1295 continue;
1296 for (j = 0; j < rs->rs_nrates; j++)
1297 if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
1298 rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
1299 }
1300}
1301
1302static void
1303addba_timeout(void *arg)
1304{
1305 struct ieee80211_tx_ampdu *tap = arg;
1306
1307 /* XXX ? */
1308 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1309 tap->txa_attempts++;
1310}
1311
1312static void
1313addba_start_timeout(struct ieee80211_tx_ampdu *tap)
1314{
1315 /* XXX use CALLOUT_PENDING instead? */
1316 callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
1317 addba_timeout, tap);
1318 tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
1319 tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
1320}
1321
1322static void
1323addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
1324{
1325 /* XXX use CALLOUT_PENDING instead? */
1326 if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
1327 callout_stop(&tap->txa_timer);
1328 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1329 }
1330}
1331
1332/*
1333 * Default method for requesting A-MPDU tx aggregation.
1334 * We setup the specified state block and start a timer
1335 * to wait for an ADDBA response frame.
1336 */
1337static int
1338ieee80211_addba_request(struct ieee80211_node *ni,
1339 struct ieee80211_tx_ampdu *tap,
1340 int dialogtoken, int baparamset, int batimeout)
1341{
1342 int bufsiz;
1343
1344 /* XXX locking */
1345 tap->txa_token = dialogtoken;
1346 tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
1347 tap->txa_start = 0;
1348 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1349 tap->txa_wnd = (bufsiz == 0) ?
1350 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1351 addba_start_timeout(tap);
1352 return 1;
1353}
1354
1355/*
1356 * Default method for processing an A-MPDU tx aggregation
1357 * response. We shutdown any pending timer and update the
1358 * state block according to the reply.
1359 */
1360static int
1361ieee80211_addba_response(struct ieee80211_node *ni,
1362 struct ieee80211_tx_ampdu *tap,
1363 int status, int baparamset, int batimeout)
1364{
1365 int bufsiz;
1366
1367 /* XXX locking */
1368 addba_stop_timeout(tap);
1369 if (status == IEEE80211_STATUS_SUCCESS) {
1370 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1371 /* XXX override our request? */
1372 tap->txa_wnd = (bufsiz == 0) ?
1373 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1374 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
1375 } else {
1376 /* mark tid so we don't try again */
1377 tap->txa_flags |= IEEE80211_AGGR_NAK;
1378 }
1379 return 1;
1380}
1381
1382/*
1383 * Default method for stopping A-MPDU tx aggregation.
1384 * Any timer is cleared and we drain any pending frames.
1385 */
1386static void
1387ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1388{
1389 /* XXX locking */
1390 addba_stop_timeout(tap);
1391 if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
1392 /* XXX clear aggregation queue */
1393 tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
1394 }
1395 tap->txa_attempts = 0;
1396}
1397
1398/*
1399 * Process a received action frame using the default aggregation
1400 * policy. We intercept ADDBA-related frames and use them to
1401 * update our aggregation state. All other frames are passed up
1402 * for processing by ieee80211_recv_action.
1403 */
1404static void
1405ieee80211_aggr_recv_action(struct ieee80211_node *ni,
1406 const uint8_t *frm, const uint8_t *efrm)
1407{
1408 struct ieee80211com *ic = ni->ni_ic;
1409 struct ieee80211vap *vap = ni->ni_vap;
1410 const struct ieee80211_action *ia;
1411 struct ieee80211_rx_ampdu *rap;
1412 struct ieee80211_tx_ampdu *tap;
1413 uint8_t dialogtoken, policy;
1414 uint16_t baparamset, batimeout, baseqctl, code;
1415 uint16_t args[4];
1416 int tid, ac, bufsiz;
1417
1418 ia = (const struct ieee80211_action *) frm;
1419 switch (ia->ia_category) {
1420 case IEEE80211_ACTION_CAT_BA:
1421 switch (ia->ia_action) {
1422 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1423 dialogtoken = frm[2];
1424 baparamset = LE_READ_2(frm+3);
1425 batimeout = LE_READ_2(frm+5);
1426 baseqctl = LE_READ_2(frm+7);
1427
1428 tid = MS(baparamset, IEEE80211_BAPS_TID);
1429 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1430
1431 IEEE80211_NOTE(vap,
1432 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1433 "recv ADDBA request: dialogtoken %u "
1434 "baparamset 0x%x (tid %d bufsiz %d) batimeout %d "
1435 "baseqctl %d:%d",
1436 dialogtoken, baparamset, tid, bufsiz, batimeout,
1437 MS(baseqctl, IEEE80211_BASEQ_START),
1438 MS(baseqctl, IEEE80211_BASEQ_FRAG));
1439
1440 rap = &ni->ni_rx_ampdu[tid];
1441
1442 /* Send ADDBA response */
1443 args[0] = dialogtoken;
1444 /*
1445 * NB: We ack only if the sta associated with HT and
1446 * the ap is configured to do AMPDU rx (the latter
1447 * violates the 11n spec and is mostly for testing).
1448 */
1449 if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
1450 (vap->iv_flags_ext & IEEE80211_FEXT_AMPDU_RX)) {
1451 ampdu_rx_start(rap, bufsiz,
1452 MS(baseqctl, IEEE80211_BASEQ_START));
1453
1454 args[1] = IEEE80211_STATUS_SUCCESS;
1455 } else {
1456 IEEE80211_NOTE(vap,
1457 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1458 ni, "reject ADDBA request: %s",
1459 ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
1460 "administratively disabled" :
1461 "not negotiated for station");
1462 vap->iv_stats.is_addba_reject++;
1463 args[1] = IEEE80211_STATUS_UNSPECIFIED;
1464 }
1465 /* XXX honor rap flags? */
1466 args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
1467 | SM(tid, IEEE80211_BAPS_TID)
1468 | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
1469 ;
1470 args[3] = 0;
1471 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1472 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
1473 return;
1474
1475 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1476 dialogtoken = frm[2];
1477 code = LE_READ_2(frm+3);
1478 baparamset = LE_READ_2(frm+5);
1479 tid = MS(baparamset, IEEE80211_BAPS_TID);
1480 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1481 policy = MS(baparamset, IEEE80211_BAPS_POLICY);
1482 batimeout = LE_READ_2(frm+7);
1483
1484 ac = TID_TO_WME_AC(tid);
1485 tap = &ni->ni_tx_ampdu[ac];
1486 if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1487 IEEE80211_DISCARD_MAC(vap,
1488 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1489 ni->ni_macaddr, "ADDBA response",
1490 "no pending ADDBA, tid %d dialogtoken %u "
1491 "code %d", tid, dialogtoken, code);
1492 vap->iv_stats.is_addba_norequest++;
1493 return;
1494 }
1495 if (dialogtoken != tap->txa_token) {
1496 IEEE80211_DISCARD_MAC(vap,
1497 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1498 ni->ni_macaddr, "ADDBA response",
1499 "dialogtoken mismatch: waiting for %d, "
1500 "received %d, tid %d code %d",
1501 tap->txa_token, dialogtoken, tid, code);
1502 vap->iv_stats.is_addba_badtoken++;
1503 return;
1504 }
1505 /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
1506 if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
1507 IEEE80211_DISCARD_MAC(vap,
1508 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1509 ni->ni_macaddr, "ADDBA response",
1510 "policy mismatch: expecting %s, "
1511 "received %s, tid %d code %d",
1512 tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
1513 policy, tid, code);
1514 vap->iv_stats.is_addba_badpolicy++;
1515 return;
1516 }
1517#if 0
1518 /* XXX we take MIN in ieee80211_addba_response */
1519 if (bufsiz > IEEE80211_AGGR_BAWMAX) {
1520 IEEE80211_DISCARD_MAC(vap,
1521 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1522 ni->ni_macaddr, "ADDBA response",
1523 "BA window too large: max %d, "
1524 "received %d, tid %d code %d",
1525 bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
1526 vap->iv_stats.is_addba_badbawinsize++;
1527 return;
1528 }
1529#endif
1530
1531 IEEE80211_NOTE(vap,
1532 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1533 "recv ADDBA response: dialogtoken %u code %d "
1534 "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
1535 dialogtoken, code, baparamset, tid, bufsiz,
1536 batimeout);
1537 ic->ic_addba_response(ni, tap,
1538 code, baparamset, batimeout);
1539 return;
1540
1541 case IEEE80211_ACTION_BA_DELBA:
1542 baparamset = LE_READ_2(frm+2);
1543 code = LE_READ_2(frm+4);
1544
1545 tid = MS(baparamset, IEEE80211_DELBAPS_TID);
1546
1547 IEEE80211_NOTE(vap,
1548 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1549 "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
1550 "code %d", baparamset, tid,
1551 MS(baparamset, IEEE80211_DELBAPS_INIT), code);
1552
1553 if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
1554 ac = TID_TO_WME_AC(tid);
1555 tap = &ni->ni_tx_ampdu[ac];
1556 ic->ic_addba_stop(ni, tap);
1557 } else {
1558 rap = &ni->ni_rx_ampdu[tid];
1559 ampdu_rx_stop(rap);
1560 }
1561 return;
1562 }
1563 break;
1564 }
1565 ieee80211_recv_action(ni, frm, efrm);
1566}
1567
1568/*
1569 * Process a received 802.11n action frame.
1570 * Aggregation-related frames are assumed to be handled
1571 * already; we handle any other frames we can, otherwise
1572 * complain about being unsupported (with debugging).
1573 */
1574void
1575ieee80211_recv_action(struct ieee80211_node *ni,
1576 const uint8_t *frm, const uint8_t *efrm)
1577{
1578 struct ieee80211vap *vap = ni->ni_vap;
1579 const struct ieee80211_action *ia;
1580 int chw;
1581
1582 ia = (const struct ieee80211_action *) frm;
1583 switch (ia->ia_category) {
1584 case IEEE80211_ACTION_CAT_BA:
1585 IEEE80211_NOTE(vap,
1586 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1587 "%s: BA action %d not implemented", __func__,
1588 ia->ia_action);
1589 vap->iv_stats.is_rx_mgtdiscard++;
1590 break;
1591 case IEEE80211_ACTION_CAT_HT:
1592 switch (ia->ia_action) {
1593 case IEEE80211_ACTION_HT_TXCHWIDTH:
1594 chw = frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040 ? 40 : 20;
1595 IEEE80211_NOTE(vap,
1596 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1597 "%s: HT txchwidth, width %d%s",
1598 __func__, chw, ni->ni_chw != chw ? "*" : "");
1599 if (chw != ni->ni_chw) {
1600 ni->ni_chw = chw;
1601 /* XXX notify on change */
1602 }
1603 break;
1604 case IEEE80211_ACTION_HT_MIMOPWRSAVE:
1605 IEEE80211_NOTE(vap,
1606 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1607 "%s: HT MIMO PS", __func__);
1608 break;
1609 default:
1610 IEEE80211_NOTE(vap,
1611 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1612 "%s: HT action %d not implemented", __func__,
1613 ia->ia_action);
1614 vap->iv_stats.is_rx_mgtdiscard++;
1615 break;
1616 }
1617 break;
1618 default:
1619 IEEE80211_NOTE(vap,
1620 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1621 "%s: category %d not implemented", __func__,
1622 ia->ia_category);
1623 vap->iv_stats.is_rx_mgtdiscard++;
1624 break;
1625 }
1626}
1627
1628/*
1629 * Transmit processing.
1630 */
1631
1632/*
1633 * Check if A-MPDU should be requested/enabled for a stream.
1634 * We require a traffic rate above a per-AC threshold and we
1635 * also handle backoff from previous failed attempts.
1636 *
1637 * Drivers may override this method to bring in information
1638 * such as link state conditions in making the decision.
1639 */
1640static int
1641ieee80211_ampdu_enable(struct ieee80211_node *ni,
1642 struct ieee80211_tx_ampdu *tap)
1643{
1644 struct ieee80211vap *vap = ni->ni_vap;
1645
1646 if (tap->txa_avgpps < vap->iv_ampdu_mintraffic[tap->txa_ac])
1647 return 0;
1648 /* XXX check rssi? */
1649 if (tap->txa_attempts >= ieee80211_addba_maxtries &&
1650 ticks < tap->txa_nextrequest) {
1651 /*
1652 * Don't retry too often; txa_nextrequest is set
1653 * to the minimum interval we'll retry after
1654 * ieee80211_addba_maxtries failed attempts are made.
1655 */
1656 return 0;
1657 }
1658 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1659 "enable AMPDU on %s, avgpps %d pkts %d",
1660 ieee80211_wme_acnames[tap->txa_ac], tap->txa_avgpps, tap->txa_pkts);
1661 return 1;
1662}
1663
1664/*
1665 * Request A-MPDU tx aggregation. Setup local state and
1666 * issue an ADDBA request. BA use will only happen after
1667 * the other end replies with ADDBA response.
1668 */
1669int
1670ieee80211_ampdu_request(struct ieee80211_node *ni,
1671 struct ieee80211_tx_ampdu *tap)
1672{
1673 struct ieee80211com *ic = ni->ni_ic;
1674 uint16_t args[4];
1675 int tid, dialogtoken;
1676 static int tokens = 0; /* XXX */
1677
1678 /* XXX locking */
1679 if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
1680 /* do deferred setup of state */
1681 callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
1682 tap->txa_flags |= IEEE80211_AGGR_SETUP;
1683 }
1684 /* XXX hack for not doing proper locking */
1685 tap->txa_flags &= ~IEEE80211_AGGR_NAK;
1686
1687 dialogtoken = (tokens+1) % 63; /* XXX */
1688 tid = WME_AC_TO_TID(tap->txa_ac);
1689 tap->txa_start = ni->ni_txseqs[tid];
1690
1691 tid = WME_AC_TO_TID(tap->txa_ac);
1692 args[0] = dialogtoken;
1693 args[1] = IEEE80211_BAPS_POLICY_IMMEDIATE
1694 | SM(tid, IEEE80211_BAPS_TID)
1695 | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
1696 ;
1697 args[2] = 0; /* batimeout */
1698 /* NB: do first so there's no race against reply */
1699 if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) {
1700 /* unable to setup state, don't make request */
1701 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
1702 ni, "%s: could not setup BA stream for AC %d",
1703 __func__, tap->txa_ac);
1704 /* defer next try so we don't slam the driver with requests */
1705 tap->txa_attempts = ieee80211_addba_maxtries;
1706 /* NB: check in case driver wants to override */
1707 if (tap->txa_nextrequest <= ticks)
1708 tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
1709 return 0;
1710 }
1711 tokens = dialogtoken; /* allocate token */
1712 /* NB: after calling ic_addba_request so driver can set txa_start */
1713 args[3] = SM(tap->txa_start, IEEE80211_BASEQ_START)
1714 | SM(0, IEEE80211_BASEQ_FRAG)
1715 ;
1716 return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1717 IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
1718}
1719
1720/*
1721 * Terminate an AMPDU tx stream. State is reclaimed
1722 * and the peer notified with a DelBA Action frame.
1723 */
1724void
1725ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1725ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
1726 int reason)
1726{
1727 struct ieee80211com *ic = ni->ni_ic;
1728 struct ieee80211vap *vap = ni->ni_vap;
1729 uint16_t args[4];
1730
1731 /* XXX locking */
1732 if (IEEE80211_AMPDU_RUNNING(tap)) {
1733 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1727{
1728 struct ieee80211com *ic = ni->ni_ic;
1729 struct ieee80211vap *vap = ni->ni_vap;
1730 uint16_t args[4];
1731
1732 /* XXX locking */
1733 if (IEEE80211_AMPDU_RUNNING(tap)) {
1734 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1734 ni, "%s: stop BA stream for AC %d", __func__, tap->txa_ac);
1735 ni, "%s: stop BA stream for AC %d (reason %d)",
1736 __func__, tap->txa_ac, reason);
1735 vap->iv_stats.is_ampdu_stop++;
1736
1737 ic->ic_addba_stop(ni, tap);
1738 args[0] = WME_AC_TO_TID(tap->txa_ac);
1739 args[1] = IEEE80211_DELBAPS_INIT;
1737 vap->iv_stats.is_ampdu_stop++;
1738
1739 ic->ic_addba_stop(ni, tap);
1740 args[0] = WME_AC_TO_TID(tap->txa_ac);
1741 args[1] = IEEE80211_DELBAPS_INIT;
1740 args[2] = 1; /* XXX reason code */
1742 args[2] = reason; /* XXX reason code */
1741 ieee80211_send_action(ni, IEEE80211_ACTION_CAT_BA,
1742 IEEE80211_ACTION_BA_DELBA, args);
1743 } else {
1744 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1743 ieee80211_send_action(ni, IEEE80211_ACTION_CAT_BA,
1744 IEEE80211_ACTION_BA_DELBA, args);
1745 } else {
1746 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1745 ni, "%s: BA stream for AC %d not running",
1746 __func__, tap->txa_ac);
1747 ni, "%s: BA stream for AC %d not running (reason %d)",
1748 __func__, tap->txa_ac, reason);
1747 vap->iv_stats.is_ampdu_stop_failed++;
1748 }
1749}
1750
1751/*
1752 * Transmit a BAR frame to the specified node. The
1753 * BAR contents are drawn from the supplied aggregation
1754 * state associated with the node.
1755 */
1756int
1757ieee80211_send_bar(struct ieee80211_node *ni,
1758 const struct ieee80211_tx_ampdu *tap)
1759{
1760#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
1761#define ADDSHORT(frm, v) do { \
1762 frm[0] = (v) & 0xff; \
1763 frm[1] = (v) >> 8; \
1764 frm += 2; \
1765} while (0)
1766 struct ieee80211vap *vap = ni->ni_vap;
1767 struct ieee80211com *ic = ni->ni_ic;
1768 struct ieee80211_frame_min *wh;
1769 struct mbuf *m;
1770 uint8_t *frm;
1771 uint16_t barctl, barseqctl;
1772 int tid, ret;
1773
1774 ieee80211_ref_node(ni);
1775
1776 m = ieee80211_getmgtframe(&frm,
1777 ic->ic_headroom + sizeof(struct ieee80211_frame_min),
1778 sizeof(struct ieee80211_ba_request)
1779 );
1780 if (m == NULL)
1781 senderr(ENOMEM, is_tx_nobuf);
1782
1783 wh = mtod(m, struct ieee80211_frame_min *);
1784 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 |
1785 IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
1786 wh->i_fc[1] = 0;
1787 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1788 IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1789
1790 tid = WME_AC_TO_TID(tap->txa_ac);
1791 barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
1792 IEEE80211_BAPS_POLICY_IMMEDIATE :
1793 IEEE80211_BAPS_POLICY_DELAYED)
1794 | SM(tid, IEEE80211_BAPS_TID)
1795 | SM(tap->txa_wnd, IEEE80211_BAPS_BUFSIZ)
1796 ;
1797 barseqctl = SM(tap->txa_start, IEEE80211_BASEQ_START)
1798 | SM(0, IEEE80211_BASEQ_FRAG)
1799 ;
1800 ADDSHORT(frm, barctl);
1801 ADDSHORT(frm, barseqctl);
1802 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1803
1804 M_WME_SETAC(m, WME_AC_VO);
1805
1806 IEEE80211_NODE_STAT(ni, tx_mgmt); /* XXX tx_ctl? */
1807
1808 IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1809 ni, "send bar frame (tid %u start %u) on channel %u",
1810 tid, tap->txa_start, ieee80211_chan2ieee(ic, ic->ic_curchan));
1811
1812 return ic->ic_raw_xmit(ni, m, NULL);
1813bad:
1814 ieee80211_free_node(ni);
1815 return ret;
1816#undef ADDSHORT
1817#undef senderr
1818}
1819
1820/*
1821 * Send an action management frame. The arguments are stuff
1822 * into a frame without inspection; the caller is assumed to
1823 * prepare them carefully (e.g. based on the aggregation state).
1824 */
1825int
1826ieee80211_send_action(struct ieee80211_node *ni,
1827 int category, int action, uint16_t args[4])
1828{
1829#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
1830#define ADDSHORT(frm, v) do { \
1831 frm[0] = (v) & 0xff; \
1832 frm[1] = (v) >> 8; \
1833 frm += 2; \
1834} while (0)
1835 struct ieee80211vap *vap = ni->ni_vap;
1836 struct ieee80211com *ic = ni->ni_ic;
1837 struct mbuf *m;
1838 uint8_t *frm;
1839 uint16_t baparamset;
1840 int ret;
1841
1842 KASSERT(ni != NULL, ("null node"));
1843
1844 /*
1845 * Hold a reference on the node so it doesn't go away until after
1846 * the xmit is complete all the way in the driver. On error we
1847 * will remove our reference.
1848 */
1849 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1850 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1851 __func__, __LINE__,
1852 ni, ether_sprintf(ni->ni_macaddr),
1853 ieee80211_node_refcnt(ni)+1);
1854 ieee80211_ref_node(ni);
1855
1856 m = ieee80211_getmgtframe(&frm,
1857 ic->ic_headroom + sizeof(struct ieee80211_frame),
1858 sizeof(uint16_t) /* action+category */
1859 /* XXX may action payload */
1860 + sizeof(struct ieee80211_action_ba_addbaresponse)
1861 );
1862 if (m == NULL)
1863 senderr(ENOMEM, is_tx_nobuf);
1864
1865 *frm++ = category;
1866 *frm++ = action;
1867 switch (category) {
1868 case IEEE80211_ACTION_CAT_BA:
1869 switch (action) {
1870 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1871 IEEE80211_NOTE(vap,
1872 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1873 "send ADDBA request: dialogtoken %d "
1874 "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
1875 args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
1876 args[2], args[3]);
1877
1878 *frm++ = args[0]; /* dialog token */
1879 ADDSHORT(frm, args[1]); /* baparamset */
1880 ADDSHORT(frm, args[2]); /* batimeout */
1881 ADDSHORT(frm, args[3]); /* baseqctl */
1882 break;
1883 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1884 IEEE80211_NOTE(vap,
1885 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1886 "send ADDBA response: dialogtoken %d status %d "
1887 "baparamset 0x%x (tid %d) batimeout %d",
1888 args[0], args[1], args[2],
1889 MS(args[2], IEEE80211_BAPS_TID), args[3]);
1890
1891 *frm++ = args[0]; /* dialog token */
1892 ADDSHORT(frm, args[1]); /* statuscode */
1893 ADDSHORT(frm, args[2]); /* baparamset */
1894 ADDSHORT(frm, args[3]); /* batimeout */
1895 break;
1896 case IEEE80211_ACTION_BA_DELBA:
1897 /* XXX */
1898 baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
1899 | args[1]
1900 ;
1901 ADDSHORT(frm, baparamset);
1902 ADDSHORT(frm, args[2]); /* reason code */
1903
1904 IEEE80211_NOTE(vap,
1905 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1906 "send DELBA action: tid %d, initiator %d reason %d",
1907 args[0], args[1], args[2]);
1908 break;
1909 default:
1910 goto badaction;
1911 }
1912 break;
1913 case IEEE80211_ACTION_CAT_HT:
1914 switch (action) {
1915 case IEEE80211_ACTION_HT_TXCHWIDTH:
1916 IEEE80211_NOTE(vap,
1917 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1918 ni, "send HT txchwidth: width %d",
1919 IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20
1920 );
1921 *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
1922 IEEE80211_A_HT_TXCHWIDTH_2040 :
1923 IEEE80211_A_HT_TXCHWIDTH_20;
1924 break;
1925 default:
1926 goto badaction;
1927 }
1928 break;
1929 default:
1930 badaction:
1931 IEEE80211_NOTE(vap,
1932 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1933 "%s: unsupported category %d action %d", __func__,
1934 category, action);
1935 senderr(EINVAL, is_tx_unknownmgt);
1936 /* NOTREACHED */
1937 }
1938 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1939
1940 return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION);
1941bad:
1942 ieee80211_free_node(ni);
1943 if (m != NULL)
1944 m_freem(m);
1945 return ret;
1946#undef ADDSHORT
1947#undef senderr
1948}
1949
1950/*
1951 * Construct the MCS bit mask for inclusion
1952 * in an HT information element.
1953 */
1954static void
1955ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1956{
1957 int i;
1958
1959 for (i = 0; i < rs->rs_nrates; i++) {
1960 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1961 if (r < IEEE80211_HTRATE_MAXSIZE) { /* XXX? */
1962 /* NB: this assumes a particular implementation */
1963 setbit(frm, r);
1964 }
1965 }
1966}
1967
1968/*
1969 * Add body of an HTCAP information element.
1970 */
1971static uint8_t *
1972ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
1973{
1974#define ADDSHORT(frm, v) do { \
1975 frm[0] = (v) & 0xff; \
1976 frm[1] = (v) >> 8; \
1977 frm += 2; \
1978} while (0)
1979 struct ieee80211vap *vap = ni->ni_vap;
1980 uint16_t caps;
1981 int rxmax, density;
1982
1983 /* HT capabilities */
1984 caps = vap->iv_htcaps & 0xffff;
1985 /*
1986 * Note channel width depends on whether we are operating as
1987 * a sta or not. When operating as a sta we are generating
1988 * a request based on our desired configuration. Otherwise
1989 * we are operational and the channel attributes identify
1990 * how we've been setup (which might be different if a fixed
1991 * channel is specified).
1992 */
1993 if (vap->iv_opmode == IEEE80211_M_STA) {
1994 /* override 20/40 use based on config */
1995 if (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)
1996 caps |= IEEE80211_HTCAP_CHWIDTH40;
1997 else
1998 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
1999 /* use advertised setting (XXX locally constraint) */
2000 rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
2001 density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
2002 } else {
2003 /* override 20/40 use based on current channel */
2004 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2005 caps |= IEEE80211_HTCAP_CHWIDTH40;
2006 else
2007 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2008 rxmax = vap->iv_ampdu_rxmax;
2009 density = vap->iv_ampdu_density;
2010 }
2011 /* adjust short GI based on channel and config */
2012 if ((vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI20) == 0)
2013 caps &= ~IEEE80211_HTCAP_SHORTGI20;
2014 if ((vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI40) == 0 ||
2015 (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
2016 caps &= ~IEEE80211_HTCAP_SHORTGI40;
2017 ADDSHORT(frm, caps);
2018
2019 /* HT parameters */
2020 *frm = SM(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
2021 | SM(density, IEEE80211_HTCAP_MPDUDENSITY)
2022 ;
2023 frm++;
2024
2025 /* pre-zero remainder of ie */
2026 memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
2027 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
2028
2029 /* supported MCS set */
2030 /*
2031 * XXX it would better to get the rate set from ni_htrates
2032 * so we can restrict it but for sta mode ni_htrates isn't
2033 * setup when we're called to form an AssocReq frame so for
2034 * now we're restricted to the default HT rate set.
2035 */
2036 ieee80211_set_htrates(frm, &ieee80211_rateset_11n);
2037
2038 frm += sizeof(struct ieee80211_ie_htcap) -
2039 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
2040 return frm;
2041#undef ADDSHORT
2042}
2043
2044/*
2045 * Add 802.11n HT capabilities information element
2046 */
2047uint8_t *
2048ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
2049{
2050 frm[0] = IEEE80211_ELEMID_HTCAP;
2051 frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
2052 return ieee80211_add_htcap_body(frm + 2, ni);
2053}
2054
2055/*
2056 * Add Broadcom OUI wrapped standard HTCAP ie; this is
2057 * used for compatibility w/ pre-draft implementations.
2058 */
2059uint8_t *
2060ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
2061{
2062 frm[0] = IEEE80211_ELEMID_VENDOR;
2063 frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
2064 frm[2] = (BCM_OUI >> 0) & 0xff;
2065 frm[3] = (BCM_OUI >> 8) & 0xff;
2066 frm[4] = (BCM_OUI >> 16) & 0xff;
2067 frm[5] = BCM_OUI_HTCAP;
2068 return ieee80211_add_htcap_body(frm + 6, ni);
2069}
2070
2071/*
2072 * Construct the MCS bit mask of basic rates
2073 * for inclusion in an HT information element.
2074 */
2075static void
2076ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
2077{
2078 int i;
2079
2080 for (i = 0; i < rs->rs_nrates; i++) {
2081 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2082 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
2083 r < IEEE80211_HTRATE_MAXSIZE) {
2084 /* NB: this assumes a particular implementation */
2085 setbit(frm, r);
2086 }
2087 }
2088}
2089
2090/*
2091 * Update the HTINFO ie for a beacon frame.
2092 */
2093void
2094ieee80211_ht_update_beacon(struct ieee80211vap *vap,
2095 struct ieee80211_beacon_offsets *bo)
2096{
2097#define PROTMODE (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
2098 const struct ieee80211_channel *bsschan = vap->iv_bss->ni_chan;
2099 struct ieee80211com *ic = vap->iv_ic;
2100 struct ieee80211_ie_htinfo *ht =
2101 (struct ieee80211_ie_htinfo *) bo->bo_htinfo;
2102
2103 /* XXX only update on channel change */
2104 ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
2105 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
2106 if (IEEE80211_IS_CHAN_HT40U(bsschan))
2107 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2108 else if (IEEE80211_IS_CHAN_HT40D(bsschan))
2109 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2110 else
2111 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
2112 if (IEEE80211_IS_CHAN_HT40(bsschan))
2113 ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
2114
2115 /* protection mode */
2116 ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
2117
2118 /* XXX propagate to vendor ie's */
2119#undef PROTMODE
2120}
2121
2122/*
2123 * Add body of an HTINFO information element.
2124 *
2125 * NB: We don't use struct ieee80211_ie_htinfo because we can
2126 * be called to fillin both a standard ie and a compat ie that
2127 * has a vendor OUI at the front.
2128 */
2129static uint8_t *
2130ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
2131{
2132 struct ieee80211com *ic = ni->ni_ic;
2133
2134 /* pre-zero remainder of ie */
2135 memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
2136
2137 /* primary/control channel center */
2138 *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
2139
2140 frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
2141 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
2142 frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2143 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
2144 frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2145 else
2146 frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
2147 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2148 frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
2149
2150 frm[1] = ic->ic_curhtprotmode;
2151
2152 frm += 5;
2153
2154 /* basic MCS set */
2155 ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
2156 frm += sizeof(struct ieee80211_ie_htinfo) -
2157 __offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
2158 return frm;
2159}
2160
2161/*
2162 * Add 802.11n HT information information element.
2163 */
2164uint8_t *
2165ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
2166{
2167 frm[0] = IEEE80211_ELEMID_HTINFO;
2168 frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
2169 return ieee80211_add_htinfo_body(frm + 2, ni);
2170}
2171
2172/*
2173 * Add Broadcom OUI wrapped standard HTINFO ie; this is
2174 * used for compatibility w/ pre-draft implementations.
2175 */
2176uint8_t *
2177ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
2178{
2179 frm[0] = IEEE80211_ELEMID_VENDOR;
2180 frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
2181 frm[2] = (BCM_OUI >> 0) & 0xff;
2182 frm[3] = (BCM_OUI >> 8) & 0xff;
2183 frm[4] = (BCM_OUI >> 16) & 0xff;
2184 frm[5] = BCM_OUI_HTINFO;
2185 return ieee80211_add_htinfo_body(frm + 6, ni);
2186}
1749 vap->iv_stats.is_ampdu_stop_failed++;
1750 }
1751}
1752
1753/*
1754 * Transmit a BAR frame to the specified node. The
1755 * BAR contents are drawn from the supplied aggregation
1756 * state associated with the node.
1757 */
1758int
1759ieee80211_send_bar(struct ieee80211_node *ni,
1760 const struct ieee80211_tx_ampdu *tap)
1761{
1762#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
1763#define ADDSHORT(frm, v) do { \
1764 frm[0] = (v) & 0xff; \
1765 frm[1] = (v) >> 8; \
1766 frm += 2; \
1767} while (0)
1768 struct ieee80211vap *vap = ni->ni_vap;
1769 struct ieee80211com *ic = ni->ni_ic;
1770 struct ieee80211_frame_min *wh;
1771 struct mbuf *m;
1772 uint8_t *frm;
1773 uint16_t barctl, barseqctl;
1774 int tid, ret;
1775
1776 ieee80211_ref_node(ni);
1777
1778 m = ieee80211_getmgtframe(&frm,
1779 ic->ic_headroom + sizeof(struct ieee80211_frame_min),
1780 sizeof(struct ieee80211_ba_request)
1781 );
1782 if (m == NULL)
1783 senderr(ENOMEM, is_tx_nobuf);
1784
1785 wh = mtod(m, struct ieee80211_frame_min *);
1786 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 |
1787 IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
1788 wh->i_fc[1] = 0;
1789 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1790 IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1791
1792 tid = WME_AC_TO_TID(tap->txa_ac);
1793 barctl = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
1794 IEEE80211_BAPS_POLICY_IMMEDIATE :
1795 IEEE80211_BAPS_POLICY_DELAYED)
1796 | SM(tid, IEEE80211_BAPS_TID)
1797 | SM(tap->txa_wnd, IEEE80211_BAPS_BUFSIZ)
1798 ;
1799 barseqctl = SM(tap->txa_start, IEEE80211_BASEQ_START)
1800 | SM(0, IEEE80211_BASEQ_FRAG)
1801 ;
1802 ADDSHORT(frm, barctl);
1803 ADDSHORT(frm, barseqctl);
1804 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1805
1806 M_WME_SETAC(m, WME_AC_VO);
1807
1808 IEEE80211_NODE_STAT(ni, tx_mgmt); /* XXX tx_ctl? */
1809
1810 IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1811 ni, "send bar frame (tid %u start %u) on channel %u",
1812 tid, tap->txa_start, ieee80211_chan2ieee(ic, ic->ic_curchan));
1813
1814 return ic->ic_raw_xmit(ni, m, NULL);
1815bad:
1816 ieee80211_free_node(ni);
1817 return ret;
1818#undef ADDSHORT
1819#undef senderr
1820}
1821
1822/*
1823 * Send an action management frame. The arguments are stuff
1824 * into a frame without inspection; the caller is assumed to
1825 * prepare them carefully (e.g. based on the aggregation state).
1826 */
1827int
1828ieee80211_send_action(struct ieee80211_node *ni,
1829 int category, int action, uint16_t args[4])
1830{
1831#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
1832#define ADDSHORT(frm, v) do { \
1833 frm[0] = (v) & 0xff; \
1834 frm[1] = (v) >> 8; \
1835 frm += 2; \
1836} while (0)
1837 struct ieee80211vap *vap = ni->ni_vap;
1838 struct ieee80211com *ic = ni->ni_ic;
1839 struct mbuf *m;
1840 uint8_t *frm;
1841 uint16_t baparamset;
1842 int ret;
1843
1844 KASSERT(ni != NULL, ("null node"));
1845
1846 /*
1847 * Hold a reference on the node so it doesn't go away until after
1848 * the xmit is complete all the way in the driver. On error we
1849 * will remove our reference.
1850 */
1851 IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
1852 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1853 __func__, __LINE__,
1854 ni, ether_sprintf(ni->ni_macaddr),
1855 ieee80211_node_refcnt(ni)+1);
1856 ieee80211_ref_node(ni);
1857
1858 m = ieee80211_getmgtframe(&frm,
1859 ic->ic_headroom + sizeof(struct ieee80211_frame),
1860 sizeof(uint16_t) /* action+category */
1861 /* XXX may action payload */
1862 + sizeof(struct ieee80211_action_ba_addbaresponse)
1863 );
1864 if (m == NULL)
1865 senderr(ENOMEM, is_tx_nobuf);
1866
1867 *frm++ = category;
1868 *frm++ = action;
1869 switch (category) {
1870 case IEEE80211_ACTION_CAT_BA:
1871 switch (action) {
1872 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1873 IEEE80211_NOTE(vap,
1874 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1875 "send ADDBA request: dialogtoken %d "
1876 "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
1877 args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
1878 args[2], args[3]);
1879
1880 *frm++ = args[0]; /* dialog token */
1881 ADDSHORT(frm, args[1]); /* baparamset */
1882 ADDSHORT(frm, args[2]); /* batimeout */
1883 ADDSHORT(frm, args[3]); /* baseqctl */
1884 break;
1885 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1886 IEEE80211_NOTE(vap,
1887 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1888 "send ADDBA response: dialogtoken %d status %d "
1889 "baparamset 0x%x (tid %d) batimeout %d",
1890 args[0], args[1], args[2],
1891 MS(args[2], IEEE80211_BAPS_TID), args[3]);
1892
1893 *frm++ = args[0]; /* dialog token */
1894 ADDSHORT(frm, args[1]); /* statuscode */
1895 ADDSHORT(frm, args[2]); /* baparamset */
1896 ADDSHORT(frm, args[3]); /* batimeout */
1897 break;
1898 case IEEE80211_ACTION_BA_DELBA:
1899 /* XXX */
1900 baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
1901 | args[1]
1902 ;
1903 ADDSHORT(frm, baparamset);
1904 ADDSHORT(frm, args[2]); /* reason code */
1905
1906 IEEE80211_NOTE(vap,
1907 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1908 "send DELBA action: tid %d, initiator %d reason %d",
1909 args[0], args[1], args[2]);
1910 break;
1911 default:
1912 goto badaction;
1913 }
1914 break;
1915 case IEEE80211_ACTION_CAT_HT:
1916 switch (action) {
1917 case IEEE80211_ACTION_HT_TXCHWIDTH:
1918 IEEE80211_NOTE(vap,
1919 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1920 ni, "send HT txchwidth: width %d",
1921 IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20
1922 );
1923 *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
1924 IEEE80211_A_HT_TXCHWIDTH_2040 :
1925 IEEE80211_A_HT_TXCHWIDTH_20;
1926 break;
1927 default:
1928 goto badaction;
1929 }
1930 break;
1931 default:
1932 badaction:
1933 IEEE80211_NOTE(vap,
1934 IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1935 "%s: unsupported category %d action %d", __func__,
1936 category, action);
1937 senderr(EINVAL, is_tx_unknownmgt);
1938 /* NOTREACHED */
1939 }
1940 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1941
1942 return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION);
1943bad:
1944 ieee80211_free_node(ni);
1945 if (m != NULL)
1946 m_freem(m);
1947 return ret;
1948#undef ADDSHORT
1949#undef senderr
1950}
1951
1952/*
1953 * Construct the MCS bit mask for inclusion
1954 * in an HT information element.
1955 */
1956static void
1957ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1958{
1959 int i;
1960
1961 for (i = 0; i < rs->rs_nrates; i++) {
1962 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1963 if (r < IEEE80211_HTRATE_MAXSIZE) { /* XXX? */
1964 /* NB: this assumes a particular implementation */
1965 setbit(frm, r);
1966 }
1967 }
1968}
1969
1970/*
1971 * Add body of an HTCAP information element.
1972 */
1973static uint8_t *
1974ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
1975{
1976#define ADDSHORT(frm, v) do { \
1977 frm[0] = (v) & 0xff; \
1978 frm[1] = (v) >> 8; \
1979 frm += 2; \
1980} while (0)
1981 struct ieee80211vap *vap = ni->ni_vap;
1982 uint16_t caps;
1983 int rxmax, density;
1984
1985 /* HT capabilities */
1986 caps = vap->iv_htcaps & 0xffff;
1987 /*
1988 * Note channel width depends on whether we are operating as
1989 * a sta or not. When operating as a sta we are generating
1990 * a request based on our desired configuration. Otherwise
1991 * we are operational and the channel attributes identify
1992 * how we've been setup (which might be different if a fixed
1993 * channel is specified).
1994 */
1995 if (vap->iv_opmode == IEEE80211_M_STA) {
1996 /* override 20/40 use based on config */
1997 if (vap->iv_flags_ext & IEEE80211_FEXT_USEHT40)
1998 caps |= IEEE80211_HTCAP_CHWIDTH40;
1999 else
2000 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2001 /* use advertised setting (XXX locally constraint) */
2002 rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
2003 density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
2004 } else {
2005 /* override 20/40 use based on current channel */
2006 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2007 caps |= IEEE80211_HTCAP_CHWIDTH40;
2008 else
2009 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2010 rxmax = vap->iv_ampdu_rxmax;
2011 density = vap->iv_ampdu_density;
2012 }
2013 /* adjust short GI based on channel and config */
2014 if ((vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI20) == 0)
2015 caps &= ~IEEE80211_HTCAP_SHORTGI20;
2016 if ((vap->iv_flags_ext & IEEE80211_FEXT_SHORTGI40) == 0 ||
2017 (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
2018 caps &= ~IEEE80211_HTCAP_SHORTGI40;
2019 ADDSHORT(frm, caps);
2020
2021 /* HT parameters */
2022 *frm = SM(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
2023 | SM(density, IEEE80211_HTCAP_MPDUDENSITY)
2024 ;
2025 frm++;
2026
2027 /* pre-zero remainder of ie */
2028 memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
2029 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
2030
2031 /* supported MCS set */
2032 /*
2033 * XXX it would better to get the rate set from ni_htrates
2034 * so we can restrict it but for sta mode ni_htrates isn't
2035 * setup when we're called to form an AssocReq frame so for
2036 * now we're restricted to the default HT rate set.
2037 */
2038 ieee80211_set_htrates(frm, &ieee80211_rateset_11n);
2039
2040 frm += sizeof(struct ieee80211_ie_htcap) -
2041 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
2042 return frm;
2043#undef ADDSHORT
2044}
2045
2046/*
2047 * Add 802.11n HT capabilities information element
2048 */
2049uint8_t *
2050ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
2051{
2052 frm[0] = IEEE80211_ELEMID_HTCAP;
2053 frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
2054 return ieee80211_add_htcap_body(frm + 2, ni);
2055}
2056
2057/*
2058 * Add Broadcom OUI wrapped standard HTCAP ie; this is
2059 * used for compatibility w/ pre-draft implementations.
2060 */
2061uint8_t *
2062ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
2063{
2064 frm[0] = IEEE80211_ELEMID_VENDOR;
2065 frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
2066 frm[2] = (BCM_OUI >> 0) & 0xff;
2067 frm[3] = (BCM_OUI >> 8) & 0xff;
2068 frm[4] = (BCM_OUI >> 16) & 0xff;
2069 frm[5] = BCM_OUI_HTCAP;
2070 return ieee80211_add_htcap_body(frm + 6, ni);
2071}
2072
2073/*
2074 * Construct the MCS bit mask of basic rates
2075 * for inclusion in an HT information element.
2076 */
2077static void
2078ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
2079{
2080 int i;
2081
2082 for (i = 0; i < rs->rs_nrates; i++) {
2083 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2084 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
2085 r < IEEE80211_HTRATE_MAXSIZE) {
2086 /* NB: this assumes a particular implementation */
2087 setbit(frm, r);
2088 }
2089 }
2090}
2091
2092/*
2093 * Update the HTINFO ie for a beacon frame.
2094 */
2095void
2096ieee80211_ht_update_beacon(struct ieee80211vap *vap,
2097 struct ieee80211_beacon_offsets *bo)
2098{
2099#define PROTMODE (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
2100 const struct ieee80211_channel *bsschan = vap->iv_bss->ni_chan;
2101 struct ieee80211com *ic = vap->iv_ic;
2102 struct ieee80211_ie_htinfo *ht =
2103 (struct ieee80211_ie_htinfo *) bo->bo_htinfo;
2104
2105 /* XXX only update on channel change */
2106 ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
2107 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
2108 if (IEEE80211_IS_CHAN_HT40U(bsschan))
2109 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2110 else if (IEEE80211_IS_CHAN_HT40D(bsschan))
2111 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2112 else
2113 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
2114 if (IEEE80211_IS_CHAN_HT40(bsschan))
2115 ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
2116
2117 /* protection mode */
2118 ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
2119
2120 /* XXX propagate to vendor ie's */
2121#undef PROTMODE
2122}
2123
2124/*
2125 * Add body of an HTINFO information element.
2126 *
2127 * NB: We don't use struct ieee80211_ie_htinfo because we can
2128 * be called to fillin both a standard ie and a compat ie that
2129 * has a vendor OUI at the front.
2130 */
2131static uint8_t *
2132ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
2133{
2134 struct ieee80211com *ic = ni->ni_ic;
2135
2136 /* pre-zero remainder of ie */
2137 memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
2138
2139 /* primary/control channel center */
2140 *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
2141
2142 frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
2143 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
2144 frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2145 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
2146 frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2147 else
2148 frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
2149 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2150 frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
2151
2152 frm[1] = ic->ic_curhtprotmode;
2153
2154 frm += 5;
2155
2156 /* basic MCS set */
2157 ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
2158 frm += sizeof(struct ieee80211_ie_htinfo) -
2159 __offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
2160 return frm;
2161}
2162
2163/*
2164 * Add 802.11n HT information information element.
2165 */
2166uint8_t *
2167ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
2168{
2169 frm[0] = IEEE80211_ELEMID_HTINFO;
2170 frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
2171 return ieee80211_add_htinfo_body(frm + 2, ni);
2172}
2173
2174/*
2175 * Add Broadcom OUI wrapped standard HTINFO ie; this is
2176 * used for compatibility w/ pre-draft implementations.
2177 */
2178uint8_t *
2179ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
2180{
2181 frm[0] = IEEE80211_ELEMID_VENDOR;
2182 frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
2183 frm[2] = (BCM_OUI >> 0) & 0xff;
2184 frm[3] = (BCM_OUI >> 8) & 0xff;
2185 frm[4] = (BCM_OUI >> 16) & 0xff;
2186 frm[5] = BCM_OUI_HTINFO;
2187 return ieee80211_add_htinfo_body(frm + 6, ni);
2188}