Home | History | Annotate | Download | only in net80211
      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