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