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