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: src/sys/net80211/ieee80211_ht.c,v 1.31 2008/10/26 00:43:11 sam Exp $");
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
56 const 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
75 static 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 */
83 int ieee80211_ampdu_age = -1; /* threshold for ampdu reorder q (ms) */
84 #endif
85 int ieee80211_recv_bar_ena = 1;
86 int ieee80211_addba_timeout = -1; /* timeout waiting for ADDBA response */
87 int ieee80211_addba_backoff = -1; /* backoff after max ADDBA requests */
88 int ieee80211_addba_maxtries = 3; /* max ADDBA requests before backoff */
89 int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
90 int ieee80211_bar_maxtries = 50; /* max BAR requests before DELBA */
91
92 /*
93 * Setup HT parameters that depends on the clock frequency.
94 */
95 static void
96 ieee80211_ht_setup(void)
97 {
98 #ifdef IEEE80211_AMPDU_AGE
99 ieee80211_ampdu_age = msecs_to_ticks(500);
100 #endif
101 ieee80211_addba_timeout = msecs_to_ticks(250);
102 ieee80211_addba_backoff = msecs_to_ticks(10*1000);
103 ieee80211_bar_timeout = msecs_to_ticks(250);
104 }
105 SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_setup, NULL);
106
107 static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
108 struct ieee80211_tx_ampdu *tap);
109 static int ieee80211_addba_request(struct ieee80211_node *ni,
110 struct ieee80211_tx_ampdu *tap,
111 int dialogtoken, int baparamset, int batimeout);
112 static int ieee80211_addba_response(struct ieee80211_node *ni,
113 struct ieee80211_tx_ampdu *tap,
114 int code, int baparamset, int batimeout);
115 static void ieee80211_addba_stop(struct ieee80211_node *ni,
116 struct ieee80211_tx_ampdu *tap);
117 static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
118 const uint8_t *frm, const uint8_t *efrm);
119 static void ieee80211_bar_response(struct ieee80211_node *ni,
120 struct ieee80211_tx_ampdu *tap, int status);
121 static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
122 static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
123
124 void
125 ieee80211_ht_attach(struct ieee80211com *ic)
126 {
127 /* setup default aggregation policy */
128 ic->ic_recv_action = ieee80211_aggr_recv_action;
129 ic->ic_send_action = ieee80211_send_action;
130 ic->ic_ampdu_enable = ieee80211_ampdu_enable;
131 ic->ic_addba_request = ieee80211_addba_request;
132 ic->ic_addba_response = ieee80211_addba_response;
133 ic->ic_addba_stop = ieee80211_addba_stop;
134 ic->ic_bar_response = ieee80211_bar_response;
135
136 ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
137 ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
138 }
139
140 void
141 ieee80211_ht_detach(struct ieee80211com *ic)
142 {
143 }
144
145 void
146 ieee80211_ht_vattach(struct ieee80211vap *vap)
147 {
148
149 /* driver can override defaults */
150 vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
151 vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
152 vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
153 vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
154 /* tx aggregation traffic thresholds */
155 vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
156 vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
157 vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
158 vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
159
160 if (vap->iv_htcaps & IEEE80211_HTC_HT) {
161 /*
162 * Device is HT capable; enable all HT-related
163 * facilities by default.
164 * XXX these choices may be too aggressive.
165 */
166 vap->iv_flags_ext |= IEEE80211_FEXT_HT
167 | IEEE80211_FEXT_HTCOMPAT
168 ;
169 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
170 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI20;
171 /* XXX infer from channel list? */
172 if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
173 vap->iv_flags_ext |= IEEE80211_FEXT_USEHT40;
174 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
175 vap->iv_flags_ext |= IEEE80211_FEXT_SHORTGI40;
176 }
177 /* enable RIFS if capable */
178 if (vap->iv_htcaps & IEEE80211_HTC_RIFS)
179 vap->iv_flags_ext |= IEEE80211_FEXT_RIFS;
180
181 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
182 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
183 if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
184 vap->iv_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
185 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
186 if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
187 vap->iv_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
188 }
189 /* NB: disable default legacy WDS, too many issues right now */
190 if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
191 vap->iv_flags_ext &= ~IEEE80211_FEXT_HT;
192 }
193
194 void
195 ieee80211_ht_vdetach(struct ieee80211vap *vap)
196 {
197 }
198
199 static void
200 ht_announce(struct ieee80211com *ic, int mode,
201 const struct ieee80211_htrateset *rs)
202 {
203 struct ifnet *ifp = ic->ic_ifp;
204 int i, rate, mword;
205
206 if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]);
207 for (i = 0; i < rs->rs_nrates; i++) {
208 mword = ieee80211_rate2media(ic,
209 rs->rs_rates[i] | IEEE80211_RATE_MCS, mode);
210 if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
211 continue;
212 rate = ieee80211_htrates[rs->rs_rates[i]].ht40_rate_400ns;
213 printf("%s%d%sMbps", (i != 0 ? " " : ""),
214 rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
215 }
216 printf("\n");
217 }
218
219 void
220 ieee80211_ht_announce(struct ieee80211com *ic)
221 {
222 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
223 ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n);
224 if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
225 ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n);
226 }
227
228 const struct ieee80211_htrateset *
229 ieee80211_get_suphtrates(struct ieee80211com *ic,
230 const struct ieee80211_channel *c)
231 {
232 return &ieee80211_rateset_11n;
233 }
234
235 /*
236 * Receive processing.
237 */
238
239 /*
240 * Decap the encapsulated A-MSDU frames and dispatch all but
241 * the last for delivery. The last frame is returned for
242 * delivery via the normal path.
243 */
244 struct mbuf *
245 ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
246 {
247 struct ieee80211vap *vap = ni->ni_vap;
248 int framelen;
249 struct mbuf *n;
250
251 /* discard 802.3 header inserted by ieee80211_decap */
252 m_adj(m, sizeof(struct ether_header));
253
254 vap->iv_stats.is_amsdu_decap++;
255
256 for (;;) {
257 /*
258 * Decap the first frame, bust it apart from the
259 * remainder and deliver. We leave the last frame
260 * delivery to the caller (for consistency with other
261 * code paths, could also do it here).
262 */
263 m = ieee80211_decap1(m, &framelen);
264 if (m == NULL) {
265 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
266 ni->ni_macaddr, "a-msdu", "%s", "decap failed");
267 vap->iv_stats.is_amsdu_tooshort++;
268 return NULL;
269 }
270 if (m->m_pkthdr.len == framelen)
271 break;
272 n = m_split(m, framelen, M_NOWAIT);
273 if (n == NULL) {
274 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
275 ni->ni_macaddr, "a-msdu",
276 "%s", "unable to split encapsulated frames");
277 vap->iv_stats.is_amsdu_split++;
278 m_freem(m); /* NB: must reclaim */
279 return NULL;
280 }
281 vap->iv_deliver_data(vap, ni, m);
282
283 /*
284 * Remove frame contents; each intermediate frame
285 * is required to be aligned to a 4-byte boundary.
286 */
287 m = n;
288 m_adj(m, roundup2(framelen, 4) - framelen); /* padding */
289 }
290 return m; /* last delivered by caller */
291 }
292
293 /*
294 * Purge all frames in the A-MPDU re-order queue.
295 */
296 static void
297 ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
298 {
299 struct mbuf *m;
300 int i;
301
302 for (i = 0; i < rap->rxa_wnd; i++) {
303 m = rap->rxa_m[i];
304 if (m != NULL) {
305 rap->rxa_m[i] = NULL;
306 rap->rxa_qbytes -= m->m_pkthdr.len;
307 m_freem(m);
308 if (--rap->rxa_qframes == 0)
309 break;
310 }
311 }
312 KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
313 ("lost %u data, %u frames on ampdu rx q",
314 rap->rxa_qbytes, rap->rxa_qframes));
315 }
316
317 /*
318 * Start A-MPDU rx/re-order processing for the specified TID.
319 */
320 static void
321 ampdu_rx_start(struct ieee80211_rx_ampdu *rap, int bufsiz, int start)
322 {
323 if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
324 /*
325 * AMPDU previously setup and not terminated with a DELBA,
326 * flush the reorder q's in case anything remains.
327 */
328 ampdu_rx_purge(rap);
329 }
330 memset(rap, 0, sizeof(*rap));
331 rap->rxa_wnd = (bufsiz == 0) ?
332 IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
333 rap->rxa_start = start;
334 rap->rxa_flags |= IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
335 }
336
337 /*
338 * Stop A-MPDU rx processing for the specified TID.
339 */
340 static void
341 ampdu_rx_stop(struct ieee80211_rx_ampdu *rap)
342 {
343 ampdu_rx_purge(rap);
344 rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND);
345 }
346
347 /*
348 * Dispatch a frame from the A-MPDU reorder queue. The
349 * frame is fed back into ieee80211_input marked with an
350 * M_AMPDU_MPDU flag so it doesn't come back to us (it also
351 * permits ieee80211_input to optimize re-processing).
352 */
353 static __inline void
354 ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
355 {
356 m->m_flags |= M_AMPDU_MPDU; /* bypass normal processing */
357 /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU_MPDU set */
358 (void) ieee80211_input(ni, m, 0, 0, 0);
359 }
360
361 /*
362 * Dispatch as many frames as possible from the re-order queue.
363 * Frames will always be "at the front"; we process all frames
364 * up to the first empty slot in the window. On completion we
365 * cleanup state if there are still pending frames in the current
366 * BA window. We assume the frame at slot 0 is already handled
367 * by the caller; we always start at slot 1.
368 */
369 static void
370 ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
371 {
372 struct ieee80211vap *vap = ni->ni_vap;
373 struct mbuf *m;
374 int i;
375
376 /* flush run of frames */
377 for (i = 1; i < rap->rxa_wnd; i++) {
378 m = rap->rxa_m[i];
379 if (m == NULL)
380 break;
381 rap->rxa_m[i] = NULL;
382 rap->rxa_qbytes -= m->m_pkthdr.len;
383 rap->rxa_qframes--;
384
385 ampdu_dispatch(ni, m);
386 }
387 /*
388 * If frames remain, copy the mbuf pointers down so
389 * they correspond to the offsets in the new window.
390 */
391 if (rap->rxa_qframes != 0) {
392 int n = rap->rxa_qframes, j;
393 for (j = i+1; j < rap->rxa_wnd; j++) {
394 if (rap->rxa_m[j] != NULL) {
395 rap->rxa_m[j-i] = rap->rxa_m[j];
396 rap->rxa_m[j] = NULL;
397 if (--n == 0)
398 break;
399 }
400 }
401 KASSERT(n == 0, ("lost %d frames", n));
402 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
403 }
404 /*
405 * Adjust the start of the BA window to
406 * reflect the frames just dispatched.
407 */
408 rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
409 vap->iv_stats.is_ampdu_rx_oor += i;
410 }
411
412 #ifdef IEEE80211_AMPDU_AGE
413 /*
414 * Dispatch all frames in the A-MPDU re-order queue.
415 */
416 static void
417 ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
418 {
419 struct ieee80211vap *vap = ni->ni_vap;
420 struct mbuf *m;
421 int i;
422
423 for (i = 0; i < rap->rxa_wnd; i++) {
424 m = rap->rxa_m[i];
425 if (m == NULL)
426 continue;
427 rap->rxa_m[i] = NULL;
428 rap->rxa_qbytes -= m->m_pkthdr.len;
429 rap->rxa_qframes--;
430 vap->iv_stats.is_ampdu_rx_oor++;
431
432 ampdu_dispatch(ni, m);
433 if (rap->rxa_qframes == 0)
434 break;
435 }
436 }
437 #endif /* IEEE80211_AMPDU_AGE */
438
439 /*
440 * Dispatch all frames in the A-MPDU re-order queue
441 * preceding the specified sequence number. This logic
442 * handles window moves due to a received MSDU or BAR.
443 */
444 static void
445 ampdu_rx_flush_upto(struct ieee80211_node *ni,
446 struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
447 {
448 struct ieee80211vap *vap = ni->ni_vap;
449 struct mbuf *m;
450 ieee80211_seq seqno;
451 int i;
452
453 /*
454 * Flush any complete MSDU's with a sequence number lower
455 * than winstart. Gaps may exist. Note that we may actually
456 * dispatch frames past winstart if a run continues; this is
457 * an optimization that avoids having to do a separate pass
458 * to dispatch frames after moving the BA window start.
459 */
460 seqno = rap->rxa_start;
461 for (i = 0; i < rap->rxa_wnd; i++) {
462 m = rap->rxa_m[i];
463 if (m != NULL) {
464 rap->rxa_m[i] = NULL;
465 rap->rxa_qbytes -= m->m_pkthdr.len;
466 rap->rxa_qframes--;
467 vap->iv_stats.is_ampdu_rx_oor++;
468
469 ampdu_dispatch(ni, m);
470 } else {
471 if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
472 break;
473 }
474 seqno = IEEE80211_SEQ_INC(seqno);
475 }
476 /*
477 * If frames remain, copy the mbuf pointers down so
478 * they correspond to the offsets in the new window.
479 */
480 if (rap->rxa_qframes != 0) {
481 int n = rap->rxa_qframes, j;
482
483 /* NB: this loop assumes i > 0 and/or rxa_m[0] is NULL */
484 KASSERT(rap->rxa_m[0] == NULL,
485 ("%s: BA window slot 0 occupied", __func__));
486 for (j = i+1; j < rap->rxa_wnd; j++) {
487 if (rap->rxa_m[j] != NULL) {
488 rap->rxa_m[j-i] = rap->rxa_m[j];
489 rap->rxa_m[j] = NULL;
490 if (--n == 0)
491 break;
492 }
493 }
494 KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
495 "BA win <%d:%d> winstart %d",
496 __func__, n, rap->rxa_qframes, i, rap->rxa_start,
497 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
498 winstart));
499 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
500 }
501 /*
502 * Move the start of the BA window; we use the
503 * sequence number of the last MSDU that was
504 * passed up the stack+1 or winstart if stopped on
505 * a gap in the reorder buffer.
506 */
507 rap->rxa_start = seqno;
508 }
509
510 /*
511 * Process a received QoS data frame for an HT station. Handle
512 * A-MPDU reordering: if this frame is received out of order
513 * and falls within the BA window hold onto it. Otherwise if
514 * this frame completes a run, flush any pending frames. We
515 * return 1 if the frame is consumed. A 0 is returned if
516 * the frame should be processed normally by the caller.
517 */
518 int
519 ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
520 {
521 #define IEEE80211_FC0_QOSDATA \
522 (IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
523 #define PROCESS 0 /* caller should process frame */
524 #define CONSUMED 1 /* frame consumed, caller does nothing */
525 struct ieee80211vap *vap = ni->ni_vap;
526 struct ieee80211_qosframe *wh;
527 struct ieee80211_rx_ampdu *rap;
528 ieee80211_seq rxseq;
529 uint8_t tid;
530 int off;
531
532 KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
533 ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
534 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
535
536 /* NB: m_len known to be sufficient */
537 wh = mtod(m, struct ieee80211_qosframe *);
538 if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) {
539 /*
540 * Not QoS data, shouldn't get here but just
541 * return it to the caller for processing.
542 */
543 return PROCESS;
544 }
545 if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
546 tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
547 else
548 tid = wh->i_qos[0];
549 tid &= IEEE80211_QOS_TID;
550 rap = &ni->ni_rx_ampdu[tid];
551 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
552 /*
553 * No ADDBA request yet, don't touch.
554 */
555 return PROCESS;
556 }
557 rxseq = le16toh(*(uint16_t *)wh->i_seq);
558 if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
559 /*
560 * Fragments are not allowed; toss.
561 */
562 IEEE80211_DISCARD_MAC(vap,
563 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
564 "A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
565 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
566 vap->iv_stats.is_ampdu_rx_drop++;
567 IEEE80211_NODE_STAT(ni, rx_drop);
568 m_freem(m);
569 return CONSUMED;
570 }
571 rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
572 rap->rxa_nframes++;
573 again:
574 if (rxseq == rap->rxa_start) {
575 /*
576 * First frame in window.
577 */
578 if (rap->rxa_qframes != 0) {
579 /*
580 * Dispatch as many packets as we can.
581 */
582 KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
583 ampdu_dispatch(ni, m);
584 ampdu_rx_dispatch(rap, ni);
585 return CONSUMED;
586 } else {
587 /*
588 * In order; advance window and notify
589 * caller to dispatch directly.
590 */
591 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
592 return PROCESS;
593 }
594 }
595 /*
596 * Frame is out of order; store if in the BA window.
597 */
598 /* calculate offset in BA window */
599 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
600 if (off < rap->rxa_wnd) {
601 /*
602 * Common case (hopefully): in the BA window.
603 * Sec 9.10.7.6 a) (D2.04 p.118 line 47)
604 */
605 #ifdef IEEE80211_AMPDU_AGE
606 /*
607 * Check for frames sitting too long in the reorder queue.
608 * This should only ever happen if frames are not delivered
609 * without the sender otherwise notifying us (e.g. with a
610 * BAR to move the window). Typically this happens because
611 * of vendor bugs that cause the sequence number to jump.
612 * When this happens we get a gap in the reorder queue that
613 * leaves frame sitting on the queue until they get pushed
614 * out due to window moves. When the vendor does not send
615 * BAR this move only happens due to explicit packet sends
616 *
617 * NB: we only track the time of the oldest frame in the
618 * reorder q; this means that if we flush we might push
619 * frames that still "new"; if this happens then subsequent
620 * frames will result in BA window moves which cost something
621 * but is still better than a big throughput dip.
622 */
623 if (rap->rxa_qframes != 0) {
624 /* XXX honor batimeout? */
625 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
626 /*
627 * Too long since we received the first
628 * frame; flush the reorder buffer.
629 */
630 if (rap->rxa_qframes != 0) {
631 vap->iv_stats.is_ampdu_rx_age +=
632 rap->rxa_qframes;
633 ampdu_rx_flush(ni, rap);
634 }
635 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
636 return PROCESS;
637 }
638 } else {
639 /*
640 * First frame, start aging timer.
641 */
642 rap->rxa_age = ticks;
643 }
644 #endif /* IEEE80211_AMPDU_AGE */
645 /* save packet */
646 if (rap->rxa_m[off] == NULL) {
647 rap->rxa_m[off] = m;
648 rap->rxa_qframes++;
649 rap->rxa_qbytes += m->m_pkthdr.len;
650 vap->iv_stats.is_ampdu_rx_reorder++;
651 } else {
652 IEEE80211_DISCARD_MAC(vap,
653 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
654 ni->ni_macaddr, "a-mpdu duplicate",
655 "seqno %u tid %u BA win <%u:%u>",
656 rxseq, tid, rap->rxa_start,
657 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
658 vap->iv_stats.is_rx_dup++;
659 IEEE80211_NODE_STAT(ni, rx_dup);
660 m_freem(m);
661 }
662 return CONSUMED;
663 }
664 if (off < IEEE80211_SEQ_BA_RANGE) {
665 /*
666 * Outside the BA window, but within range;
667 * flush the reorder q and move the window.
668 * Sec 9.10.7.6 b) (D2.04 p.118 line 60)
669 */
670 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
671 "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
672 rap->rxa_start,
673 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
674 rap->rxa_qframes, rxseq, tid);
675 vap->iv_stats.is_ampdu_rx_move++;
676
677 /*
678 * The spec says to flush frames up to but not including:
679 * WinStart_B = rxseq - rap->rxa_wnd + 1
680 * Then insert the frame or notify the caller to process
681 * it immediately. We can safely do this by just starting
682 * over again because we know the frame will now be within
683 * the BA window.
684 */
685 /* NB: rxa_wnd known to be >0 */
686 ampdu_rx_flush_upto(ni, rap,
687 IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
688 goto again;
689 } else {
690 /*
691 * Outside the BA window and out of range; toss.
692 * Sec 9.10.7.6 c) (D2.04 p.119 line 16)
693 */
694 IEEE80211_DISCARD_MAC(vap,
695 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
696 "MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
697 rap->rxa_start,
698 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
699 rap->rxa_qframes, rxseq, tid,
700 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
701 vap->iv_stats.is_ampdu_rx_drop++;
702 IEEE80211_NODE_STAT(ni, rx_drop);
703 m_freem(m);
704 return CONSUMED;
705 }
706 #undef CONSUMED
707 #undef PROCESS
708 #undef IEEE80211_FC0_QOSDATA
709 }
710
711 /*
712 * Process a BAR ctl frame. Dispatch all frames up to
713 * the sequence number of the frame. If this frame is
714 * out of range it's discarded.
715 */
716 void
717 ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
718 {
719 struct ieee80211vap *vap = ni->ni_vap;
720 struct ieee80211_frame_bar *wh;
721 struct ieee80211_rx_ampdu *rap;
722 ieee80211_seq rxseq;
723 int tid, off;
724
725 if (!ieee80211_recv_bar_ena) {
726 #if 0
727 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
728 ni->ni_macaddr, "BAR", "%s", "processing disabled");
729 #endif
730 vap->iv_stats.is_ampdu_bar_bad++;
731 return;
732 }
733 wh = mtod(m0, struct ieee80211_frame_bar *);
734 /* XXX check basic BAR */
735 tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
736 rap = &ni->ni_rx_ampdu[tid];
737 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
738 /*
739 * No ADDBA request yet, don't touch.
740 */
741 IEEE80211_DISCARD_MAC(vap,
742 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
743 ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
744 vap->iv_stats.is_ampdu_bar_bad++;
745 return;
746 }
747 vap->iv_stats.is_ampdu_bar_rx++;
748 rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
749 if (rxseq == rap->rxa_start)
750 return;
751 /* calculate offset in BA window */
752 off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
753 if (off < IEEE80211_SEQ_BA_RANGE) {
754 /*
755 * Flush the reorder q up to rxseq and move the window.
756 * Sec 9.10.7.6 a) (D2.04 p.119 line 22)
757 */
758 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
759 "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
760 rap->rxa_start,
761 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
762 rap->rxa_qframes, rxseq, tid);
763 vap->iv_stats.is_ampdu_bar_move++;
764
765 ampdu_rx_flush_upto(ni, rap, rxseq);
766 if (off >= rap->rxa_wnd) {
767 /*
768 * BAR specifies a window start to the right of BA
769 * window; we must move it explicitly since
770 * ampdu_rx_flush_upto will not.
771 */
772 rap->rxa_start = rxseq;
773 }
774 } else {
775 /*
776 * Out of range; toss.
777 * Sec 9.10.7.6 b) (D2.04 p.119 line 41)
778 */
779 IEEE80211_DISCARD_MAC(vap,
780 IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
781 "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
782 rap->rxa_start,
783 IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
784 rap->rxa_qframes, rxseq, tid,
785 wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
786 vap->iv_stats.is_ampdu_bar_oow++;
787 IEEE80211_NODE_STAT(ni, rx_drop);
788 }
789 }
790
791 /*
792 * Setup HT-specific state in a node. Called only
793 * when HT use is negotiated so we don't do extra
794 * work for temporary and/or legacy sta's.
795 */
796 void
797 ieee80211_ht_node_init(struct ieee80211_node *ni)
798 {
799 struct ieee80211_tx_ampdu *tap;
800 int ac;
801
802 if (ni->ni_flags & IEEE80211_NODE_HT) {
803 /*
804 * Clean AMPDU state on re-associate. This handles the case
805 * where a station leaves w/o notifying us and then returns
806 * before node is reaped for inactivity.
807 */
808 ieee80211_ht_node_cleanup(ni);
809 }
810 for (ac = 0; ac < WME_NUM_AC; ac++) {
811 tap = &ni->ni_tx_ampdu[ac];
812 tap->txa_ac = ac;
813 tap->txa_ni = ni;
814 /* NB: further initialization deferred */
815 }
816 ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
817 }
818
819 /*
820 * Cleanup HT-specific state in a node. Called only
821 * when HT use has been marked.
822 */
823 void
824 ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
825 {
826 int i;
827
828 KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
829
830 /* XXX optimize this */
831 for (i = 0; i < WME_NUM_AC; i++) {
832 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
833 if (tap->txa_flags & IEEE80211_AGGR_SETUP)
834 ampdu_tx_stop(tap);
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 */
846 void
847 ieee80211_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
882 static struct ieee80211_channel *
883 findhtchan(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 */
892 struct ieee80211_channel *
893 ieee80211_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 */
931 void
932 ieee80211_ht_wds_init(struct ieee80211_node *ni)
933 {
|