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