]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net80211/ieee80211_ht.c
Merge tnftp-20100108 from the vendor branch into head.
[FreeBSD/FreeBSD.git] / sys / net80211 / ieee80211_ht.c
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$");
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_action.h>
51 #include <net80211/ieee80211_input.h>
52
53 /* define here, used throughout file */
54 #define MS(_v, _f)      (((_v) & _f) >> _f##_S)
55 #define SM(_v, _f)      (((_v) << _f##_S) & _f)
56
57 const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = {
58         {  13,  14,   27,   30 },       /* MCS 0 */
59         {  26,  29,   54,   60 },       /* MCS 1 */
60         {  39,  43,   81,   90 },       /* MCS 2 */
61         {  52,  58,  108,  120 },       /* MCS 3 */
62         {  78,  87,  162,  180 },       /* MCS 4 */
63         { 104, 116,  216,  240 },       /* MCS 5 */
64         { 117, 130,  243,  270 },       /* MCS 6 */
65         { 130, 144,  270,  300 },       /* MCS 7 */
66         {  26,  29,   54,   60 },       /* MCS 8 */
67         {  52,  58,  108,  120 },       /* MCS 9 */
68         {  78,  87,  162,  180 },       /* MCS 10 */
69         { 104, 116,  216,  240 },       /* MCS 11 */
70         { 156, 173,  324,  360 },       /* MCS 12 */
71         { 208, 231,  432,  480 },       /* MCS 13 */
72         { 234, 260,  486,  540 },       /* MCS 14 */
73         { 260, 289,  540,  600 },       /* MCS 15 */
74         {  39,  43,   81,   90 },       /* MCS 16 */
75         {  78,  87,  162,  180 },       /* MCS 17 */
76         { 117, 130,  243,  270 },       /* MCS 18 */
77         { 156, 173,  324,  360 },       /* MCS 19 */
78         { 234, 260,  486,  540 },       /* MCS 20 */
79         { 312, 347,  648,  720 },       /* MCS 21 */
80         { 351, 390,  729,  810 },       /* MCS 22 */
81         { 390, 433,  810,  900 },       /* MCS 23 */
82         {  52,  58,  108,  120 },       /* MCS 24 */
83         { 104, 116,  216,  240 },       /* MCS 25 */
84         { 156, 173,  324,  360 },       /* MCS 26 */
85         { 208, 231,  432,  480 },       /* MCS 27 */
86         { 312, 347,  648,  720 },       /* MCS 28 */
87         { 416, 462,  864,  960 },       /* MCS 29 */
88         { 468, 520,  972, 1080 },       /* MCS 30 */
89         { 520, 578, 1080, 1200 },       /* MCS 31 */
90         {   0,   0,   12,   13 },       /* MCS 32 */
91         {  78,  87,  162,  180 },       /* MCS 33 */
92         { 104, 116,  216,  240 },       /* MCS 34 */
93         { 130, 144,  270,  300 },       /* MCS 35 */
94         { 117, 130,  243,  270 },       /* MCS 36 */
95         { 156, 173,  324,  360 },       /* MCS 37 */
96         { 195, 217,  405,  450 },       /* MCS 38 */
97         { 104, 116,  216,  240 },       /* MCS 39 */
98         { 130, 144,  270,  300 },       /* MCS 40 */
99         { 130, 144,  270,  300 },       /* MCS 41 */
100         { 156, 173,  324,  360 },       /* MCS 42 */
101         { 182, 202,  378,  420 },       /* MCS 43 */
102         { 182, 202,  378,  420 },       /* MCS 44 */
103         { 208, 231,  432,  480 },       /* MCS 45 */
104         { 156, 173,  324,  360 },       /* MCS 46 */
105         { 195, 217,  405,  450 },       /* MCS 47 */
106         { 195, 217,  405,  450 },       /* MCS 48 */
107         { 234, 260,  486,  540 },       /* MCS 49 */
108         { 273, 303,  567,  630 },       /* MCS 50 */
109         { 273, 303,  567,  630 },       /* MCS 51 */
110         { 312, 347,  648,  720 },       /* MCS 52 */
111         { 130, 144,  270,  300 },       /* MCS 53 */
112         { 156, 173,  324,  360 },       /* MCS 54 */
113         { 182, 202,  378,  420 },       /* MCS 55 */
114         { 156, 173,  324,  360 },       /* MCS 56 */
115         { 182, 202,  378,  420 },       /* MCS 57 */
116         { 208, 231,  432,  480 },       /* MCS 58 */
117         { 234, 260,  486,  540 },       /* MCS 59 */
118         { 208, 231,  432,  480 },       /* MCS 60 */
119         { 234, 260,  486,  540 },       /* MCS 61 */
120         { 260, 289,  540,  600 },       /* MCS 62 */
121         { 260, 289,  540,  600 },       /* MCS 63 */
122         { 286, 318,  594,  660 },       /* MCS 64 */
123         { 195, 217,  405,  450 },       /* MCS 65 */
124         { 234, 260,  486,  540 },       /* MCS 66 */
125         { 273, 303,  567,  630 },       /* MCS 67 */
126         { 234, 260,  486,  540 },       /* MCS 68 */
127         { 273, 303,  567,  630 },       /* MCS 69 */
128         { 312, 347,  648,  720 },       /* MCS 70 */
129         { 351, 390,  729,  810 },       /* MCS 71 */
130         { 312, 347,  648,  720 },       /* MCS 72 */
131         { 351, 390,  729,  810 },       /* MCS 73 */
132         { 390, 433,  810,  900 },       /* MCS 74 */
133         { 390, 433,  810,  900 },       /* MCS 75 */
134         { 429, 477,  891,  990 },       /* MCS 76 */
135 };
136
137 #ifdef IEEE80211_AMPDU_AGE
138 static  int ieee80211_ampdu_age = -1;   /* threshold for ampdu reorder q (ms) */
139 SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW,
140         &ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I",
141         "AMPDU max reorder age (ms)");
142 #endif
143
144 static  int ieee80211_recv_bar_ena = 1;
145 SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena,
146             0, "BAR frame processing (ena/dis)");
147
148 static  int ieee80211_addba_timeout = -1;/* timeout for ADDBA response */
149 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_timeout, CTLTYPE_INT | CTLFLAG_RW,
150         &ieee80211_addba_timeout, 0, ieee80211_sysctl_msecs_ticks, "I",
151         "ADDBA request timeout (ms)");
152 static  int ieee80211_addba_backoff = -1;/* backoff after max ADDBA requests */
153 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff, CTLTYPE_INT | CTLFLAG_RW,
154         &ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I",
155         "ADDBA request backoff (ms)");
156 static  int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
157 SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW,
158         &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
159
160 static  int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
161 static  int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
162
163 static  ieee80211_recv_action_func ht_recv_action_ba_addba_request;
164 static  ieee80211_recv_action_func ht_recv_action_ba_addba_response;
165 static  ieee80211_recv_action_func ht_recv_action_ba_delba;
166 static  ieee80211_recv_action_func ht_recv_action_ht_mimopwrsave;
167 static  ieee80211_recv_action_func ht_recv_action_ht_txchwidth;
168
169 static  ieee80211_send_action_func ht_send_action_ba_addba;
170 static  ieee80211_send_action_func ht_send_action_ba_delba;
171 static  ieee80211_send_action_func ht_send_action_ht_txchwidth;
172
173 static void
174 ieee80211_ht_init(void)
175 {
176         /*
177          * Setup HT parameters that depends on the clock frequency.
178          */
179 #ifdef IEEE80211_AMPDU_AGE
180         ieee80211_ampdu_age = msecs_to_ticks(500);
181 #endif
182         ieee80211_addba_timeout = msecs_to_ticks(250);
183         ieee80211_addba_backoff = msecs_to_ticks(10*1000);
184         ieee80211_bar_timeout = msecs_to_ticks(250);
185         /*
186          * Register action frame handlers.
187          */
188         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
189             IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_recv_action_ba_addba_request);
190         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
191             IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_recv_action_ba_addba_response);
192         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
193             IEEE80211_ACTION_BA_DELBA, ht_recv_action_ba_delba);
194         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT, 
195             IEEE80211_ACTION_HT_MIMOPWRSAVE, ht_recv_action_ht_mimopwrsave);
196         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT, 
197             IEEE80211_ACTION_HT_TXCHWIDTH, ht_recv_action_ht_txchwidth);
198
199         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
200             IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_send_action_ba_addba);
201         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
202             IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_send_action_ba_addba);
203         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
204             IEEE80211_ACTION_BA_DELBA, ht_send_action_ba_delba);
205         ieee80211_send_action_register(IEEE80211_ACTION_CAT_HT, 
206             IEEE80211_ACTION_HT_TXCHWIDTH, ht_send_action_ht_txchwidth);
207 }
208 SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
209
210 static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
211         struct ieee80211_tx_ampdu *tap);
212 static int ieee80211_addba_request(struct ieee80211_node *ni,
213         struct ieee80211_tx_ampdu *tap,
214         int dialogtoken, int baparamset, int batimeout);
215 static int ieee80211_addba_response(struct ieee80211_node *ni,
216         struct ieee80211_tx_ampdu *tap,
217         int code, int baparamset, int batimeout);
218 static void ieee80211_addba_stop(struct ieee80211_node *ni,
219         struct ieee80211_tx_ampdu *tap);
220 static void ieee80211_bar_response(struct ieee80211_node *ni,
221         struct ieee80211_tx_ampdu *tap, int status);
222 static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
223 static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
224 static int ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *,
225         int baparamset, int batimeout, int baseqctl);
226 static void ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *);
227
228 void
229 ieee80211_ht_attach(struct ieee80211com *ic)
230 {
231         /* setup default aggregation policy */
232         ic->ic_recv_action = ieee80211_recv_action;
233         ic->ic_send_action = ieee80211_send_action;
234         ic->ic_ampdu_enable = ieee80211_ampdu_enable;
235         ic->ic_addba_request = ieee80211_addba_request;
236         ic->ic_addba_response = ieee80211_addba_response;
237         ic->ic_addba_stop = ieee80211_addba_stop;
238         ic->ic_bar_response = ieee80211_bar_response;
239         ic->ic_ampdu_rx_start = ampdu_rx_start;
240         ic->ic_ampdu_rx_stop = ampdu_rx_stop;
241
242         ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
243         ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
244 }
245
246 void
247 ieee80211_ht_detach(struct ieee80211com *ic)
248 {
249 }
250
251 void
252 ieee80211_ht_vattach(struct ieee80211vap *vap)
253 {
254
255         /* driver can override defaults */
256         vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
257         vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
258         vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
259         vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
260         /* tx aggregation traffic thresholds */
261         vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
262         vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
263         vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
264         vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
265
266         if (vap->iv_htcaps & IEEE80211_HTC_HT) {
267                 /*
268                  * Device is HT capable; enable all HT-related
269                  * facilities by default.
270                  * XXX these choices may be too aggressive.
271                  */
272                 vap->iv_flags_ht |= IEEE80211_FHT_HT
273                                  |  IEEE80211_FHT_HTCOMPAT
274                                  ;
275                 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
276                         vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI20;
277                 /* XXX infer from channel list? */
278                 if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
279                         vap->iv_flags_ht |= IEEE80211_FHT_USEHT40;
280                         if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
281                                 vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI40;
282                 }
283                 /* enable RIFS if capable */
284                 if (vap->iv_htcaps & IEEE80211_HTC_RIFS)
285                         vap->iv_flags_ht |= IEEE80211_FHT_RIFS;
286
287                 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
288                 vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_RX;
289                 if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
290                         vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_TX;
291                 vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_RX;
292                 if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
293                         vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_TX;
294         }
295         /* NB: disable default legacy WDS, too many issues right now */
296         if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
297                 vap->iv_flags_ht &= ~IEEE80211_FHT_HT;
298 }
299
300 void
301 ieee80211_ht_vdetach(struct ieee80211vap *vap)
302 {
303 }
304
305 static int
306 ht_getrate(struct ieee80211com *ic, int index, int mode, int ratetype)
307 {
308         int mword, rate;
309
310         mword = ieee80211_rate2media(ic, index | IEEE80211_RATE_MCS, mode);
311         if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
312                 return (0);
313         switch (ratetype) {
314         case 0:
315                 rate = ieee80211_htrates[index].ht20_rate_800ns;
316                 break;
317         case 1:
318                 rate = ieee80211_htrates[index].ht20_rate_400ns;
319                 break;
320         case 2:
321                 rate = ieee80211_htrates[index].ht40_rate_800ns;
322                 break;
323         default:
324                 rate = ieee80211_htrates[index].ht40_rate_400ns;
325                 break;
326         }
327         return (rate);
328 }
329
330 static struct printranges {
331         int     minmcs;
332         int     maxmcs;
333         int     txstream;
334         int     ratetype;
335         int     htcapflags;
336 } ranges[] = {
337         {  0,  7, 1, 0, 0 },
338         {  8, 15, 2, 0, 0 },
339         { 16, 23, 3, 0, 0 },
340         { 24, 31, 4, 0, 0 },
341         { 32,  0, 1, 2, IEEE80211_HTC_TXMCS32 },
342         { 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL },
343         { 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL },
344         { 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL },
345         {  0,  0, 0, 0, 0 },
346 };
347
348 static void
349 ht_rateprint(struct ieee80211com *ic, int mode, int ratetype)
350 {
351         struct ifnet *ifp = ic->ic_ifp;
352         int minrate, maxrate;
353         struct printranges *range;
354
355         for (range = ranges; range->txstream != 0; range++) {
356                 if (ic->ic_txstream < range->txstream)
357                         continue;
358                 if (range->htcapflags &&
359                     (ic->ic_htcaps & range->htcapflags) == 0)
360                         continue;
361                 if (ratetype < range->ratetype)
362                         continue;
363                 minrate = ht_getrate(ic, range->minmcs, mode, ratetype);
364                 maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype);
365                 if (range->maxmcs) {
366                         if_printf(ifp, "MCS %d-%d: %d%sMbps - %d%sMbps\n",
367                             range->minmcs, range->maxmcs,
368                             minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""),
369                             maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : ""));
370                 } else {
371                         if_printf(ifp, "MCS %d: %d%sMbps\n", range->minmcs,
372                             minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""));
373                 }
374         }
375 }
376
377 static void
378 ht_announce(struct ieee80211com *ic, int mode)
379 {
380         struct ifnet *ifp = ic->ic_ifp;
381         const char *modestr = ieee80211_phymode_name[mode];
382
383         if_printf(ifp, "%s MCS 20MHz\n", modestr);
384         ht_rateprint(ic, mode, 0);
385         if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) {
386                 if_printf(ifp, "%s MCS 20MHz SGI\n", modestr);
387                 ht_rateprint(ic, mode, 1);
388         }
389         if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
390                 if_printf(ifp, "%s MCS 40MHz:\n", modestr);
391                 ht_rateprint(ic, mode, 2);
392         }
393         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
394             (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) {
395                 if_printf(ifp, "%s MCS 40MHz SGI:\n", modestr);
396                 ht_rateprint(ic, mode, 3);
397         }
398 }
399
400 void
401 ieee80211_ht_announce(struct ieee80211com *ic)
402 {
403         struct ifnet *ifp = ic->ic_ifp;
404
405         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
406             isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
407                 if_printf(ifp, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream);
408         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
409                 ht_announce(ic, IEEE80211_MODE_11NA);
410         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
411                 ht_announce(ic, IEEE80211_MODE_11NG);
412 }
413
414 static struct ieee80211_htrateset htrateset;
415
416 const struct ieee80211_htrateset *
417 ieee80211_get_suphtrates(struct ieee80211com *ic,
418     const struct ieee80211_channel *c)
419 {
420 #define ADDRATE(x)      do {                                            \
421         htrateset.rs_rates[htrateset.rs_nrates] = x;                    \
422         htrateset.rs_nrates++;                                          \
423 } while (0)
424         int i;
425
426         memset(&htrateset, 0, sizeof(struct ieee80211_htrateset));
427         for (i = 0; i < ic->ic_txstream * 8; i++)
428                 ADDRATE(i);
429         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
430             (ic->ic_htcaps & IEEE80211_HTC_TXMCS32))
431                 ADDRATE(i);
432         if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
433                 if (ic->ic_txstream >= 2) {
434                          for (i = 33; i <= 38; i++)
435                                 ADDRATE(i);
436                 }
437                 if (ic->ic_txstream >= 3) {
438                         for (i = 39; i <= 52; i++)
439                                 ADDRATE(i);
440                 }
441                 if (ic->ic_txstream == 4) {
442                         for (i = 53; i <= 76; i++)
443                                 ADDRATE(i);
444                 }
445         }
446         return &htrateset;
447 #undef  ADDRATE
448 }
449
450 /*
451  * Receive processing.
452  */
453
454 /*
455  * Decap the encapsulated A-MSDU frames and dispatch all but
456  * the last for delivery.  The last frame is returned for 
457  * delivery via the normal path.
458  */
459 struct mbuf *
460 ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
461 {
462         struct ieee80211vap *vap = ni->ni_vap;
463         int framelen;
464         struct mbuf *n;
465
466         /* discard 802.3 header inserted by ieee80211_decap */
467         m_adj(m, sizeof(struct ether_header));
468
469         vap->iv_stats.is_amsdu_decap++;
470
471         for (;;) {
472                 /*
473                  * Decap the first frame, bust it apart from the
474                  * remainder and deliver.  We leave the last frame
475                  * delivery to the caller (for consistency with other
476                  * code paths, could also do it here).
477                  */
478                 m = ieee80211_decap1(m, &framelen);
479                 if (m == NULL) {
480                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
481                             ni->ni_macaddr, "a-msdu", "%s", "decap failed");
482                         vap->iv_stats.is_amsdu_tooshort++;
483                         return NULL;
484                 }
485                 if (m->m_pkthdr.len == framelen)
486                         break;
487                 n = m_split(m, framelen, M_NOWAIT);
488                 if (n == NULL) {
489                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
490                             ni->ni_macaddr, "a-msdu",
491                             "%s", "unable to split encapsulated frames");
492                         vap->iv_stats.is_amsdu_split++;
493                         m_freem(m);                     /* NB: must reclaim */
494                         return NULL;
495                 }
496                 vap->iv_deliver_data(vap, ni, m);
497
498                 /*
499                  * Remove frame contents; each intermediate frame
500                  * is required to be aligned to a 4-byte boundary.
501                  */
502                 m = n;
503                 m_adj(m, roundup2(framelen, 4) - framelen);     /* padding */
504         }
505         return m;                               /* last delivered by caller */
506 }
507
508 /*
509  * Purge all frames in the A-MPDU re-order queue.
510  */
511 static void
512 ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
513 {
514         struct mbuf *m;
515         int i;
516
517         for (i = 0; i < rap->rxa_wnd; i++) {
518                 m = rap->rxa_m[i];
519                 if (m != NULL) {
520                         rap->rxa_m[i] = NULL;
521                         rap->rxa_qbytes -= m->m_pkthdr.len;
522                         m_freem(m);
523                         if (--rap->rxa_qframes == 0)
524                                 break;
525                 }
526         }
527         KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
528             ("lost %u data, %u frames on ampdu rx q",
529             rap->rxa_qbytes, rap->rxa_qframes));
530 }
531
532 /*
533  * Start A-MPDU rx/re-order processing for the specified TID.
534  */
535 static int
536 ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,
537         int baparamset, int batimeout, int baseqctl)
538 {
539         int bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
540
541         if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
542                 /*
543                  * AMPDU previously setup and not terminated with a DELBA,
544                  * flush the reorder q's in case anything remains.
545                  */
546                 ampdu_rx_purge(rap);
547         }
548         memset(rap, 0, sizeof(*rap));
549         rap->rxa_wnd = (bufsiz == 0) ?
550             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
551         rap->rxa_start = MS(baseqctl, IEEE80211_BASEQ_START);
552         rap->rxa_flags |=  IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
553
554         return 0;
555 }
556
557 /*
558  * Stop A-MPDU rx processing for the specified TID.
559  */
560 static void
561 ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
562 {
563
564         ampdu_rx_purge(rap);
565         rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND);
566 }
567
568 /*
569  * Dispatch a frame from the A-MPDU reorder queue.  The
570  * frame is fed back into ieee80211_input marked with an
571  * M_AMPDU_MPDU flag so it doesn't come back to us (it also
572  * permits ieee80211_input to optimize re-processing).
573  */
574 static __inline void
575 ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
576 {
577         m->m_flags |= M_AMPDU_MPDU;     /* bypass normal processing */
578         /* NB: rssi and noise are ignored w/ M_AMPDU_MPDU set */
579         (void) ieee80211_input(ni, m, 0, 0);
580 }
581
582 /*
583  * Dispatch as many frames as possible from the re-order queue.
584  * Frames will always be "at the front"; we process all frames
585  * up to the first empty slot in the window.  On completion we
586  * cleanup state if there are still pending frames in the current
587  * BA window.  We assume the frame at slot 0 is already handled
588  * by the caller; we always start at slot 1.
589  */
590 static void
591 ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
592 {
593         struct ieee80211vap *vap = ni->ni_vap;
594         struct mbuf *m;
595         int i;
596
597         /* flush run of frames */
598         for (i = 1; i < rap->rxa_wnd; i++) {
599                 m = rap->rxa_m[i];
600                 if (m == NULL)
601                         break;
602                 rap->rxa_m[i] = NULL;
603                 rap->rxa_qbytes -= m->m_pkthdr.len;
604                 rap->rxa_qframes--;
605
606                 ampdu_dispatch(ni, m);
607         }
608         /*
609          * If frames remain, copy the mbuf pointers down so
610          * they correspond to the offsets in the new window.
611          */
612         if (rap->rxa_qframes != 0) {
613                 int n = rap->rxa_qframes, j;
614                 for (j = i+1; j < rap->rxa_wnd; j++) {
615                         if (rap->rxa_m[j] != NULL) {
616                                 rap->rxa_m[j-i] = rap->rxa_m[j];
617                                 rap->rxa_m[j] = NULL;
618                                 if (--n == 0)
619                                         break;
620                         }
621                 }
622                 KASSERT(n == 0, ("lost %d frames", n));
623                 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
624         }
625         /*
626          * Adjust the start of the BA window to
627          * reflect the frames just dispatched.
628          */
629         rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
630         vap->iv_stats.is_ampdu_rx_oor += i;
631 }
632
633 #ifdef IEEE80211_AMPDU_AGE
634 /*
635  * Dispatch all frames in the A-MPDU re-order queue.
636  */
637 static void
638 ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
639 {
640         struct ieee80211vap *vap = ni->ni_vap;
641         struct mbuf *m;
642         int i;
643
644         for (i = 0; i < rap->rxa_wnd; i++) {
645                 m = rap->rxa_m[i];
646                 if (m == NULL)
647                         continue;
648                 rap->rxa_m[i] = NULL;
649                 rap->rxa_qbytes -= m->m_pkthdr.len;
650                 rap->rxa_qframes--;
651                 vap->iv_stats.is_ampdu_rx_oor++;
652
653                 ampdu_dispatch(ni, m);
654                 if (rap->rxa_qframes == 0)
655                         break;
656         }
657 }
658 #endif /* IEEE80211_AMPDU_AGE */
659
660 /*
661  * Dispatch all frames in the A-MPDU re-order queue
662  * preceding the specified sequence number.  This logic
663  * handles window moves due to a received MSDU or BAR.
664  */
665 static void
666 ampdu_rx_flush_upto(struct ieee80211_node *ni,
667         struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
668 {
669         struct ieee80211vap *vap = ni->ni_vap;
670         struct mbuf *m;
671         ieee80211_seq seqno;
672         int i;
673
674         /*
675          * Flush any complete MSDU's with a sequence number lower
676          * than winstart.  Gaps may exist.  Note that we may actually
677          * dispatch frames past winstart if a run continues; this is
678          * an optimization that avoids having to do a separate pass
679          * to dispatch frames after moving the BA window start.
680          */
681         seqno = rap->rxa_start;
682         for (i = 0; i < rap->rxa_wnd; i++) {
683                 m = rap->rxa_m[i];
684                 if (m != NULL) {
685                         rap->rxa_m[i] = NULL;
686                         rap->rxa_qbytes -= m->m_pkthdr.len;
687                         rap->rxa_qframes--;
688                         vap->iv_stats.is_ampdu_rx_oor++;
689
690                         ampdu_dispatch(ni, m);
691                 } else {
692                         if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
693                                 break;
694                 }
695                 seqno = IEEE80211_SEQ_INC(seqno);
696         }
697         /*
698          * If frames remain, copy the mbuf pointers down so
699          * they correspond to the offsets in the new window.
700          */
701         if (rap->rxa_qframes != 0) {
702                 int n = rap->rxa_qframes, j;
703
704                 /* NB: this loop assumes i > 0 and/or rxa_m[0] is NULL */
705                 KASSERT(rap->rxa_m[0] == NULL,
706                     ("%s: BA window slot 0 occupied", __func__));
707                 for (j = i+1; j < rap->rxa_wnd; j++) {
708                         if (rap->rxa_m[j] != NULL) {
709                                 rap->rxa_m[j-i] = rap->rxa_m[j];
710                                 rap->rxa_m[j] = NULL;
711                                 if (--n == 0)
712                                         break;
713                         }
714                 }
715                 KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
716                     "BA win <%d:%d> winstart %d",
717                     __func__, n, rap->rxa_qframes, i, rap->rxa_start,
718                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
719                     winstart));
720                 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
721         }
722         /*
723          * Move the start of the BA window; we use the
724          * sequence number of the last MSDU that was
725          * passed up the stack+1 or winstart if stopped on
726          * a gap in the reorder buffer.
727          */
728         rap->rxa_start = seqno;
729 }
730
731 /*
732  * Process a received QoS data frame for an HT station.  Handle
733  * A-MPDU reordering: if this frame is received out of order
734  * and falls within the BA window hold onto it.  Otherwise if
735  * this frame completes a run, flush any pending frames.  We
736  * return 1 if the frame is consumed.  A 0 is returned if
737  * the frame should be processed normally by the caller.
738  */
739 int
740 ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
741 {
742 #define IEEE80211_FC0_QOSDATA \
743         (IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
744 #define PROCESS         0       /* caller should process frame */
745 #define CONSUMED        1       /* frame consumed, caller does nothing */
746         struct ieee80211vap *vap = ni->ni_vap;
747         struct ieee80211_qosframe *wh;
748         struct ieee80211_rx_ampdu *rap;
749         ieee80211_seq rxseq;
750         uint8_t tid;
751         int off;
752
753         KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
754             ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
755         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
756
757         /* NB: m_len known to be sufficient */
758         wh = mtod(m, struct ieee80211_qosframe *);
759         if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) {
760                 /*
761                  * Not QoS data, shouldn't get here but just
762                  * return it to the caller for processing.
763                  */
764                 return PROCESS;
765         }
766         if (IEEE80211_IS_DSTODS(wh))
767                 tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
768         else
769                 tid = wh->i_qos[0];
770         tid &= IEEE80211_QOS_TID;
771         rap = &ni->ni_rx_ampdu[tid];
772         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
773                 /*
774                  * No ADDBA request yet, don't touch.
775                  */
776                 return PROCESS;
777         }
778         rxseq = le16toh(*(uint16_t *)wh->i_seq);
779         if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
780                 /*
781                  * Fragments are not allowed; toss.
782                  */
783                 IEEE80211_DISCARD_MAC(vap,
784                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
785                     "A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
786                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
787                 vap->iv_stats.is_ampdu_rx_drop++;
788                 IEEE80211_NODE_STAT(ni, rx_drop);
789                 m_freem(m);
790                 return CONSUMED;
791         }
792         rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
793         rap->rxa_nframes++;
794 again:
795         if (rxseq == rap->rxa_start) {
796                 /*
797                  * First frame in window.
798                  */
799                 if (rap->rxa_qframes != 0) {
800                         /*
801                          * Dispatch as many packets as we can.
802                          */
803                         KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
804                         ampdu_dispatch(ni, m);
805                         ampdu_rx_dispatch(rap, ni);
806                         return CONSUMED;
807                 } else {
808                         /*
809                          * In order; advance window and notify
810                          * caller to dispatch directly.
811                          */
812                         rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
813                         return PROCESS;
814                 }
815         }
816         /*
817          * Frame is out of order; store if in the BA window.
818          */
819         /* calculate offset in BA window */
820         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
821         if (off < rap->rxa_wnd) {
822                 /*
823                  * Common case (hopefully): in the BA window.
824                  * Sec 9.10.7.6.2 a) (p.137)
825                  */
826 #ifdef IEEE80211_AMPDU_AGE
827                 /* 
828                  * Check for frames sitting too long in the reorder queue.
829                  * This should only ever happen if frames are not delivered
830                  * without the sender otherwise notifying us (e.g. with a
831                  * BAR to move the window).  Typically this happens because
832                  * of vendor bugs that cause the sequence number to jump.
833                  * When this happens we get a gap in the reorder queue that
834                  * leaves frame sitting on the queue until they get pushed
835                  * out due to window moves.  When the vendor does not send
836                  * BAR this move only happens due to explicit packet sends
837                  *
838                  * NB: we only track the time of the oldest frame in the
839                  * reorder q; this means that if we flush we might push
840                  * frames that still "new"; if this happens then subsequent
841                  * frames will result in BA window moves which cost something
842                  * but is still better than a big throughput dip.
843                  */
844                 if (rap->rxa_qframes != 0) {
845                         /* XXX honor batimeout? */
846                         if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
847                                 /*
848                                  * Too long since we received the first
849                                  * frame; flush the reorder buffer.
850                                  */
851                                 if (rap->rxa_qframes != 0) {
852                                         vap->iv_stats.is_ampdu_rx_age +=
853                                             rap->rxa_qframes;
854                                         ampdu_rx_flush(ni, rap);
855                                 }
856                                 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
857                                 return PROCESS;
858                         }
859                 } else {
860                         /*
861                          * First frame, start aging timer.
862                          */
863                         rap->rxa_age = ticks;
864                 }
865 #endif /* IEEE80211_AMPDU_AGE */
866                 /* save packet */
867                 if (rap->rxa_m[off] == NULL) {
868                         rap->rxa_m[off] = m;
869                         rap->rxa_qframes++;
870                         rap->rxa_qbytes += m->m_pkthdr.len;
871                         vap->iv_stats.is_ampdu_rx_reorder++;
872                 } else {
873                         IEEE80211_DISCARD_MAC(vap,
874                             IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
875                             ni->ni_macaddr, "a-mpdu duplicate",
876                             "seqno %u tid %u BA win <%u:%u>",
877                             rxseq, tid, rap->rxa_start,
878                             IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
879                         vap->iv_stats.is_rx_dup++;
880                         IEEE80211_NODE_STAT(ni, rx_dup);
881                         m_freem(m);
882                 }
883                 return CONSUMED;
884         }
885         if (off < IEEE80211_SEQ_BA_RANGE) {
886                 /*
887                  * Outside the BA window, but within range;
888                  * flush the reorder q and move the window.
889                  * Sec 9.10.7.6.2 b) (p.138)
890                  */
891                 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
892                     "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
893                     rap->rxa_start,
894                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
895                     rap->rxa_qframes, rxseq, tid);
896                 vap->iv_stats.is_ampdu_rx_move++;
897
898                 /*
899                  * The spec says to flush frames up to but not including:
900                  *      WinStart_B = rxseq - rap->rxa_wnd + 1
901                  * Then insert the frame or notify the caller to process
902                  * it immediately.  We can safely do this by just starting
903                  * over again because we know the frame will now be within
904                  * the BA window.
905                  */
906                 /* NB: rxa_wnd known to be >0 */
907                 ampdu_rx_flush_upto(ni, rap,
908                     IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
909                 goto again;
910         } else {
911                 /*
912                  * Outside the BA window and out of range; toss.
913                  * Sec 9.10.7.6.2 c) (p.138)
914                  */
915                 IEEE80211_DISCARD_MAC(vap,
916                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
917                     "MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
918                     rap->rxa_start,
919                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
920                     rap->rxa_qframes, rxseq, tid,
921                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
922                 vap->iv_stats.is_ampdu_rx_drop++;
923                 IEEE80211_NODE_STAT(ni, rx_drop);
924                 m_freem(m);
925                 return CONSUMED;
926         }
927 #undef CONSUMED
928 #undef PROCESS
929 #undef IEEE80211_FC0_QOSDATA
930 }
931
932 /*
933  * Process a BAR ctl frame.  Dispatch all frames up to
934  * the sequence number of the frame.  If this frame is
935  * out of range it's discarded.
936  */
937 void
938 ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
939 {
940         struct ieee80211vap *vap = ni->ni_vap;
941         struct ieee80211_frame_bar *wh;
942         struct ieee80211_rx_ampdu *rap;
943         ieee80211_seq rxseq;
944         int tid, off;
945
946         if (!ieee80211_recv_bar_ena) {
947 #if 0
948                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
949                     ni->ni_macaddr, "BAR", "%s", "processing disabled");
950 #endif
951                 vap->iv_stats.is_ampdu_bar_bad++;
952                 return;
953         }
954         wh = mtod(m0, struct ieee80211_frame_bar *);
955         /* XXX check basic BAR */
956         tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
957         rap = &ni->ni_rx_ampdu[tid];
958         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
959                 /*
960                  * No ADDBA request yet, don't touch.
961                  */
962                 IEEE80211_DISCARD_MAC(vap,
963                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
964                     ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
965                 vap->iv_stats.is_ampdu_bar_bad++;
966                 return;
967         }
968         vap->iv_stats.is_ampdu_bar_rx++;
969         rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
970         if (rxseq == rap->rxa_start)
971                 return;
972         /* calculate offset in BA window */
973         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
974         if (off < IEEE80211_SEQ_BA_RANGE) {
975                 /*
976                  * Flush the reorder q up to rxseq and move the window.
977                  * Sec 9.10.7.6.3 a) (p.138)
978                  */
979                 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
980                     "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
981                     rap->rxa_start,
982                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
983                     rap->rxa_qframes, rxseq, tid);
984                 vap->iv_stats.is_ampdu_bar_move++;
985
986                 ampdu_rx_flush_upto(ni, rap, rxseq);
987                 if (off >= rap->rxa_wnd) {
988                         /*
989                          * BAR specifies a window start to the right of BA
990                          * window; we must move it explicitly since
991                          * ampdu_rx_flush_upto will not.
992                          */
993                         rap->rxa_start = rxseq;
994                 }
995         } else {
996                 /*
997                  * Out of range; toss.
998                  * Sec 9.10.7.6.3 b) (p.138)
999                  */
1000                 IEEE80211_DISCARD_MAC(vap,
1001                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
1002                     "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
1003                     rap->rxa_start,
1004                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
1005                     rap->rxa_qframes, rxseq, tid,
1006                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
1007                 vap->iv_stats.is_ampdu_bar_oow++;
1008                 IEEE80211_NODE_STAT(ni, rx_drop);
1009         }
1010 }
1011
1012 /*
1013  * Setup HT-specific state in a node.  Called only
1014  * when HT use is negotiated so we don't do extra
1015  * work for temporary and/or legacy sta's.
1016  */
1017 void
1018 ieee80211_ht_node_init(struct ieee80211_node *ni)
1019 {
1020         struct ieee80211_tx_ampdu *tap;
1021         int ac;
1022
1023         if (ni->ni_flags & IEEE80211_NODE_HT) {
1024                 /*
1025                  * Clean AMPDU state on re-associate.  This handles the case
1026                  * where a station leaves w/o notifying us and then returns
1027                  * before node is reaped for inactivity.
1028                  */
1029                 ieee80211_ht_node_cleanup(ni);
1030         }
1031         for (ac = 0; ac < WME_NUM_AC; ac++) {
1032                 tap = &ni->ni_tx_ampdu[ac];
1033                 tap->txa_ac = ac;
1034                 tap->txa_ni = ni;
1035                 /* NB: further initialization deferred */
1036         }
1037         ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
1038 }
1039
1040 /*
1041  * Cleanup HT-specific state in a node.  Called only
1042  * when HT use has been marked.
1043  */
1044 void
1045 ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
1046 {
1047         struct ieee80211com *ic = ni->ni_ic;
1048         int i;
1049
1050         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
1051
1052         /* XXX optimize this */
1053         for (i = 0; i < WME_NUM_AC; i++) {
1054                 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
1055                 if (tap->txa_flags & IEEE80211_AGGR_SETUP)
1056                         ampdu_tx_stop(tap);
1057         }
1058         for (i = 0; i < WME_NUM_TID; i++)
1059                 ic->ic_ampdu_rx_stop(ni, &ni->ni_rx_ampdu[i]);
1060
1061         ni->ni_htcap = 0;
1062         ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
1063 }
1064
1065 /*
1066  * Age out HT resources for a station.
1067  */
1068 void
1069 ieee80211_ht_node_age(struct ieee80211_node *ni)
1070 {
1071 #ifdef IEEE80211_AMPDU_AGE
1072         struct ieee80211vap *vap = ni->ni_vap;
1073         uint8_t tid;
1074 #endif
1075
1076         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
1077
1078 #ifdef IEEE80211_AMPDU_AGE
1079         for (tid = 0; tid < WME_NUM_TID; tid++) {
1080                 struct ieee80211_rx_ampdu *rap;
1081
1082                 rap = &ni->ni_rx_ampdu[tid];
1083                 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
1084                         continue;
1085                 if (rap->rxa_qframes == 0)
1086                         continue;
1087                 /* 
1088                  * Check for frames sitting too long in the reorder queue.
1089                  * See above for more details on what's happening here.
1090                  */
1091                 /* XXX honor batimeout? */
1092                 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
1093                         /*
1094                          * Too long since we received the first
1095                          * frame; flush the reorder buffer.
1096                          */
1097                         vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
1098                         ampdu_rx_flush(ni, rap);
1099                 }
1100         }
1101 #endif /* IEEE80211_AMPDU_AGE */
1102 }
1103
1104 static struct ieee80211_channel *
1105 findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
1106 {
1107         return ieee80211_find_channel(ic, c->ic_freq,
1108             (c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
1109 }
1110
1111 /*
1112  * Adjust a channel to be HT/non-HT according to the vap's configuration.
1113  */
1114 struct ieee80211_channel *
1115 ieee80211_ht_adjust_channel(struct ieee80211com *ic,
1116         struct ieee80211_channel *chan, int flags)
1117 {
1118         struct ieee80211_channel *c;
1119
1120         if (flags & IEEE80211_FHT_HT) {
1121                 /* promote to HT if possible */
1122                 if (flags & IEEE80211_FHT_USEHT40) {
1123                         if (!IEEE80211_IS_CHAN_HT40(chan)) {
1124                                 /* NB: arbitrarily pick ht40+ over ht40- */
1125                                 c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
1126                                 if (c == NULL)
1127                                         c = findhtchan(ic, chan,
1128                                                 IEEE80211_CHAN_HT40D);
1129                                 if (c == NULL)
1130                                         c = findhtchan(ic, chan,
1131                                                 IEEE80211_CHAN_HT20);
1132                                 if (c != NULL)
1133                                         chan = c;
1134                         }
1135                 } else if (!IEEE80211_IS_CHAN_HT20(chan)) {
1136                         c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
1137                         if (c != NULL)
1138                                 chan = c;
1139                 }
1140         } else if (IEEE80211_IS_CHAN_HT(chan)) {
1141                 /* demote to legacy, HT use is disabled */
1142                 c = ieee80211_find_channel(ic, chan->ic_freq,
1143                     chan->ic_flags &~ IEEE80211_CHAN_HT);
1144                 if (c != NULL)
1145                         chan = c;
1146         }
1147         return chan;
1148 }
1149
1150 /*
1151  * Setup HT-specific state for a legacy WDS peer.
1152  */
1153 void
1154 ieee80211_ht_wds_init(struct ieee80211_node *ni)
1155 {
1156         struct ieee80211vap *vap = ni->ni_vap;
1157         struct ieee80211_tx_ampdu *tap;
1158         int ac;
1159
1160         KASSERT(vap->iv_flags_ht & IEEE80211_FHT_HT, ("no HT requested"));
1161
1162         /* XXX check scan cache in case peer has an ap and we have info */
1163         /*
1164          * If setup with a legacy channel; locate an HT channel.
1165          * Otherwise if the inherited channel (from a companion
1166          * AP) is suitable use it so we use the same location
1167          * for the extension channel).
1168          */
1169         ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
1170             ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
1171
1172         ni->ni_htcap = 0;
1173         if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
1174                 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
1175         if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
1176                 ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
1177                 ni->ni_chw = 40;
1178                 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
1179                         ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
1180                 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
1181                         ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
1182                 if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
1183                         ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
1184         } else {
1185                 ni->ni_chw = 20;
1186                 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
1187         }
1188         ni->ni_htctlchan = ni->ni_chan->ic_ieee;
1189         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
1190                 ni->ni_flags |= IEEE80211_NODE_RIFS;
1191         /* XXX does it make sense to enable SMPS? */
1192
1193         ni->ni_htopmode = 0;            /* XXX need protection state */
1194         ni->ni_htstbc = 0;              /* XXX need info */
1195
1196         for (ac = 0; ac < WME_NUM_AC; ac++) {
1197                 tap = &ni->ni_tx_ampdu[ac];
1198                 tap->txa_ac = ac;
1199         }
1200         /* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
1201         ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
1202 }
1203
1204 /*
1205  * Notify hostap vaps of a change in the HTINFO ie.
1206  */
1207 static void
1208 htinfo_notify(struct ieee80211com *ic)
1209 {
1210         struct ieee80211vap *vap;
1211         int first = 1;
1212
1213         IEEE80211_LOCK_ASSERT(ic);
1214
1215         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
1216                 if (vap->iv_opmode != IEEE80211_M_HOSTAP)
1217                         continue;
1218                 if (vap->iv_state != IEEE80211_S_RUN ||
1219                     !IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
1220                         continue;
1221                 if (first) {
1222                         IEEE80211_NOTE(vap,
1223                             IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
1224                             vap->iv_bss,
1225                             "HT bss occupancy change: %d sta, %d ht, "
1226                             "%d ht40%s, HT protmode now 0x%x"
1227                             , ic->ic_sta_assoc
1228                             , ic->ic_ht_sta_assoc
1229                             , ic->ic_ht40_sta_assoc
1230                             , (ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) ?
1231                                  ", non-HT sta present" : ""
1232                             , ic->ic_curhtprotmode);
1233                         first = 0;
1234                 }
1235                 ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
1236         }
1237 }
1238
1239 /*
1240  * Calculate HT protection mode from current
1241  * state and handle updates.
1242  */
1243 static void
1244 htinfo_update(struct ieee80211com *ic)
1245 {
1246         uint8_t protmode;
1247
1248         if (ic->ic_sta_assoc != ic->ic_ht_sta_assoc) {
1249                 protmode = IEEE80211_HTINFO_OPMODE_MIXED
1250                          | IEEE80211_HTINFO_NONHT_PRESENT;
1251         } else if (ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) {
1252                 protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
1253                          | IEEE80211_HTINFO_NONHT_PRESENT;
1254         } else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
1255             IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) && 
1256             ic->ic_sta_assoc != ic->ic_ht40_sta_assoc) {
1257                 protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
1258         } else {
1259                 protmode = IEEE80211_HTINFO_OPMODE_PURE;
1260         }
1261         if (protmode != ic->ic_curhtprotmode) {
1262                 ic->ic_curhtprotmode = protmode;
1263                 htinfo_notify(ic);
1264         }
1265 }
1266
1267 /*
1268  * Handle an HT station joining a BSS.
1269  */
1270 void
1271 ieee80211_ht_node_join(struct ieee80211_node *ni)
1272 {
1273         struct ieee80211com *ic = ni->ni_ic;
1274
1275         IEEE80211_LOCK_ASSERT(ic);
1276
1277         if (ni->ni_flags & IEEE80211_NODE_HT) {
1278                 ic->ic_ht_sta_assoc++;
1279                 if (ni->ni_chw == 40)
1280                         ic->ic_ht40_sta_assoc++;
1281         }
1282         htinfo_update(ic);
1283 }
1284
1285 /*
1286  * Handle an HT station leaving a BSS.
1287  */
1288 void
1289 ieee80211_ht_node_leave(struct ieee80211_node *ni)
1290 {
1291         struct ieee80211com *ic = ni->ni_ic;
1292
1293         IEEE80211_LOCK_ASSERT(ic);
1294
1295         if (ni->ni_flags & IEEE80211_NODE_HT) {
1296                 ic->ic_ht_sta_assoc--;
1297                 if (ni->ni_chw == 40)
1298                         ic->ic_ht40_sta_assoc--;
1299         }
1300         htinfo_update(ic);
1301 }
1302
1303 /*
1304  * Public version of htinfo_update; used for processing
1305  * beacon frames from overlapping bss.
1306  *
1307  * Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
1308  * (on receipt of a beacon that advertises MIXED) or
1309  * IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
1310  * from an overlapping legacy bss).  We treat MIXED with
1311  * a higher precedence than PROTOPT (i.e. we will not change
1312  * change PROTOPT -> MIXED; only MIXED -> PROTOPT).  This
1313  * corresponds to how we handle things in htinfo_update.
1314  */
1315 void
1316 ieee80211_htprot_update(struct ieee80211com *ic, int protmode)
1317 {
1318 #define OPMODE(x)       SM(x, IEEE80211_HTINFO_OPMODE)
1319         IEEE80211_LOCK(ic);
1320
1321         /* track non-HT station presence */
1322         KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
1323             ("protmode 0x%x", protmode));
1324         ic->ic_flags_ht |= IEEE80211_FHT_NONHT_PR;
1325         ic->ic_lastnonht = ticks;
1326
1327         if (protmode != ic->ic_curhtprotmode &&
1328             (OPMODE(ic->ic_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
1329              OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
1330                 /* push beacon update */
1331                 ic->ic_curhtprotmode = protmode;
1332                 htinfo_notify(ic);
1333         }
1334         IEEE80211_UNLOCK(ic);
1335 #undef OPMODE
1336 }
1337
1338 /*
1339  * Time out presence of an overlapping bss with non-HT
1340  * stations.  When operating in hostap mode we listen for
1341  * beacons from other stations and if we identify a non-HT
1342  * station is present we update the opmode field of the
1343  * HTINFO ie.  To identify when all non-HT stations are
1344  * gone we time out this condition.
1345  */
1346 void
1347 ieee80211_ht_timeout(struct ieee80211com *ic)
1348 {
1349         IEEE80211_LOCK_ASSERT(ic);
1350
1351         if ((ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) &&
1352             time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
1353 #if 0
1354                 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
1355                     "%s", "time out non-HT STA present on channel");
1356 #endif
1357                 ic->ic_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
1358                 htinfo_update(ic);
1359         }
1360 }
1361
1362 /* unalligned little endian access */     
1363 #define LE_READ_2(p)                                    \
1364         ((uint16_t)                                     \
1365          ((((const uint8_t *)(p))[0]      ) |           \
1366           (((const uint8_t *)(p))[1] <<  8)))
1367
1368 /*
1369  * Process an 802.11n HT capabilities ie.
1370  */
1371 void
1372 ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1373 {
1374         if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1375                 /*
1376                  * Station used Vendor OUI ie to associate;
1377                  * mark the node so when we respond we'll use
1378                  * the Vendor OUI's and not the standard ie's.
1379                  */
1380                 ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1381                 ie += 4;
1382         } else
1383                 ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1384
1385         ni->ni_htcap = LE_READ_2(ie +
1386                 __offsetof(struct ieee80211_ie_htcap, hc_cap));
1387         ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1388 }
1389
1390 static void
1391 htinfo_parse(struct ieee80211_node *ni,
1392         const struct ieee80211_ie_htinfo *htinfo)
1393 {
1394         uint16_t w;
1395
1396         ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1397         ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
1398         w = LE_READ_2(&htinfo->hi_byte2);
1399         ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
1400         w = LE_READ_2(&htinfo->hi_byte45);
1401         ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1402 }
1403
1404 /*
1405  * Parse an 802.11n HT info ie and save useful information
1406  * to the node state.  Note this does not effect any state
1407  * changes such as for channel width change.
1408  */
1409 void
1410 ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1411 {
1412         if (ie[0] == IEEE80211_ELEMID_VENDOR)
1413                 ie += 4;
1414         htinfo_parse(ni, (const struct ieee80211_ie_htinfo *) ie);
1415 }
1416
1417 /*
1418  * Handle 11n channel switch.  Use the received HT ie's to
1419  * identify the right channel to use.  If we cannot locate it
1420  * in the channel table then fallback to legacy operation.
1421  * Note that we use this information to identify the node's
1422  * channel only; the caller is responsible for insuring any
1423  * required channel change is done (e.g. in sta mode when
1424  * parsing the contents of a beacon frame).
1425  */
1426 static void
1427 htinfo_update_chw(struct ieee80211_node *ni, int htflags)
1428 {
1429         struct ieee80211com *ic = ni->ni_ic;
1430         struct ieee80211_channel *c;
1431         int chanflags;
1432
1433         chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
1434         if (chanflags != ni->ni_chan->ic_flags) {
1435                 /* XXX not right for ht40- */
1436                 c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1437                 if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
1438                         /*
1439                          * No HT40 channel entry in our table; fall back
1440                          * to HT20 operation.  This should not happen.
1441                          */
1442                         c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1443 #if 0
1444                         IEEE80211_NOTE(ni->ni_vap,
1445                             IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1446                             "no HT40 channel (freq %u), falling back to HT20",
1447                             ni->ni_chan->ic_freq);
1448 #endif
1449                         /* XXX stat */
1450                 }
1451                 if (c != NULL && c != ni->ni_chan) {
1452                         IEEE80211_NOTE(ni->ni_vap,
1453                             IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1454                             "switch station to HT%d channel %u/0x%x",
1455                             IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
1456                             c->ic_freq, c->ic_flags);
1457                         ni->ni_chan = c;
1458                 }
1459                 /* NB: caller responsible for forcing any channel change */
1460         }
1461         /* update node's tx channel width */
1462         ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
1463 }
1464
1465 /*
1466  * Update 11n MIMO PS state according to received htcap.
1467  */
1468 static __inline int
1469 htcap_update_mimo_ps(struct ieee80211_node *ni)
1470 {
1471         uint16_t oflags = ni->ni_flags;
1472
1473         switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) {
1474         case IEEE80211_HTCAP_SMPS_DYNAMIC:
1475                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1476                 ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
1477                 break;
1478         case IEEE80211_HTCAP_SMPS_ENA:
1479                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
1480                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1481                 break;
1482         case IEEE80211_HTCAP_SMPS_OFF:
1483         default:                /* disable on rx of reserved value */
1484                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
1485                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
1486                 break;
1487         }
1488         return (oflags ^ ni->ni_flags);
1489 }
1490
1491 /*
1492  * Update short GI state according to received htcap
1493  * and local settings.
1494  */
1495 static __inline void
1496 htcap_update_shortgi(struct ieee80211_node *ni)
1497 {
1498         struct ieee80211vap *vap = ni->ni_vap;
1499
1500         ni->ni_flags &= ~(IEEE80211_NODE_SGI20|IEEE80211_NODE_SGI40);
1501         if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
1502             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20))
1503                 ni->ni_flags |= IEEE80211_NODE_SGI20;
1504         if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
1505             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
1506                 ni->ni_flags |= IEEE80211_NODE_SGI40;
1507 }
1508
1509 /*
1510  * Parse and update HT-related state extracted from
1511  * the HT cap and info ie's.
1512  */
1513 void
1514 ieee80211_ht_updateparams(struct ieee80211_node *ni,
1515         const uint8_t *htcapie, const uint8_t *htinfoie)
1516 {
1517         struct ieee80211vap *vap = ni->ni_vap;
1518         const struct ieee80211_ie_htinfo *htinfo;
1519         int htflags;
1520
1521         ieee80211_parse_htcap(ni, htcapie);
1522         if (vap->iv_htcaps & IEEE80211_HTCAP_SMPS)
1523                 htcap_update_mimo_ps(ni);
1524         htcap_update_shortgi(ni);
1525
1526         if (htinfoie[0] == IEEE80211_ELEMID_VENDOR)
1527                 htinfoie += 4;
1528         htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
1529         htinfo_parse(ni, htinfo);
1530
1531         htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
1532             IEEE80211_CHAN_HT20 : 0;
1533         /* NB: honor operating mode constraint */
1534         if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
1535             (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
1536                 if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
1537                         htflags = IEEE80211_CHAN_HT40U;
1538                 else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
1539                         htflags = IEEE80211_CHAN_HT40D;
1540         }
1541         htinfo_update_chw(ni, htflags);
1542
1543         if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
1544             (vap->iv_flags_ht & IEEE80211_FHT_RIFS))
1545                 ni->ni_flags |= IEEE80211_NODE_RIFS;
1546         else
1547                 ni->ni_flags &= ~IEEE80211_NODE_RIFS;
1548 }
1549
1550 /*
1551  * Parse and update HT-related state extracted from the HT cap ie
1552  * for a station joining an HT BSS.
1553  */
1554 void
1555 ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
1556 {
1557         struct ieee80211vap *vap = ni->ni_vap;
1558         int htflags;
1559
1560         ieee80211_parse_htcap(ni, htcapie);
1561         if (vap->iv_htcaps & IEEE80211_HTCAP_SMPS)
1562                 htcap_update_mimo_ps(ni);
1563         htcap_update_shortgi(ni);
1564
1565         /* NB: honor operating mode constraint */
1566         /* XXX 40 MHz intolerant */
1567         htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
1568             IEEE80211_CHAN_HT20 : 0;
1569         if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
1570             (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
1571                 if (IEEE80211_IS_CHAN_HT40U(vap->iv_bss->ni_chan))
1572                         htflags = IEEE80211_CHAN_HT40U;
1573                 else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
1574                         htflags = IEEE80211_CHAN_HT40D;
1575         }
1576         htinfo_update_chw(ni, htflags);
1577 }
1578
1579 /*
1580  * Install received HT rate set by parsing the HT cap ie.
1581  */
1582 int
1583 ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
1584 {
1585         struct ieee80211com *ic = ni->ni_ic;
1586         struct ieee80211vap *vap = ni->ni_vap;
1587         const struct ieee80211_ie_htcap *htcap;
1588         struct ieee80211_htrateset *rs;
1589         int i, maxequalmcs, maxunequalmcs;
1590
1591         maxequalmcs = ic->ic_txstream * 8 - 1;
1592         if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
1593                 if (ic->ic_txstream >= 2)
1594                         maxunequalmcs = 38;
1595                 if (ic->ic_txstream >= 3)
1596                         maxunequalmcs = 52;
1597                 if (ic->ic_txstream >= 4)
1598                         maxunequalmcs = 76;
1599         } else
1600                 maxunequalmcs = 0;
1601
1602         rs = &ni->ni_htrates;
1603         memset(rs, 0, sizeof(*rs));
1604         if (ie != NULL) {
1605                 if (ie[0] == IEEE80211_ELEMID_VENDOR)
1606                         ie += 4;
1607                 htcap = (const struct ieee80211_ie_htcap *) ie;
1608                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1609                         if (isclr(htcap->hc_mcsset, i))
1610                                 continue;
1611                         if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
1612                                 IEEE80211_NOTE(vap,
1613                                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1614                                     "WARNING, HT rate set too large; only "
1615                                     "using %u rates", IEEE80211_HTRATE_MAXSIZE);
1616                                 vap->iv_stats.is_rx_rstoobig++;
1617                                 break;
1618                         }
1619                         if (i <= 31 && i > maxequalmcs)
1620                                 continue;
1621                         if (i == 32 &&
1622                             (ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
1623                                 continue;
1624                         if (i > 32 && i > maxunequalmcs)
1625                                 continue;
1626                         rs->rs_rates[rs->rs_nrates++] = i;
1627                 }
1628         }
1629         return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
1630 }
1631
1632 /*
1633  * Mark rates in a node's HT rate set as basic according
1634  * to the information in the supplied HT info ie.
1635  */
1636 void
1637 ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
1638 {
1639         const struct ieee80211_ie_htinfo *htinfo;
1640         struct ieee80211_htrateset *rs;
1641         int i, j;
1642
1643         if (ie[0] == IEEE80211_ELEMID_VENDOR)
1644                 ie += 4;
1645         htinfo = (const struct ieee80211_ie_htinfo *) ie;
1646         rs = &ni->ni_htrates;
1647         if (rs->rs_nrates == 0) {
1648                 IEEE80211_NOTE(ni->ni_vap,
1649                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1650                     "%s", "WARNING, empty HT rate set");
1651                 return;
1652         }
1653         for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1654                 if (isclr(htinfo->hi_basicmcsset, i))
1655                         continue;
1656                 for (j = 0; j < rs->rs_nrates; j++)
1657                         if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
1658                                 rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
1659         }
1660 }
1661
1662 static void
1663 ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
1664 {
1665         callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
1666         tap->txa_flags |= IEEE80211_AGGR_SETUP;
1667 }
1668
1669 static void
1670 ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
1671 {
1672         struct ieee80211_node *ni = tap->txa_ni;
1673         struct ieee80211com *ic = ni->ni_ic;
1674
1675         KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
1676             ("txa_flags 0x%x ac %d", tap->txa_flags, tap->txa_ac));
1677
1678         /*
1679          * Stop BA stream if setup so driver has a chance
1680          * to reclaim any resources it might have allocated.
1681          */
1682         ic->ic_addba_stop(ni, tap);
1683         /*
1684          * Stop any pending BAR transmit.
1685          */
1686         bar_stop_timer(tap);
1687
1688         tap->txa_lastsample = 0;
1689         tap->txa_avgpps = 0;
1690         /* NB: clearing NAK means we may re-send ADDBA */ 
1691         tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
1692 }
1693
1694 static void
1695 addba_timeout(void *arg)
1696 {
1697         struct ieee80211_tx_ampdu *tap = arg;
1698
1699         /* XXX ? */
1700         tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1701         tap->txa_attempts++;
1702 }
1703
1704 static void
1705 addba_start_timeout(struct ieee80211_tx_ampdu *tap)
1706 {
1707         /* XXX use CALLOUT_PENDING instead? */
1708         callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
1709             addba_timeout, tap);
1710         tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
1711         tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
1712 }
1713
1714 static void
1715 addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
1716 {
1717         /* XXX use CALLOUT_PENDING instead? */
1718         if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
1719                 callout_stop(&tap->txa_timer);
1720                 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1721         }
1722 }
1723
1724 /*
1725  * Default method for requesting A-MPDU tx aggregation.
1726  * We setup the specified state block and start a timer
1727  * to wait for an ADDBA response frame.
1728  */
1729 static int
1730 ieee80211_addba_request(struct ieee80211_node *ni,
1731         struct ieee80211_tx_ampdu *tap,
1732         int dialogtoken, int baparamset, int batimeout)
1733 {
1734         int bufsiz;
1735
1736         /* XXX locking */
1737         tap->txa_token = dialogtoken;
1738         tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
1739         bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1740         tap->txa_wnd = (bufsiz == 0) ?
1741             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1742         addba_start_timeout(tap);
1743         return 1;
1744 }
1745
1746 /*
1747  * Default method for processing an A-MPDU tx aggregation
1748  * response.  We shutdown any pending timer and update the
1749  * state block according to the reply.
1750  */
1751 static int
1752 ieee80211_addba_response(struct ieee80211_node *ni,
1753         struct ieee80211_tx_ampdu *tap,
1754         int status, int baparamset, int batimeout)
1755 {
1756         int bufsiz, tid;
1757
1758         /* XXX locking */
1759         addba_stop_timeout(tap);
1760         if (status == IEEE80211_STATUS_SUCCESS) {
1761                 bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1762                 /* XXX override our request? */
1763                 tap->txa_wnd = (bufsiz == 0) ?
1764                     IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1765                 /* XXX AC/TID */
1766                 tid = MS(baparamset, IEEE80211_BAPS_TID);
1767                 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
1768                 tap->txa_attempts = 0;
1769         } else {
1770                 /* mark tid so we don't try again */
1771                 tap->txa_flags |= IEEE80211_AGGR_NAK;
1772         }
1773         return 1;
1774 }
1775
1776 /*
1777  * Default method for stopping A-MPDU tx aggregation.
1778  * Any timer is cleared and we drain any pending frames.
1779  */
1780 static void
1781 ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1782 {
1783         /* XXX locking */
1784         addba_stop_timeout(tap);
1785         if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
1786                 /* XXX clear aggregation queue */
1787                 tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
1788         }
1789         tap->txa_attempts = 0;
1790 }
1791
1792 /*
1793  * Process a received action frame using the default aggregation
1794  * policy.  We intercept ADDBA-related frames and use them to
1795  * update our aggregation state.  All other frames are passed up
1796  * for processing by ieee80211_recv_action.
1797  */
1798 static int
1799 ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
1800         const struct ieee80211_frame *wh,
1801         const uint8_t *frm, const uint8_t *efrm)
1802 {
1803         struct ieee80211com *ic = ni->ni_ic;
1804         struct ieee80211vap *vap = ni->ni_vap;
1805         struct ieee80211_rx_ampdu *rap;
1806         uint8_t dialogtoken;
1807         uint16_t baparamset, batimeout, baseqctl;
1808         uint16_t args[5];
1809         int tid;
1810
1811         dialogtoken = frm[2];
1812         baparamset = LE_READ_2(frm+3);
1813         batimeout = LE_READ_2(frm+5);
1814         baseqctl = LE_READ_2(frm+7);
1815
1816         tid = MS(baparamset, IEEE80211_BAPS_TID);
1817
1818         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1819             "recv ADDBA request: dialogtoken %u baparamset 0x%x "
1820             "(tid %d bufsiz %d) batimeout %d baseqctl %d:%d",
1821             dialogtoken, baparamset,
1822             tid, MS(baparamset, IEEE80211_BAPS_BUFSIZ),
1823             batimeout,
1824             MS(baseqctl, IEEE80211_BASEQ_START),
1825             MS(baseqctl, IEEE80211_BASEQ_FRAG));
1826
1827         rap = &ni->ni_rx_ampdu[tid];
1828
1829         /* Send ADDBA response */
1830         args[0] = dialogtoken;
1831         /*
1832          * NB: We ack only if the sta associated with HT and
1833          * the ap is configured to do AMPDU rx (the latter
1834          * violates the 11n spec and is mostly for testing).
1835          */
1836         if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
1837             (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
1838                 /* XXX handle ampdu_rx_start failure */
1839                 ic->ic_ampdu_rx_start(ni, rap,
1840                     baparamset, batimeout, baseqctl);
1841
1842                 args[1] = IEEE80211_STATUS_SUCCESS;
1843         } else {
1844                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1845                     ni, "reject ADDBA request: %s",
1846                     ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
1847                        "administratively disabled" :
1848                        "not negotiated for station");
1849                 vap->iv_stats.is_addba_reject++;
1850                 args[1] = IEEE80211_STATUS_UNSPECIFIED;
1851         }
1852         /* XXX honor rap flags? */
1853         args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
1854                 | SM(tid, IEEE80211_BAPS_TID)
1855                 | SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
1856                 ;
1857         args[3] = 0;
1858         args[4] = 0;
1859         ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1860                 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
1861         return 0;
1862 }
1863
1864 static int
1865 ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
1866         const struct ieee80211_frame *wh,
1867         const uint8_t *frm, const uint8_t *efrm)
1868 {
1869         struct ieee80211com *ic = ni->ni_ic;
1870         struct ieee80211vap *vap = ni->ni_vap;
1871         struct ieee80211_tx_ampdu *tap;
1872         uint8_t dialogtoken, policy;
1873         uint16_t baparamset, batimeout, code;
1874         int tid, ac, bufsiz;
1875
1876         dialogtoken = frm[2];
1877         code = LE_READ_2(frm+3);
1878         baparamset = LE_READ_2(frm+5);
1879         tid = MS(baparamset, IEEE80211_BAPS_TID);
1880         bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1881         policy = MS(baparamset, IEEE80211_BAPS_POLICY);
1882         batimeout = LE_READ_2(frm+7);
1883
1884         ac = TID_TO_WME_AC(tid);
1885         tap = &ni->ni_tx_ampdu[ac];
1886         if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1887                 IEEE80211_DISCARD_MAC(vap,
1888                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1889                     ni->ni_macaddr, "ADDBA response",
1890                     "no pending ADDBA, tid %d dialogtoken %u "
1891                     "code %d", tid, dialogtoken, code);
1892                 vap->iv_stats.is_addba_norequest++;
1893                 return 0;
1894         }
1895         if (dialogtoken != tap->txa_token) {
1896                 IEEE80211_DISCARD_MAC(vap,
1897                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1898                     ni->ni_macaddr, "ADDBA response",
1899                     "dialogtoken mismatch: waiting for %d, "
1900                     "received %d, tid %d code %d",
1901                     tap->txa_token, dialogtoken, tid, code);
1902                 vap->iv_stats.is_addba_badtoken++;
1903                 return 0;
1904         }
1905         /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
1906         if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
1907                 IEEE80211_DISCARD_MAC(vap,
1908                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1909                     ni->ni_macaddr, "ADDBA response",
1910                     "policy mismatch: expecting %s, "
1911                     "received %s, tid %d code %d",
1912                     tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
1913                     policy, tid, code);
1914                 vap->iv_stats.is_addba_badpolicy++;
1915                 return 0;
1916         }
1917 #if 0
1918         /* XXX we take MIN in ieee80211_addba_response */
1919         if (bufsiz > IEEE80211_AGGR_BAWMAX) {
1920                 IEEE80211_DISCARD_MAC(vap,
1921                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1922                     ni->ni_macaddr, "ADDBA response",
1923                     "BA window too large: max %d, "
1924                     "received %d, tid %d code %d",
1925                     bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
1926                 vap->iv_stats.is_addba_badbawinsize++;
1927                 return 0;
1928         }
1929 #endif
1930         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1931             "recv ADDBA response: dialogtoken %u code %d "
1932             "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
1933             dialogtoken, code, baparamset, tid, bufsiz,
1934             batimeout);
1935         ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
1936         return 0;
1937 }
1938
1939 static int
1940 ht_recv_action_ba_delba(struct ieee80211_node *ni,
1941         const struct ieee80211_frame *wh,
1942         const uint8_t *frm, const uint8_t *efrm)
1943 {
1944         struct ieee80211com *ic = ni->ni_ic;
1945         struct ieee80211_rx_ampdu *rap;
1946         struct ieee80211_tx_ampdu *tap;
1947         uint16_t baparamset, code;
1948         int tid, ac;
1949
1950         baparamset = LE_READ_2(frm+2);
1951         code = LE_READ_2(frm+4);
1952
1953         tid = MS(baparamset, IEEE80211_DELBAPS_TID);
1954
1955         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1956             "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
1957             "code %d", baparamset, tid,
1958             MS(baparamset, IEEE80211_DELBAPS_INIT), code);
1959
1960         if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
1961                 ac = TID_TO_WME_AC(tid);
1962                 tap = &ni->ni_tx_ampdu[ac];
1963                 ic->ic_addba_stop(ni, tap);
1964         } else {
1965                 rap = &ni->ni_rx_ampdu[tid];
1966                 ic->ic_ampdu_rx_stop(ni, rap);
1967         }
1968         return 0;
1969 }
1970
1971 static int
1972 ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
1973         const struct ieee80211_frame *wh,
1974         const uint8_t *frm, const uint8_t *efrm)
1975 {
1976         int chw;
1977
1978         chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ? 40 : 20;
1979
1980         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1981             "%s: HT txchwidth, width %d%s",
1982             __func__, chw, ni->ni_chw != chw ? "*" : "");
1983         if (chw != ni->ni_chw) {
1984                 ni->ni_chw = chw;
1985                 /* XXX notify on change */
1986         }
1987         return 0;
1988 }
1989
1990 static int
1991 ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
1992         const struct ieee80211_frame *wh,
1993         const uint8_t *frm, const uint8_t *efrm)
1994 {
1995         const struct ieee80211_action_ht_mimopowersave *mps =
1996             (const struct ieee80211_action_ht_mimopowersave *) frm;
1997
1998         /* XXX check iv_htcaps */
1999         if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
2000                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
2001         else
2002                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
2003         if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
2004                 ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
2005         else
2006                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
2007         /* XXX notify on change */
2008         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2009             "%s: HT MIMO PS (%s%s)", __func__,
2010             (ni->ni_flags & IEEE80211_NODE_MIMO_PS) ?  "on" : "off",
2011             (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ?  "+rts" : ""
2012         );
2013         return 0;
2014 }
2015
2016 /*
2017  * Transmit processing.
2018  */
2019
2020 /*
2021  * Check if A-MPDU should be requested/enabled for a stream.
2022  * We require a traffic rate above a per-AC threshold and we
2023  * also handle backoff from previous failed attempts.
2024  *
2025  * Drivers may override this method to bring in information
2026  * such as link state conditions in making the decision.
2027  */
2028 static int
2029 ieee80211_ampdu_enable(struct ieee80211_node *ni,
2030         struct ieee80211_tx_ampdu *tap)
2031 {
2032         struct ieee80211vap *vap = ni->ni_vap;
2033
2034         if (tap->txa_avgpps < vap->iv_ampdu_mintraffic[tap->txa_ac])
2035                 return 0;
2036         /* XXX check rssi? */
2037         if (tap->txa_attempts >= ieee80211_addba_maxtries &&
2038             ticks < tap->txa_nextrequest) {
2039                 /*
2040                  * Don't retry too often; txa_nextrequest is set
2041                  * to the minimum interval we'll retry after
2042                  * ieee80211_addba_maxtries failed attempts are made.
2043                  */
2044                 return 0;
2045         }
2046         IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
2047             "enable AMPDU on %s, avgpps %d pkts %d",
2048             ieee80211_wme_acnames[tap->txa_ac], tap->txa_avgpps, tap->txa_pkts);
2049         return 1;
2050 }
2051
2052 /*
2053  * Request A-MPDU tx aggregation.  Setup local state and
2054  * issue an ADDBA request.  BA use will only happen after
2055  * the other end replies with ADDBA response.
2056  */
2057 int
2058 ieee80211_ampdu_request(struct ieee80211_node *ni,
2059         struct ieee80211_tx_ampdu *tap)
2060 {
2061         struct ieee80211com *ic = ni->ni_ic;
2062         uint16_t args[5];
2063         int tid, dialogtoken;
2064         static int tokens = 0;  /* XXX */
2065
2066         /* XXX locking */
2067         if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
2068                 /* do deferred setup of state */
2069                 ampdu_tx_setup(tap);
2070         }
2071         /* XXX hack for not doing proper locking */
2072         tap->txa_flags &= ~IEEE80211_AGGR_NAK;
2073
2074         dialogtoken = (tokens+1) % 63;          /* XXX */
2075         tid = WME_AC_TO_TID(tap->txa_ac);
2076         tap->txa_start = ni->ni_txseqs[tid];
2077
2078         args[0] = dialogtoken;
2079         args[1] = 0;    /* NB: status code not used */
2080         args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
2081                 | SM(tid, IEEE80211_BAPS_TID)
2082                 | SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
2083                 ;
2084         args[3] = 0;    /* batimeout */
2085         /* NB: do first so there's no race against reply */
2086         if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
2087                 /* unable to setup state, don't make request */
2088                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2089                     ni, "%s: could not setup BA stream for AC %d",
2090                     __func__, tap->txa_ac);
2091                 /* defer next try so we don't slam the driver with requests */
2092                 tap->txa_attempts = ieee80211_addba_maxtries;
2093                 /* NB: check in case driver wants to override */
2094                 if (tap->txa_nextrequest <= ticks)
2095                         tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
2096                 return 0;
2097         }
2098         tokens = dialogtoken;                   /* allocate token */
2099         /* NB: after calling ic_addba_request so driver can set txa_start */
2100         args[4] = SM(tap->txa_start, IEEE80211_BASEQ_START)
2101                 | SM(0, IEEE80211_BASEQ_FRAG)
2102                 ;
2103         return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2104                 IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
2105 }
2106
2107 /*
2108  * Terminate an AMPDU tx stream.  State is reclaimed
2109  * and the peer notified with a DelBA Action frame.
2110  */
2111 void
2112 ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
2113         int reason)
2114 {
2115         struct ieee80211com *ic = ni->ni_ic;
2116         struct ieee80211vap *vap = ni->ni_vap;
2117         uint16_t args[4];
2118
2119         /* XXX locking */
2120         tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2121         if (IEEE80211_AMPDU_RUNNING(tap)) {
2122                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2123                     ni, "%s: stop BA stream for AC %d (reason %d)",
2124                     __func__, tap->txa_ac, reason);
2125                 vap->iv_stats.is_ampdu_stop++;
2126
2127                 ic->ic_addba_stop(ni, tap);
2128                 args[0] = WME_AC_TO_TID(tap->txa_ac);
2129                 args[1] = IEEE80211_DELBAPS_INIT;
2130                 args[2] = reason;                       /* XXX reason code */
2131                 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
2132                         IEEE80211_ACTION_BA_DELBA, args);
2133         } else {
2134                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
2135                     ni, "%s: BA stream for AC %d not running (reason %d)",
2136                     __func__, tap->txa_ac, reason);
2137                 vap->iv_stats.is_ampdu_stop_failed++;
2138         }
2139 }
2140
2141 static void
2142 bar_timeout(void *arg)
2143 {
2144         struct ieee80211_tx_ampdu *tap = arg;
2145         struct ieee80211_node *ni = tap->txa_ni;
2146
2147         KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
2148             ("bar/addba collision, flags 0x%x", tap->txa_flags));
2149
2150         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2151             ni, "%s: tid %u flags 0x%x attempts %d", __func__,
2152             tap->txa_ac, tap->txa_flags, tap->txa_attempts);
2153
2154         /* guard against race with bar_tx_complete */
2155         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
2156                 return;
2157         /* XXX ? */
2158         if (tap->txa_attempts >= ieee80211_bar_maxtries)
2159                 ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
2160         else
2161                 ieee80211_send_bar(ni, tap, tap->txa_seqpending);
2162 }
2163
2164 static void
2165 bar_start_timer(struct ieee80211_tx_ampdu *tap)
2166 {
2167         callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
2168 }
2169
2170 static void
2171 bar_stop_timer(struct ieee80211_tx_ampdu *tap)
2172 {
2173         callout_stop(&tap->txa_timer);
2174 }
2175
2176 static void
2177 bar_tx_complete(struct ieee80211_node *ni, void *arg, int status)
2178 {
2179         struct ieee80211_tx_ampdu *tap = arg;
2180
2181         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2182             ni, "%s: tid %u flags 0x%x pending %d status %d",
2183             __func__, tap->txa_ac, tap->txa_flags,
2184             callout_pending(&tap->txa_timer), status);
2185
2186         /* XXX locking */
2187         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
2188             callout_pending(&tap->txa_timer)) {
2189                 struct ieee80211com *ic = ni->ni_ic;
2190
2191                 if (status)             /* ACK'd */
2192                         bar_stop_timer(tap);
2193                 ic->ic_bar_response(ni, tap, status);
2194                 /* NB: just let timer expire so we pace requests */
2195         }
2196 }
2197
2198 static void
2199 ieee80211_bar_response(struct ieee80211_node *ni,
2200         struct ieee80211_tx_ampdu *tap, int status)
2201 {
2202
2203         if (status != 0) {              /* got ACK */
2204                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
2205                     ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
2206                     tap->txa_start,
2207                     IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
2208                     tap->txa_qframes, tap->txa_seqpending,
2209                     WME_AC_TO_TID(tap->txa_ac));
2210
2211                 /* NB: timer already stopped in bar_tx_complete */
2212                 tap->txa_start = tap->txa_seqpending;
2213                 tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2214         }
2215 }
2216
2217 /*
2218  * Transmit a BAR frame to the specified node.  The
2219  * BAR contents are drawn from the supplied aggregation
2220  * state associated with the node.
2221  *
2222  * NB: we only handle immediate ACK w/ compressed bitmap.
2223  */
2224 int
2225 ieee80211_send_bar(struct ieee80211_node *ni,
2226         struct ieee80211_tx_ampdu *tap, ieee80211_seq seq)
2227 {
2228 #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
2229         struct ieee80211vap *vap = ni->ni_vap;
2230         struct ieee80211com *ic = ni->ni_ic;
2231         struct ieee80211_frame_bar *bar;
2232         struct mbuf *m;
2233         uint16_t barctl, barseqctl;
2234         uint8_t *frm;
2235         int tid, ret;
2236
2237         if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
2238                 /* no ADDBA response, should not happen */
2239                 /* XXX stat+msg */
2240                 return EINVAL;
2241         }
2242         /* XXX locking */
2243         bar_stop_timer(tap);
2244
2245         ieee80211_ref_node(ni);
2246
2247         m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
2248         if (m == NULL)
2249                 senderr(ENOMEM, is_tx_nobuf);
2250
2251         if (!ieee80211_add_callback(m, bar_tx_complete, tap)) {
2252                 m_freem(m);
2253                 senderr(ENOMEM, is_tx_nobuf);   /* XXX */
2254                 /* NOTREACHED */
2255         }
2256
2257         bar = mtod(m, struct ieee80211_frame_bar *);
2258         bar->i_fc[0] = IEEE80211_FC0_VERSION_0 |
2259                 IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
2260         bar->i_fc[1] = 0;
2261         IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
2262         IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
2263
2264         tid = WME_AC_TO_TID(tap->txa_ac);
2265         barctl  = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
2266                         0 : IEEE80211_BAR_NOACK)
2267                 | IEEE80211_BAR_COMP
2268                 | SM(tid, IEEE80211_BAR_TID)
2269                 ;
2270         barseqctl = SM(seq, IEEE80211_BAR_SEQ_START);
2271         /* NB: known to have proper alignment */
2272         bar->i_ctl = htole16(barctl);
2273         bar->i_seq = htole16(barseqctl);
2274         m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
2275
2276         M_WME_SETAC(m, WME_AC_VO);
2277
2278         IEEE80211_NODE_STAT(ni, tx_mgmt);       /* XXX tx_ctl? */
2279
2280         /* XXX locking */
2281         /* init/bump attempts counter */
2282         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
2283                 tap->txa_attempts = 1;
2284         else
2285                 tap->txa_attempts++;
2286         tap->txa_seqpending = seq;
2287         tap->txa_flags |= IEEE80211_AGGR_BARPEND;
2288
2289         IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
2290             ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)",
2291             tid, barctl, seq, tap->txa_attempts);
2292
2293         ret = ic->ic_raw_xmit(ni, m, NULL);
2294         if (ret != 0) {
2295                 /* xmit failed, clear state flag */
2296                 tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
2297                 goto bad;
2298         }
2299         /* XXX hack against tx complete happening before timer is started */
2300         if (tap->txa_flags & IEEE80211_AGGR_BARPEND)
2301                 bar_start_timer(tap);
2302         return 0;
2303 bad:
2304         ieee80211_free_node(ni);
2305         return ret;
2306 #undef senderr
2307 }
2308
2309 static int
2310 ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
2311 {
2312         struct ieee80211_bpf_params params;
2313
2314         memset(&params, 0, sizeof(params));
2315         params.ibp_pri = WME_AC_VO;
2316         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
2317         /* NB: we know all frames are unicast */
2318         params.ibp_try0 = ni->ni_txparms->maxretry;
2319         params.ibp_power = ni->ni_txpower;
2320         return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
2321              &params);
2322 }
2323
2324 #define ADDSHORT(frm, v) do {                   \
2325         frm[0] = (v) & 0xff;                    \
2326         frm[1] = (v) >> 8;                      \
2327         frm += 2;                               \
2328 } while (0)
2329
2330 /*
2331  * Send an action management frame.  The arguments are stuff
2332  * into a frame without inspection; the caller is assumed to
2333  * prepare them carefully (e.g. based on the aggregation state).
2334  */
2335 static int
2336 ht_send_action_ba_addba(struct ieee80211_node *ni,
2337         int category, int action, void *arg0)
2338 {
2339         struct ieee80211vap *vap = ni->ni_vap;
2340         struct ieee80211com *ic = ni->ni_ic;
2341         uint16_t *args = arg0;
2342         struct mbuf *m;
2343         uint8_t *frm;
2344
2345         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2346             "send ADDBA %s: dialogtoken %d status %d "
2347             "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
2348             (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
2349                 "request" : "response",
2350             args[0], args[1], args[2], MS(args[2], IEEE80211_BAPS_TID),
2351             args[3], args[4]);
2352
2353         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2354             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2355             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2356         ieee80211_ref_node(ni);
2357
2358         m = ieee80211_getmgtframe(&frm,
2359             ic->ic_headroom + sizeof(struct ieee80211_frame),
2360             sizeof(uint16_t)    /* action+category */
2361             /* XXX may action payload */
2362             + sizeof(struct ieee80211_action_ba_addbaresponse)
2363         );
2364         if (m != NULL) {
2365                 *frm++ = category;
2366                 *frm++ = action;
2367                 *frm++ = args[0];               /* dialog token */
2368                 if (action == IEEE80211_ACTION_BA_ADDBA_RESPONSE)
2369                         ADDSHORT(frm, args[1]); /* status code */
2370                 ADDSHORT(frm, args[2]);         /* baparamset */
2371                 ADDSHORT(frm, args[3]);         /* batimeout */
2372                 if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
2373                         ADDSHORT(frm, args[4]); /* baseqctl */
2374                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2375                 return ht_action_output(ni, m);
2376         } else {
2377                 vap->iv_stats.is_tx_nobuf++;
2378                 ieee80211_free_node(ni);
2379                 return ENOMEM;
2380         }
2381 }
2382
2383 static int
2384 ht_send_action_ba_delba(struct ieee80211_node *ni,
2385         int category, int action, void *arg0)
2386 {
2387         struct ieee80211vap *vap = ni->ni_vap;
2388         struct ieee80211com *ic = ni->ni_ic;
2389         uint16_t *args = arg0;
2390         struct mbuf *m;
2391         uint16_t baparamset;
2392         uint8_t *frm;
2393
2394         baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
2395                    | args[1]
2396                    ;
2397         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2398             "send DELBA action: tid %d, initiator %d reason %d",
2399             args[0], args[1], args[2]);
2400
2401         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2402             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2403             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2404         ieee80211_ref_node(ni);
2405
2406         m = ieee80211_getmgtframe(&frm,
2407             ic->ic_headroom + sizeof(struct ieee80211_frame),
2408             sizeof(uint16_t)    /* action+category */
2409             /* XXX may action payload */
2410             + sizeof(struct ieee80211_action_ba_addbaresponse)
2411         );
2412         if (m != NULL) {
2413                 *frm++ = category;
2414                 *frm++ = action;
2415                 ADDSHORT(frm, baparamset);
2416                 ADDSHORT(frm, args[2]);         /* reason code */
2417                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2418                 return ht_action_output(ni, m);
2419         } else {
2420                 vap->iv_stats.is_tx_nobuf++;
2421                 ieee80211_free_node(ni);
2422                 return ENOMEM;
2423         }
2424 }
2425
2426 static int
2427 ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
2428         int category, int action, void *arg0)
2429 {
2430         struct ieee80211vap *vap = ni->ni_vap;
2431         struct ieee80211com *ic = ni->ni_ic;
2432         struct mbuf *m;
2433         uint8_t *frm;
2434
2435         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
2436             "send HT txchwidth: width %d",
2437             IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
2438
2439         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
2440             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
2441             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
2442         ieee80211_ref_node(ni);
2443
2444         m = ieee80211_getmgtframe(&frm,
2445             ic->ic_headroom + sizeof(struct ieee80211_frame),
2446             sizeof(uint16_t)    /* action+category */
2447             /* XXX may action payload */
2448             + sizeof(struct ieee80211_action_ba_addbaresponse)
2449         );
2450         if (m != NULL) {
2451                 *frm++ = category;
2452                 *frm++ = action;
2453                 *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 
2454                         IEEE80211_A_HT_TXCHWIDTH_2040 :
2455                         IEEE80211_A_HT_TXCHWIDTH_20;
2456                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
2457                 return ht_action_output(ni, m);
2458         } else {
2459                 vap->iv_stats.is_tx_nobuf++;
2460                 ieee80211_free_node(ni);
2461                 return ENOMEM;
2462         }
2463 }
2464 #undef ADDSHORT
2465
2466 /*
2467  * Construct the MCS bit mask for inclusion in an HT capabilities
2468  * information element.
2469  */
2470 static void
2471 ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm)
2472 {
2473         int i;
2474         uint8_t txparams;
2475
2476         KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4),
2477             ("ic_rxstream %d out of range", ic->ic_rxstream));
2478         KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4),
2479             ("ic_txstream %d out of range", ic->ic_txstream));
2480
2481         for (i = 0; i < ic->ic_rxstream * 8; i++)
2482                 setbit(frm, i);
2483         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
2484             (ic->ic_htcaps & IEEE80211_HTC_RXMCS32))
2485                 setbit(frm, 32);
2486         if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) {
2487                 if (ic->ic_rxstream >= 2) {
2488                         for (i = 33; i <= 38; i++)
2489                                 setbit(frm, i);
2490                 }
2491                 if (ic->ic_rxstream >= 3) {
2492                         for (i = 39; i <= 52; i++)
2493                                 setbit(frm, i);
2494                 }
2495                 if (ic->ic_txstream >= 4) {
2496                         for (i = 53; i <= 76; i++)
2497                                 setbit(frm, i);
2498                 }
2499         }
2500
2501         if (ic->ic_rxstream != ic->ic_txstream) {
2502                 txparams = 0x1;                 /* TX MCS set defined */
2503                 txparams |= 0x2;                /* TX RX MCS not equal */
2504                 txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */
2505                 if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL)
2506                         txparams |= 0x16;       /* TX unequal modulation sup */
2507         } else
2508                 txparams = 0;
2509         frm[12] = txparams;
2510 }
2511
2512 /*
2513  * Add body of an HTCAP information element.
2514  */
2515 static uint8_t *
2516 ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
2517 {
2518 #define ADDSHORT(frm, v) do {                   \
2519         frm[0] = (v) & 0xff;                    \
2520         frm[1] = (v) >> 8;                      \
2521         frm += 2;                               \
2522 } while (0)
2523         struct ieee80211com *ic = ni->ni_ic;
2524         struct ieee80211vap *vap = ni->ni_vap;
2525         uint16_t caps, extcaps;
2526         int rxmax, density;
2527
2528         /* HT capabilities */
2529         caps = vap->iv_htcaps & 0xffff;
2530         /*
2531          * Note channel width depends on whether we are operating as
2532          * a sta or not.  When operating as a sta we are generating
2533          * a request based on our desired configuration.  Otherwise
2534          * we are operational and the channel attributes identify
2535          * how we've been setup (which might be different if a fixed
2536          * channel is specified).
2537          */
2538         if (vap->iv_opmode == IEEE80211_M_STA) {
2539                 /* override 20/40 use based on config */
2540                 if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
2541                         caps |= IEEE80211_HTCAP_CHWIDTH40;
2542                 else
2543                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2544                 /* use advertised setting (XXX locally constraint) */
2545                 rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
2546                 density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
2547
2548                 /*
2549                  * NB: Hardware might support HT40 on some but not all
2550                  * channels. We can't determine this earlier because only
2551                  * after association the channel is upgraded to HT based
2552                  * on the negotiated capabilities.
2553                  */
2554                 if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
2555                     findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL &&
2556                     findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL)
2557                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2558         } else {
2559                 /* override 20/40 use based on current channel */
2560                 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2561                         caps |= IEEE80211_HTCAP_CHWIDTH40;
2562                 else
2563                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
2564                 rxmax = vap->iv_ampdu_rxmax;
2565                 density = vap->iv_ampdu_density;
2566         }
2567         /* adjust short GI based on channel and config */
2568         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
2569                 caps &= ~IEEE80211_HTCAP_SHORTGI20;
2570         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
2571             (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
2572                 caps &= ~IEEE80211_HTCAP_SHORTGI40;
2573         ADDSHORT(frm, caps);
2574
2575         /* HT parameters */
2576         *frm = SM(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
2577              | SM(density, IEEE80211_HTCAP_MPDUDENSITY)
2578              ;
2579         frm++;
2580
2581         /* pre-zero remainder of ie */
2582         memset(frm, 0, sizeof(struct ieee80211_ie_htcap) - 
2583                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
2584
2585         /* supported MCS set */
2586         /*
2587          * XXX: For sta mode the rate set should be restricted based
2588          * on the AP's capabilities, but ni_htrates isn't setup when
2589          * we're called to form an AssocReq frame so for now we're
2590          * restricted to the device capabilities.
2591          */
2592         ieee80211_set_mcsset(ni->ni_ic, frm);
2593
2594         frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
2595                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
2596
2597         /* HT extended capabilities */
2598         extcaps = vap->iv_htextcaps & 0xffff;
2599
2600         ADDSHORT(frm, extcaps);
2601
2602         frm += sizeof(struct ieee80211_ie_htcap) -
2603                 __offsetof(struct ieee80211_ie_htcap, hc_txbf);
2604
2605         return frm;
2606 #undef ADDSHORT
2607 }
2608
2609 /*
2610  * Add 802.11n HT capabilities information element
2611  */
2612 uint8_t *
2613 ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
2614 {
2615         frm[0] = IEEE80211_ELEMID_HTCAP;
2616         frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
2617         return ieee80211_add_htcap_body(frm + 2, ni);
2618 }
2619
2620 /*
2621  * Add Broadcom OUI wrapped standard HTCAP ie; this is
2622  * used for compatibility w/ pre-draft implementations.
2623  */
2624 uint8_t *
2625 ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
2626 {
2627         frm[0] = IEEE80211_ELEMID_VENDOR;
2628         frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
2629         frm[2] = (BCM_OUI >> 0) & 0xff;
2630         frm[3] = (BCM_OUI >> 8) & 0xff;
2631         frm[4] = (BCM_OUI >> 16) & 0xff;
2632         frm[5] = BCM_OUI_HTCAP;
2633         return ieee80211_add_htcap_body(frm + 6, ni);
2634 }
2635
2636 /*
2637  * Construct the MCS bit mask of basic rates
2638  * for inclusion in an HT information element.
2639  */
2640 static void
2641 ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
2642 {
2643         int i;
2644
2645         for (i = 0; i < rs->rs_nrates; i++) {
2646                 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
2647                 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
2648                     r < IEEE80211_HTRATE_MAXSIZE) {
2649                         /* NB: this assumes a particular implementation */
2650                         setbit(frm, r);
2651                 }
2652         }
2653 }
2654
2655 /*
2656  * Update the HTINFO ie for a beacon frame.
2657  */
2658 void
2659 ieee80211_ht_update_beacon(struct ieee80211vap *vap,
2660         struct ieee80211_beacon_offsets *bo)
2661 {
2662 #define PROTMODE        (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
2663         const struct ieee80211_channel *bsschan = vap->iv_bss->ni_chan;
2664         struct ieee80211com *ic = vap->iv_ic;
2665         struct ieee80211_ie_htinfo *ht =
2666            (struct ieee80211_ie_htinfo *) bo->bo_htinfo;
2667
2668         /* XXX only update on channel change */
2669         ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
2670         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
2671                 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PERM;
2672         else
2673                 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
2674         if (IEEE80211_IS_CHAN_HT40U(bsschan))
2675                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2676         else if (IEEE80211_IS_CHAN_HT40D(bsschan))
2677                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2678         else
2679                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
2680         if (IEEE80211_IS_CHAN_HT40(bsschan))
2681                 ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
2682
2683         /* protection mode */
2684         ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
2685
2686         /* XXX propagate to vendor ie's */
2687 #undef PROTMODE
2688 }
2689
2690 /*
2691  * Add body of an HTINFO information element.
2692  *
2693  * NB: We don't use struct ieee80211_ie_htinfo because we can
2694  * be called to fillin both a standard ie and a compat ie that
2695  * has a vendor OUI at the front.
2696  */
2697 static uint8_t *
2698 ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
2699 {
2700         struct ieee80211vap *vap = ni->ni_vap;
2701         struct ieee80211com *ic = ni->ni_ic;
2702
2703         /* pre-zero remainder of ie */
2704         memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
2705
2706         /* primary/control channel center */
2707         *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
2708
2709         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
2710                 frm[0] = IEEE80211_HTINFO_RIFSMODE_PERM;
2711         else
2712                 frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
2713         if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
2714                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
2715         else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
2716                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
2717         else
2718                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
2719         if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
2720                 frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
2721
2722         frm[1] = ic->ic_curhtprotmode;
2723
2724         frm += 5;
2725
2726         /* basic MCS set */
2727         ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
2728         frm += sizeof(struct ieee80211_ie_htinfo) -
2729                 __offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
2730         return frm;
2731 }
2732
2733 /*
2734  * Add 802.11n HT information information element.
2735  */
2736 uint8_t *
2737 ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
2738 {
2739         frm[0] = IEEE80211_ELEMID_HTINFO;
2740         frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
2741         return ieee80211_add_htinfo_body(frm + 2, ni);
2742 }
2743
2744 /*
2745  * Add Broadcom OUI wrapped standard HTINFO ie; this is
2746  * used for compatibility w/ pre-draft implementations.
2747  */
2748 uint8_t *
2749 ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
2750 {
2751         frm[0] = IEEE80211_ELEMID_VENDOR;
2752         frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
2753         frm[2] = (BCM_OUI >> 0) & 0xff;
2754         frm[3] = (BCM_OUI >> 8) & 0xff;
2755         frm[4] = (BCM_OUI >> 16) & 0xff;
2756         frm[5] = BCM_OUI_HTINFO;
2757         return ieee80211_add_htinfo_body(frm + 6, ni);
2758 }