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