xref: /illumos-gate/usr/src/uts/common/io/net80211/net80211_output.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  *
5  * Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org>
6  */
7 
8 /*
9  * Copyright (c) 2001 Atsushi Onoe
10  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. The name of the author may not be used to endorse or promote products
22  *    derived from this software without specific prior written permission.
23  *
24  * Alternatively, this software may be distributed under the terms of the
25  * GNU General Public License ("GPL") version 2 as published by the Free
26  * Software Foundation.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
29  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
30  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
37  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*
41  * Send out 802.11 frames
42  */
43 
44 #include <sys/byteorder.h>
45 #include <sys/strsun.h>
46 #include "net80211_impl.h"
47 
48 /*
49  * Set the direction field and address fields of an outgoing
50  * non-QoS frame.  Note this should be called early on in
51  * constructing a frame as it sets i_fc[1]; other bits can
52  * then be or'd in.
53  */
54 static void
55 ieee80211_send_setup(ieee80211com_t *ic, ieee80211_node_t *in,
56     struct ieee80211_frame *wh, int type, const uint8_t *sa, const uint8_t *da,
57     const uint8_t *bssid)
58 {
59 	wh->i_fc[0] = (uint8_t)(IEEE80211_FC0_VERSION_0 | type);
60 	if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
61 		switch (ic->ic_opmode) {
62 		case IEEE80211_M_STA:
63 			wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
64 			IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
65 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
66 			IEEE80211_ADDR_COPY(wh->i_addr3, da);
67 			break;
68 		case IEEE80211_M_IBSS:
69 		case IEEE80211_M_AHDEMO:
70 			wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
71 			IEEE80211_ADDR_COPY(wh->i_addr1, da);
72 			IEEE80211_ADDR_COPY(wh->i_addr2, sa);
73 			IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
74 			break;
75 		default:
76 			ieee80211_err("ieee80211_send_setup: "
77 			    "Invalid mode %u\n", ic->ic_opmode);
78 			return;
79 		}
80 	} else {
81 		wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
82 		IEEE80211_ADDR_COPY(wh->i_addr1, da);
83 		IEEE80211_ADDR_COPY(wh->i_addr2, sa);
84 		IEEE80211_ADDR_COPY(wh->i_addr3, bssid);
85 	}
86 	*(uint16_t *)&wh->i_dur[0] = 0;	/* set duration */
87 	/* NB: use non-QoS tid */
88 	*(uint16_t *)&wh->i_seq[0] =
89 	    LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] <<
90 	    IEEE80211_SEQ_SEQ_SHIFT);
91 	in->in_txseqs[IEEE80211_NONQOS_TID]++;
92 }
93 
94 /*
95  * Send a management frame to the specified node.  The node pointer
96  * must have a reference as the pointer will be passed to the driver
97  * and potentially held for a long time.  If the frame is successfully
98  * dispatched to the driver, then it is responsible for freeing the
99  * reference (and potentially free'ing up any associated storage).
100  *
101  * Return 0 on success
102  */
103 int
104 ieee80211_mgmt_output(ieee80211com_t *ic, ieee80211_node_t *in, mblk_t *mp,
105     int type, int timer)
106 {
107 	ieee80211_impl_t *im = ic->ic_private;
108 	struct ieee80211_frame *wh;
109 
110 	ASSERT(in != NULL);
111 
112 	wh = (struct ieee80211_frame *)mp->b_rptr;
113 	ieee80211_send_setup(ic, in, wh, IEEE80211_FC0_TYPE_MGT | type,
114 	    ic->ic_macaddr, in->in_macaddr, in->in_bssid);
115 	if (in->in_challenge != NULL)
116 		wh->i_fc[1] |= IEEE80211_FC1_WEP;
117 
118 	if (timer > 0) {
119 		/*
120 		 * Set the mgt frame timeout.
121 		 */
122 		im->im_mgt_timer = timer;
123 		ieee80211_start_watchdog(ic, 1);
124 	}
125 	return ((*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT));
126 }
127 
128 /*
129  * Send a null data frame to the specified node.
130  *
131  * NB: the caller is assumed to have setup a node reference
132  *     for use; this is necessary to deal with a race condition
133  *     when probing for inactive stations.
134  */
135 int
136 ieee80211_send_nulldata(ieee80211_node_t *in)
137 {
138 	ieee80211com_t *ic = in->in_ic;
139 	mblk_t *m;
140 	struct ieee80211_frame *wh;
141 	uint8_t *frm;
142 
143 	m = ieee80211_getmgtframe(&frm, 0);
144 	if (m == NULL) {
145 		ic->ic_stats.is_tx_nobuf++;
146 		return (ENOMEM);
147 	}
148 
149 	wh = (struct ieee80211_frame *)m->b_rptr;
150 	ieee80211_send_setup(ic, in, wh,
151 	    IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
152 	    ic->ic_macaddr, in->in_macaddr, in->in_bssid);
153 	/* NB: power management bit is never sent by an AP */
154 	if ((in->in_flags & IEEE80211_NODE_PWR_MGT) &&
155 	    ic->ic_opmode != IEEE80211_M_HOSTAP)
156 		wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
157 	m->b_wptr = m->b_rptr + sizeof (struct ieee80211_frame);
158 
159 	ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, "net80211: "
160 	    "send null data frame on channel %u, pwr mgt %s\n",
161 	    ieee80211_macaddr_sprintf(in->in_macaddr),
162 	    ieee80211_chan2ieee(ic, ic->ic_curchan),
163 	    wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis");
164 
165 	(void) (*ic->ic_xmit)(ic, m, IEEE80211_FC0_TYPE_MGT);
166 
167 	return (0);
168 }
169 
170 /*
171  * Encapsulate an outbound data frame for GLDv3 based driver.
172  * Fill in the variable part of the 80211 frame
173  */
174 /* ARGSUSED */
175 mblk_t *
176 ieee80211_encap(ieee80211com_t *ic, mblk_t *mp, ieee80211_node_t *in)
177 {
178 	struct ieee80211_frame	*wh;
179 	struct ieee80211_key *key;
180 	int addqos, ac, tid;
181 
182 	ASSERT(mp != NULL && MBLKL(mp) >= sizeof (struct ieee80211_frame));
183 	/*
184 	 * Some ap's don't handle QoS-encapsulated EAPOL
185 	 * frames so suppress use.  This may be an issue if other
186 	 * ap's require all data frames to be QoS-encapsulated
187 	 * once negotiated in which case we'll need to make this
188 	 * configurable.
189 	 */
190 	addqos = in->in_flags & (IEEE80211_NODE_QOS | IEEE80211_NODE_HT);
191 	wh = (struct ieee80211_frame *)mp->b_rptr;
192 	*(uint16_t *)wh->i_dur = 0;
193 	if (addqos) {
194 		struct ieee80211_qosframe *qwh =
195 		    (struct ieee80211_qosframe *)wh;
196 
197 		ac = ieee80211_classify(ic, mp, in);
198 		/* map from access class/queue to 11e header priorty value */
199 		tid = WME_AC_TO_TID(ac);
200 		qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
201 		/*
202 		 * Check if A-MPDU tx aggregation is setup or if we
203 		 * should try to enable it.  The sta must be associated
204 		 * with HT and A-MPDU enabled for use.  On the first
205 		 * frame that goes out We issue an ADDBA request and
206 		 * wait for a reply.  The frame being encapsulated
207 		 * will go out w/o using A-MPDU, or possibly it might
208 		 * be collected by the driver and held/retransmit.
209 		 * ieee80211_ampdu_request handles staggering requests
210 		 * in case the receiver NAK's us or we are otherwise
211 		 * unable to establish a BA stream.
212 		 */
213 		if ((in->in_flags & IEEE80211_NODE_AMPDU_TX) &&
214 		    (ic->ic_flags_ext & IEEE80211_FEXT_AMPDU_TX)) {
215 			struct ieee80211_tx_ampdu *tap = &in->in_tx_ampdu[ac];
216 
217 			if (IEEE80211_AMPDU_RUNNING(tap)) {
218 				/*
219 				 * Operational, mark frame for aggregation.
220 				 */
221 				qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_BA;
222 			} else if (!IEEE80211_AMPDU_REQUESTED(tap)) {
223 				/*
224 				 * Not negotiated yet, request service.
225 				 */
226 				(void) ieee80211_ampdu_request(in, tap);
227 			}
228 		}
229 		/* works even when BA marked above */
230 		if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].
231 		    wmep_noackPolicy) {
232 			qwh->i_qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
233 		}
234 
235 		*(uint16_t *)wh->i_seq =
236 		    LE_16(in->in_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
237 		in->in_txseqs[tid]++;
238 	} else {
239 		*(uint16_t *)wh->i_seq =
240 		    LE_16(in->in_txseqs[IEEE80211_NONQOS_TID] <<
241 		    IEEE80211_SEQ_SEQ_SHIFT);
242 		in->in_txseqs[IEEE80211_NONQOS_TID]++;
243 	}
244 
245 	if (ic->ic_flags & IEEE80211_F_PRIVACY)
246 		key = ieee80211_crypto_getkey(ic);
247 	else
248 		key = NULL;
249 
250 	/*
251 	 * IEEE 802.1X: send EAPOL frames always in the clear.
252 	 * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set.
253 	 */
254 	if (key != NULL && (ic->ic_flags & IEEE80211_F_WPA)) {
255 		wh->i_fc[1] |= IEEE80211_FC1_WEP;
256 		if (!ieee80211_crypto_enmic(isc, key, mp, 0))
257 			ieee80211_err("ieee80211_crypto_enmic failed.\n");
258 	}
259 
260 	return (mp);
261 }
262 
263 /*
264  * Add supported rates information element to a frame.
265  */
266 static uint8_t *
267 ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs)
268 {
269 	uint8_t nrates;
270 
271 	*frm++ = IEEE80211_ELEMID_RATES;
272 	nrates = rs->ir_nrates;
273 	if (nrates > IEEE80211_RATE_SIZE)
274 		nrates = IEEE80211_RATE_SIZE;
275 	*frm++ = nrates;
276 	bcopy(rs->ir_rates, frm, nrates);
277 	return (frm + nrates);
278 }
279 
280 /*
281  * Add extended supported rates element to a frame, usually for 11g mode
282  */
283 static uint8_t *
284 ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs)
285 {
286 	if (rs->ir_nrates > IEEE80211_RATE_SIZE) {
287 		uint8_t nrates = rs->ir_nrates - IEEE80211_RATE_SIZE;
288 
289 		*frm++ = IEEE80211_ELEMID_XRATES;
290 		*frm++ = nrates;
291 		bcopy(rs->ir_rates + IEEE80211_RATE_SIZE, frm, nrates);
292 		frm += nrates;
293 	}
294 	return (frm);
295 }
296 
297 #define	WME_OUI_BYTES		0x00, 0x50, 0xf2
298 /*
299  * Add a WME information element to a frame.
300  */
301 /* ARGSUSED */
302 static uint8_t *
303 ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme)
304 {
305 	static const struct ieee80211_wme_info info = {
306 		.wme_id		= IEEE80211_ELEMID_VENDOR,
307 		.wme_len	= sizeof (struct ieee80211_wme_info) - 2,
308 		.wme_oui	= { WME_OUI_BYTES },
309 		.wme_type	= WME_OUI_TYPE,
310 		.wme_subtype	= WME_INFO_OUI_SUBTYPE,
311 		.wme_version	= WME_VERSION,
312 		.wme_info	= 0,
313 	};
314 	(void) memcpy(frm, &info, sizeof (info));
315 	return (frm + sizeof (info));
316 }
317 
318 /*
319  * Add a WME parameters element to a frame.
320  */
321 static uint8_t *
322 ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme)
323 {
324 #define	SM(_v, _f)	(((_v) << _f##_S) & _f)
325 #define	ADDSHORT(frm, v) do {			\
326 	_NOTE(CONSTCOND)			\
327 	frm[0] = (v) & 0xff;			\
328 	frm[1] = (v) >> 8;			\
329 	frm += 2;				\
330 	_NOTE(CONSTCOND)			\
331 } while (0)
332 	/* NB: this works 'cuz a param has an info at the front */
333 	static const struct ieee80211_wme_info param = {
334 		.wme_id		= IEEE80211_ELEMID_VENDOR,
335 		.wme_len	= sizeof (struct ieee80211_wme_param) - 2,
336 		.wme_oui	= { WME_OUI_BYTES },
337 		.wme_type	= WME_OUI_TYPE,
338 		.wme_subtype	= WME_PARAM_OUI_SUBTYPE,
339 		.wme_version	= WME_VERSION,
340 	};
341 	int i;
342 
343 	(void) memcpy(frm, &param, sizeof (param));
344 	frm += offsetof(struct ieee80211_wme_info, wme_info);
345 	*frm++ = wme->wme_bssChanParams.cap_info;	/* AC info */
346 	*frm++ = 0;					/* reserved field */
347 	for (i = 0; i < WME_NUM_AC; i++) {
348 		const struct wmeParams *ac =
349 		    &wme->wme_bssChanParams.cap_wmeParams[i];
350 		*frm++ = SM(i, WME_PARAM_ACI)
351 		    | SM(ac->wmep_acm, WME_PARAM_ACM)
352 		    | SM(ac->wmep_aifsn, WME_PARAM_AIFSN);
353 		*frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX)
354 		    | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN);
355 		ADDSHORT(frm, ac->wmep_txopLimit);
356 	}
357 	return (frm);
358 #undef SM
359 #undef ADDSHORT
360 }
361 #undef WME_OUI_BYTES
362 
363 /*
364  * Add SSID element to a frame
365  */
366 static uint8_t *
367 ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, uint32_t len)
368 {
369 	*frm++ = IEEE80211_ELEMID_SSID;
370 	*frm++ = (uint8_t)len;
371 	bcopy(ssid, frm, len);
372 	return (frm + len);
373 }
374 
375 /*
376  * Add an erp element to a frame.
377  */
378 static uint8_t *
379 ieee80211_add_erp(uint8_t *frm, ieee80211com_t *ic)
380 {
381 	uint8_t erp;
382 
383 	*frm++ = IEEE80211_ELEMID_ERP;
384 	*frm++ = 1;
385 	erp = 0;
386 	if (ic->ic_flags & IEEE80211_F_USEPROT)
387 		erp |= IEEE80211_ERP_USE_PROTECTION;
388 	if (ic->ic_flags & IEEE80211_F_USEBARKER)
389 		erp |= IEEE80211_ERP_LONG_PREAMBLE;
390 	*frm++ = erp;
391 	return (frm);
392 }
393 
394 /*
395  * Get capability information from the interface softc, ic.
396  */
397 static uint16_t
398 ieee80211_get_capinfo(ieee80211com_t *ic)
399 {
400 	uint16_t capinfo;
401 
402 	if (ic->ic_opmode == IEEE80211_M_IBSS)
403 		capinfo = IEEE80211_CAPINFO_IBSS;
404 	else
405 		capinfo = IEEE80211_CAPINFO_ESS;
406 	if (ic->ic_flags & IEEE80211_F_PRIVACY)
407 		capinfo |= IEEE80211_CAPINFO_PRIVACY;
408 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
409 	    IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
410 		capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
411 	}
412 	if (ic->ic_flags & IEEE80211_F_SHSLOT)
413 		capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
414 
415 	return (capinfo);
416 }
417 
418 /*
419  * Send a probe request frame with the specified ssid
420  * and any optional information element data.
421  */
422 int
423 ieee80211_send_probereq(ieee80211_node_t *in,
424     const uint8_t *sa, const uint8_t *da, const uint8_t *bssid,
425     const uint8_t *ssid, size_t ssidlen, const void *optie, size_t optielen)
426 {
427 	mblk_t *mp;
428 	ieee80211com_t *ic = in->in_ic;
429 	enum ieee80211_phymode mode;
430 	struct ieee80211_frame *wh;
431 	uint8_t *frm;
432 
433 	/*
434 	 * prreq frame format ([tlv] - 1 byte element ID + 1 byte length)
435 	 *	[tlv] ssid
436 	 *	[tlv] supported rates
437 	 *	[tlv] extended supported rates
438 	 *	[tlv] user-specified ie's
439 	 */
440 	mp = ieee80211_getmgtframe(&frm,
441 	    2 + IEEE80211_NWID_LEN
442 	    + 2 + IEEE80211_RATE_SIZE +
443 	    + 2 + IEEE80211_XRATE_SIZE
444 	    + optielen);
445 	if (mp == NULL)
446 		return (ENOMEM);
447 
448 	frm = ieee80211_add_ssid(frm, ssid, ssidlen);
449 	mode = ieee80211_chan2mode(ic, ic->ic_curchan);
450 	frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
451 	frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
452 	if (optie != NULL) {
453 		(void) memcpy(frm, optie, optielen);
454 		frm += optielen;
455 	}
456 	mp->b_wptr = frm;
457 
458 	wh = (struct ieee80211_frame *)mp->b_rptr;
459 	ieee80211_send_setup(ic, in, wh,
460 	    IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
461 	    sa, da, bssid);
462 
463 	ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS,
464 	    "[%s] send probe req on channel %u\n",
465 	    ieee80211_macaddr_sprintf(wh->i_addr1),
466 	    ieee80211_chan2ieee(ic, ic->ic_curchan));
467 
468 	(void) (*ic->ic_xmit)(ic, mp, IEEE80211_FC0_TYPE_MGT);
469 	return (0);
470 }
471 
472 /*
473  * Send a management frame.  The node is for the destination (or ic_bss
474  * when in station mode).  Nodes other than ic_bss have their reference
475  * count bumped to reflect our use for an indeterminant time.
476  */
477 int
478 ieee80211_send_mgmt(ieee80211com_t *ic, ieee80211_node_t *in, int type, int arg)
479 {
480 	mblk_t *mp;
481 	uint8_t *frm;
482 	uint16_t capinfo;
483 	struct ieee80211_key *key;
484 	boolean_t has_challenge;
485 	boolean_t is_shared_key;
486 	int ret;
487 	int timer;
488 	int status;
489 
490 	ASSERT(in != NULL);
491 
492 	timer = 0;
493 	switch (type) {
494 	case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
495 		/*
496 		 * probe response frame format
497 		 *	[8] time stamp
498 		 *	[2] beacon interval
499 		 *	[2] capability information
500 		 *	[tlv] ssid
501 		 *	[tlv] supported rates
502 		 *	[tlv] parameter set (FH/DS)
503 		 *	[tlv] parameter set (IBSS)
504 		 *	[tlv] extended rate phy (ERP)
505 		 *	[tlv] extended supported rates
506 		 *	[tlv] WPA
507 		 *	[tlv] WME (optional)
508 		 *	[tlv] HT capabilities
509 		 *	[tlv] HT information
510 		 *	[tlv] Vendor OUI HT capabilities (optional)
511 		 *	[tlv] Vendor OUI HT information (optional)
512 		 */
513 		mp = ieee80211_getmgtframe(&frm,
514 		    8			/* time stamp  */
515 		    + sizeof (uint16_t)	/* beacon interval  */
516 		    + sizeof (uint16_t)	/* capability  */
517 		    + 2 + IEEE80211_NWID_LEN
518 		    + 2 + IEEE80211_RATE_SIZE
519 		    + 2 + IEEE80211_FH_LEN
520 		    + 2 + IEEE80211_IBSS_LEN
521 		    + 2 + IEEE80211_ERP_LEN
522 		    + 2 + IEEE80211_XRATE_SIZE
523 		    + (ic->ic_flags & IEEE80211_F_WPA ?
524 		    2 * sizeof (struct ieee80211_ie_wpa) : 0)
525 					/* [tlv] WPA  */
526 		    + (ic->ic_flags & IEEE80211_F_WME ?
527 		    sizeof (struct ieee80211_wme_param) : 0)
528 					/* [tlv] WME  */
529 		    /* check for cluster requirement */
530 		    + 2 * sizeof (struct ieee80211_ie_htcap) + 4
531 		    + 2 * sizeof (struct ieee80211_ie_htinfo) + 4);
532 
533 		if (mp == NULL)
534 			return (ENOMEM);
535 
536 		bzero(frm, 8);	/* timestamp should be filled later */
537 		frm += 8;
538 		*(uint16_t *)frm = LE_16(ic->ic_bss->in_intval);
539 		frm += 2;
540 		capinfo = ieee80211_get_capinfo(ic);
541 		*(uint16_t *)frm = LE_16(capinfo);
542 		frm += 2;
543 
544 		/* ssid */
545 		frm = ieee80211_add_ssid(frm, ic->ic_bss->in_essid,
546 		    ic->ic_bss->in_esslen);
547 		/* supported rates */
548 		frm = ieee80211_add_rates(frm, &in->in_rates);
549 
550 		if (IEEE80211_IS_CHAN_FHSS(ic->ic_curchan)) {
551 			*frm++ = IEEE80211_ELEMID_FHPARMS;
552 			*frm++ = IEEE80211_FH_LEN;
553 			*frm++ = in->in_fhdwell & 0x00ff;
554 			*frm++ = (in->in_fhdwell >> 8) & 0x00ff;
555 			*frm++ = IEEE80211_FH_CHANSET(
556 			    ieee80211_chan2ieee(ic, ic->ic_curchan));
557 			*frm++ = IEEE80211_FH_CHANPAT(
558 			    ieee80211_chan2ieee(ic, ic->ic_curchan));
559 			*frm++ = in->in_fhindex;
560 		} else {
561 			*frm++ = IEEE80211_ELEMID_DSPARMS;
562 			*frm++ = IEEE80211_DS_LEN;
563 			*frm++ = ieee80211_chan2ieee(ic, ic->ic_curchan);
564 		}
565 
566 		if (ic->ic_opmode == IEEE80211_M_IBSS) {
567 			*frm++ = IEEE80211_ELEMID_IBSSPARMS;
568 			*frm++ = IEEE80211_IBSS_LEN;
569 			*frm++ = 0; *frm++ = 0;		/* ATIM window */
570 		}
571 		if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan))
572 			frm = ieee80211_add_erp(frm, ic);
573 		frm = ieee80211_add_xrates(frm, &in->in_rates);
574 		/*
575 		 * NB: legacy 11b clients do not get certain ie's.
576 		 * The caller identifies such clients by passing
577 		 * a token in arg to us.  Could expand this to be
578 		 * any legacy client for stuff like HT ie's.
579 		 */
580 		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) &&
581 		    arg != IEEE80211_SEND_LEGACY_11B) {
582 			frm = ieee80211_add_htcap(frm, in);
583 			frm = ieee80211_add_htinfo(frm, in);
584 		}
585 		if (ic->ic_flags & IEEE80211_F_WME)
586 			frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
587 		if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) &&
588 		    (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT) &&
589 		    arg != IEEE80211_SEND_LEGACY_11B) {
590 			frm = ieee80211_add_htcap_vendor(frm, in);
591 			frm = ieee80211_add_htinfo_vendor(frm, in);
592 		}
593 		mp->b_wptr = frm;	/* allocated is greater than used */
594 
595 		break;
596 
597 	case IEEE80211_FC0_SUBTYPE_AUTH:
598 		status = arg >> 16;
599 		arg &= 0xffff;
600 		has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
601 		    arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
602 		    in->in_challenge != NULL);
603 
604 		/*
605 		 * Deduce whether we're doing open authentication or
606 		 * shared key authentication.  We do the latter if
607 		 * we're in the middle of a shared key authentication
608 		 * handshake or if we're initiating an authentication
609 		 * request and configured to use shared key.
610 		 */
611 		is_shared_key = has_challenge ||
612 		    arg >= IEEE80211_AUTH_SHARED_RESPONSE ||
613 		    (arg == IEEE80211_AUTH_SHARED_REQUEST &&
614 		    ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED);
615 
616 		if (has_challenge && status == IEEE80211_STATUS_SUCCESS)
617 			key = ieee80211_crypto_getkey(ic);
618 		else
619 			key = NULL;
620 
621 		mp = ieee80211_getmgtframe(&frm,
622 		    3 * sizeof (uint16_t)
623 		    + (has_challenge && status == IEEE80211_STATUS_SUCCESS ?
624 		    sizeof (uint16_t) + IEEE80211_CHALLENGE_LEN : 0)
625 		    + (key != NULL ? key->wk_cipher->ic_header : 0));
626 		if (mp == NULL)
627 			return (ENOMEM);
628 
629 		if (key != NULL)
630 			frm += key->wk_cipher->ic_header;
631 
632 		((uint16_t *)frm)[0] =
633 		    (is_shared_key) ? LE_16(IEEE80211_AUTH_ALG_SHARED)
634 		    : LE_16(IEEE80211_AUTH_ALG_OPEN);
635 		((uint16_t *)frm)[1] = LE_16(arg);	/* sequence number */
636 		((uint16_t *)frm)[2] = LE_16(status);	/* status */
637 
638 		if (has_challenge && status == IEEE80211_STATUS_SUCCESS) {
639 			frm += IEEE80211_AUTH_ELEM_MIN;
640 			*frm = IEEE80211_ELEMID_CHALLENGE;
641 			frm++;
642 			*frm = IEEE80211_CHALLENGE_LEN;
643 			frm++;
644 			bcopy(in->in_challenge, frm, IEEE80211_CHALLENGE_LEN);
645 		}
646 
647 		if (ic->ic_opmode == IEEE80211_M_STA)
648 			timer = IEEE80211_TRANS_WAIT;
649 		break;
650 
651 	case IEEE80211_FC0_SUBTYPE_DEAUTH:
652 		mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t));
653 		if (mp == NULL)
654 			return (ENOMEM);
655 
656 		*(uint16_t *)frm = LE_16(arg);	/* reason */
657 
658 		ieee80211_node_unauthorize(in);	/* port closed */
659 		break;
660 
661 	case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
662 	case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
663 		/*
664 		 * asreq frame format
665 		 *	[2] capability information
666 		 *	[2] listen interval
667 		 *	[6*] current AP address (reassoc only)
668 		 *	[tlv] ssid
669 		 *	[tlv] supported rates
670 		 *	[tlv] extended supported rates
671 		 *	[tlv] WME
672 		 *	[tlv] HT capabilities
673 		 *	[tlv] Vendor OUI HT capabilities (optional)
674 		 *	[tlv] user-specified ie's
675 		 */
676 		mp = ieee80211_getmgtframe(&frm,
677 		    sizeof (uint16_t)
678 		    + sizeof (uint16_t) + IEEE80211_ADDR_LEN
679 		    + 2 + IEEE80211_NWID_LEN
680 		    + 2 + IEEE80211_RATE_SIZE
681 		    + 2 + IEEE80211_XRATE_SIZE
682 		    + sizeof (struct ieee80211_wme_info)
683 		    + 2 * sizeof (struct ieee80211_ie_htcap) + 4
684 		    + ic->ic_opt_ie_len);
685 		if (mp == NULL)
686 			return (ENOMEM);
687 
688 		capinfo = ieee80211_get_capinfo(ic);
689 		if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) ||
690 		    !(ic->ic_caps & IEEE80211_C_SHSLOT)) {
691 			capinfo &= ~IEEE80211_CAPINFO_SHORT_SLOTTIME;
692 		} else {
693 			capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
694 		}
695 		if (!(in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) ||
696 		    !(ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
697 			capinfo &= ~IEEE80211_CAPINFO_SHORT_PREAMBLE;
698 		} else {
699 			capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
700 		}
701 		*(uint16_t *)frm = LE_16(capinfo);
702 		frm += 2;
703 
704 		*(uint16_t *)frm = LE_16(ic->ic_lintval);
705 		frm += 2;
706 
707 		if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
708 			IEEE80211_ADDR_COPY(frm, ic->ic_bss->in_bssid);
709 			frm += IEEE80211_ADDR_LEN;
710 		}
711 
712 		frm = ieee80211_add_ssid(frm, in->in_essid, in->in_esslen);
713 		frm = ieee80211_add_rates(frm, &in->in_rates);
714 		frm = ieee80211_add_xrates(frm, &in->in_rates);
715 		if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) &&
716 		    in->in_htcap_ie != NULL &&
717 		    in->in_htcap_ie[0] == IEEE80211_ELEMID_HTCAP)
718 			frm = ieee80211_add_htcap(frm, in);
719 		if ((ic->ic_flags & IEEE80211_F_WME) && in->in_wme_ie != NULL)
720 			frm = ieee80211_add_wme_info(frm, &ic->ic_wme);
721 		if ((ic->ic_flags_ext & IEEE80211_FEXT_HT) &&
722 		    in->in_htcap_ie != NULL &&
723 		    in->in_htcap_ie[0] == IEEE80211_ELEMID_VENDOR)
724 			frm = ieee80211_add_htcap_vendor(frm, in);
725 		if (ic->ic_opt_ie != NULL) {
726 			bcopy(ic->ic_opt_ie, frm, ic->ic_opt_ie_len);
727 			frm += ic->ic_opt_ie_len;
728 		}
729 		mp->b_wptr = frm;	/* allocated is greater than used */
730 
731 		timer = IEEE80211_TRANS_WAIT;
732 		break;
733 
734 	case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
735 	case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
736 		/*
737 		 * asreq frame format
738 		 *	[2] capability information
739 		 *	[2] status
740 		 *	[2] association ID
741 		 *	[tlv] supported rates
742 		 *	[tlv] extended supported rates
743 		 *	[tlv] WME (if enabled and STA enabled)
744 		 *	[tlv] HT capabilities (standard or vendor OUI)
745 		 *	[tlv] HT information (standard or vendor OUI)
746 		 */
747 		mp = ieee80211_getmgtframe(&frm,
748 		    3 * sizeof (uint16_t)
749 		    + 2 + IEEE80211_RATE_SIZE
750 		    + 2 + IEEE80211_XRATE_SIZE);
751 		if (mp == NULL)
752 			return (ENOMEM);
753 
754 		capinfo = ieee80211_get_capinfo(ic);
755 		*(uint16_t *)frm = LE_16(capinfo);
756 		frm += 2;
757 
758 		*(uint16_t *)frm = LE_16(arg);	/* status */
759 		frm += 2;
760 
761 		if (arg == IEEE80211_STATUS_SUCCESS)
762 			*(uint16_t *)frm = LE_16(in->in_associd);
763 		else
764 			*(uint16_t *)frm = LE_16(0);
765 		frm += 2;
766 
767 		frm = ieee80211_add_rates(frm, &in->in_rates);
768 		frm = ieee80211_add_xrates(frm, &in->in_rates);
769 		mp->b_wptr = frm;
770 		break;
771 
772 	case IEEE80211_FC0_SUBTYPE_DISASSOC:
773 		mp = ieee80211_getmgtframe(&frm, sizeof (uint16_t));
774 		if (mp == NULL)
775 			return (ENOMEM);
776 		*(uint16_t *)frm = LE_16(arg);	/* reason */
777 		break;
778 
779 	default:
780 		ieee80211_dbg(IEEE80211_MSG_ANY,
781 		    "[%s] invalid mgmt frame type %u\n",
782 		    ieee80211_macaddr_sprintf(in->in_macaddr), type);
783 		return (EINVAL);
784 	} /* type */
785 	ret = ieee80211_mgmt_output(ic, in, mp, type, timer);
786 	return (ret);
787 }
788 
789 /*
790  * Allocate a beacon frame and fillin the appropriate bits.
791  */
792 mblk_t *
793 ieee80211_beacon_alloc(ieee80211com_t *ic, ieee80211_node_t *in,
794     struct ieee80211_beacon_offsets *bo)
795 {
796 	struct ieee80211_frame *wh;
797 	struct ieee80211_rateset *rs;
798 	mblk_t *m;
799 	uint8_t *frm;
800 	int pktlen;
801 	uint16_t capinfo;
802 
803 	IEEE80211_LOCK(ic);
804 	/*
805 	 * beacon frame format
806 	 *	[8] time stamp
807 	 *	[2] beacon interval
808 	 *	[2] cabability information
809 	 *	[tlv] ssid
810 	 *	[tlv] supported rates
811 	 *	[3] parameter set (DS)
812 	 *	[tlv] parameter set (IBSS/TIM)
813 	 *	[tlv] extended rate phy (ERP)
814 	 *	[tlv] extended supported rates
815 	 *	[tlv] WME parameters
816 	 *	[tlv] WPA/RSN parameters
817 	 *	[tlv] HT capabilities
818 	 *	[tlv] HT information
819 	 *	[tlv] Vendor OUI HT capabilities (optional)
820 	 *	[tlv] Vendor OUI HT information (optional)
821 	 * Vendor-specific OIDs (e.g. Atheros)
822 	 * NB: we allocate the max space required for the TIM bitmap.
823 	 */
824 	rs = &in->in_rates;
825 	pktlen =  8			/* time stamp */
826 	    + sizeof (uint16_t)		/* beacon interval */
827 	    + sizeof (uint16_t)		/* capabilities */
828 	    + 2 + in->in_esslen		/* ssid */
829 	    + 2 + IEEE80211_RATE_SIZE	/* supported rates */
830 	    + 2 + 1			/* DS parameters */
831 	    + 2 + 4 + ic->ic_tim_len	/* DTIM/IBSSPARMS */
832 	    + 2 + 1			/* ERP */
833 	    + 2 + IEEE80211_XRATE_SIZE
834 	    + (ic->ic_caps & IEEE80211_C_WME ?	/* WME */
835 	    sizeof (struct ieee80211_wme_param) : 0)
836 	    /* conditional? */
837 	    + 4 + 2 * sizeof (struct ieee80211_ie_htcap)	/* HT caps */
838 	    + 4 + 2 * sizeof (struct ieee80211_ie_htinfo);	/* HT info */
839 
840 	m = ieee80211_getmgtframe(&frm, pktlen);
841 	if (m == NULL) {
842 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_beacon_alloc: "
843 		    "cannot get buf; size %u\n", pktlen);
844 		IEEE80211_UNLOCK(ic);
845 		return (NULL);
846 	}
847 
848 	/* timestamp is set by hardware/driver */
849 	(void) memset(frm, 0, 8);
850 	frm += 8;
851 	*(uint16_t *)frm = LE_16(in->in_intval);
852 	frm += 2;
853 	capinfo = ieee80211_get_capinfo(ic);
854 	bo->bo_caps = (uint16_t *)frm;
855 	*(uint16_t *)frm = LE_16(capinfo);
856 	frm += 2;
857 	*frm++ = IEEE80211_ELEMID_SSID;
858 	if (!(ic->ic_flags & IEEE80211_F_HIDESSID)) {
859 		*frm++ = in->in_esslen;
860 		bcopy(in->in_essid, frm, in->in_esslen);
861 		frm += in->in_esslen;
862 	} else {
863 		*frm++ = 0;
864 	}
865 	frm = ieee80211_add_rates(frm, rs);
866 	if (ic->ic_curmode != IEEE80211_MODE_FH) {
867 		*frm++ = IEEE80211_ELEMID_DSPARMS;
868 		*frm++ = 1;
869 		*frm++ = ieee80211_chan2ieee(ic, in->in_chan);
870 	}
871 	bo->bo_tim = frm;
872 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
873 		*frm++ = IEEE80211_ELEMID_IBSSPARMS;
874 		*frm++ = 2;
875 		*frm++ = 0; *frm++ = 0;		/* TODO: ATIM window */
876 		bo->bo_tim_len = 0;
877 	} else {
878 		struct ieee80211_tim_ie *tie =
879 		    (struct ieee80211_tim_ie *)frm;
880 
881 		tie->tim_ie = IEEE80211_ELEMID_TIM;
882 		tie->tim_len = 4;	/* length */
883 		tie->tim_count = 0;	/* DTIM count */
884 		tie->tim_period = IEEE80211_DTIM_DEFAULT;
885 		tie->tim_bitctl = 0;	/* bitmap control */
886 		tie->tim_bitmap[0] = 0;	/* Partial Virtual Bitmap */
887 		frm += sizeof (struct ieee80211_tim_ie);
888 		bo->bo_tim_len = 1;
889 	}
890 	bo->bo_trailer = frm;
891 
892 	if (ic->ic_curmode == IEEE80211_MODE_11G) {
893 		bo->bo_erp = frm;
894 		frm = ieee80211_add_erp(frm, ic);
895 	}
896 	frm = ieee80211_add_xrates(frm, rs);
897 	if (IEEE80211_IS_CHAN_HT(ic->ic_curchan)) {
898 		frm = ieee80211_add_htcap(frm, in);
899 		bo->bo_htinfo = frm;
900 		frm = ieee80211_add_htinfo(frm, in);
901 	}
902 	if (ic->ic_flags & IEEE80211_F_WME) {
903 		bo->bo_wme = frm;
904 		frm = ieee80211_add_wme_param(frm, &ic->ic_wme);
905 	}
906 	if (IEEE80211_IS_CHAN_HT(ic->ic_curchan) &&
907 	    (ic->ic_flags_ext & IEEE80211_FEXT_HTCOMPAT)) {
908 		frm = ieee80211_add_htcap_vendor(frm, in);
909 		frm = ieee80211_add_htinfo_vendor(frm, in);
910 	}
911 	bo->bo_trailer_len = _PTRDIFF(frm, bo->bo_trailer);
912 	m->b_wptr = frm;
913 
914 	wh = (struct ieee80211_frame *)m->b_rptr;
915 	wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
916 	    IEEE80211_FC0_SUBTYPE_BEACON;
917 	wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
918 	*(uint16_t *)wh->i_dur = 0;
919 	IEEE80211_ADDR_COPY(wh->i_addr1, wifi_bcastaddr);
920 	IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_macaddr);
921 	IEEE80211_ADDR_COPY(wh->i_addr3, in->in_bssid);
922 	*(uint16_t *)wh->i_seq = 0;
923 
924 	IEEE80211_UNLOCK(ic);
925 	return (m);
926 }
927 
928 /*
929  * Update the dynamic parts of a beacon frame based on the current state.
930  */
931 /* ARGSUSED */
932 int
933 ieee80211_beacon_update(ieee80211com_t *ic, ieee80211_node_t *in,
934     struct ieee80211_beacon_offsets *bo, mblk_t *mp, int mcast)
935 {
936 	uint16_t capinfo;
937 
938 	IEEE80211_LOCK(ic);
939 
940 	capinfo = ieee80211_get_capinfo(ic);
941 	*bo->bo_caps = LE_16(capinfo);
942 
943 	IEEE80211_UNLOCK(ic);
944 	return (0);
945 }
946 
947 /*
948  * Assign priority to a frame based on any vlan tag assigned
949  * to the station and/or any Diffserv setting in an IP header.
950  * Finally, if an ACM policy is setup (in station mode) it's
951  * applied.
952  */
953 /* ARGSUSED */
954 int
955 ieee80211_classify(struct ieee80211com *ic, mblk_t *m,
956     struct ieee80211_node *ni)
957 {
958 	int ac;
959 
960 	if ((ni->in_flags & IEEE80211_NODE_QOS) == 0)
961 		return (WME_AC_BE);
962 
963 	/* Process VLan */
964 	/* Process IPQoS */
965 
966 	ac = WME_AC_BE;
967 
968 	/*
969 	 * Apply ACM policy.
970 	 */
971 	if (ic->ic_opmode == IEEE80211_M_STA) {
972 		static const int acmap[4] = {
973 			WME_AC_BK,	/* WME_AC_BE */
974 			WME_AC_BK,	/* WME_AC_BK */
975 			WME_AC_BE,	/* WME_AC_VI */
976 			WME_AC_VI,	/* WME_AC_VO */
977 		};
978 		while (ac != WME_AC_BK &&
979 		    ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].
980 		    wmep_acm) {
981 			ac = acmap[ac];
982 		}
983 	}
984 
985 	return (ac);
986 }
987