]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_ht.c
This commit was generated by cvs2svn to compensate for changes in r171827,
[FreeBSD/FreeBSD.git] / sys / net80211 / ieee80211_ht.c
1 /*-
2  * Copyright (c) 2007 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$");
29 #endif
30
31 /*
32  * IEEE 802.11n protocol support.
33  */
34
35 #include "opt_inet.h"
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h> 
40 #include <sys/endian.h>
41  
42 #include <sys/socket.h>
43
44 #include <net/if.h>
45 #include <net/if_media.h>
46 #include <net/ethernet.h>
47
48 #include <net80211/ieee80211_var.h>
49
50 /* define here, used throughout file */
51 #define MS(_v, _f)      (((_v) & _f) >> _f##_S)
52 #define SM(_v, _f)      (((_v) << _f##_S) & _f)
53
54 /* XXX need max array size */
55 const int ieee80211_htrates[16] = {
56         13,             /* IFM_IEEE80211_MCS0 */
57         26,             /* IFM_IEEE80211_MCS1 */
58         39,             /* IFM_IEEE80211_MCS2 */
59         52,             /* IFM_IEEE80211_MCS3 */
60         78,             /* IFM_IEEE80211_MCS4 */
61         104,            /* IFM_IEEE80211_MCS5 */
62         117,            /* IFM_IEEE80211_MCS6 */
63         130,            /* IFM_IEEE80211_MCS7 */
64         26,             /* IFM_IEEE80211_MCS8 */
65         52,             /* IFM_IEEE80211_MCS9 */
66         78,             /* IFM_IEEE80211_MCS10 */
67         104,            /* IFM_IEEE80211_MCS11 */
68         156,            /* IFM_IEEE80211_MCS12 */
69         208,            /* IFM_IEEE80211_MCS13 */
70         234,            /* IFM_IEEE80211_MCS14 */
71         260,            /* IFM_IEEE80211_MCS15 */
72 };
73
74 static const struct ieee80211_htrateset ieee80211_rateset_11n =
75         { 16, {
76         /* MCS: 6.5   13 19.5   26   39  52 58.5  65  13  26 */
77                   0,   1,   2,   3,   4,  5,   6,  7,  8,  9,
78         /*       39   52   78  104  117, 130 */
79                  10,  11,  12,  13,  14,  15 }
80         };
81
82 #define IEEE80211_AGGR_TIMEOUT  msecs_to_ticks(250)
83 #define IEEE80211_AGGR_MINRETRY msecs_to_ticks(10*1000)
84 #define IEEE80211_AGGR_MAXTRIES 3
85
86 static int ieee80211_addba_request(struct ieee80211_node *ni,
87         struct ieee80211_tx_ampdu *tap,
88         int dialogtoken, int baparamset, int batimeout);
89 static int ieee80211_addba_response(struct ieee80211_node *ni,
90         struct ieee80211_tx_ampdu *tap,
91         int code, int baparamset, int batimeout);
92 static void ieee80211_addba_stop(struct ieee80211_node *ni,
93         struct ieee80211_tx_ampdu *tap);
94 static void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
95         const uint8_t *frm, const uint8_t *efrm);
96
97 void
98 ieee80211_ht_attach(struct ieee80211com *ic)
99 {
100
101         ic->ic_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
102         ic->ic_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
103         ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
104
105         ic->ic_amsdu_limit = IEEE80211_HTCAP_MAXAMSDU_3839;
106
107         /* setup default aggregation policy */
108         ic->ic_recv_action = ieee80211_aggr_recv_action;
109         ic->ic_send_action = ieee80211_send_action;
110         ic->ic_addba_request = ieee80211_addba_request;
111         ic->ic_addba_response = ieee80211_addba_response;
112         ic->ic_addba_stop = ieee80211_addba_stop;
113
114         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
115             isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
116                 /*
117                  * There are HT channels in the channel list; enable
118                  * all HT-related facilities by default.
119                  * XXX these choices may be too aggressive.
120                  */
121                 ic->ic_flags_ext |= IEEE80211_FEXT_HT
122                                  |  IEEE80211_FEXT_HTCOMPAT
123                                  ;
124                 if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)
125                         ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
126                 /* XXX infer from channel list */
127                 if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
128                         ic->ic_flags_ext |= IEEE80211_FEXT_USEHT40;
129                         if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)
130                                 ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
131                 }
132                 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
133                 ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
134                 if (ic->ic_htcaps & IEEE80211_HTC_AMPDU)
135                         ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
136                 ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
137                 if (ic->ic_htcaps & IEEE80211_HTC_AMSDU)
138                         ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
139         }
140 }
141
142 void
143 ieee80211_ht_detach(struct ieee80211com *ic)
144 {
145 }
146
147 static void
148 ht_announce(struct ieee80211com *ic, int mode,
149         const struct ieee80211_htrateset *rs)
150 {
151         struct ifnet *ifp = ic->ic_ifp;
152         int i, rate, mword;
153
154         if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]);
155         for (i = 0; i < rs->rs_nrates; i++) {
156                 mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
157                 if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
158                         continue;
159                 rate = ieee80211_htrates[rs->rs_rates[i]];
160                 printf("%s%d%sMbps", (i != 0 ? " " : ""),
161                     rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
162         }
163         printf("\n");
164 }
165
166 void
167 ieee80211_ht_announce(struct ieee80211com *ic)
168 {
169         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
170                 ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n);
171         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
172                 ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n);
173 }
174
175 const struct ieee80211_htrateset *
176 ieee80211_get_suphtrates(struct ieee80211com *ic,
177         const struct ieee80211_channel *c)
178 {
179         if (IEEE80211_IS_CHAN_HT(c))
180                 return &ieee80211_rateset_11n;
181         /* XXX what's the right thing to do here? */
182         return (const struct ieee80211_htrateset *)
183                 ieee80211_get_suprates(ic, c);
184 }
185
186 /*
187  * Receive processing.
188  */
189
190 /*
191  * Decap the encapsulated A-MSDU frames and dispatch all but
192  * the last for delivery.  The last frame is returned for 
193  * delivery via the normal path.
194  */
195 struct mbuf *
196 ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
197 {
198         struct ieee80211com *ic = ni->ni_ic;
199         int totallen, framelen;
200         struct mbuf *n;
201
202         /* discard 802.3 header inserted by ieee80211_decap */
203         m_adj(m, sizeof(struct ether_header));
204
205         ic->ic_stats.is_amsdu_decap++;
206
207         totallen = m->m_pkthdr.len;
208         for (;;) {
209                 /*
210                  * Decap the first frame, bust it apart from the
211                  * remainder and deliver.  We leave the last frame
212                  * delivery to the caller (for consistency with other
213                  * code paths, could also do it here).
214                  */
215                 m = ieee80211_decap1(m, &framelen);
216                 if (m == NULL) {
217                         IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
218                             ni->ni_macaddr, "a-msdu", "%s", "first decap failed");
219                         ic->ic_stats.is_amsdu_tooshort++;
220                         return NULL;
221                 }
222                 if (framelen == totallen)
223                         break;
224                 n = m_split(m, framelen, M_NOWAIT);
225                 if (n == NULL) {
226                         IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
227                             ni->ni_macaddr, "a-msdu",
228                             "%s", "unable to split encapsulated frames");
229                         ic->ic_stats.is_amsdu_split++;
230                         m_freem(m);                     /* NB: must reclaim */
231                         return NULL;
232                 }
233                 ieee80211_deliver_data(ic, ni, m);
234
235                 /*
236                  * Remove frame contents; each intermediate frame
237                  * is required to be aligned to a 4-byte boundary.
238                  */
239                 m = n;
240                 m_adj(m, roundup2(framelen, 4) - framelen);     /* padding */
241         }
242         return m;                               /* last delivered by caller */
243 }
244
245 /*
246  * Start A-MPDU rx/re-order processing for the specified TID.
247  */
248 static void
249 ampdu_rx_start(struct ieee80211_rx_ampdu *rap, int bufsiz, int start)
250 {
251         memset(rap, 0, sizeof(*rap));
252         rap->rxa_wnd = (bufsiz == 0) ?
253             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
254         rap->rxa_start = start;
255         rap->rxa_nxt = rap->rxa_start;
256         rap->rxa_flags |= IEEE80211_AGGR_XCHGPEND;
257 }
258
259 /*
260  * Purge all frames in the A-MPDU re-order queue.
261  */
262 static void
263 ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
264 {
265         struct mbuf *m;
266         int i;
267
268         for (i = 0; i < rap->rxa_wnd; i++) {
269                 m = rap->rxa_m[i];
270                 if (m != NULL) {
271                         rap->rxa_m[i] = NULL;
272                         rap->rxa_qbytes -= m->m_pkthdr.len;
273                         m_freem(m);
274                         if (--rap->rxa_qframes == 0)
275                                 break;
276                 }
277         }
278         KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
279             ("lost %u data, %u frames on ampdu rx q",
280             rap->rxa_qbytes, rap->rxa_qframes));
281 }
282
283 /*
284  * Stop A-MPDU rx processing for the specified TID.
285  */
286 static void
287 ampdu_rx_stop(struct ieee80211_rx_ampdu *rap)
288 {
289         rap->rxa_flags &= ~IEEE80211_AGGR_XCHGPEND;
290         ampdu_rx_purge(rap);
291 }
292
293 /*
294  * Dispatch a frame from the A-MPDU reorder queue.  The
295  * frame is fed back into ieee80211_input marked with an
296  * M_AMPDU flag so it doesn't come back to us (it also
297  * permits ieee80211_input to optimize re-processing).
298  */
299 static __inline void
300 ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
301 {
302         m->m_flags |= M_AMPDU;  /* bypass normal processing */
303         /* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU set */
304         (void) ieee80211_input(ni->ni_ic, m, ni, 0, 0, 0);
305 }
306
307 /*
308  * Dispatch as many frames as possible from the re-order queue.
309  * Frames will always be "at the front"; we process all frames
310  * up to the first empty slot in the window.  On completion we
311  * cleanup state if there are still pending frames in the current
312  * BA window.  We assume the frame at slot 0 is already handled
313  * by the caller; we always start at slot 1.
314  */
315 static void
316 ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
317 {
318         struct ieee80211com *ic = ni->ni_ic;
319         struct mbuf *m;
320         int i;
321
322         /* flush run of frames */
323         for (i = 1; i < rap->rxa_wnd; i++) {
324                 m = rap->rxa_m[i];
325                 if (m == NULL)
326                         break;
327                 rap->rxa_m[i] = NULL;
328                 rap->rxa_qbytes -= m->m_pkthdr.len;
329                 rap->rxa_qframes--;
330
331                 ampdu_dispatch(ni, m);
332         }
333         /*
334          * Adjust the start of the BA window to
335          * reflect the frames just dispatched.
336          */
337         rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
338         rap->rxa_nxt = rap->rxa_start;
339         ic->ic_stats.is_ampdu_rx_oor += i;
340         /*
341          * If frames remain, copy the mbuf pointers down so
342          * they correspond to the offsets in the new window.
343          */
344         if (rap->rxa_qframes != 0) {
345                 int n = rap->rxa_qframes, j;
346                 for (j = i+1; j < rap->rxa_wnd; j++) {
347                         if (rap->rxa_m[j] != NULL) {
348                                 rap->rxa_m[j-i] = rap->rxa_m[j];
349                                 rap->rxa_m[j] = NULL;
350                                 if (--n == 0)
351                                         break;
352                         }
353                 }
354                 KASSERT(n == 0, ("lost %d frames", n));
355                 ic->ic_stats.is_ampdu_rx_copy += rap->rxa_qframes;
356         }
357 }
358
359 /*
360  * Dispatch all frames in the A-MPDU
361  * re-order queue up to the specified slot.
362  */
363 static void
364 ampdu_rx_flush(struct ieee80211_node *ni,
365         struct ieee80211_rx_ampdu *rap, int limit)
366 {
367         struct mbuf *m;
368         int i;
369
370         for (i = 0; i < limit; i++) {
371                 m = rap->rxa_m[i];
372                 if (m == NULL)
373                         continue;
374                 rap->rxa_m[i] = NULL;
375                 rap->rxa_qbytes -= m->m_pkthdr.len;
376                 ampdu_dispatch(ni, m);
377                 if (--rap->rxa_qframes == 0)
378                         break;
379         }
380 }
381
382 /*
383  * Process a received QoS data frame for an HT station.  Handle
384  * A-MPDU reordering: if this frame is received out of order
385  * and falls within the BA window hold onto it.  Otherwise if
386  * this frame completes a run flush any pending frames.  We
387  * return 1 if the frame is consumed.  A 0 is returned if
388  * the frame should be processed normally by the caller.
389  */
390 int
391 ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
392 {
393 #define IEEE80211_FC0_QOSDATA \
394         (IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
395         struct ieee80211com *ic = ni->ni_ic;
396         struct ieee80211_qosframe *wh;
397         struct ieee80211_rx_ampdu *rap;
398         ieee80211_seq rxseq;
399         uint8_t tid;
400         int off;
401
402         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
403
404         /* NB: m_len known to be sufficient */
405         wh = mtod(m, struct ieee80211_qosframe *);
406         KASSERT(wh->i_fc[0] == IEEE80211_FC0_QOSDATA, ("not QoS data"));
407
408         /* XXX 4-address frame */
409         tid = wh->i_qos[0] & IEEE80211_QOS_TID;
410         rap = &ni->ni_rx_ampdu[tid];
411         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
412                 /*
413                  * No ADDBA request yet, don't touch.
414                  */
415                 return 0;
416         }
417         rxseq = le16toh(*(uint16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
418         if (rxseq == rap->rxa_start) {
419                 /*
420                  * First frame in window.
421                  */
422                 if (rap->rxa_qframes != 0) {
423                         /*
424                          * Dispatch as many packets as we can.
425                          */
426                         KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
427                         ampdu_dispatch(ni, m);
428                         ampdu_rx_dispatch(rap, ni);
429                         return 1;               /* NB: consumed */
430                 } else {
431                         /*
432                          * In order; advance window and notify
433                          * caller to dispatch directly.
434                          */
435                         rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
436                         rap->rxa_nxt = rap->rxa_start;
437                         return 0;               /* NB: process packet */
438                 }
439         }
440         /*
441          * This packet is out of order; store it
442          * if it's in the BA window.
443          */
444         /* calculate offset in BA window */
445         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
446         if (off >= rap->rxa_wnd) {
447                 /*
448                  * Outside the window, clear the q and start over.
449                  *
450                  * NB: this handles the case where rxseq is before
451                  *     rxa_start because our max BA window is 64
452                  *     and the sequence number range is 4096.
453                  */
454                 IEEE80211_NOTE(ic, IEEE80211_MSG_11N, ni,
455                     "flush BA win <%u:%u> (%u frames) rxseq %u tid %u",
456                     rap->rxa_start,
457                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd),
458                     rap->rxa_qframes, rxseq, tid);
459
460                 if (rap->rxa_qframes != 0) {
461                         ic->ic_stats.is_ampdu_rx_oor += rap->rxa_qframes;
462                         ampdu_rx_flush(ni, rap, rap->rxa_wnd);
463                         KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
464                             ("lost %u data, %u frames on ampdu rx q",
465                             rap->rxa_qbytes, rap->rxa_qframes));
466                 }
467                 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
468                 rap->rxa_nxt = rap->rxa_start;
469                 return 0;       /* NB: process packet */
470         }
471         if (rap->rxa_qframes != 0) {
472 #if 0
473                 /* XXX honor batimeout? */
474                 if (ticks - mn->mn_age[tid] > 50) {
475                         /*
476                          * Too long since we received the first frame; flush.
477                          */
478                         if (rap->rxa_qframes != 0) {
479                                 ic->ic_stats.is_ampdu_rx_oor +=
480                                     rap->rxa_qframes;
481                                 ampdu_rx_flush(ni, rap, rap->rxa_wnd);
482                         }
483                         rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
484                         rap->rxa_nxt = rap->rxa_start;
485                         return 0;               /* NB: process packet */
486                 }
487 #endif
488                 rap->rxa_nxt = rxseq;
489         } else {
490                 /*
491                  * First frame, start aging timer.
492                  */
493 #if 0
494                 mn->mn_age[tid] = ticks;
495 #endif
496         }
497         /* save packet */
498         if (rap->rxa_m[off] == NULL) {
499                 rap->rxa_m[off] = m;
500                 rap->rxa_qframes++;
501                 rap->rxa_qbytes += m->m_pkthdr.len;
502         } else {
503                 IEEE80211_DISCARD_MAC(ic,
504                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
505                     ni->ni_macaddr, "a-mpdu duplicate",
506                     "seqno %u tid %u BA win <%u:%u>",
507                     rxseq, tid, rap->rxa_start, rap->rxa_wnd);
508                 ic->ic_stats.is_rx_dup++;
509                 IEEE80211_NODE_STAT(ni, rx_dup);
510                 m_freem(m);
511         }
512         return 1;               /* NB: consumed */
513 #undef IEEE80211_FC0_QOSDATA
514 }
515
516 /*
517  * Process a BAR ctl frame.  Dispatch all frames up to
518  * the sequence number of the frame.  If this frame is
519  * out of the window it's discarded.
520  */
521 void
522 ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
523 {
524         struct ieee80211com *ic = ni->ni_ic;
525         struct ieee80211_frame_bar *wh;
526         struct ieee80211_rx_ampdu *rap;
527         ieee80211_seq rxseq;
528         int tid, off;
529
530         wh = mtod(m0, struct ieee80211_frame_bar *);
531         /* XXX check basic BAR */
532         tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
533         rap = &ni->ni_rx_ampdu[tid];
534         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
535                 /*
536                  * No ADDBA request yet, don't touch.
537                  */
538                 IEEE80211_DISCARD_MAC(ic,
539                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
540                     ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
541                 ic->ic_stats.is_ampdu_bar_bad++;
542                 return;
543         }
544         ic->ic_stats.is_ampdu_bar_rx++;
545         rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
546         /* calculate offset in BA window */
547         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
548         if (off >= rap->rxa_wnd) {
549                 /*
550                  * Outside the window, flush the reorder q if
551                  * not pulling the sequence # backward.  The
552                  * latter is typically caused by a dropped BA.
553                  */
554                 IEEE80211_NOTE(ic, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni,
555                     "recv BAR outside BA win <%u:%u> rxseq %u tid %u",
556                     rap->rxa_start,
557                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd),
558                     rxseq, tid);
559                 ic->ic_stats.is_ampdu_bar_oow++;
560                 if (rxseq < rap->rxa_start) {
561                         /* XXX stat? */
562                         return;
563                 }
564                 if (rap->rxa_qframes != 0) {
565                         ic->ic_stats.is_ampdu_rx_oor += rap->rxa_qframes;
566                         ampdu_rx_flush(ni, rap, rap->rxa_wnd);
567                         KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
568                             ("lost %u data, %u frames on ampdu rx q",
569                             rap->rxa_qbytes, rap->rxa_qframes));
570                 }
571         } else if (rap->rxa_qframes != 0) {
572                 /*
573                  * Dispatch packets up to rxseq.
574                  */
575                 ampdu_rx_flush(ni, rap, off);
576                 ic->ic_stats.is_ampdu_rx_oor += off;
577
578                 /*
579                  * If frames remain, copy the mbuf pointers down so
580                  * they correspond to the offsets in the new window.
581                  */
582                 if (rap->rxa_qframes != 0) {
583                         int n = rap->rxa_qframes, j;
584                         for (j = off+1; j < rap->rxa_wnd; j++) {
585                                 if (rap->rxa_m[j] != NULL) {
586                                         rap->rxa_m[j-off] = rap->rxa_m[j];
587                                         rap->rxa_m[j] = NULL;
588                                         if (--n == 0)
589                                                 break;
590                                 }
591                         }
592                         KASSERT(n == 0, ("lost %d frames", n));
593                         ic->ic_stats.is_ampdu_rx_copy += rap->rxa_qframes;
594                 }
595         }
596         rap->rxa_start = rxseq;
597         rap->rxa_nxt = rap->rxa_start;
598 }
599
600 /*
601  * Setup HT-specific state in a node.  Called only
602  * when HT use is negotiated so we don't do extra
603  * work for temporary and/or legacy sta's.
604  */
605 void
606 ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
607 {
608         struct ieee80211_tx_ampdu *tap;
609         int ac;
610
611         ieee80211_parse_htcap(ni, htcap);
612         for (ac = 0; ac < WME_NUM_AC; ac++) {
613                 tap = &ni->ni_tx_ampdu[ac];
614                 tap->txa_ac = ac;
615         }
616         ni->ni_flags |= IEEE80211_NODE_HT;
617 }
618
619 /*
620  * Cleanup HT-specific state in a node.  Called only
621  * when HT use has been marked.
622  */
623 void
624 ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
625 {
626         struct ieee80211com *ic = ni->ni_ic;
627         int i;
628
629         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
630
631         /* XXX optimize this */
632         for (i = 0; i < WME_NUM_AC; i++) {
633                 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
634                 if (IEEE80211_AMPDU_REQUESTED(tap))
635                         ic->ic_addba_stop(ni, &ni->ni_tx_ampdu[i]);
636         }
637         for (i = 0; i < WME_NUM_TID; i++)
638                 ampdu_rx_stop(&ni->ni_rx_ampdu[i]);
639
640         ni->ni_htcap = 0;
641         ni->ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT);
642 }
643
644 /* unalligned little endian access */     
645 #define LE_READ_2(p)                                    \
646         ((uint16_t)                                     \
647          ((((const uint8_t *)(p))[0]      ) |           \
648           (((const uint8_t *)(p))[1] <<  8)))
649
650 /*
651  * Process an 802.11n HT capabilities ie.
652  */
653 void
654 ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
655 {
656         struct ieee80211com *ic = ni->ni_ic;
657
658         if (ie[0] == IEEE80211_ELEMID_VENDOR) {
659                 /*
660                  * Station used Vendor OUI ie to associate;
661                  * mark the node so when we respond we'll use
662                  * the Vendor OUI's and not the standard ie's.
663                  */
664                 ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
665                 ie += 4;
666         } else
667                 ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
668
669         ni->ni_htcap = LE_READ_2(ie +
670                 __offsetof(struct ieee80211_ie_htcap, hc_cap));
671         if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40) == 0)
672                 ni->ni_htcap &= ~IEEE80211_HTCAP_SHORTGI40;
673         if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20) == 0)
674                 ni->ni_htcap &= ~IEEE80211_HTCAP_SHORTGI20;
675         ni->ni_chw = (ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) ? 40 : 20;
676         ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
677 #if 0
678         ni->ni_maxampdu =
679             (8*1024) << MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
680         ni->ni_mpdudensity = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
681 #endif
682 }
683
684 /*
685  * Process an 802.11n HT info ie.
686  */
687 void
688 ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
689 {
690         const struct ieee80211_ie_htinfo *htinfo;
691         uint16_t w;
692         int chw;
693
694         if (ie[0] == IEEE80211_ELEMID_VENDOR)
695                 ie += 4;
696         htinfo = (const struct ieee80211_ie_htinfo *) ie;
697         ni->ni_htctlchan = htinfo->hi_ctrlchannel;
698         ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
699         w = LE_READ_2(&htinfo->hi_byte23);
700         ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
701         w = LE_READ_2(&htinfo->hi_byte45);
702         ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
703         /* update node's recommended tx channel width */
704         chw = (htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) ? 40 : 20;
705         if (chw != ni->ni_chw) {
706                 ni->ni_chw = chw;
707                 ni->ni_flags |= IEEE80211_NODE_CHWUPDATE;
708         }
709 }
710
711 /*
712  * Install received HT rate set by parsing the HT cap ie.
713  */
714 int
715 ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
716 {
717         struct ieee80211com *ic = ni->ni_ic;
718         const struct ieee80211_ie_htcap *htcap;
719         struct ieee80211_htrateset *rs;
720         int i;
721
722         rs = &ni->ni_htrates;
723         memset(rs, 0, sizeof(*rs));
724         if (ie != NULL) {
725                 if (ie[0] == IEEE80211_ELEMID_VENDOR)
726                         ie += 4;
727                 htcap = (const struct ieee80211_ie_htcap *) ie;
728                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
729                         if (isclr(htcap->hc_mcsset, i))
730                                 continue;
731                         if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
732                                 IEEE80211_NOTE(ic,
733                                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
734                                     "WARNING, HT rate set too large; only "
735                                     "using %u rates", IEEE80211_HTRATE_MAXSIZE);
736                                 ic->ic_stats.is_rx_rstoobig++;
737                                 break;
738                         }
739                         rs->rs_rates[rs->rs_nrates++] = i;
740                 }
741         }
742         return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
743 }
744
745 /*
746  * Mark rates in a node's HT rate set as basic according
747  * to the information in the supplied HT info ie.
748  */
749 void
750 ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
751 {
752         const struct ieee80211_ie_htinfo *htinfo;
753         struct ieee80211_htrateset *rs;
754         int i, j;
755
756         if (ie[0] == IEEE80211_ELEMID_VENDOR)
757                 ie += 4;
758         htinfo = (const struct ieee80211_ie_htinfo *) ie;
759         rs = &ni->ni_htrates;
760         if (rs->rs_nrates == 0) {
761                 IEEE80211_NOTE(ni->ni_ic,
762                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
763                     "%s", "WARNING, empty HT rate set");
764                 return;
765         }
766         for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
767                 if (isclr(htinfo->hi_basicmcsset, i))
768                         continue;
769                 for (j = 0; j < rs->rs_nrates; j++)
770                         if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
771                                 rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
772         }
773 }
774
775 static void
776 addba_timeout(void *arg)
777 {
778         struct ieee80211_tx_ampdu *tap = arg;
779
780         /* XXX ? */
781         tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
782         tap->txa_attempts++;
783 }
784
785 static void
786 addba_start_timeout(struct ieee80211_tx_ampdu *tap)
787 {
788         /* XXX use CALLOUT_PENDING instead? */
789         callout_reset(&tap->txa_timer, IEEE80211_AGGR_TIMEOUT,
790             addba_timeout, tap);
791         tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
792         tap->txa_lastrequest = ticks;
793 }
794
795 static void
796 addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
797 {
798         /* XXX use CALLOUT_PENDING instead? */
799         if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
800                 callout_stop(&tap->txa_timer);
801                 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
802         }
803 }
804
805 /*
806  * Default method for requesting A-MPDU tx aggregation.
807  * We setup the specified state block and start a timer
808  * to wait for an ADDBA response frame.
809  */
810 static int
811 ieee80211_addba_request(struct ieee80211_node *ni,
812         struct ieee80211_tx_ampdu *tap,
813         int dialogtoken, int baparamset, int batimeout)
814 {
815         int bufsiz;
816
817         /* XXX locking */
818         tap->txa_token = dialogtoken;
819         tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
820         tap->txa_start = tap->txa_seqstart = 0;
821         bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
822         tap->txa_wnd = (bufsiz == 0) ?
823             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
824         addba_start_timeout(tap);
825         return 1;
826 }
827
828 /*
829  * Default method for processing an A-MPDU tx aggregation
830  * response.  We shutdown any pending timer and update the
831  * state block according to the reply.
832  */
833 static int
834 ieee80211_addba_response(struct ieee80211_node *ni,
835         struct ieee80211_tx_ampdu *tap,
836         int status, int baparamset, int batimeout)
837 {
838         int bufsiz;
839
840         /* XXX locking */
841         addba_stop_timeout(tap);
842         if (status == IEEE80211_STATUS_SUCCESS) {
843                 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
844                 /* XXX override our request? */
845                 tap->txa_wnd = (bufsiz == 0) ?
846                     IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
847                 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
848         }
849         return 1;
850 }
851
852 /*
853  * Default method for stopping A-MPDU tx aggregation.
854  * Any timer is cleared and we drain any pending frames.
855  */
856 static void
857 ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
858 {
859         /* XXX locking */
860         addba_stop_timeout(tap);
861         if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
862                 /* clear aggregation queue */
863                 ieee80211_drain_ifq(&tap->txa_q);
864                 tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
865         }
866         tap->txa_attempts = 0;
867 }
868
869 /*
870  * Process a received action frame using the default aggregation
871  * policy.  We intercept ADDBA-related frames and use them to
872  * update our aggregation state.  All other frames are passed up
873  * for processing by ieee80211_recv_action.
874  */
875 static void
876 ieee80211_aggr_recv_action(struct ieee80211_node *ni,
877         const uint8_t *frm, const uint8_t *efrm)
878 {
879         struct ieee80211com *ic = ni->ni_ic;
880         const struct ieee80211_action *ia;
881         struct ieee80211_rx_ampdu *rap;
882         struct ieee80211_tx_ampdu *tap;
883         uint8_t dialogtoken;
884         uint16_t baparamset, batimeout, baseqctl, code;
885         uint16_t args[4];
886         int tid, ac, bufsiz;
887
888         ia = (const struct ieee80211_action *) frm;
889         switch (ia->ia_category) {
890         case IEEE80211_ACTION_CAT_BA:
891                 switch (ia->ia_action) {
892                 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
893                         dialogtoken = frm[2];
894                         baparamset = LE_READ_2(frm+3);
895                         batimeout = LE_READ_2(frm+5);
896                         baseqctl = LE_READ_2(frm+7);
897
898                         tid = MS(baparamset, IEEE80211_BAPS_TID);
899                         bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
900
901                         IEEE80211_NOTE(ic,
902                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
903                             "recv ADDBA request: dialogtoken %u "
904                             "baparamset 0x%x (tid %d bufsiz %d) batimeout %d "
905                             "baseqctl %d",
906                             dialogtoken, baparamset, tid, bufsiz,
907                             batimeout, baseqctl);
908
909                         rap = &ni->ni_rx_ampdu[tid];
910
911                         /* Send ADDBA response */
912                         args[0] = dialogtoken;
913                         if (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX) {
914                                 ampdu_rx_start(rap, bufsiz,
915                                     MS(baseqctl, IEEE80211_BASEQ_START));
916
917                                 args[1] = IEEE80211_STATUS_SUCCESS;
918                         } else
919                                 args[1] = IEEE80211_STATUS_UNSPECIFIED;
920                         /* XXX honor rap flags? */
921                         args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
922                                 | SM(tid, IEEE80211_BAPS_TID)
923                                 | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
924                                 ;
925                         args[3] = 0;
926                         ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
927                                 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
928                         return;
929
930                 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
931                         dialogtoken = frm[2];
932                         code = LE_READ_2(frm+3);
933                         baparamset = LE_READ_2(frm+5);
934                         tid = MS(baparamset, IEEE80211_BAPS_TID);
935                         bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
936                         batimeout = LE_READ_2(frm+7);
937
938                         IEEE80211_NOTE(ic,
939                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
940                             "recv ADDBA response: dialogtoken %u code %d "
941                             "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
942                             dialogtoken, code, baparamset, tid, bufsiz,
943                             batimeout);
944
945                         ac = TID_TO_WME_AC(tid);
946                         tap = &ni->ni_tx_ampdu[ac];
947
948                         ic->ic_addba_response(ni, tap,
949                                 code, baparamset, batimeout);
950                         return;
951
952                 case IEEE80211_ACTION_BA_DELBA:
953                         baparamset = LE_READ_2(frm+2);
954                         code = LE_READ_2(frm+4);
955
956                         tid = MS(baparamset, IEEE80211_DELBAPS_TID);
957
958                         IEEE80211_NOTE(ic,
959                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
960                             "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
961                             "code %d", baparamset, tid,
962                             MS(baparamset, IEEE80211_DELBAPS_INIT), code);
963
964                         if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
965                                 ac = TID_TO_WME_AC(tid);
966                                 tap = &ni->ni_tx_ampdu[ac];
967                                 ic->ic_addba_stop(ni, tap);
968                         } else {
969                                 rap = &ni->ni_rx_ampdu[tid];
970                                 ampdu_rx_stop(rap);
971                         }
972                         return;
973                 }
974                 break;
975         }
976         return ieee80211_recv_action(ni, frm, efrm);
977 }
978
979 /*
980  * Process a received 802.11n action frame.
981  * Aggregation-related frames are assumed to be handled
982  * already; we handle any other frames we can, otherwise
983  * complain about being unsupported (with debugging).
984  */
985 void
986 ieee80211_recv_action(struct ieee80211_node *ni,
987         const uint8_t *frm, const uint8_t *efrm)
988 {
989         struct ieee80211com *ic = ni->ni_ic;
990         const struct ieee80211_action *ia;
991         int chw;
992
993         ia = (const struct ieee80211_action *) frm;
994         switch (ia->ia_category) {
995         case IEEE80211_ACTION_CAT_BA:
996                 IEEE80211_NOTE(ic,
997                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
998                     "%s: BA action %d not implemented", __func__,
999                     ia->ia_action);
1000                 ic->ic_stats.is_rx_mgtdiscard++;
1001                 break;
1002         case IEEE80211_ACTION_CAT_HT:
1003                 switch (ia->ia_action) {
1004                 case IEEE80211_ACTION_HT_TXCHWIDTH:
1005                         chw = frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040 ? 40 : 20;
1006                         if (chw != ni->ni_chw) {
1007                                 ni->ni_chw = chw;
1008                                 ni->ni_flags |= IEEE80211_NODE_CHWUPDATE;
1009                         }
1010                         IEEE80211_NOTE(ic,
1011                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1012                             "%s: HT txchwidth. width %d (%s)",
1013                             __func__, chw,
1014                             ni->ni_flags & IEEE80211_NODE_CHWUPDATE ?
1015                                 "new" : "no change");
1016                         break;
1017                 default:
1018                         IEEE80211_NOTE(ic,
1019                            IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1020                            "%s: HT action %d not implemented", __func__,
1021                            ia->ia_action);
1022                         ic->ic_stats.is_rx_mgtdiscard++;
1023                         break;
1024                 }
1025                 break;
1026         default:
1027                 IEEE80211_NOTE(ic,
1028                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1029                     "%s: category %d not implemented", __func__,
1030                     ia->ia_category);
1031                 ic->ic_stats.is_rx_mgtdiscard++;
1032                 break;
1033         }
1034 }
1035
1036 /*
1037  * Transmit processing.
1038  */
1039
1040 /*
1041  * Request A-MPDU tx aggregation.  Setup local state and
1042  * issue an ADDBA request.  BA use will only happen after
1043  * the other end replies with ADDBA response.
1044  */
1045 int
1046 ieee80211_ampdu_request(struct ieee80211_node *ni,
1047         struct ieee80211_tx_ampdu *tap)
1048 {
1049         struct ieee80211com *ic = ni->ni_ic;
1050         uint16_t args[4];
1051         int tid, dialogtoken;
1052         static int tokens = 0;  /* XXX */
1053
1054         /* XXX locking */
1055         if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
1056                 /* do deferred setup of state */
1057                 /* XXX tap->txa_q */
1058                 callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
1059                 tap->txa_flags |= IEEE80211_AGGR_SETUP;
1060         }
1061         if (tap->txa_attempts >= IEEE80211_AGGR_MAXTRIES &&
1062             (ticks - tap->txa_lastrequest) < IEEE80211_AGGR_MINRETRY) {
1063                 /*
1064                  * Don't retry too often; IEEE80211_AGGR_MINRETRY
1065                  * defines the minimum interval we'll retry after
1066                  * IEEE80211_AGGR_MAXTRIES failed attempts to
1067                  * negotiate use.
1068                  */
1069                 return 0;
1070         }
1071         dialogtoken = (tokens+1) % 63;          /* XXX */
1072
1073         tid = WME_AC_TO_TID(tap->txa_ac);
1074         args[0] = dialogtoken;
1075         args[1] = IEEE80211_BAPS_POLICY_IMMEDIATE
1076                 | SM(tid, IEEE80211_BAPS_TID)
1077                 | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
1078                 ;
1079         args[2] = 0;    /* batimeout */
1080         args[3] = SM(0, IEEE80211_BASEQ_START)
1081                 | SM(0, IEEE80211_BASEQ_FRAG)
1082                 ;
1083         /* NB: do first so there's no race against reply */
1084         if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) {
1085                 /* unable to setup state, don't make request */
1086                 return 0;
1087         }
1088         tokens = dialogtoken;                   /* allocate token */
1089         return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1090                 IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
1091 }
1092
1093 /*
1094  * Transmit a BAR frame to the specified node.  The
1095  * BAR contents are drawn from the supplied aggregation
1096  * state associated with the node.
1097  */
1098 int
1099 ieee80211_send_bar(struct ieee80211_node *ni,
1100         const struct ieee80211_tx_ampdu *tap)
1101 {
1102 #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
1103 #define ADDSHORT(frm, v) do {                   \
1104         frm[0] = (v) & 0xff;                    \
1105         frm[1] = (v) >> 8;                      \
1106         frm += 2;                               \
1107 } while (0)
1108         struct ieee80211com *ic = ni->ni_ic;
1109         struct ifnet *ifp = ic->ic_ifp;
1110         struct ieee80211_frame_min *wh;
1111         struct mbuf *m;
1112         uint8_t *frm;
1113         uint16_t barctl, barseqctl;
1114         int tid, ret;
1115
1116         ieee80211_ref_node(ni);
1117
1118         m = ieee80211_getmgtframe(&frm,
1119                 ic->ic_headroom + sizeof(struct ieee80211_frame_min),
1120                 sizeof(struct ieee80211_ba_request)
1121         );
1122         if (m == NULL)
1123                 senderr(ENOMEM, is_tx_nobuf);
1124
1125         wh = mtod(m, struct ieee80211_frame_min *);
1126         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 |
1127                 IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
1128         wh->i_fc[1] = 0;
1129         IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1130         IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
1131
1132         tid = WME_AC_TO_TID(tap->txa_ac);
1133         barctl  = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
1134                         IEEE80211_BAPS_POLICY_IMMEDIATE :
1135                         IEEE80211_BAPS_POLICY_DELAYED)
1136                 | SM(tid, IEEE80211_BAPS_TID)
1137                 | SM(tap->txa_wnd, IEEE80211_BAPS_BUFSIZ)
1138                 ;
1139         barseqctl = SM(tap->txa_start, IEEE80211_BASEQ_START)
1140                 | SM(0, IEEE80211_BASEQ_FRAG)
1141                 ;
1142         ADDSHORT(frm, barctl);
1143         ADDSHORT(frm, barseqctl);
1144         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1145
1146         IEEE80211_NODE_STAT(ni, tx_mgmt);       /* XXX tx_ctl? */
1147
1148         IEEE80211_DPRINTF(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1149             "[%s] send bar frame (tid %u start %u) on channel %u\n",
1150             ether_sprintf(ni->ni_macaddr), tid, tap->txa_start,
1151             ieee80211_chan2ieee(ic, ic->ic_curchan));
1152
1153         m->m_pkthdr.rcvif = (void *)ni;
1154         IF_ENQUEUE(&ic->ic_mgtq, m);            /* cheat */
1155         (*ifp->if_start)(ifp);
1156
1157         return 0;
1158 bad:
1159         ieee80211_free_node(ni);
1160         return ret;
1161 #undef ADDSHORT
1162 #undef senderr
1163 }
1164
1165 /*
1166  * Send an action management frame.  The arguments are stuff
1167  * into a frame without inspection; the caller is assumed to
1168  * prepare them carefully (e.g. based on the aggregation state).
1169  */
1170 int
1171 ieee80211_send_action(struct ieee80211_node *ni,
1172         int category, int action, uint16_t args[4])
1173 {
1174 #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
1175 #define ADDSHORT(frm, v) do {                   \
1176         frm[0] = (v) & 0xff;                    \
1177         frm[1] = (v) >> 8;                      \
1178         frm += 2;                               \
1179 } while (0)
1180         struct ieee80211com *ic = ni->ni_ic;
1181         struct mbuf *m;
1182         uint8_t *frm;
1183         uint16_t baparamset;
1184         int ret;
1185
1186         KASSERT(ni != NULL, ("null node"));
1187
1188         /*
1189          * Hold a reference on the node so it doesn't go away until after
1190          * the xmit is complete all the way in the driver.  On error we
1191          * will remove our reference.
1192          */
1193         IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1194                 "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1195                 __func__, __LINE__,
1196                 ni, ether_sprintf(ni->ni_macaddr),
1197                 ieee80211_node_refcnt(ni)+1);
1198         ieee80211_ref_node(ni);
1199
1200         m = ieee80211_getmgtframe(&frm,
1201                 ic->ic_headroom + sizeof(struct ieee80211_frame),
1202                   sizeof(uint16_t)      /* action+category */
1203                 /* XXX may action payload */
1204                 + sizeof(struct ieee80211_action_ba_addbaresponse)
1205         );
1206         if (m == NULL)
1207                 senderr(ENOMEM, is_tx_nobuf);
1208
1209         *frm++ = category;
1210         *frm++ = action;
1211         switch (category) {
1212         case IEEE80211_ACTION_CAT_BA:
1213                 switch (action) {
1214                 case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1215                         IEEE80211_NOTE(ic,
1216                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1217                             "send ADDBA request: tid %d, baparamset 0x%x",
1218                             args[0], args[1]);
1219
1220                         *frm++ = args[0];       /* dialog token */
1221                         ADDSHORT(frm, args[1]); /* baparamset */
1222                         ADDSHORT(frm, args[2]); /* batimeout */
1223                         ADDSHORT(frm, args[3]); /* baseqctl */
1224                         break;
1225                 case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1226                         IEEE80211_NOTE(ic,
1227                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1228                             "send ADDBA response: dialogtoken %d status %d "
1229                             "baparamset 0x%x (tid %d) batimeout %d",
1230                             args[0], args[1], args[2],
1231                             MS(args[2], IEEE80211_BAPS_TID), args[3]);
1232
1233                         *frm++ = args[0];       /* dialog token */
1234                         ADDSHORT(frm, args[1]); /* statuscode */
1235                         ADDSHORT(frm, args[2]); /* baparamset */
1236                         ADDSHORT(frm, args[3]); /* batimeout */
1237                         break;
1238                 case IEEE80211_ACTION_BA_DELBA:
1239                         /* XXX */
1240                         baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
1241                                    | SM(args[1], IEEE80211_DELBAPS_INIT)
1242                                    ;
1243                         ADDSHORT(frm, baparamset);
1244                         ADDSHORT(frm, args[2]); /* reason code */
1245
1246                         IEEE80211_NOTE(ic,
1247                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1248                             "send DELBA action: tid %d, initiator %d reason %d",
1249                             args[0], args[1], args[2]);
1250                         break;
1251                 default:
1252                         goto badaction;
1253                 }
1254                 break;
1255         case IEEE80211_ACTION_CAT_HT:
1256                 switch (action) {
1257                 case IEEE80211_ACTION_HT_TXCHWIDTH:
1258                         IEEE80211_NOTE(ic,
1259                             IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1260                             ni, "send HT txchwidth: width %d",
1261                            IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) ?  40 : 20
1262                         );
1263                         *frm++ = IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) ? 
1264                                 IEEE80211_A_HT_TXCHWIDTH_2040 :
1265                                 IEEE80211_A_HT_TXCHWIDTH_20;
1266                         break;
1267                 default:
1268                         goto badaction;
1269                 }
1270                 break;
1271         default:
1272         badaction:
1273                 IEEE80211_NOTE(ic,
1274                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1275                     "%s: unsupported category %d action %d", __func__,
1276                     category, action);
1277                 senderr(EINVAL, is_tx_unknownmgt);
1278                 /* NOTREACHED */
1279         }
1280         m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1281
1282         ret = ieee80211_mgmt_output(ic, ni, m, IEEE80211_FC0_SUBTYPE_ACTION);
1283         if (ret != 0)
1284                 goto bad;
1285         return 0;
1286 bad:
1287         ieee80211_free_node(ni);
1288         return ret;
1289 #undef ADDSHORT
1290 #undef senderr
1291 }
1292
1293 /*
1294  * Construct the MCS bit mask for inclusion
1295  * in an HT information element.
1296  */
1297 static void 
1298 ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1299 {
1300         int i;
1301
1302         for (i = 0; i < rs->rs_nrates; i++) {
1303                 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1304                 if (r < IEEE80211_HTRATE_MAXSIZE) {     /* XXX? */
1305                         /* NB: this assumes a particular implementation */
1306                         setbit(frm, r);
1307                 }
1308         }
1309 }
1310
1311 /*
1312  * Add body of an HTCAP information element.
1313  */
1314 static uint8_t *
1315 ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
1316 {
1317 #define ADDSHORT(frm, v) do {                   \
1318         frm[0] = (v) & 0xff;                    \
1319         frm[1] = (v) >> 8;                      \
1320         frm += 2;                               \
1321 } while (0)
1322         struct ieee80211com *ic = ni->ni_ic;
1323         uint16_t caps;
1324
1325         /* HT capabilities */
1326         caps = ic->ic_htcaps & 0xffff;
1327         /* override 20/40 use based on channel and config */
1328         if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
1329             (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40))
1330                 caps |= IEEE80211_HTCAP_CHWIDTH40;
1331         else
1332                 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
1333         /* adjust short GI based on channel and config */
1334         if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20) == 0)
1335                 caps &= ~IEEE80211_HTCAP_SHORTGI20;
1336         if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40) == 0 ||
1337             (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
1338                 caps &= ~IEEE80211_HTCAP_SHORTGI40;
1339         ADDSHORT(frm, caps);
1340
1341         /* HT parameters */
1342         switch (ic->ic_ampdu_rxmax / 1024) {
1343         case 8:  *frm = IEEE80211_HTCAP_MAXRXAMPDU_8K; break;
1344         case 16: *frm = IEEE80211_HTCAP_MAXRXAMPDU_16K; break;
1345         case 32: *frm = IEEE80211_HTCAP_MAXRXAMPDU_32K; break;
1346         default: *frm = IEEE80211_HTCAP_MAXRXAMPDU_64K; break;
1347         }
1348         *frm |= SM(ic->ic_ampdu_density, IEEE80211_HTCAP_MPDUDENSITY);
1349         frm++;
1350
1351         /* pre-zero remainder of ie */
1352         memset(frm, 0, sizeof(struct ieee80211_ie_htcap) - 
1353                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
1354
1355         /* supported MCS set */
1356         ieee80211_set_htrates(frm, &ni->ni_htrates);
1357
1358         frm += sizeof(struct ieee80211_ie_htcap) -
1359                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
1360         return frm;
1361 #undef ADDSHORT
1362 }
1363
1364 /*
1365  * Add 802.11n HT capabilities information element
1366  */
1367 uint8_t *
1368 ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
1369 {
1370         frm[0] = IEEE80211_ELEMID_HTCAP;
1371         frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
1372         return ieee80211_add_htcap_body(frm + 2, ni);
1373 }
1374
1375 /*
1376  * Add Broadcom OUI wrapped standard HTCAP ie; this is
1377  * used for compatibility w/ pre-draft implementations.
1378  */
1379 uint8_t *
1380 ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
1381 {
1382         frm[0] = IEEE80211_ELEMID_VENDOR;
1383         frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
1384         frm[2] = (BCM_OUI >> 0) & 0xff;
1385         frm[3] = (BCM_OUI >> 8) & 0xff;
1386         frm[4] = (BCM_OUI >> 16) & 0xff;
1387         frm[5] = BCM_OUI_HTCAP;
1388         return ieee80211_add_htcap_body(frm + 6, ni);
1389 }
1390
1391 /*
1392  * Construct the MCS bit mask of basic rates
1393  * for inclusion in an HT information element.
1394  */
1395 static void
1396 ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1397 {
1398         int i;
1399
1400         for (i = 0; i < rs->rs_nrates; i++) {
1401                 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1402                 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
1403                     r < IEEE80211_HTRATE_MAXSIZE) {
1404                         /* NB: this assumes a particular implementation */
1405                         setbit(frm, r);
1406                 }
1407         }
1408 }
1409
1410 /*
1411  * Add body of an HTINFO information element.
1412  */
1413 static uint8_t *
1414 ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
1415 {
1416         struct ieee80211com *ic = ni->ni_ic;
1417
1418         /* pre-zero remainder of ie */
1419         memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
1420
1421         /* primary/control channel center */
1422         *frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan);
1423
1424         frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
1425         if (IEEE80211_IS_CHAN_HT40U(ic->ic_bsschan))
1426                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
1427         else if (IEEE80211_IS_CHAN_HT40D(ic->ic_bsschan))
1428                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
1429         else
1430                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
1431         if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan))
1432                 frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
1433
1434         frm[1] = (ic->ic_flags_ext & IEEE80211_FEXT_PUREN) ?
1435                 IEEE80211_HTINFO_OPMODE_PURE : IEEE80211_HTINFO_OPMODE_MIXED;
1436         /* XXX IEEE80211_HTINFO_NONHT_PRESENT */
1437
1438         frm += 5;
1439
1440         /* basic MCS set */
1441         ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
1442         frm += sizeof(struct ieee80211_ie_htinfo) -
1443                 __offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
1444         return frm;
1445 }
1446
1447 /*
1448  * Add 802.11n HT information information element.
1449  */
1450 uint8_t *
1451 ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
1452 {
1453         frm[0] = IEEE80211_ELEMID_HTINFO;
1454         frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
1455         return ieee80211_add_htinfo_body(frm + 2, ni);
1456 }
1457
1458 /*
1459  * Add Broadcom OUI wrapped standard HTINFO ie; this is
1460  * used for compatibility w/ pre-draft implementations.
1461  */
1462 uint8_t *
1463 ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
1464 {
1465         frm[0] = IEEE80211_ELEMID_VENDOR;
1466         frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
1467         frm[2] = (BCM_OUI >> 0) & 0xff;
1468         frm[3] = (BCM_OUI >> 8) & 0xff;
1469         frm[4] = (BCM_OUI >> 16) & 0xff;
1470         frm[5] = BCM_OUI_HTINFO;
1471         return ieee80211_add_htinfo_body(frm + 6, ni);
1472 }