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