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 */
54static void
55ieee80211_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 */
103int
104ieee80211_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 */
135int
136ieee80211_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 */
175mblk_t *
176ieee80211_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 */
266static uint8_t *
267ieee80211_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 */
283static uint8_t *
284ieee80211_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 */
302static uint8_t *
303ieee80211_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 */
321static uint8_t *
322ieee80211_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 */
366static uint8_t *
367ieee80211_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 */
378static uint8_t *
379ieee80211_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 */
397static uint16_t
398ieee80211_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 */
422int
423ieee80211_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 */
477int
478ieee80211_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 */
792mblk_t *
793ieee80211_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 */
932int
933ieee80211_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 */
954int
955ieee80211_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