ieee80211_ht.c revision 175877
1214501Srpaulo/*-
2214501Srpaulo * Copyright (c) 2007 Sam Leffler, Errno Consulting
3214501Srpaulo * All rights reserved.
4214501Srpaulo *
5252726Srpaulo * Redistribution and use in source and binary forms, with or without
6252726Srpaulo * modification, are permitted provided that the following conditions
7214501Srpaulo * are met:
8214501Srpaulo * 1. Redistributions of source code must retain the above copyright
9214501Srpaulo *    notice, this list of conditions and the following disclaimer.
10214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11214501Srpaulo *    notice, this list of conditions and the following disclaimer in the
12214501Srpaulo *    documentation and/or other materials provided with the distribution.
13214501Srpaulo *
14214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15214501Srpaulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16214501Srpaulo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17252726Srpaulo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18214501Srpaulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19214501Srpaulo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20214501Srpaulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21214501Srpaulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22214501Srpaulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23214501Srpaulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24214501Srpaulo */
25214501Srpaulo
26214501Srpaulo#include <sys/cdefs.h>
27214501Srpaulo#ifdef __FreeBSD__
28214501Srpaulo__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_ht.c 175877 2008-02-01 21:31:10Z sam $");
29214501Srpaulo#endif
30252726Srpaulo
31252726Srpaulo/*
32214501Srpaulo * IEEE 802.11n protocol support.
33214501Srpaulo */
34214501Srpaulo
35214501Srpaulo#include "opt_inet.h"
36214501Srpaulo
37214501Srpaulo#include <sys/param.h>
38214501Srpaulo#include <sys/kernel.h>
39214501Srpaulo#include <sys/systm.h>
40214501Srpaulo#include <sys/endian.h>
41214501Srpaulo
42214501Srpaulo#include <sys/socket.h>
43214501Srpaulo
44214501Srpaulo#include <net/if.h>
45214501Srpaulo#include <net/if_media.h>
46214501Srpaulo#include <net/ethernet.h>
47214501Srpaulo
48214501Srpaulo#include <net80211/ieee80211_var.h>
49214501Srpaulo
50214501Srpaulo/* define here, used throughout file */
51214501Srpaulo#define	MS(_v, _f)	(((_v) & _f) >> _f##_S)
52214501Srpaulo#define	SM(_v, _f)	(((_v) << _f##_S) & _f)
53214501Srpaulo
54214501Srpaulo/* XXX need max array size */
55214501Srpaulo/* NB: these are for HT20 w/ long GI */
56214501Srpauloconst int ieee80211_htrates[16] = {
57214501Srpaulo	13,		/* IFM_IEEE80211_MCS0 */
58214501Srpaulo	26,		/* IFM_IEEE80211_MCS1 */
59214501Srpaulo	39,		/* IFM_IEEE80211_MCS2 */
60214501Srpaulo	52,		/* IFM_IEEE80211_MCS3 */
61214501Srpaulo	78,		/* IFM_IEEE80211_MCS4 */
62214501Srpaulo	104,		/* IFM_IEEE80211_MCS5 */
63214501Srpaulo	117,		/* IFM_IEEE80211_MCS6 */
64214501Srpaulo	130,		/* IFM_IEEE80211_MCS7 */
65214501Srpaulo	26,		/* IFM_IEEE80211_MCS8 */
66214501Srpaulo	52,		/* IFM_IEEE80211_MCS9 */
67214501Srpaulo	78,		/* IFM_IEEE80211_MCS10 */
68214501Srpaulo	104,		/* IFM_IEEE80211_MCS11 */
69214501Srpaulo	156,		/* IFM_IEEE80211_MCS12 */
70214501Srpaulo	208,		/* IFM_IEEE80211_MCS13 */
71252726Srpaulo	234,		/* IFM_IEEE80211_MCS14 */
72214501Srpaulo	260,		/* IFM_IEEE80211_MCS15 */
73214501Srpaulo};
74214501Srpaulo
75214501Srpaulostatic const struct ieee80211_htrateset ieee80211_rateset_11n =
76214501Srpaulo	{ 16, {
77214501Srpaulo	/* MCS: 6.5   13 19.5   26   39  52 58.5  65  13  26 */
78252726Srpaulo	          0,   1,   2,   3,   4,  5,   6,  7,  8,  9,
79214501Srpaulo	/*       39   52   78  104  117, 130 */
80252726Srpaulo		 10,  11,  12,  13,  14,  15 }
81214501Srpaulo	};
82214501Srpaulo
83214501Srpaulo#ifdef IEEE80211_AMPDU_AGE
84214501Srpaulo/* XXX public for sysctl hookup */
85214501Srpauloint	ieee80211_ampdu_age = -1;	/* threshold for ampdu reorder q (ms) */
86214501Srpaulo#endif
87214501Srpauloint	ieee80211_recv_bar_ena = 1;
88214501Srpaulo
89214501Srpaulo#define	IEEE80211_AGGR_TIMEOUT	msecs_to_ticks(250)
90214501Srpaulo#define	IEEE80211_AGGR_MINRETRY	msecs_to_ticks(10*1000)
91214501Srpaulo#define	IEEE80211_AGGR_MAXTRIES	3
92214501Srpaulo
93214501Srpaulostatic int ieee80211_addba_request(struct ieee80211_node *ni,
94214501Srpaulo	struct ieee80211_tx_ampdu *tap,
95351611Scy	int dialogtoken, int baparamset, int batimeout);
96351611Scystatic int ieee80211_addba_response(struct ieee80211_node *ni,
97351611Scy	struct ieee80211_tx_ampdu *tap,
98351611Scy	int code, int baparamset, int batimeout);
99289549Srpaulostatic void ieee80211_addba_stop(struct ieee80211_node *ni,
100214501Srpaulo	struct ieee80211_tx_ampdu *tap);
101214501Srpaulostatic void ieee80211_aggr_recv_action(struct ieee80211_node *ni,
102	const uint8_t *frm, const uint8_t *efrm);
103
104void
105ieee80211_ht_attach(struct ieee80211com *ic)
106{
107#ifdef IEEE80211_AMPDU_AGE
108	if (ieee80211_ampdu_age == -1)
109		ieee80211_ampdu_age = msecs_to_ticks(500);
110#endif
111
112	/* setup default aggregation policy */
113	ic->ic_recv_action = ieee80211_aggr_recv_action;
114	ic->ic_send_action = ieee80211_send_action;
115	ic->ic_addba_request = ieee80211_addba_request;
116	ic->ic_addba_response = ieee80211_addba_response;
117	ic->ic_addba_stop = ieee80211_addba_stop;
118
119	ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
120	ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
121
122	/* XXX get from driver */
123	ic->ic_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
124	ic->ic_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
125	ic->ic_ampdu_limit = ic->ic_ampdu_rxmax;
126	ic->ic_amsdu_limit = IEEE80211_HTCAP_MAXAMSDU_3839;
127
128	if (ic->ic_htcaps & IEEE80211_HTC_HT) {
129		/*
130		 * Device is HT capable; enable all HT-related
131		 * facilities by default.
132		 * XXX these choices may be too aggressive.
133		 */
134		ic->ic_flags_ext |= IEEE80211_FEXT_HT
135				 |  IEEE80211_FEXT_HTCOMPAT
136				 ;
137		if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20)
138			ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI20;
139		/* XXX infer from channel list? */
140		if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
141			ic->ic_flags_ext |= IEEE80211_FEXT_USEHT40;
142			if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)
143				ic->ic_flags_ext |= IEEE80211_FEXT_SHORTGI40;
144		}
145		/* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
146		ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_RX;
147		if (ic->ic_htcaps & IEEE80211_HTC_AMPDU)
148			ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_TX;
149		ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_RX;
150		if (ic->ic_htcaps & IEEE80211_HTC_AMSDU)
151			ic->ic_flags_ext |= IEEE80211_FEXT_AMSDU_TX;
152	}
153}
154
155void
156ieee80211_ht_detach(struct ieee80211com *ic)
157{
158}
159
160static void
161ht_announce(struct ieee80211com *ic, int mode,
162	const struct ieee80211_htrateset *rs)
163{
164	struct ifnet *ifp = ic->ic_ifp;
165	int i, rate, mword;
166
167	if_printf(ifp, "%s MCS: ", ieee80211_phymode_name[mode]);
168	for (i = 0; i < rs->rs_nrates; i++) {
169		mword = ieee80211_rate2media(ic,
170		    rs->rs_rates[i] | IEEE80211_RATE_MCS, mode);
171		if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
172			continue;
173		rate = ieee80211_htrates[rs->rs_rates[i]];
174		printf("%s%d%sMbps", (i != 0 ? " " : ""),
175		    rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
176	}
177	printf("\n");
178}
179
180void
181ieee80211_ht_announce(struct ieee80211com *ic)
182{
183	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
184		ht_announce(ic, IEEE80211_MODE_11NA, &ieee80211_rateset_11n);
185	if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
186		ht_announce(ic, IEEE80211_MODE_11NG, &ieee80211_rateset_11n);
187}
188
189const struct ieee80211_htrateset *
190ieee80211_get_suphtrates(struct ieee80211com *ic,
191	const struct ieee80211_channel *c)
192{
193	return &ieee80211_rateset_11n;
194}
195
196/*
197 * Receive processing.
198 */
199
200/*
201 * Decap the encapsulated A-MSDU frames and dispatch all but
202 * the last for delivery.  The last frame is returned for
203 * delivery via the normal path.
204 */
205struct mbuf *
206ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
207{
208	struct ieee80211com *ic = ni->ni_ic;
209	int framelen;
210	struct mbuf *n;
211
212	/* discard 802.3 header inserted by ieee80211_decap */
213	m_adj(m, sizeof(struct ether_header));
214
215	ic->ic_stats.is_amsdu_decap++;
216
217	for (;;) {
218		/*
219		 * Decap the first frame, bust it apart from the
220		 * remainder and deliver.  We leave the last frame
221		 * delivery to the caller (for consistency with other
222		 * code paths, could also do it here).
223		 */
224		m = ieee80211_decap1(m, &framelen);
225		if (m == NULL) {
226			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
227			    ni->ni_macaddr, "a-msdu", "%s", "decap failed");
228			ic->ic_stats.is_amsdu_tooshort++;
229			return NULL;
230		}
231		if (m->m_pkthdr.len == framelen)
232			break;
233		n = m_split(m, framelen, M_NOWAIT);
234		if (n == NULL) {
235			IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_ANY,
236			    ni->ni_macaddr, "a-msdu",
237			    "%s", "unable to split encapsulated frames");
238			ic->ic_stats.is_amsdu_split++;
239			m_freem(m);			/* NB: must reclaim */
240			return NULL;
241		}
242		ieee80211_deliver_data(ic, ni, m);
243
244		/*
245		 * Remove frame contents; each intermediate frame
246		 * is required to be aligned to a 4-byte boundary.
247		 */
248		m = n;
249		m_adj(m, roundup2(framelen, 4) - framelen);	/* padding */
250	}
251	return m;				/* last delivered by caller */
252}
253
254/*
255 * Start A-MPDU rx/re-order processing for the specified TID.
256 */
257static void
258ampdu_rx_start(struct ieee80211_rx_ampdu *rap, int bufsiz, int start)
259{
260	memset(rap, 0, sizeof(*rap));
261	rap->rxa_wnd = (bufsiz == 0) ?
262	    IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
263	rap->rxa_start = start;
264	rap->rxa_flags |= IEEE80211_AGGR_XCHGPEND;
265}
266
267/*
268 * Purge all frames in the A-MPDU re-order queue.
269 */
270static void
271ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
272{
273	struct mbuf *m;
274	int i;
275
276	for (i = 0; i < rap->rxa_wnd; i++) {
277		m = rap->rxa_m[i];
278		if (m != NULL) {
279			rap->rxa_m[i] = NULL;
280			rap->rxa_qbytes -= m->m_pkthdr.len;
281			m_freem(m);
282			if (--rap->rxa_qframes == 0)
283				break;
284		}
285	}
286	KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
287	    ("lost %u data, %u frames on ampdu rx q",
288	    rap->rxa_qbytes, rap->rxa_qframes));
289}
290
291/*
292 * Stop A-MPDU rx processing for the specified TID.
293 */
294static void
295ampdu_rx_stop(struct ieee80211_rx_ampdu *rap)
296{
297	rap->rxa_flags &= ~IEEE80211_AGGR_XCHGPEND;
298	ampdu_rx_purge(rap);
299}
300
301/*
302 * Dispatch a frame from the A-MPDU reorder queue.  The
303 * frame is fed back into ieee80211_input marked with an
304 * M_AMPDU flag so it doesn't come back to us (it also
305 * permits ieee80211_input to optimize re-processing).
306 */
307static __inline void
308ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
309{
310	m->m_flags |= M_AMPDU;	/* bypass normal processing */
311	/* NB: rssi, noise, and rstamp are ignored w/ M_AMPDU set */
312	(void) ieee80211_input(ni->ni_ic, m, ni, 0, 0, 0);
313}
314
315/*
316 * Dispatch as many frames as possible from the re-order queue.
317 * Frames will always be "at the front"; we process all frames
318 * up to the first empty slot in the window.  On completion we
319 * cleanup state if there are still pending frames in the current
320 * BA window.  We assume the frame at slot 0 is already handled
321 * by the caller; we always start at slot 1.
322 */
323static void
324ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
325{
326	struct ieee80211com *ic = ni->ni_ic;
327	struct mbuf *m;
328	int i;
329
330	/* flush run of frames */
331	for (i = 1; i < rap->rxa_wnd; i++) {
332		m = rap->rxa_m[i];
333		if (m == NULL)
334			break;
335		rap->rxa_m[i] = NULL;
336		rap->rxa_qbytes -= m->m_pkthdr.len;
337		rap->rxa_qframes--;
338
339		ampdu_dispatch(ni, m);
340	}
341	/*
342	 * If frames remain, copy the mbuf pointers down so
343	 * they correspond to the offsets in the new window.
344	 */
345	if (rap->rxa_qframes != 0) {
346		int n = rap->rxa_qframes, j;
347		for (j = i+1; j < rap->rxa_wnd; j++) {
348			if (rap->rxa_m[j] != NULL) {
349				rap->rxa_m[j-i] = rap->rxa_m[j];
350				rap->rxa_m[j] = NULL;
351				if (--n == 0)
352					break;
353			}
354		}
355		KASSERT(n == 0, ("lost %d frames", n));
356		ic->ic_stats.is_ampdu_rx_copy += rap->rxa_qframes;
357	}
358	/*
359	 * Adjust the start of the BA window to
360	 * reflect the frames just dispatched.
361	 */
362	rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
363	ic->ic_stats.is_ampdu_rx_oor += i;
364}
365
366#ifdef IEEE80211_AMPDU_AGE
367/*
368 * Dispatch all frames in the A-MPDU re-order queue.
369 */
370static void
371ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
372{
373	struct ieee80211com *ic = ni->ni_ic;
374	struct mbuf *m;
375	int i;
376
377	for (i = 0; i < rap->rxa_wnd; i++) {
378		m = rap->rxa_m[i];
379		if (m == NULL)
380			continue;
381		rap->rxa_m[i] = NULL;
382		rap->rxa_qbytes -= m->m_pkthdr.len;
383		rap->rxa_qframes--;
384		ic->ic_stats.is_ampdu_rx_oor++;
385
386		ampdu_dispatch(ni, m);
387		if (rap->rxa_qframes == 0)
388			break;
389	}
390}
391#endif /* IEEE80211_AMPDU_AGE */
392
393/*
394 * Dispatch all frames in the A-MPDU re-order queue
395 * preceding the specified sequence number.  This logic
396 * handles window moves due to a received MSDU or BAR.
397 */
398static void
399ampdu_rx_flush_upto(struct ieee80211_node *ni,
400	struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
401{
402	struct ieee80211com *ic = ni->ni_ic;
403	struct mbuf *m;
404	ieee80211_seq seqno;
405	int i;
406
407	/*
408	 * Flush any complete MSDU's with a sequence number lower
409	 * than winstart.  Gaps may exist.  Note that we may actually
410	 * dispatch frames past winstart if a run continues; this is
411	 * an optimization that avoids having to do a separate pass
412	 * to dispatch frames after moving the BA window start.
413	 */
414	seqno = rap->rxa_start;
415	for (i = 0; i < rap->rxa_wnd; i++) {
416		m = rap->rxa_m[i];
417		if (m != NULL) {
418			rap->rxa_m[i] = NULL;
419			rap->rxa_qbytes -= m->m_pkthdr.len;
420			rap->rxa_qframes--;
421			ic->ic_stats.is_ampdu_rx_oor++;
422
423			ampdu_dispatch(ni, m);
424		} else {
425			if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
426				break;
427		}
428		seqno = IEEE80211_SEQ_INC(seqno);
429	}
430	/*
431	 * If frames remain, copy the mbuf pointers down so
432	 * they correspond to the offsets in the new window.
433	 */
434	if (rap->rxa_qframes != 0) {
435		int n = rap->rxa_qframes, j;
436		for (j = i+1; j < rap->rxa_wnd; j++) {
437			if (rap->rxa_m[j] != NULL) {
438				rap->rxa_m[j-i] = rap->rxa_m[j];
439				rap->rxa_m[j] = NULL;
440				if (--n == 0)
441					break;
442			}
443		}
444		KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
445		    "BA win <%d:%d> winstart %d",
446		    __func__, n, rap->rxa_qframes, i, rap->rxa_start,
447		    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
448		    winstart));
449		ic->ic_stats.is_ampdu_rx_copy += rap->rxa_qframes;
450	}
451	/*
452	 * Move the start of the BA window; we use the
453	 * sequence number of the last MSDU that was
454	 * passed up the stack+1 or winstart if stopped on
455	 * a gap in the reorder buffer.
456	 */
457	rap->rxa_start = seqno;
458}
459
460/*
461 * Process a received QoS data frame for an HT station.  Handle
462 * A-MPDU reordering: if this frame is received out of order
463 * and falls within the BA window hold onto it.  Otherwise if
464 * this frame completes a run, flush any pending frames.  We
465 * return 1 if the frame is consumed.  A 0 is returned if
466 * the frame should be processed normally by the caller.
467 */
468int
469ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m)
470{
471#define	IEEE80211_FC0_QOSDATA \
472	(IEEE80211_FC0_TYPE_DATA|IEEE80211_FC0_SUBTYPE_QOS|IEEE80211_FC0_VERSION_0)
473#define	PROCESS		0	/* caller should process frame */
474#define	CONSUMED	1	/* frame consumed, caller does nothing */
475	struct ieee80211com *ic = ni->ni_ic;
476	struct ieee80211_qosframe *wh;
477	struct ieee80211_rx_ampdu *rap;
478	ieee80211_seq rxseq;
479	uint8_t tid;
480	int off;
481
482	KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
483
484	/* NB: m_len known to be sufficient */
485	wh = mtod(m, struct ieee80211_qosframe *);
486	KASSERT(wh->i_fc[0] == IEEE80211_FC0_QOSDATA, ("not QoS data"));
487
488	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
489		tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0];
490	else
491		tid = wh->i_qos[0];
492	tid &= IEEE80211_QOS_TID;
493	rap = &ni->ni_rx_ampdu[tid];
494	if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
495		/*
496		 * No ADDBA request yet, don't touch.
497		 */
498		return PROCESS;
499	}
500	rxseq = le16toh(*(uint16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
501	rap->rxa_nframes++;
502again:
503	if (rxseq == rap->rxa_start) {
504		/*
505		 * First frame in window.
506		 */
507		if (rap->rxa_qframes != 0) {
508			/*
509			 * Dispatch as many packets as we can.
510			 */
511			KASSERT(rap->rxa_m[0] == NULL, ("unexpected dup"));
512			ampdu_dispatch(ni, m);
513			ampdu_rx_dispatch(rap, ni);
514			return CONSUMED;
515		} else {
516			/*
517			 * In order; advance window and notify
518			 * caller to dispatch directly.
519			 */
520			rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
521			return PROCESS;
522		}
523	}
524	/*
525	 * Frame is out of order; store if in the BA window.
526	 */
527	/* calculate offset in BA window */
528	off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
529	if (off < rap->rxa_wnd) {
530		/*
531		 * Common case (hopefully): in the BA window.
532		 * Sec 9.10.7.6 a) (D2.04 p.118 line 47)
533		 */
534#ifdef IEEE80211_AMPDU_AGE
535		/*
536		 * Check for frames sitting too long in the reorder queue.
537		 * This should only ever happen if frames are not delivered
538		 * without the sender otherwise notifying us (e.g. with a
539		 * BAR to move the window).  Typically this happens because
540		 * of vendor bugs that cause the sequence number to jump.
541		 * When this happens we get a gap in the reorder queue that
542		 * leaves frame sitting on the queue until they get pushed
543		 * out due to window moves.  When the vendor does not send
544		 * BAR this move only happens due to explicit packet sends
545		 *
546		 * NB: we only track the time of the oldest frame in the
547		 * reorder q; this means that if we flush we might push
548		 * frames that still "new"; if this happens then subsequent
549		 * frames will result in BA window moves which cost something
550		 * but is still better than a big throughput dip.
551		 */
552		if (rap->rxa_qframes != 0) {
553			/* XXX honor batimeout? */
554			if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
555				/*
556				 * Too long since we received the first
557				 * frame; flush the reorder buffer.
558				 */
559				if (rap->rxa_qframes != 0) {
560					ic->ic_stats.is_ampdu_rx_age +=
561					    rap->rxa_qframes;
562					ampdu_rx_flush(ni, rap);
563				}
564				rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
565				return PROCESS;
566			}
567		} else {
568			/*
569			 * First frame, start aging timer.
570			 */
571			rap->rxa_age = ticks;
572		}
573#endif /* IEEE80211_AMPDU_AGE */
574		/* save packet */
575		if (rap->rxa_m[off] == NULL) {
576			rap->rxa_m[off] = m;
577			rap->rxa_qframes++;
578			rap->rxa_qbytes += m->m_pkthdr.len;
579			ic->ic_stats.is_ampdu_rx_reorder++;
580		} else {
581			IEEE80211_DISCARD_MAC(ic,
582			    IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
583			    ni->ni_macaddr, "a-mpdu duplicate",
584			    "seqno %u tid %u BA win <%u:%u>",
585			    rxseq, tid, rap->rxa_start,
586			    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
587			ic->ic_stats.is_rx_dup++;
588			IEEE80211_NODE_STAT(ni, rx_dup);
589			m_freem(m);
590		}
591		return CONSUMED;
592	}
593	if (off < IEEE80211_SEQ_BA_RANGE) {
594		/*
595		 * Outside the BA window, but within range;
596		 * flush the reorder q and move the window.
597		 * Sec 9.10.7.6 b) (D2.04 p.118 line 60)
598		 */
599		IEEE80211_NOTE(ic, IEEE80211_MSG_11N, ni,
600		    "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
601		    rap->rxa_start,
602		    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
603		    rap->rxa_qframes, rxseq, tid);
604		ic->ic_stats.is_ampdu_rx_move++;
605
606		/*
607		 * The spec says to flush frames up to but not including:
608		 * 	WinStart_B = rxseq - rap->rxa_wnd + 1
609		 * Then insert the frame or notify the caller to process
610		 * it immediately.  We can safely do this by just starting
611		 * over again because we know the frame will now be within
612		 * the BA window.
613		 */
614		/* NB: rxa_wnd known to be >0 */
615		ampdu_rx_flush_upto(ni, rap,
616		    IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
617		goto again;
618	} else {
619		/*
620		 * Outside the BA window and out of range; toss.
621		 * Sec 9.10.7.6 c) (D2.04 p.119 line 16)
622		 */
623		IEEE80211_DISCARD_MAC(ic,
624		    IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
625		    "MSDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
626		    rap->rxa_start,
627		    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
628		    rap->rxa_qframes, rxseq, tid,
629		    wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
630		ic->ic_stats.is_ampdu_rx_drop++;
631		IEEE80211_NODE_STAT(ni, rx_drop);
632		m_freem(m);
633		return CONSUMED;
634	}
635#undef CONSUMED
636#undef PROCESS
637#undef IEEE80211_FC0_QOSDATA
638}
639
640/*
641 * Process a BAR ctl frame.  Dispatch all frames up to
642 * the sequence number of the frame.  If this frame is
643 * out of range it's discarded.
644 */
645void
646ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
647{
648	struct ieee80211com *ic = ni->ni_ic;
649	struct ieee80211_frame_bar *wh;
650	struct ieee80211_rx_ampdu *rap;
651	ieee80211_seq rxseq;
652	int tid, off;
653
654	if (!ieee80211_recv_bar_ena) {
655#if 0
656		IEEE80211_DISCARD_MAC(ic, IEEE80211_MSG_11N,
657		    ni->ni_macaddr, "BAR", "%s", "processing disabled");
658#endif
659		ic->ic_stats.is_ampdu_bar_bad++;
660		return;
661	}
662	wh = mtod(m0, struct ieee80211_frame_bar *);
663	/* XXX check basic BAR */
664	tid = MS(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
665	rap = &ni->ni_rx_ampdu[tid];
666	if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
667		/*
668		 * No ADDBA request yet, don't touch.
669		 */
670		IEEE80211_DISCARD_MAC(ic,
671		    IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
672		    ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
673		ic->ic_stats.is_ampdu_bar_bad++;
674		return;
675	}
676	ic->ic_stats.is_ampdu_bar_rx++;
677	rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
678	if (rxseq == rap->rxa_start)
679		return;
680	/* calculate offset in BA window */
681	off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
682	if (off < IEEE80211_SEQ_BA_RANGE) {
683		/*
684		 * Flush the reorder q up to rxseq and move the window.
685		 * Sec 9.10.7.6 a) (D2.04 p.119 line 22)
686		 */
687		IEEE80211_NOTE(ic, IEEE80211_MSG_11N, ni,
688		    "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
689		    rap->rxa_start,
690		    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
691		    rap->rxa_qframes, rxseq, tid);
692		ic->ic_stats.is_ampdu_bar_move++;
693
694		ampdu_rx_flush_upto(ni, rap, rxseq);
695		if (off >= rap->rxa_wnd) {
696			/*
697			 * BAR specifies a window start to the right of BA
698			 * window; we must move it explicitly since
699			 * ampdu_rx_flush_upto will not.
700			 */
701			rap->rxa_start = rxseq;
702		}
703	} else {
704		/*
705		 * Out of range; toss.
706		 * Sec 9.10.7.6 b) (D2.04 p.119 line 41)
707		 */
708		IEEE80211_DISCARD_MAC(ic,
709		    IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
710		    "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
711		    rap->rxa_start,
712		    IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
713		    rap->rxa_qframes, rxseq, tid,
714		    wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
715		ic->ic_stats.is_ampdu_bar_oow++;
716		IEEE80211_NODE_STAT(ni, rx_drop);
717	}
718}
719
720/*
721 * Setup HT-specific state in a node.  Called only
722 * when HT use is negotiated so we don't do extra
723 * work for temporary and/or legacy sta's.
724 */
725void
726ieee80211_ht_node_init(struct ieee80211_node *ni, const uint8_t *htcap)
727{
728	struct ieee80211_tx_ampdu *tap;
729	int ac;
730
731	if (ni->ni_flags & IEEE80211_NODE_HT) {
732		/*
733		 * Clean AMPDU state on re-associate.  This handles the case
734		 * where a station leaves w/o notifying us and then returns
735		 * before node is reaped for inactivity.
736		 */
737		ieee80211_ht_node_cleanup(ni);
738	}
739	ieee80211_parse_htcap(ni, htcap);
740	for (ac = 0; ac < WME_NUM_AC; ac++) {
741		tap = &ni->ni_tx_ampdu[ac];
742		tap->txa_ac = ac;
743		/* NB: further initialization deferred */
744	}
745	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
746}
747
748/*
749 * Cleanup HT-specific state in a node.  Called only
750 * when HT use has been marked.
751 */
752void
753ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
754{
755	struct ieee80211com *ic = ni->ni_ic;
756	int i;
757
758	KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
759
760	/* XXX optimize this */
761	for (i = 0; i < WME_NUM_AC; i++) {
762		struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
763		if (tap->txa_flags & IEEE80211_AGGR_SETUP) {
764			/*
765			 * Stop BA stream if setup so driver has a chance
766			 * to reclaim any resources it might have allocated.
767			 */
768			ic->ic_addba_stop(ni, &ni->ni_tx_ampdu[i]);
769			IEEE80211_TAPQ_DESTROY(tap);
770			/* NB: clearing NAK means we may re-send ADDBA */
771			tap->txa_flags &=
772			    ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
773		}
774	}
775	for (i = 0; i < WME_NUM_TID; i++)
776		ampdu_rx_stop(&ni->ni_rx_ampdu[i]);
777
778	ni->ni_htcap = 0;
779	ni->ni_flags &= ~(IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT |
780		IEEE80211_NODE_AMPDU);
781}
782
783static struct ieee80211_channel *
784findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
785{
786	return ieee80211_find_channel(ic, c->ic_freq,
787	    (c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
788}
789
790/*
791 * Adjust a channel to be HT/non-HT according to the vap's configuration.
792 */
793struct ieee80211_channel *
794ieee80211_ht_adjust_channel(struct ieee80211com *ic,
795	struct ieee80211_channel *chan, int flags)
796{
797	struct ieee80211_channel *c;
798
799	if (flags & IEEE80211_FEXT_HT) {
800		/* promote to HT if possible */
801		if (flags & IEEE80211_FEXT_USEHT40) {
802			if (!IEEE80211_IS_CHAN_HT40(chan)) {
803				/* NB: arbitrarily pick ht40+ over ht40- */
804				c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
805				if (c == NULL)
806					c = findhtchan(ic, chan,
807						IEEE80211_CHAN_HT40D);
808				if (c == NULL)
809					c = findhtchan(ic, chan,
810						IEEE80211_CHAN_HT20);
811				if (c != NULL)
812					chan = c;
813			}
814		} else if (!IEEE80211_IS_CHAN_HT20(chan)) {
815			c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
816			if (c != NULL)
817				chan = c;
818		}
819	} else if (IEEE80211_IS_CHAN_HT(chan)) {
820		/* demote to legacy, HT use is disabled */
821		c = ieee80211_find_channel(ic, chan->ic_freq,
822		    chan->ic_flags &~ IEEE80211_CHAN_HT);
823		if (c != NULL)
824			chan = c;
825	}
826	return chan;
827}
828
829/*
830 * Setup HT-specific state for a legacy WDS peer.
831 */
832void
833ieee80211_ht_wds_init(struct ieee80211_node *ni)
834{
835	struct ieee80211com *ic = ni->ni_ic;
836	struct ieee80211_tx_ampdu *tap;
837	int ac;
838
839	KASSERT(ic->ic_flags_ext & IEEE80211_FEXT_HT, ("no HT requested"));
840
841	/* XXX check scan cache in case peer has an ap and we have info */
842	/*
843	 * If setup with a legacy channel; locate an HT channel.
844	 * Otherwise if the inherited channel (from a companion
845	 * AP) is suitable use it so we use the same location
846	 * for the extension channel).
847	 */
848	ni->ni_chan = ieee80211_ht_adjust_channel(ic, ni->ni_chan,
849	    ic->ic_flags_ext);
850
851	ni->ni_htcap = 0;
852	if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20)
853		ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
854	if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
855		ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
856		ni->ni_chw = 40;
857		if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
858			ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
859		else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
860			ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
861		if (ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40)
862			ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
863	} else {
864		ni->ni_chw = 20;
865		ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
866	}
867	ni->ni_htctlchan = ni->ni_chan->ic_ieee;
868
869	ni->ni_htopmode = 0;		/* XXX need protection state */
870	ni->ni_htstbc = 0;		/* XXX need info */
871
872	for (ac = 0; ac < WME_NUM_AC; ac++) {
873		tap = &ni->ni_tx_ampdu[ac];
874		tap->txa_ac = ac;
875	}
876	/* NB: AMPDU tx/rx governed by IEEE80211_FEXT_AMPDU_{TX,RX} */
877	ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU;
878}
879
880/*
881 * Notify hostap vaps of a change in the HTINFO ie.
882 */
883static void
884htinfo_notify(struct ieee80211com *ic)
885{
886	if (ic->ic_opmode != IEEE80211_M_HOSTAP)
887		return;
888	IEEE80211_NOTE(ic,
889	    IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
890	    ic->ic_bss,
891	    "HT bss occupancy change: %d sta, %d ht, "
892	    "%d ht40%s, HT protmode now 0x%x"
893	    , ic->ic_sta_assoc
894	    , ic->ic_ht_sta_assoc
895	    , ic->ic_ht40_sta_assoc
896	    , (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) ?
897		 ", non-HT sta present" : ""
898	    , ic->ic_curhtprotmode);
899	ieee80211_beacon_notify(ic, IEEE80211_BEACON_HTINFO);
900}
901
902/*
903 * Calculate HT protection mode from current
904 * state and handle updates.
905 */
906static void
907htinfo_update(struct ieee80211com *ic)
908{
909	uint8_t protmode;
910
911	if (ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) {
912		protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
913		         | IEEE80211_HTINFO_NONHT_PRESENT;
914	} else if (ic->ic_sta_assoc != ic->ic_ht_sta_assoc) {
915		protmode = IEEE80211_HTINFO_OPMODE_MIXED
916		         | IEEE80211_HTINFO_NONHT_PRESENT;
917	} else if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
918	    ic->ic_sta_assoc != ic->ic_ht40_sta_assoc) {
919		protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
920	} else {
921		protmode = IEEE80211_HTINFO_OPMODE_PURE;
922	}
923	if (protmode != ic->ic_curhtprotmode) {
924		ic->ic_curhtprotmode = protmode;
925		htinfo_notify(ic);
926	}
927}
928
929/*
930 * Handle an HT station joining a BSS.
931 */
932void
933ieee80211_ht_node_join(struct ieee80211_node *ni)
934{
935	struct ieee80211com *ic = ni->ni_ic;
936
937	IEEE80211_LOCK_ASSERT(ic);
938
939	if (ni->ni_flags & IEEE80211_NODE_HT) {
940		ic->ic_ht_sta_assoc++;
941		if (ni->ni_chw == 40)
942			ic->ic_ht40_sta_assoc++;
943	}
944	htinfo_update(ic);
945}
946
947/*
948 * Handle an HT station leaving a BSS.
949 */
950void
951ieee80211_ht_node_leave(struct ieee80211_node *ni)
952{
953	struct ieee80211com *ic = ni->ni_ic;
954
955	IEEE80211_LOCK_ASSERT(ic);
956
957	if (ni->ni_flags & IEEE80211_NODE_HT) {
958		ic->ic_ht_sta_assoc--;
959		if (ni->ni_chw == 40)
960			ic->ic_ht40_sta_assoc--;
961	}
962	htinfo_update(ic);
963}
964
965/*
966 * Public version of htinfo_update; used for processing
967 * beacon frames from overlapping bss in hostap_recv_mgmt.
968 */
969void
970ieee80211_htinfo_update(struct ieee80211com *ic, int protmode)
971{
972	if (protmode != ic->ic_curhtprotmode) {
973		ic->ic_curhtprotmode = protmode;
974		htinfo_notify(ic);
975	}
976}
977
978/*
979 * Time out presence of an overlapping bss with non-HT
980 * stations.  When operating in hostap mode we listen for
981 * beacons from other stations and if we identify a non-HT
982 * station is present we update the opmode field of the
983 * HTINFO ie.  To identify when all non-HT stations are
984 * gone we time out this condition.
985 */
986void
987ieee80211_ht_timeout(struct ieee80211com *ic)
988{
989	IEEE80211_LOCK_ASSERT(ic);
990
991	if ((ic->ic_flags_ext & IEEE80211_FEXT_NONHT_PR) &&
992	    time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
993#if 0
994		IEEE80211_NOTE(ic, IEEE80211_MSG_11N, ni,
995		    "%s", "time out non-HT STA present on channel");
996#endif
997		ic->ic_flags_ext &= ~IEEE80211_FEXT_NONHT_PR;
998		htinfo_update(ic);
999	}
1000}
1001
1002/* unalligned little endian access */
1003#define LE_READ_2(p)					\
1004	((uint16_t)					\
1005	 ((((const uint8_t *)(p))[0]      ) |		\
1006	  (((const uint8_t *)(p))[1] <<  8)))
1007
1008/*
1009 * Process an 802.11n HT capabilities ie.
1010 */
1011void
1012ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
1013{
1014	struct ieee80211com *ic = ni->ni_ic;
1015
1016	if (ie[0] == IEEE80211_ELEMID_VENDOR) {
1017		/*
1018		 * Station used Vendor OUI ie to associate;
1019		 * mark the node so when we respond we'll use
1020		 * the Vendor OUI's and not the standard ie's.
1021		 */
1022		ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
1023		ie += 4;
1024	} else
1025		ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
1026
1027	ni->ni_htcap = LE_READ_2(ie +
1028		__offsetof(struct ieee80211_ie_htcap, hc_cap));
1029	ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
1030	/* XXX needed or will ieee80211_parse_htinfo always be called? */
1031	ni->ni_chw = (ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
1032		     (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40) ? 40 : 20;
1033}
1034
1035/*
1036 * Process an 802.11n HT info ie and update the node state.
1037 * Note that we handle use this information to identify the
1038 * correct channel (HT20, HT40+, HT40-, legacy).  The caller
1039 * is responsible for insuring any required channel change is
1040 * done (e.g. in sta mode when parsing the contents of a
1041 * beacon frame).
1042 */
1043void
1044ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
1045{
1046	struct ieee80211com *ic = ni->ni_ic;
1047 	const struct ieee80211_ie_htinfo *htinfo;
1048	struct ieee80211_channel *c;
1049	uint16_t w;
1050	int htflags, chanflags;
1051
1052	if (ie[0] == IEEE80211_ELEMID_VENDOR)
1053		ie += 4;
1054 	htinfo = (const struct ieee80211_ie_htinfo *) ie;
1055	ni->ni_htctlchan = htinfo->hi_ctrlchannel;
1056	ni->ni_ht2ndchan = SM(htinfo->hi_byte1, IEEE80211_HTINFO_2NDCHAN);
1057	w = LE_READ_2(&htinfo->hi_byte2);
1058	ni->ni_htopmode = SM(w, IEEE80211_HTINFO_OPMODE);
1059	w = LE_READ_2(&htinfo->hi_byte45);
1060	ni->ni_htstbc = SM(w, IEEE80211_HTINFO_BASIC_STBCMCS);
1061	/*
1062	 * Handle 11n channel switch.  Use the received HT ie's to
1063	 * identify the right channel to use.  If we cannot locate it
1064	 * in the channel table then fallback to legacy operation.
1065	 */
1066	htflags = (ic->ic_flags_ext & IEEE80211_FEXT_HT) ?
1067	    IEEE80211_CHAN_HT20 : 0;
1068	/* NB: honor operating mode constraint */
1069	if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
1070	    (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40)) {
1071		if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
1072			htflags = IEEE80211_CHAN_HT40U;
1073		else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
1074			htflags = IEEE80211_CHAN_HT40D;
1075	}
1076	chanflags = (ni->ni_chan->ic_flags &~ IEEE80211_CHAN_HT) | htflags;
1077	if (chanflags != ni->ni_chan->ic_flags) {
1078		c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
1079		if (c == NULL && htflags != IEEE80211_CHAN_HT20) {
1080			/*
1081			 * No HT40 channel entry in our table; fall back
1082			 * to HT20 operation.  This should not happen.
1083			 */
1084			c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
1085			IEEE80211_NOTE(ni->ni_ic,
1086			    IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1087			    "no HT40 channel (freq %u), falling back to HT20",
1088			    ni->ni_chan->ic_freq);
1089			/* XXX stat */
1090		}
1091		if (c != NULL && c != ni->ni_chan) {
1092			IEEE80211_NOTE(ni->ni_ic,
1093			    IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
1094			    "switch station to HT%d channel %u/0x%x",
1095			    IEEE80211_IS_CHAN_HT40(c) ? 40 : 20,
1096			    c->ic_freq, c->ic_flags);
1097			ni->ni_chan = c;
1098		}
1099		/* NB: caller responsible for forcing any channel change */
1100	}
1101	/* update node's tx channel width */
1102	ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
1103}
1104
1105/*
1106 * Install received HT rate set by parsing the HT cap ie.
1107 */
1108int
1109ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
1110{
1111	struct ieee80211com *ic = ni->ni_ic;
1112	const struct ieee80211_ie_htcap *htcap;
1113	struct ieee80211_htrateset *rs;
1114	int i;
1115
1116	rs = &ni->ni_htrates;
1117	memset(rs, 0, sizeof(*rs));
1118	if (ie != NULL) {
1119		if (ie[0] == IEEE80211_ELEMID_VENDOR)
1120			ie += 4;
1121		htcap = (const struct ieee80211_ie_htcap *) ie;
1122		for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1123			if (isclr(htcap->hc_mcsset, i))
1124				continue;
1125			if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
1126				IEEE80211_NOTE(ic,
1127				    IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1128				    "WARNING, HT rate set too large; only "
1129				    "using %u rates", IEEE80211_HTRATE_MAXSIZE);
1130				ic->ic_stats.is_rx_rstoobig++;
1131				break;
1132			}
1133			rs->rs_rates[rs->rs_nrates++] = i;
1134		}
1135	}
1136	return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
1137}
1138
1139/*
1140 * Mark rates in a node's HT rate set as basic according
1141 * to the information in the supplied HT info ie.
1142 */
1143void
1144ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
1145{
1146	const struct ieee80211_ie_htinfo *htinfo;
1147	struct ieee80211_htrateset *rs;
1148	int i, j;
1149
1150	if (ie[0] == IEEE80211_ELEMID_VENDOR)
1151		ie += 4;
1152	htinfo = (const struct ieee80211_ie_htinfo *) ie;
1153	rs = &ni->ni_htrates;
1154	if (rs->rs_nrates == 0) {
1155		IEEE80211_NOTE(ni->ni_ic,
1156		    IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
1157		    "%s", "WARNING, empty HT rate set");
1158		return;
1159	}
1160	for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
1161		if (isclr(htinfo->hi_basicmcsset, i))
1162			continue;
1163		for (j = 0; j < rs->rs_nrates; j++)
1164			if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
1165				rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
1166	}
1167}
1168
1169static void
1170addba_timeout(void *arg)
1171{
1172	struct ieee80211_tx_ampdu *tap = arg;
1173
1174	/* XXX ? */
1175	tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1176	tap->txa_attempts++;
1177}
1178
1179static void
1180addba_start_timeout(struct ieee80211_tx_ampdu *tap)
1181{
1182	/* XXX use CALLOUT_PENDING instead? */
1183	callout_reset(&tap->txa_timer, IEEE80211_AGGR_TIMEOUT,
1184	    addba_timeout, tap);
1185	tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
1186	tap->txa_lastrequest = ticks;
1187}
1188
1189static void
1190addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
1191{
1192	/* XXX use CALLOUT_PENDING instead? */
1193	if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
1194		callout_stop(&tap->txa_timer);
1195		tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
1196	}
1197}
1198
1199/*
1200 * Default method for requesting A-MPDU tx aggregation.
1201 * We setup the specified state block and start a timer
1202 * to wait for an ADDBA response frame.
1203 */
1204static int
1205ieee80211_addba_request(struct ieee80211_node *ni,
1206	struct ieee80211_tx_ampdu *tap,
1207	int dialogtoken, int baparamset, int batimeout)
1208{
1209	int bufsiz;
1210
1211	/* XXX locking */
1212	tap->txa_token = dialogtoken;
1213	tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
1214	tap->txa_start = tap->txa_seqstart = 0;
1215	bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1216	tap->txa_wnd = (bufsiz == 0) ?
1217	    IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1218	addba_start_timeout(tap);
1219	return 1;
1220}
1221
1222/*
1223 * Default method for processing an A-MPDU tx aggregation
1224 * response.  We shutdown any pending timer and update the
1225 * state block according to the reply.
1226 */
1227static int
1228ieee80211_addba_response(struct ieee80211_node *ni,
1229	struct ieee80211_tx_ampdu *tap,
1230	int status, int baparamset, int batimeout)
1231{
1232	int bufsiz;
1233
1234	/* XXX locking */
1235	addba_stop_timeout(tap);
1236	if (status == IEEE80211_STATUS_SUCCESS) {
1237		bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1238		/* XXX override our request? */
1239		tap->txa_wnd = (bufsiz == 0) ?
1240		    IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
1241		tap->txa_flags |= IEEE80211_AGGR_RUNNING;
1242	} else {
1243		/* mark tid so we don't try again */
1244		tap->txa_flags |= IEEE80211_AGGR_NAK;
1245	}
1246	return 1;
1247}
1248
1249/*
1250 * Default method for stopping A-MPDU tx aggregation.
1251 * Any timer is cleared and we drain any pending frames.
1252 */
1253static void
1254ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1255{
1256	/* XXX locking */
1257	addba_stop_timeout(tap);
1258	if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
1259		/* clear aggregation queue */
1260		ieee80211_drain_ifq(&tap->txa_q);
1261		tap->txa_flags &= ~IEEE80211_AGGR_RUNNING;
1262	}
1263	tap->txa_attempts = 0;
1264}
1265
1266/*
1267 * Process a received action frame using the default aggregation
1268 * policy.  We intercept ADDBA-related frames and use them to
1269 * update our aggregation state.  All other frames are passed up
1270 * for processing by ieee80211_recv_action.
1271 */
1272static void
1273ieee80211_aggr_recv_action(struct ieee80211_node *ni,
1274	const uint8_t *frm, const uint8_t *efrm)
1275{
1276	struct ieee80211com *ic = ni->ni_ic;
1277	const struct ieee80211_action *ia;
1278	struct ieee80211_rx_ampdu *rap;
1279	struct ieee80211_tx_ampdu *tap;
1280	uint8_t dialogtoken;
1281	uint16_t baparamset, batimeout, baseqctl, code;
1282	uint16_t args[4];
1283	int tid, ac, bufsiz;
1284
1285	ia = (const struct ieee80211_action *) frm;
1286	switch (ia->ia_category) {
1287	case IEEE80211_ACTION_CAT_BA:
1288		switch (ia->ia_action) {
1289		case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1290			dialogtoken = frm[2];
1291			baparamset = LE_READ_2(frm+3);
1292			batimeout = LE_READ_2(frm+5);
1293			baseqctl = LE_READ_2(frm+7);
1294
1295			tid = MS(baparamset, IEEE80211_BAPS_TID);
1296			bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1297
1298			IEEE80211_NOTE(ic,
1299			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1300			    "recv ADDBA request: dialogtoken %u "
1301			    "baparamset 0x%x (tid %d bufsiz %d) batimeout %d "
1302			    "baseqctl %d:%d",
1303			    dialogtoken, baparamset, tid, bufsiz, batimeout,
1304			    MS(baseqctl, IEEE80211_BASEQ_START),
1305			    MS(baseqctl, IEEE80211_BASEQ_FRAG));
1306
1307			rap = &ni->ni_rx_ampdu[tid];
1308
1309			/* Send ADDBA response */
1310			args[0] = dialogtoken;
1311			/*
1312			 * NB: We ack only if the sta associated with HT and
1313			 * the ap is configured to do AMPDU rx (the latter
1314			 * violates the 11n spec and is mostly for testing).
1315			 */
1316			if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
1317			    (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_RX)) {
1318				ampdu_rx_start(rap, bufsiz,
1319				    MS(baseqctl, IEEE80211_BASEQ_START));
1320
1321				args[1] = IEEE80211_STATUS_SUCCESS;
1322			} else {
1323				IEEE80211_NOTE(ic,
1324				    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1325				    ni, "reject ADDBA request: %s",
1326				    ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
1327				       "administratively disabled" :
1328				       "not negotiated for station");
1329				ic->ic_stats.is_addba_reject++;
1330				args[1] = IEEE80211_STATUS_UNSPECIFIED;
1331			}
1332			/* XXX honor rap flags? */
1333			args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
1334				| SM(tid, IEEE80211_BAPS_TID)
1335				| SM(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
1336				;
1337			args[3] = 0;
1338			ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1339				IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
1340			return;
1341
1342		case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1343			dialogtoken = frm[2];
1344			code = LE_READ_2(frm+3);
1345			baparamset = LE_READ_2(frm+5);
1346			tid = MS(baparamset, IEEE80211_BAPS_TID);
1347			bufsiz = MS(baparamset, IEEE80211_BAPS_BUFSIZ);
1348			batimeout = LE_READ_2(frm+7);
1349
1350			ac = TID_TO_WME_AC(tid);
1351			tap = &ni->ni_tx_ampdu[ac];
1352			if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
1353				IEEE80211_DISCARD_MAC(ic,
1354				    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1355				    ni->ni_macaddr, "ADDBA response",
1356				    "no pending ADDBA, tid %d dialogtoken %u "
1357				    "code %d", tid, dialogtoken, code);
1358				ic->ic_stats.is_addba_norequest++;
1359				return;
1360			}
1361			if (dialogtoken != tap->txa_token) {
1362				IEEE80211_DISCARD_MAC(ic,
1363				    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1364				    ni->ni_macaddr, "ADDBA response",
1365				    "dialogtoken mismatch: waiting for %d, "
1366				    "received %d, tid %d code %d",
1367				    tap->txa_token, dialogtoken, tid, code);
1368				ic->ic_stats.is_addba_badtoken++;
1369				return;
1370			}
1371
1372			IEEE80211_NOTE(ic,
1373			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1374			    "recv ADDBA response: dialogtoken %u code %d "
1375			    "baparamset 0x%x (tid %d bufsiz %d) batimeout %d",
1376			    dialogtoken, code, baparamset, tid, bufsiz,
1377			    batimeout);
1378			ic->ic_addba_response(ni, tap,
1379				code, baparamset, batimeout);
1380			return;
1381
1382		case IEEE80211_ACTION_BA_DELBA:
1383			baparamset = LE_READ_2(frm+2);
1384			code = LE_READ_2(frm+4);
1385
1386			tid = MS(baparamset, IEEE80211_DELBAPS_TID);
1387
1388			IEEE80211_NOTE(ic,
1389			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1390			    "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
1391			    "code %d", baparamset, tid,
1392			    MS(baparamset, IEEE80211_DELBAPS_INIT), code);
1393
1394			if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
1395				ac = TID_TO_WME_AC(tid);
1396				tap = &ni->ni_tx_ampdu[ac];
1397				ic->ic_addba_stop(ni, tap);
1398			} else {
1399				rap = &ni->ni_rx_ampdu[tid];
1400				ampdu_rx_stop(rap);
1401			}
1402			return;
1403		}
1404		break;
1405	}
1406	ieee80211_recv_action(ni, frm, efrm);
1407}
1408
1409/*
1410 * Process a received 802.11n action frame.
1411 * Aggregation-related frames are assumed to be handled
1412 * already; we handle any other frames we can, otherwise
1413 * complain about being unsupported (with debugging).
1414 */
1415void
1416ieee80211_recv_action(struct ieee80211_node *ni,
1417	const uint8_t *frm, const uint8_t *efrm)
1418{
1419	struct ieee80211com *ic = ni->ni_ic;
1420	const struct ieee80211_action *ia;
1421	int chw;
1422
1423	ia = (const struct ieee80211_action *) frm;
1424	switch (ia->ia_category) {
1425	case IEEE80211_ACTION_CAT_BA:
1426		IEEE80211_NOTE(ic,
1427		    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1428		    "%s: BA action %d not implemented", __func__,
1429		    ia->ia_action);
1430		ic->ic_stats.is_rx_mgtdiscard++;
1431		break;
1432	case IEEE80211_ACTION_CAT_HT:
1433		switch (ia->ia_action) {
1434		case IEEE80211_ACTION_HT_TXCHWIDTH:
1435			chw = frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040 ? 40 : 20;
1436			if (chw != ni->ni_chw) {
1437				ni->ni_chw = chw;
1438				ni->ni_flags |= IEEE80211_NODE_CHWUPDATE;
1439			}
1440			IEEE80211_NOTE(ic,
1441			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1442		            "%s: HT txchwidth, width %d (%s)",
1443			    __func__, chw,
1444			    ni->ni_flags & IEEE80211_NODE_CHWUPDATE ?
1445				"new" : "no change");
1446			break;
1447		case IEEE80211_ACTION_HT_MIMOPWRSAVE:
1448			IEEE80211_NOTE(ic,
1449			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1450		            "%s: HT MIMO PS", __func__);
1451			break;
1452		default:
1453			IEEE80211_NOTE(ic,
1454			   IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1455		           "%s: HT action %d not implemented", __func__,
1456			   ia->ia_action);
1457			ic->ic_stats.is_rx_mgtdiscard++;
1458			break;
1459		}
1460		break;
1461	default:
1462		IEEE80211_NOTE(ic,
1463		    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1464		    "%s: category %d not implemented", __func__,
1465		    ia->ia_category);
1466		ic->ic_stats.is_rx_mgtdiscard++;
1467		break;
1468	}
1469}
1470
1471/*
1472 * Transmit processing.
1473 */
1474
1475/*
1476 * Request A-MPDU tx aggregation.  Setup local state and
1477 * issue an ADDBA request.  BA use will only happen after
1478 * the other end replies with ADDBA response.
1479 */
1480int
1481ieee80211_ampdu_request(struct ieee80211_node *ni,
1482	struct ieee80211_tx_ampdu *tap)
1483{
1484	struct ieee80211com *ic = ni->ni_ic;
1485	uint16_t args[4];
1486	int tid, dialogtoken;
1487	static int tokens = 0;	/* XXX */
1488
1489	/* XXX locking */
1490	if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
1491		/* do deferred setup of state */
1492		IEEE80211_TAPQ_INIT(tap);
1493		callout_init(&tap->txa_timer, CALLOUT_MPSAFE);
1494		tap->txa_flags |= IEEE80211_AGGR_SETUP;
1495	}
1496	if (tap->txa_attempts >= IEEE80211_AGGR_MAXTRIES &&
1497	    (ticks - tap->txa_lastrequest) < IEEE80211_AGGR_MINRETRY) {
1498		/*
1499		 * Don't retry too often; IEEE80211_AGGR_MINRETRY
1500		 * defines the minimum interval we'll retry after
1501		 * IEEE80211_AGGR_MAXTRIES failed attempts to
1502		 * negotiate use.
1503		 */
1504		return 0;
1505	}
1506	/* XXX hack for not doing proper locking */
1507	tap->txa_flags &= ~IEEE80211_AGGR_NAK;
1508
1509	dialogtoken = (tokens+1) % 63;		/* XXX */
1510
1511	tid = WME_AC_TO_TID(tap->txa_ac);
1512	args[0] = dialogtoken;
1513	args[1]	= IEEE80211_BAPS_POLICY_IMMEDIATE
1514		| SM(tid, IEEE80211_BAPS_TID)
1515		| SM(IEEE80211_AGGR_BAWMAX, IEEE80211_BAPS_BUFSIZ)
1516		;
1517	args[2] = 0;	/* batimeout */
1518	args[3] = SM(0, IEEE80211_BASEQ_START)
1519		| SM(0, IEEE80211_BASEQ_FRAG)
1520		;
1521	/* NB: do first so there's no race against reply */
1522	if (!ic->ic_addba_request(ni, tap, dialogtoken, args[1], args[2])) {
1523		/* unable to setup state, don't make request */
1524		IEEE80211_NOTE(ni->ni_ic, IEEE80211_MSG_11N,
1525		    ni, "%s: could not setup BA stream for AC %d",
1526		    __func__, tap->txa_ac);
1527		/* defer next try so we don't slam the driver with requests */
1528		tap->txa_attempts = IEEE80211_AGGR_MAXTRIES;
1529		tap->txa_lastrequest = ticks;
1530		return 0;
1531	}
1532	tokens = dialogtoken;			/* allocate token */
1533	return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
1534		IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
1535}
1536
1537/*
1538 * Terminate an AMPDU tx stream.  State is reclaimed
1539 * and the peer notified with a DelBA Action frame.
1540 */
1541void
1542ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
1543{
1544	struct ieee80211com *ic = ni->ni_ic;
1545	uint16_t args[4];
1546
1547	/* XXX locking */
1548	if (IEEE80211_AMPDU_RUNNING(tap)) {
1549		IEEE80211_NOTE(ic, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1550		    ni, "%s: stop BA stream for AC %d", __func__, tap->txa_ac);
1551		ic->ic_stats.is_ampdu_stop++;
1552
1553		ic->ic_addba_stop(ni, tap);
1554		args[0] = WME_AC_TO_TID(tap->txa_ac);
1555		args[1] = IEEE80211_DELBAPS_INIT;
1556		args[2] = 1;				/* XXX reason code */
1557		ieee80211_send_action(ni, IEEE80211_ACTION_CAT_BA,
1558			IEEE80211_ACTION_BA_DELBA, args);
1559	} else {
1560		IEEE80211_NOTE(ic, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1561		    ni, "%s: BA stream for AC %d not running",
1562		    __func__, tap->txa_ac);
1563		ic->ic_stats.is_ampdu_stop_failed++;
1564	}
1565}
1566
1567/*
1568 * Transmit a BAR frame to the specified node.  The
1569 * BAR contents are drawn from the supplied aggregation
1570 * state associated with the node.
1571 */
1572int
1573ieee80211_send_bar(struct ieee80211_node *ni,
1574	const struct ieee80211_tx_ampdu *tap)
1575{
1576#define	senderr(_x, _v)	do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
1577#define	ADDSHORT(frm, v) do {			\
1578	frm[0] = (v) & 0xff;			\
1579	frm[1] = (v) >> 8;			\
1580	frm += 2;				\
1581} while (0)
1582	struct ieee80211com *ic = ni->ni_ic;
1583	struct ifnet *ifp = ic->ic_ifp;
1584	struct ieee80211_frame_min *wh;
1585	struct mbuf *m;
1586	uint8_t *frm;
1587	uint16_t barctl, barseqctl;
1588	int tid, ret;
1589
1590	ieee80211_ref_node(ni);
1591
1592	m = ieee80211_getmgtframe(&frm,
1593		ic->ic_headroom + sizeof(struct ieee80211_frame_min),
1594		sizeof(struct ieee80211_ba_request)
1595	);
1596	if (m == NULL)
1597		senderr(ENOMEM, is_tx_nobuf);
1598
1599	wh = mtod(m, struct ieee80211_frame_min *);
1600	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 |
1601		IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
1602	wh->i_fc[1] = 0;
1603	IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1604	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
1605
1606	tid = WME_AC_TO_TID(tap->txa_ac);
1607	barctl 	= (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
1608			IEEE80211_BAPS_POLICY_IMMEDIATE :
1609			IEEE80211_BAPS_POLICY_DELAYED)
1610		| SM(tid, IEEE80211_BAPS_TID)
1611		| SM(tap->txa_wnd, IEEE80211_BAPS_BUFSIZ)
1612		;
1613	barseqctl = SM(tap->txa_start, IEEE80211_BASEQ_START)
1614		| SM(0, IEEE80211_BASEQ_FRAG)
1615		;
1616	ADDSHORT(frm, barctl);
1617	ADDSHORT(frm, barseqctl);
1618	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1619
1620	IEEE80211_NODE_STAT(ni, tx_mgmt);	/* XXX tx_ctl? */
1621
1622	IEEE80211_NOTE(ic, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
1623	    ni, "send bar frame (tid %u start %u) on channel %u",
1624	    tid, tap->txa_start, ieee80211_chan2ieee(ic, ic->ic_curchan));
1625
1626	m->m_pkthdr.rcvif = (void *)ni;
1627	IF_ENQUEUE(&ic->ic_mgtq, m);		/* cheat */
1628	if_start(ifp);
1629
1630	return 0;
1631bad:
1632	ieee80211_free_node(ni);
1633	return ret;
1634#undef ADDSHORT
1635#undef senderr
1636}
1637
1638/*
1639 * Send an action management frame.  The arguments are stuff
1640 * into a frame without inspection; the caller is assumed to
1641 * prepare them carefully (e.g. based on the aggregation state).
1642 */
1643int
1644ieee80211_send_action(struct ieee80211_node *ni,
1645	int category, int action, uint16_t args[4])
1646{
1647#define	senderr(_x, _v)	do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
1648#define	ADDSHORT(frm, v) do {			\
1649	frm[0] = (v) & 0xff;			\
1650	frm[1] = (v) >> 8;			\
1651	frm += 2;				\
1652} while (0)
1653	struct ieee80211com *ic = ni->ni_ic;
1654	struct mbuf *m;
1655	uint8_t *frm;
1656	uint16_t baparamset;
1657	int ret;
1658
1659	KASSERT(ni != NULL, ("null node"));
1660
1661	/*
1662	 * Hold a reference on the node so it doesn't go away until after
1663	 * the xmit is complete all the way in the driver.  On error we
1664	 * will remove our reference.
1665	 */
1666	IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE,
1667		"ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n",
1668		__func__, __LINE__,
1669		ni, ether_sprintf(ni->ni_macaddr),
1670		ieee80211_node_refcnt(ni)+1);
1671	ieee80211_ref_node(ni);
1672
1673	m = ieee80211_getmgtframe(&frm,
1674		ic->ic_headroom + sizeof(struct ieee80211_frame),
1675		  sizeof(uint16_t)	/* action+category */
1676		/* XXX may action payload */
1677		+ sizeof(struct ieee80211_action_ba_addbaresponse)
1678	);
1679	if (m == NULL)
1680		senderr(ENOMEM, is_tx_nobuf);
1681
1682	*frm++ = category;
1683	*frm++ = action;
1684	switch (category) {
1685	case IEEE80211_ACTION_CAT_BA:
1686		switch (action) {
1687		case IEEE80211_ACTION_BA_ADDBA_REQUEST:
1688			IEEE80211_NOTE(ic,
1689			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1690			    "send ADDBA request: dialogtoken %d "
1691			    "baparamset 0x%x (tid %d) batimeout 0x%x baseqctl 0x%x",
1692			    args[0], args[1], MS(args[1], IEEE80211_BAPS_TID),
1693			    args[2], args[3]);
1694
1695			*frm++ = args[0];	/* dialog token */
1696			ADDSHORT(frm, args[1]);	/* baparamset */
1697			ADDSHORT(frm, args[2]);	/* batimeout */
1698			ADDSHORT(frm, args[3]);	/* baseqctl */
1699			break;
1700		case IEEE80211_ACTION_BA_ADDBA_RESPONSE:
1701			IEEE80211_NOTE(ic,
1702			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1703			    "send ADDBA response: dialogtoken %d status %d "
1704			    "baparamset 0x%x (tid %d) batimeout %d",
1705			    args[0], args[1], args[2],
1706			    MS(args[2], IEEE80211_BAPS_TID), args[3]);
1707
1708			*frm++ = args[0];	/* dialog token */
1709			ADDSHORT(frm, args[1]);	/* statuscode */
1710			ADDSHORT(frm, args[2]);	/* baparamset */
1711			ADDSHORT(frm, args[3]);	/* batimeout */
1712			break;
1713		case IEEE80211_ACTION_BA_DELBA:
1714			/* XXX */
1715			baparamset = SM(args[0], IEEE80211_DELBAPS_TID)
1716				   | SM(args[1], IEEE80211_DELBAPS_INIT)
1717				   ;
1718			ADDSHORT(frm, baparamset);
1719			ADDSHORT(frm, args[2]);	/* reason code */
1720
1721			IEEE80211_NOTE(ic,
1722			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1723			    "send DELBA action: tid %d, initiator %d reason %d",
1724			    args[0], args[1], args[2]);
1725			break;
1726		default:
1727			goto badaction;
1728		}
1729		break;
1730	case IEEE80211_ACTION_CAT_HT:
1731		switch (action) {
1732		case IEEE80211_ACTION_HT_TXCHWIDTH:
1733			IEEE80211_NOTE(ic,
1734			    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
1735			    ni, "send HT txchwidth: width %d",
1736			    IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) ? 40 : 20
1737			);
1738			*frm++ = IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) ?
1739				IEEE80211_A_HT_TXCHWIDTH_2040 :
1740				IEEE80211_A_HT_TXCHWIDTH_20;
1741			break;
1742		default:
1743			goto badaction;
1744		}
1745		break;
1746	default:
1747	badaction:
1748		IEEE80211_NOTE(ic,
1749		    IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
1750		    "%s: unsupported category %d action %d", __func__,
1751		    category, action);
1752		senderr(EINVAL, is_tx_unknownmgt);
1753		/* NOTREACHED */
1754	}
1755	m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
1756
1757	ret = ieee80211_mgmt_output(ic, ni, m, IEEE80211_FC0_SUBTYPE_ACTION);
1758	if (ret != 0)
1759		goto bad;
1760	return 0;
1761bad:
1762	ieee80211_free_node(ni);
1763	return ret;
1764#undef ADDSHORT
1765#undef senderr
1766}
1767
1768/*
1769 * Construct the MCS bit mask for inclusion
1770 * in an HT information element.
1771 */
1772static void
1773ieee80211_set_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1774{
1775	int i;
1776
1777	for (i = 0; i < rs->rs_nrates; i++) {
1778		int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1779		if (r < IEEE80211_HTRATE_MAXSIZE) {	/* XXX? */
1780			/* NB: this assumes a particular implementation */
1781			setbit(frm, r);
1782		}
1783	}
1784}
1785
1786/*
1787 * Add body of an HTCAP information element.
1788 */
1789static uint8_t *
1790ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
1791{
1792#define	ADDSHORT(frm, v) do {			\
1793	frm[0] = (v) & 0xff;			\
1794	frm[1] = (v) >> 8;			\
1795	frm += 2;				\
1796} while (0)
1797	struct ieee80211com *ic = ni->ni_ic;
1798	uint16_t caps;
1799	int rxmax, density;
1800
1801	/* HT capabilities */
1802	caps = ic->ic_htcaps & 0xffff;
1803	/*
1804	 * Note channel width depends on whether we are operating as
1805	 * a sta or not.  When operating as a sta we are generating
1806	 * a request based on our desired configuration.  Otherwise
1807	 * we are operational and the channel attributes identify
1808	 * how we've been setup (which might be different if a fixed
1809	 * channel is specified).
1810	 */
1811	if (ic->ic_opmode == IEEE80211_M_STA) {
1812		/* override 20/40 use based on config */
1813		if (ic->ic_flags_ext & IEEE80211_FEXT_USEHT40)
1814			caps |= IEEE80211_HTCAP_CHWIDTH40;
1815		else
1816			caps &= ~IEEE80211_HTCAP_CHWIDTH40;
1817		/* use advertised setting (XXX locally constraint) */
1818		rxmax = MS(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU);
1819		density = MS(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY);
1820	} else {
1821		/* override 20/40 use based on current channel */
1822		if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan))
1823			caps |= IEEE80211_HTCAP_CHWIDTH40;
1824		else
1825			caps &= ~IEEE80211_HTCAP_CHWIDTH40;
1826		rxmax = ic->ic_ampdu_rxmax;
1827		density = ic->ic_ampdu_density;
1828	}
1829	/* adjust short GI based on channel and config */
1830	if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI20) == 0)
1831		caps &= ~IEEE80211_HTCAP_SHORTGI20;
1832	if ((ic->ic_flags_ext & IEEE80211_FEXT_SHORTGI40) == 0 ||
1833	    (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
1834		caps &= ~IEEE80211_HTCAP_SHORTGI40;
1835	ADDSHORT(frm, caps);
1836
1837	/* HT parameters */
1838	*frm = SM(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
1839	     | SM(density, IEEE80211_HTCAP_MPDUDENSITY)
1840	     ;
1841	frm++;
1842
1843	/* pre-zero remainder of ie */
1844	memset(frm, 0, sizeof(struct ieee80211_ie_htcap) -
1845		__offsetof(struct ieee80211_ie_htcap, hc_mcsset));
1846
1847	/* supported MCS set */
1848	/*
1849	 * XXX it would better to get the rate set from ni_htrates
1850	 * so we can restrict it but for sta mode ni_htrates isn't
1851	 * setup when we're called to form an AssocReq frame so for
1852	 * now we're restricted to the default HT rate set.
1853	 */
1854	ieee80211_set_htrates(frm, &ieee80211_rateset_11n);
1855
1856	frm += sizeof(struct ieee80211_ie_htcap) -
1857		__offsetof(struct ieee80211_ie_htcap, hc_mcsset);
1858	return frm;
1859#undef ADDSHORT
1860}
1861
1862/*
1863 * Add 802.11n HT capabilities information element
1864 */
1865uint8_t *
1866ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
1867{
1868	frm[0] = IEEE80211_ELEMID_HTCAP;
1869	frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
1870	return ieee80211_add_htcap_body(frm + 2, ni);
1871}
1872
1873/*
1874 * Add Broadcom OUI wrapped standard HTCAP ie; this is
1875 * used for compatibility w/ pre-draft implementations.
1876 */
1877uint8_t *
1878ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
1879{
1880	frm[0] = IEEE80211_ELEMID_VENDOR;
1881	frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
1882	frm[2] = (BCM_OUI >> 0) & 0xff;
1883	frm[3] = (BCM_OUI >> 8) & 0xff;
1884	frm[4] = (BCM_OUI >> 16) & 0xff;
1885	frm[5] = BCM_OUI_HTCAP;
1886	return ieee80211_add_htcap_body(frm + 6, ni);
1887}
1888
1889/*
1890 * Construct the MCS bit mask of basic rates
1891 * for inclusion in an HT information element.
1892 */
1893static void
1894ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
1895{
1896	int i;
1897
1898	for (i = 0; i < rs->rs_nrates; i++) {
1899		int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
1900		if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
1901		    r < IEEE80211_HTRATE_MAXSIZE) {
1902			/* NB: this assumes a particular implementation */
1903			setbit(frm, r);
1904		}
1905	}
1906}
1907
1908/*
1909 * Update the HTINFO ie for a beacon frame.
1910 */
1911void
1912ieee80211_ht_update_beacon(struct ieee80211com *ic,
1913	struct ieee80211_beacon_offsets *bo)
1914{
1915#define	PROTMODE	(IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
1916	struct ieee80211_ie_htinfo *ht =
1917	   (struct ieee80211_ie_htinfo *) bo->bo_htinfo;
1918
1919	/* XXX only update on channel change */
1920	ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, ic->ic_bsschan);
1921	ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
1922	if (IEEE80211_IS_CHAN_HT40U(ic->ic_bsschan))
1923		ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
1924	else if (IEEE80211_IS_CHAN_HT40D(ic->ic_bsschan))
1925		ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
1926	else
1927		ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
1928	if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan))
1929		ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
1930
1931	/* protection mode */
1932	ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
1933
1934	/* XXX propagate to vendor ie's */
1935#undef PROTMODE
1936}
1937
1938/*
1939 * Add body of an HTINFO information element.
1940 *
1941 * NB: We don't use struct ieee80211_ie_htinfo because we can
1942 * be called to fillin both a standard ie and a compat ie that
1943 * has a vendor OUI at the front.
1944 */
1945static uint8_t *
1946ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
1947{
1948	struct ieee80211com *ic = ni->ni_ic;
1949
1950	/* pre-zero remainder of ie */
1951	memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
1952
1953	/* primary/control channel center */
1954	*frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan);
1955
1956	frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
1957	if (IEEE80211_IS_CHAN_HT40U(ic->ic_bsschan))
1958		frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
1959	else if (IEEE80211_IS_CHAN_HT40D(ic->ic_bsschan))
1960		frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
1961	else
1962		frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
1963	if (IEEE80211_IS_CHAN_HT40(ic->ic_bsschan))
1964		frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
1965
1966	frm[1] = ic->ic_curhtprotmode;
1967
1968	frm += 5;
1969
1970	/* basic MCS set */
1971	ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
1972	frm += sizeof(struct ieee80211_ie_htinfo) -
1973		__offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
1974	return frm;
1975}
1976
1977/*
1978 * Add 802.11n HT information information element.
1979 */
1980uint8_t *
1981ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
1982{
1983	frm[0] = IEEE80211_ELEMID_HTINFO;
1984	frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
1985	return ieee80211_add_htinfo_body(frm + 2, ni);
1986}
1987
1988/*
1989 * Add Broadcom OUI wrapped standard HTINFO ie; this is
1990 * used for compatibility w/ pre-draft implementations.
1991 */
1992uint8_t *
1993ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
1994{
1995	frm[0] = IEEE80211_ELEMID_VENDOR;
1996	frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
1997	frm[2] = (BCM_OUI >> 0) & 0xff;
1998	frm[3] = (BCM_OUI >> 8) & 0xff;
1999	frm[4] = (BCM_OUI >> 16) & 0xff;
2000	frm[5] = BCM_OUI_HTINFO;
2001	return ieee80211_add_htinfo_body(frm + 6, ni);
2002}
2003