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  * IEEE 802.11 protocol support
     40  */
     41 
     42 #include "net80211_impl.h"
     43 
     44 /* tunables */
     45 #define	AGGRESSIVE_MODE_SWITCH_HYSTERESIS	3	/* pkts / 100ms */
     46 #define	HIGH_PRI_SWITCH_THRESH			10	/* pkts / 100ms */
     47 
     48 #define	IEEE80211_RATE2MBS(r)	(((r) & IEEE80211_RATE_VAL) / 2)
     49 
     50 const char *ieee80211_mgt_subtype_name[] = {
     51 	"assoc_req",	"assoc_resp",	"reassoc_req",	"reassoc_resp",
     52 	"probe_req",	"probe_resp",	"reserved#6",	"reserved#7",
     53 	"beacon",	"atim",		"disassoc",	"auth",
     54 	"deauth",	"reserved#13",	"reserved#14",	"reserved#15"
     55 };
     56 const char *ieee80211_ctl_subtype_name[] = {
     57 	"reserved#0",	"reserved#1",	"reserved#2",	"reserved#3",
     58 	"reserved#3",	"reserved#5",	"reserved#6",	"reserved#7",
     59 	"reserved#8",	"reserved#9",	"ps_poll",	"rts",
     60 	"cts",		"ack",		"cf_end",	"cf_end_ack"
     61 };
     62 const char *ieee80211_state_name[IEEE80211_S_MAX] = {
     63 	"INIT",		/* IEEE80211_S_INIT */
     64 	"SCAN",		/* IEEE80211_S_SCAN */
     65 	"AUTH",		/* IEEE80211_S_AUTH */
     66 	"ASSOC",	/* IEEE80211_S_ASSOC */
     67 	"RUN"		/* IEEE80211_S_RUN */
     68 };
     69 const char *ieee80211_wme_acnames[] = {
     70 	"WME_AC_BE",
     71 	"WME_AC_BK",
     72 	"WME_AC_VI",
     73 	"WME_AC_VO",
     74 	"WME_UPSD",
     75 };
     76 
     77 static int ieee80211_newstate(ieee80211com_t *, enum ieee80211_state, int);
     78 
     79 /*
     80  * Initialize the interface softc, ic, with protocol management
     81  * related data structures and functions.
     82  */
     83 void
     84 ieee80211_proto_attach(ieee80211com_t *ic)
     85 {
     86 	struct ieee80211_impl *im = ic->ic_private;
     87 
     88 	ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT;
     89 	ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT;
     90 	ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
     91 	ic->ic_protmode = IEEE80211_PROT_CTSONLY;
     92 	im->im_bmiss_max = IEEE80211_BMISS_MAX;
     93 
     94 	ic->ic_wme.wme_hipri_switch_hysteresis =
     95 	    AGGRESSIVE_MODE_SWITCH_HYSTERESIS;
     96 
     97 	/* protocol state change handler */
     98 	ic->ic_newstate = ieee80211_newstate;
     99 
    100 	/* initialize management frame handlers */
    101 	ic->ic_recv_mgmt = ieee80211_recv_mgmt;
    102 	ic->ic_send_mgmt = ieee80211_send_mgmt;
    103 }
    104 
    105 /*
    106  * Print a 802.11 frame header
    107  */
    108 void
    109 ieee80211_dump_pkt(const uint8_t *buf, int32_t len, int32_t rate, int32_t rssi)
    110 {
    111 	struct ieee80211_frame *wh;
    112 	int8_t buf1[100];
    113 	int8_t buf2[25];
    114 	int i;
    115 
    116 	bzero(buf1, sizeof (buf1));
    117 	bzero(buf2, sizeof (buf2));
    118 	wh = (struct ieee80211_frame *)buf;
    119 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
    120 	case IEEE80211_FC1_DIR_NODS:
    121 		(void) snprintf(buf2, sizeof (buf2), "NODS %s",
    122 		    ieee80211_macaddr_sprintf(wh->i_addr2));
    123 		(void) strncat(buf1, buf2, sizeof (buf2));
    124 		(void) snprintf(buf2, sizeof (buf2), "->%s",
    125 		    ieee80211_macaddr_sprintf(wh->i_addr1));
    126 		(void) strncat(buf1, buf2, sizeof (buf2));
    127 		(void) snprintf(buf2, sizeof (buf2), "(%s)",
    128 		    ieee80211_macaddr_sprintf(wh->i_addr3));
    129 		(void) strncat(buf1, buf2, sizeof (buf2));
    130 		break;
    131 	case IEEE80211_FC1_DIR_TODS:
    132 		(void) snprintf(buf2, sizeof (buf2), "TODS %s",
    133 		    ieee80211_macaddr_sprintf(wh->i_addr2));
    134 		(void) strncat(buf1, buf2, sizeof (buf2));
    135 		(void) snprintf(buf2, sizeof (buf2), "->%s",
    136 		    ieee80211_macaddr_sprintf(wh->i_addr3));
    137 		(void) strncat(buf1, buf2, sizeof (buf2));
    138 		(void) snprintf(buf2, sizeof (buf2), "(%s)",
    139 		    ieee80211_macaddr_sprintf(wh->i_addr1));
    140 		(void) strncat(buf1, buf2, sizeof (buf2));
    141 		break;
    142 	case IEEE80211_FC1_DIR_FROMDS:
    143 		(void) snprintf(buf2, sizeof (buf2), "FRDS %s",
    144 		    ieee80211_macaddr_sprintf(wh->i_addr3));
    145 		(void) strncat(buf1, buf2, sizeof (buf2));
    146 		(void) snprintf(buf2, sizeof (buf2), "->%s",
    147 		    ieee80211_macaddr_sprintf(wh->i_addr1));
    148 		(void) strncat(buf1, buf2, sizeof (buf2));
    149 		(void) snprintf(buf2, sizeof (buf2), "(%s)",
    150 		    ieee80211_macaddr_sprintf(wh->i_addr2));
    151 		(void) strncat(buf1, buf2, sizeof (buf2));
    152 		break;
    153 	case IEEE80211_FC1_DIR_DSTODS:
    154 		(void) snprintf(buf2, sizeof (buf2), "DSDS %s",
    155 		    ieee80211_macaddr_sprintf((uint8_t *)&wh[1]));
    156 		(void) strncat(buf1, buf2, sizeof (buf2));
    157 		(void) snprintf(buf2, sizeof (buf2), "->%s  ",
    158 		    ieee80211_macaddr_sprintf(wh->i_addr3));
    159 		(void) strncat(buf1, buf2, sizeof (buf2));
    160 		(void) snprintf(buf2, sizeof (buf2), "%s",
    161 		    ieee80211_macaddr_sprintf(wh->i_addr2));
    162 		(void) strncat(buf1, buf2, sizeof (buf2));
    163 		(void) snprintf(buf2, sizeof (buf2), "->%s",
    164 		    ieee80211_macaddr_sprintf(wh->i_addr1));
    165 		(void) strncat(buf1, buf2, sizeof (buf2));
    166 		break;
    167 	}
    168 	ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1);
    169 	bzero(buf1, sizeof (buf1));
    170 
    171 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
    172 	case IEEE80211_FC0_TYPE_DATA:
    173 		(void) sprintf(buf2, "data");
    174 		break;
    175 	case IEEE80211_FC0_TYPE_MGT:
    176 		(void) snprintf(buf2, sizeof (buf2), "%s",
    177 		    ieee80211_mgt_subtype_name[
    178 		    (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
    179 		    >> IEEE80211_FC0_SUBTYPE_SHIFT]);
    180 		break;
    181 	default:
    182 		(void) snprintf(buf2, sizeof (buf2), "type#%d",
    183 		    wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
    184 		break;
    185 	}
    186 	(void) strncat(buf1, buf2, sizeof (buf2));
    187 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
    188 		(void) sprintf(buf2, " WEP");
    189 		(void) strcat(buf1, buf2);
    190 	}
    191 	if (rate >= 0) {
    192 		(void) snprintf(buf2,  sizeof (buf2), " %dM", rate / 2);
    193 		(void) strncat(buf1, buf2, sizeof (buf2));
    194 	}
    195 	if (rssi >= 0) {
    196 		(void) snprintf(buf2,  sizeof (buf2), " +%d", rssi);
    197 		(void) strncat(buf1, buf2, sizeof (buf2));
    198 	}
    199 	ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1);
    200 	bzero(buf1, sizeof (buf1));
    201 
    202 	if (len > 0) {
    203 		for (i = 0; i < (len > 40 ? 40 : len); i++) {
    204 			if ((i & 0x03) == 0)
    205 				(void) strcat(buf1, " ");
    206 			(void) snprintf(buf2, 3, "%02x", buf[i]);
    207 			(void) strncat(buf1, buf2, 3);
    208 		}
    209 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s",
    210 		    buf1);
    211 	}
    212 }
    213 
    214 /*
    215  * Adjust/Fix the specified node's rate table
    216  *
    217  * in   node
    218  * flag IEEE80211_F_DOSORT : sort the node's rate table
    219  *      IEEE80211_F_DONEGO : mark a rate as basic rate if it is
    220  *                           a device's basic rate
    221  *      IEEE80211_F_DODEL  : delete rates not supported by the device
    222  *      IEEE80211_F_DOFRATE: check if the fixed rate is supported by
    223  *                           the device
    224  *
    225  * The highest bit of returned rate value is set to 1 on failure.
    226  */
    227 int
    228 ieee80211_fix_rate(ieee80211_node_t *in,
    229     struct ieee80211_rateset *nrs, int flags)
    230 {
    231 	ieee80211com_t *ic = in->in_ic;
    232 	struct ieee80211_rateset *srs;
    233 	boolean_t ignore;
    234 	int i;
    235 	int okrate;
    236 	int badrate;
    237 	int fixedrate;
    238 	uint8_t r;
    239 
    240 	/*
    241 	 * If the fixed rate check was requested but no
    242 	 * fixed has been defined then just remove it.
    243 	 */
    244 	if ((flags & IEEE80211_F_DOFRATE) &&
    245 	    (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)) {
    246 		flags &= ~IEEE80211_F_DOFRATE;
    247 	}
    248 	if (in->in_chan == IEEE80211_CHAN_ANYC) {
    249 		return (IEEE80211_RATE_BASIC);
    250 	}
    251 	okrate = badrate = fixedrate = 0;
    252 	srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, in->in_chan)];
    253 	for (i = 0; i < nrs->ir_nrates; ) {
    254 		int j;
    255 
    256 		ignore = B_FALSE;
    257 		if (flags & IEEE80211_F_DOSORT) {
    258 			/*
    259 			 * Sort rates.
    260 			 */
    261 			for (j = i + 1; j < nrs->ir_nrates; j++) {
    262 				if (IEEE80211_RV(nrs->ir_rates[i]) >
    263 				    IEEE80211_RV(nrs->ir_rates[j])) {
    264 					r = nrs->ir_rates[i];
    265 					nrs->ir_rates[i] = nrs->ir_rates[j];
    266 					nrs->ir_rates[j] = r;
    267 				}
    268 			}
    269 		}
    270 		r = IEEE80211_RV(nrs->ir_rates[i]);
    271 		badrate = r;
    272 
    273 		/*
    274 		 * Check against supported rates.
    275 		 */
    276 		for (j = 0; j < srs->ir_nrates; j++) {
    277 			if (r == IEEE80211_RV(srs->ir_rates[j])) {
    278 				/*
    279 				 * Overwrite with the supported rate
    280 				 * value so any basic rate bit is set.
    281 				 * This insures that response we send
    282 				 * to stations have the necessary basic
    283 				 * rate bit set.
    284 				 */
    285 				if (flags & IEEE80211_F_DONEGO)
    286 					nrs->ir_rates[i] = srs->ir_rates[j];
    287 				break;
    288 			}
    289 		}
    290 		if (j == srs->ir_nrates) {
    291 			/*
    292 			 * A rate in the node's rate set is not
    293 			 * supported. We just discard/ignore the rate.
    294 			 * Note that this is important for 11b stations
    295 			 * when they want to associate with an 11g AP.
    296 			 */
    297 			ignore = B_TRUE;
    298 		}
    299 
    300 		if (flags & IEEE80211_F_DODEL) {
    301 			/*
    302 			 * Delete unacceptable rates.
    303 			 */
    304 			if (ignore) {
    305 				nrs->ir_nrates--;
    306 				for (j = i; j < nrs->ir_nrates; j++)
    307 					nrs->ir_rates[j] = nrs->ir_rates[j + 1];
    308 				nrs->ir_rates[j] = 0;
    309 				continue;
    310 			}
    311 		}
    312 		if (flags & IEEE80211_F_DOFRATE) {
    313 			/*
    314 			 * Check any fixed rate is included.
    315 			 */
    316 			if (r == ic->ic_fixed_rate)
    317 				fixedrate = r;
    318 		}
    319 		if (!ignore)
    320 			okrate = nrs->ir_rates[i];
    321 		i++;
    322 	}
    323 	if (okrate == 0 || ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0))
    324 		return (badrate | IEEE80211_RATE_BASIC);
    325 	else
    326 		return (IEEE80211_RV(okrate));
    327 }
    328 
    329 /*
    330  * Reset 11g-related state.
    331  */
    332 void
    333 ieee80211_reset_erp(ieee80211com_t *ic)
    334 {
    335 	ic->ic_flags &= ~IEEE80211_F_USEPROT;
    336 	/*
    337 	 * Short slot time is enabled only when operating in 11g
    338 	 * and not in an IBSS.  We must also honor whether or not
    339 	 * the driver is capable of doing it.
    340 	 */
    341 	ieee80211_set_shortslottime(ic,
    342 	    ic->ic_curmode == IEEE80211_MODE_11A);
    343 	/*
    344 	 * Set short preamble and ERP barker-preamble flags.
    345 	 */
    346 	if (ic->ic_curmode == IEEE80211_MODE_11A ||
    347 	    (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) {
    348 		ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
    349 		ic->ic_flags &= ~IEEE80211_F_USEBARKER;
    350 	} else {
    351 		ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
    352 		ic->ic_flags |= IEEE80211_F_USEBARKER;
    353 	}
    354 }
    355 
    356 /*
    357  * Change current channel to be the next available channel
    358  */
    359 void
    360 ieee80211_reset_chan(ieee80211com_t *ic)
    361 {
    362 	struct ieee80211_channel *ch = ic->ic_curchan;
    363 
    364 	IEEE80211_LOCK(ic);
    365 	do {
    366 		if (++ch > &ic->ic_sup_channels[IEEE80211_CHAN_MAX])
    367 			ch = &ic->ic_sup_channels[0];
    368 		if (ieee80211_isset(ic->ic_chan_active,
    369 		    ieee80211_chan2ieee(ic, ch))) {
    370 			break;
    371 		}
    372 	} while (ch != ic->ic_curchan);
    373 	ic->ic_curchan = ch;
    374 	IEEE80211_UNLOCK(ic);
    375 }
    376 
    377 /*
    378  * Set the short slot time state and notify the driver.
    379  */
    380 void
    381 ieee80211_set_shortslottime(ieee80211com_t *ic, boolean_t on)
    382 {
    383 	if (on)
    384 		ic->ic_flags |= IEEE80211_F_SHSLOT;
    385 	else
    386 		ic->ic_flags &= ~IEEE80211_F_SHSLOT;
    387 	/* notify driver */
    388 	if (ic->ic_set_shortslot != NULL)
    389 		ic->ic_set_shortslot(ic, on);
    390 }
    391 
    392 /*
    393  * Mark the basic rates for the 11g rate table based on the
    394  * operating mode.  For real 11g we mark all the 11b rates
    395  * and 6, 12, and 24 OFDM.  For 11b compatibility we mark only
    396  * 11b rates.  There's also a pseudo 11a-mode used to mark only
    397  * the basic OFDM rates.
    398  */
    399 void
    400 ieee80211_setbasicrates(struct ieee80211_rateset *rs,
    401     enum ieee80211_phymode mode)
    402 {
    403 	static const struct ieee80211_rateset basic[] = {
    404 		{ 0 },			/* IEEE80211_MODE_AUTO */
    405 		{ 3, { 12, 24, 48 } },	/* IEEE80211_MODE_11A */
    406 		{ 2, { 2, 4} },		/* IEEE80211_MODE_11B */
    407 		{ 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G mixed b/g */
    408 		{ 0 },			/* IEEE80211_MODE_FH */
    409 		{ 3, { 12, 24, 48 } },	/* IEEE80211_MODE_TURBO_A */
    410 		{ 4, { 2, 4, 11, 22 } },
    411 					/* IEEE80211_MODE_TURBO_G (mixed b/g) */
    412 		{ 0 },			/* IEEE80211_MODE_STURBO_A */
    413 		{ 3, { 12, 24, 48 } },	/* IEEE80211_MODE_11NA */
    414 					/* IEEE80211_MODE_11NG (mixed b/g) */
    415 		{ 7, { 2, 4, 11, 22, 12, 24, 48 } }
    416 	};
    417 	int i, j;
    418 
    419 	ASSERT(mode < IEEE80211_MODE_MAX);
    420 	for (i = 0; i < rs->ir_nrates; i++) {
    421 		rs->ir_rates[i] &= IEEE80211_RATE_VAL;
    422 		for (j = 0; j < basic[mode].ir_nrates; j++) {
    423 			if (basic[mode].ir_rates[j] == rs->ir_rates[i]) {
    424 				rs->ir_rates[i] |= IEEE80211_RATE_BASIC;
    425 				break;
    426 			}
    427 		}
    428 	}
    429 }
    430 
    431 /*
    432  * WME protocol support.  The following parameters come from the spec.
    433  */
    434 typedef struct phyParamType {
    435 	uint8_t aifsn;
    436 	uint8_t logcwmin;
    437 	uint8_t logcwmax;
    438 	uint16_t txopLimit;
    439 	uint8_t acm;
    440 } paramType;
    441 
    442 static const paramType phyParamForAC_BE[IEEE80211_MODE_MAX] = {
    443 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_AUTO */
    444 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_11A */
    445 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_11B */
    446 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_11G */
    447 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_FH */
    448 	{ 2, 3,  5,  0, 0 },	/* IEEE80211_MODE_TURBO_A */
    449 	{ 2, 3,  5,  0, 0 },	/* IEEE80211_MODE_TURBO_G */
    450 	{ 2, 3,  5,  0, 0 },	/* IEEE80211_MODE_STURBO_A */
    451 	{ 3, 4,  6,  0, 0 },	/* IEEE80211_MODE_11NA */
    452 	{ 3, 4,  6,  0, 0 }	/* IEEE80211_MODE_11NG */
    453 };
    454 static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = {
    455 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_AUTO */
    456 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_11A */
    457 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_11B */
    458 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_11G */
    459 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_FH */
    460 	{ 7, 3, 10,  0, 0 },	/* IEEE80211_MODE_TURBO_A */
    461 	{ 7, 3, 10,  0, 0 },	/* IEEE80211_MODE_TURBO_G */
    462 	{ 7, 3, 10,  0, 0 },	/* IEEE80211_MODE_STURBO_A */
    463 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_11NA */
    464 	{ 7, 4, 10,  0, 0 },	/* IEEE80211_MODE_11NG */
    465 };
    466 static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = {
    467 	{ 1, 3, 4,  94, 0 },	/* IEEE80211_MODE_AUTO */
    468 	{ 1, 3, 4,  94, 0 },	/* IEEE80211_MODE_11A */
    469 	{ 1, 3, 4, 188, 0 },	/* IEEE80211_MODE_11B */
    470 	{ 1, 3, 4,  94, 0 },	/* IEEE80211_MODE_11G */
    471 	{ 1, 3, 4, 188, 0 },	/* IEEE80211_MODE_FH */
    472 	{ 1, 2, 3,  94, 0 },	/* IEEE80211_MODE_TURBO_A */
    473 	{ 1, 2, 3,  94, 0 },	/* IEEE80211_MODE_TURBO_G */
    474 	{ 1, 2, 3,  94, 0 },	/* IEEE80211_MODE_STURBO_A */
    475 	{ 1, 3, 4,  94, 0 },	/* IEEE80211_MODE_11NA */
    476 	{ 1, 3, 4,  94, 0 },	/* IEEE80211_MODE_11NG */
    477 };
    478 static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = {
    479 	{ 1, 2, 3,  47, 0 },	/* IEEE80211_MODE_AUTO */
    480 	{ 1, 2, 3,  47, 0 },	/* IEEE80211_MODE_11A */
    481 	{ 1, 2, 3, 102, 0 },	/* IEEE80211_MODE_11B */
    482 	{ 1, 2, 3,  47, 0 },	/* IEEE80211_MODE_11G */
    483 	{ 1, 2, 3, 102, 0 },	/* IEEE80211_MODE_FH */
    484 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_TURBO_A */
    485 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_TURBO_G */
    486 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_STURBO_A */
    487 	{ 1, 2, 3,  47, 0 },	/* IEEE80211_MODE_11NA */
    488 	{ 1, 2, 3,  47, 0 },	/* IEEE80211_MODE_11NG */
    489 };
    490 
    491 static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = {
    492 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_AUTO */
    493 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_11A */
    494 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_11B */
    495 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_11G */
    496 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_FH */
    497 	{ 2, 3, 10,  0, 0 },	/* IEEE80211_MODE_TURBO_A */
    498 	{ 2, 3, 10,  0, 0 },	/* IEEE80211_MODE_TURBO_G */
    499 	{ 2, 3, 10,  0, 0 },	/* IEEE80211_MODE_STURBO_A */
    500 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_11NA */
    501 	{ 3, 4, 10,  0, 0 },	/* IEEE80211_MODE_11NG */
    502 };
    503 static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = {
    504 	{ 2, 3, 4,  94, 0 },	/* IEEE80211_MODE_AUTO */
    505 	{ 2, 3, 4,  94, 0 },	/* IEEE80211_MODE_11A */
    506 	{ 2, 3, 4, 188, 0 },	/* IEEE80211_MODE_11B */
    507 	{ 2, 3, 4,  94, 0 },	/* IEEE80211_MODE_11G */
    508 	{ 2, 3, 4, 188, 0 },	/* IEEE80211_MODE_FH */
    509 	{ 2, 2, 3,  94, 0 },	/* IEEE80211_MODE_TURBO_A */
    510 	{ 2, 2, 3,  94, 0 },	/* IEEE80211_MODE_TURBO_G */
    511 	{ 2, 2, 3,  94, 0 },	/* IEEE80211_MODE_STURBO_A */
    512 	{ 2, 3, 4,  94, 0 },	/* IEEE80211_MODE_11NA */
    513 	{ 2, 3, 4,  94, 0 },	/* IEEE80211_MODE_11NG */
    514 };
    515 static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = {
    516 	{ 2, 2, 3,  47, 0 },	/* IEEE80211_MODE_AUTO */
    517 	{ 2, 2, 3,  47, 0 },	/* IEEE80211_MODE_11A */
    518 	{ 2, 2, 3, 102, 0 },	/* IEEE80211_MODE_11B */
    519 	{ 2, 2, 3,  47, 0 },	/* IEEE80211_MODE_11G */
    520 	{ 2, 2, 3, 102, 0 },	/* IEEE80211_MODE_FH */
    521 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_TURBO_A */
    522 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_TURBO_G */
    523 	{ 1, 2, 2,  47, 0 },	/* IEEE80211_MODE_STURBO_A */
    524 	{ 2, 2, 3,  47, 0 },	/* IEEE80211_MODE_11NA */
    525 	{ 2, 2, 3,  47, 0 },	/* IEEE80211_MODE_11NG */
    526 };
    527 
    528 void
    529 ieee80211_wme_initparams(struct ieee80211com *ic)
    530 {
    531 	struct ieee80211_wme_state *wme = &ic->ic_wme;
    532 	const paramType *pPhyParam, *pBssPhyParam;
    533 	struct wmeParams *wmep;
    534 	enum ieee80211_phymode mode;
    535 	int i;
    536 
    537 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
    538 		return;
    539 
    540 	/*
    541 	 * Select mode; we can be called early in which case we
    542 	 * always use auto mode.  We know we'll be called when
    543 	 * entering the RUN state with bsschan setup properly
    544 	 * so state will eventually get set correctly
    545 	 */
    546 	if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
    547 		mode = ieee80211_chan2mode(ic, ic->ic_curchan);
    548 	else
    549 		mode = IEEE80211_MODE_AUTO;
    550 	for (i = 0; i < WME_NUM_AC; i++) {
    551 		switch (i) {
    552 		case WME_AC_BK:
    553 			pPhyParam = &phyParamForAC_BK[mode];
    554 			pBssPhyParam = &phyParamForAC_BK[mode];
    555 			break;
    556 		case WME_AC_VI:
    557 			pPhyParam = &phyParamForAC_VI[mode];
    558 			pBssPhyParam = &bssPhyParamForAC_VI[mode];
    559 			break;
    560 		case WME_AC_VO:
    561 			pPhyParam = &phyParamForAC_VO[mode];
    562 			pBssPhyParam = &bssPhyParamForAC_VO[mode];
    563 			break;
    564 		case WME_AC_BE:
    565 		default:
    566 			pPhyParam = &phyParamForAC_BE[mode];
    567 			pBssPhyParam = &bssPhyParamForAC_BE[mode];
    568 			break;
    569 		}
    570 
    571 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
    572 		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
    573 			wmep->wmep_acm = pPhyParam->acm;
    574 			wmep->wmep_aifsn = pPhyParam->aifsn;
    575 			wmep->wmep_logcwmin = pPhyParam->logcwmin;
    576 			wmep->wmep_logcwmax = pPhyParam->logcwmax;
    577 			wmep->wmep_txopLimit = pPhyParam->txopLimit;
    578 		} else {
    579 			wmep->wmep_acm = pBssPhyParam->acm;
    580 			wmep->wmep_aifsn = pBssPhyParam->aifsn;
    581 			wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
    582 			wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
    583 			wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
    584 
    585 		}
    586 		ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_initparams: "
    587 		    "%s chan [acm %u aifsn %u log2(cwmin) %u "
    588 		    "log2(cwmax) %u txpoLimit %u]\n",
    589 		    ieee80211_wme_acnames[i],
    590 		    wmep->wmep_acm,
    591 		    wmep->wmep_aifsn,
    592 		    wmep->wmep_logcwmin,
    593 		    wmep->wmep_logcwmax,
    594 		    wmep->wmep_txopLimit);
    595 
    596 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
    597 		wmep->wmep_acm = pBssPhyParam->acm;
    598 		wmep->wmep_aifsn = pBssPhyParam->aifsn;
    599 		wmep->wmep_logcwmin = pBssPhyParam->logcwmin;
    600 		wmep->wmep_logcwmax = pBssPhyParam->logcwmax;
    601 		wmep->wmep_txopLimit = pBssPhyParam->txopLimit;
    602 		ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_initparams: "
    603 		    "%s  bss [acm %u aifsn %u log2(cwmin) %u "
    604 		    "log2(cwmax) %u txpoLimit %u]\n",
    605 		    ieee80211_wme_acnames[i],
    606 		    wmep->wmep_acm,
    607 		    wmep->wmep_aifsn,
    608 		    wmep->wmep_logcwmin,
    609 		    wmep->wmep_logcwmax,
    610 		    wmep->wmep_txopLimit);
    611 	}
    612 	/* NB: check ic_bss to avoid NULL deref on initial attach */
    613 	if (ic->ic_bss != NULL) {
    614 		/*
    615 		 * Calculate agressive mode switching threshold based
    616 		 * on beacon interval.  This doesn't need locking since
    617 		 * we're only called before entering the RUN state at
    618 		 * which point we start sending beacon frames.
    619 		 */
    620 		wme->wme_hipri_switch_thresh =
    621 		    (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->in_intval) / 100;
    622 		ieee80211_wme_updateparams(ic);
    623 	}
    624 }
    625 
    626 /*
    627  * Update WME parameters for ourself and the BSS.
    628  */
    629 void
    630 ieee80211_wme_updateparams(struct ieee80211com *ic)
    631 {
    632 	static const paramType phyParam[IEEE80211_MODE_MAX] = {
    633 		{ 2, 4, 10, 64, 0 },	/* IEEE80211_MODE_AUTO */
    634 		{ 2, 4, 10, 64, 0 },	/* IEEE80211_MODE_11A */
    635 		{ 2, 5, 10, 64, 0 },	/* IEEE80211_MODE_11B */
    636 		{ 2, 4, 10, 64, 0 },	/* IEEE80211_MODE_11G */
    637 		{ 2, 5, 10, 64, 0 },	/* IEEE80211_MODE_FH */
    638 		{ 1, 3, 10, 64, 0 },	/* IEEE80211_MODE_TURBO_A */
    639 		{ 1, 3, 10, 64, 0 },	/* IEEE80211_MODE_TURBO_G */
    640 		{ 1, 3, 10, 64, 0 },	/* IEEE80211_MODE_STURBO_A */
    641 		{ 2, 4, 10, 64, 0 },	/* IEEE80211_MODE_11NA */
    642 		{ 2, 4, 10, 64, 0 },	/* IEEE80211_MODE_11NG */
    643 	};
    644 	struct ieee80211_wme_state *wme = &ic->ic_wme;
    645 	const struct wmeParams *wmep;
    646 	struct wmeParams *chanp, *bssp;
    647 	enum ieee80211_phymode mode;
    648 	int i;
    649 
    650 	if ((ic->ic_caps & IEEE80211_C_WME) == 0)
    651 		return;
    652 
    653 	/* set up the channel access parameters for the physical device */
    654 	for (i = 0; i < WME_NUM_AC; i++) {
    655 		chanp = &wme->wme_chanParams.cap_wmeParams[i];
    656 		wmep = &wme->wme_wmeChanParams.cap_wmeParams[i];
    657 		chanp->wmep_aifsn = wmep->wmep_aifsn;
    658 		chanp->wmep_logcwmin = wmep->wmep_logcwmin;
    659 		chanp->wmep_logcwmax = wmep->wmep_logcwmax;
    660 		chanp->wmep_txopLimit = wmep->wmep_txopLimit;
    661 
    662 		chanp = &wme->wme_bssChanParams.cap_wmeParams[i];
    663 		wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i];
    664 		chanp->wmep_aifsn = wmep->wmep_aifsn;
    665 		chanp->wmep_logcwmin = wmep->wmep_logcwmin;
    666 		chanp->wmep_logcwmax = wmep->wmep_logcwmax;
    667 		chanp->wmep_txopLimit = wmep->wmep_txopLimit;
    668 	}
    669 
    670 	/*
    671 	 * Select mode; we can be called early in which case we
    672 	 * always use auto mode.  We know we'll be called when
    673 	 * entering the RUN state with bsschan setup properly
    674 	 * so state will eventually get set correctly
    675 	 */
    676 	if (ic->ic_curchan != IEEE80211_CHAN_ANYC)
    677 		mode = ieee80211_chan2mode(ic, ic->ic_curchan);
    678 	else
    679 		mode = IEEE80211_MODE_AUTO;
    680 
    681 	/*
    682 	 * This implements agressive mode as found in certain
    683 	 * vendors' AP's.  When there is significant high
    684 	 * priority (VI/VO) traffic in the BSS throttle back BE
    685 	 * traffic by using conservative parameters.  Otherwise
    686 	 * BE uses agressive params to optimize performance of
    687 	 * legacy/non-QoS traffic.
    688 	 */
    689 	if ((ic->ic_opmode == IEEE80211_M_HOSTAP &&
    690 	    (wme->wme_flags & WME_F_AGGRMODE) != 0) ||
    691 	    (ic->ic_opmode == IEEE80211_M_STA &&
    692 	    (ic->ic_bss->in_flags & IEEE80211_NODE_QOS) == 0) ||
    693 	    (ic->ic_flags & IEEE80211_F_WME) == 0) {
    694 		chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE];
    695 		bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE];
    696 
    697 		chanp->wmep_aifsn = bssp->wmep_aifsn = phyParam[mode].aifsn;
    698 		chanp->wmep_logcwmin = bssp->wmep_logcwmin =
    699 		    phyParam[mode].logcwmin;
    700 		chanp->wmep_logcwmax = bssp->wmep_logcwmax =
    701 		    phyParam[mode].logcwmax;
    702 		chanp->wmep_txopLimit = bssp->wmep_txopLimit =
    703 		    (ic->ic_flags & IEEE80211_F_BURST) ?
    704 		    phyParam[mode].txopLimit : 0;
    705 		ieee80211_dbg(IEEE80211_MSG_WME,
    706 		    "ieee80211_wme_updateparams_locked: "
    707 		    "%s [acm %u aifsn %u log2(cwmin) %u "
    708 		    "log2(cwmax) %u txpoLimit %u]\n",
    709 		    ieee80211_wme_acnames[WME_AC_BE],
    710 		    chanp->wmep_acm,
    711 		    chanp->wmep_aifsn,
    712 		    chanp->wmep_logcwmin,
    713 		    chanp->wmep_logcwmax,
    714 		    chanp->wmep_txopLimit);
    715 	}
    716 
    717 	wme->wme_update(ic);
    718 
    719 	ieee80211_dbg(IEEE80211_MSG_WME, "ieee80211_wme_updateparams(): "
    720 	    "%s: WME params updated, cap_info 0x%x\n",
    721 	    ic->ic_opmode == IEEE80211_M_STA ?
    722 	    wme->wme_wmeChanParams.cap_info :
    723 	    wme->wme_bssChanParams.cap_info);
    724 }
    725 
    726 /*
    727  * Process STA mode beacon miss events. Send a direct probe request
    728  * frame to the current ap bmiss_max times (w/o answer) before
    729  * scanning for a new ap.
    730  */
    731 void
    732 ieee80211_beacon_miss(ieee80211com_t *ic)
    733 {
    734 	ieee80211_impl_t *im = ic->ic_private;
    735 
    736 	if (ic->ic_flags & IEEE80211_F_SCAN)
    737 		return;
    738 	ieee80211_dbg(IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
    739 	    "%s\n", "beacon miss");
    740 
    741 	/*
    742 	 * Our handling is only meaningful for stations that are
    743 	 * associated; any other conditions else will be handled
    744 	 * through different means (e.g. the tx timeout on mgt frames).
    745 	 */
    746 	if (ic->ic_opmode != IEEE80211_M_STA ||
    747 	    ic->ic_state != IEEE80211_S_RUN) {
    748 		return;
    749 	}
    750 
    751 	IEEE80211_LOCK(ic);
    752 	if (++im->im_bmiss_count < im->im_bmiss_max) {
    753 		/*
    754 		 * Send a directed probe req before falling back to a scan;
    755 		 * if we receive a response ic_bmiss_count will be reset.
    756 		 * Some cards mistakenly report beacon miss so this avoids
    757 		 * the expensive scan if the ap is still there.
    758 		 */
    759 		IEEE80211_UNLOCK(ic);
    760 		(void) ieee80211_send_probereq(ic->ic_bss, ic->ic_macaddr,
    761 		    ic->ic_bss->in_bssid, ic->ic_bss->in_bssid,
    762 		    ic->ic_bss->in_essid, ic->ic_bss->in_esslen,
    763 		    ic->ic_opt_ie, ic->ic_opt_ie_len);
    764 		return;
    765 	}
    766 	im->im_bmiss_count = 0;
    767 	IEEE80211_UNLOCK(ic);
    768 	ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
    769 }
    770 
    771 /*
    772  * Manage state transition between INIT | AUTH | ASSOC | RUN.
    773  */
    774 static int
    775 ieee80211_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
    776 {
    777 	struct ieee80211_impl *im = ic->ic_private;
    778 	ieee80211_node_t *in;
    779 	enum ieee80211_state ostate;
    780 	wifi_data_t wd = { 0 };
    781 
    782 	IEEE80211_LOCK(ic);
    783 	ostate = ic->ic_state;
    784 	ieee80211_dbg(IEEE80211_MSG_STATE, "ieee80211_newstate(): "
    785 	    "%s -> %s\n",
    786 	    ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
    787 	ic->ic_state = nstate;
    788 	in = ic->ic_bss;
    789 	im->im_swbmiss_period = 0;	/* Reset software beacon miss period */
    790 
    791 	switch (nstate) {
    792 	case IEEE80211_S_INIT:
    793 		IEEE80211_UNLOCK(ic);
    794 		switch (ostate) {
    795 		case IEEE80211_S_INIT:
    796 			return (0);
    797 		case IEEE80211_S_SCAN:
    798 			ieee80211_cancel_scan(ic);
    799 			break;
    800 		case IEEE80211_S_AUTH:
    801 			break;
    802 		case IEEE80211_S_ASSOC:
    803 			if (ic->ic_opmode == IEEE80211_M_STA) {
    804 				IEEE80211_SEND_MGMT(ic, in,
    805 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
    806 				    IEEE80211_REASON_AUTH_LEAVE);
    807 			}
    808 			break;
    809 		case IEEE80211_S_RUN:
    810 			switch (ic->ic_opmode) {
    811 			case IEEE80211_M_STA:
    812 				IEEE80211_SEND_MGMT(ic, in,
    813 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
    814 				    IEEE80211_REASON_AUTH_LEAVE);
    815 				ieee80211_sta_leave(ic, in);
    816 				break;
    817 			case IEEE80211_M_IBSS:
    818 				ieee80211_notify_node_leave(ic, in);
    819 				break;
    820 			default:
    821 				break;
    822 			}
    823 			break;
    824 		}
    825 		IEEE80211_LOCK(ic);
    826 		im->im_mgt_timer = 0;
    827 		ieee80211_reset_bss(ic);
    828 		break;
    829 	case IEEE80211_S_SCAN:
    830 		switch (ostate) {
    831 		case IEEE80211_S_INIT:
    832 			IEEE80211_UNLOCK(ic);
    833 			ieee80211_begin_scan(ic, (arg == 0) ? B_FALSE : B_TRUE);
    834 			return (0);
    835 		case IEEE80211_S_SCAN:
    836 			/*
    837 			 * Scan next. If doing an active scan and the
    838 			 * channel is not marked passive-only then send
    839 			 * a probe request.  Otherwise just listen for
    840 			 * beacons on the channel.
    841 			 */
    842 			if ((ic->ic_flags & IEEE80211_F_ASCAN) &&
    843 			    !IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) {
    844 				IEEE80211_UNLOCK(ic);
    845 				(void) ieee80211_send_probereq(in,
    846 				    ic->ic_macaddr, wifi_bcastaddr,
    847 				    wifi_bcastaddr,
    848 				    ic->ic_des_essid, ic->ic_des_esslen,
    849 				    ic->ic_opt_ie, ic->ic_opt_ie_len);
    850 				return (0);
    851 			}
    852 			break;
    853 		case IEEE80211_S_RUN:
    854 			/* beacon miss */
    855 			ieee80211_dbg(IEEE80211_MSG_STATE,
    856 			    "no recent beacons from %s, rescanning\n",
    857 			    ieee80211_macaddr_sprintf(in->in_macaddr));
    858 			IEEE80211_UNLOCK(ic);
    859 			ieee80211_sta_leave(ic, in);
    860 			IEEE80211_LOCK(ic);
    861 			ic->ic_flags &= ~IEEE80211_F_SIBSS;
    862 			/* FALLTHRU */
    863 		case IEEE80211_S_AUTH:
    864 		case IEEE80211_S_ASSOC:
    865 			/* timeout restart scan */
    866 			in = ieee80211_find_node(&ic->ic_scan,
    867 			    ic->ic_bss->in_macaddr);
    868 			if (in != NULL) {
    869 				in->in_fails++;
    870 				ieee80211_unref_node(&in);
    871 			}
    872 			break;
    873 		}
    874 		break;
    875 	case IEEE80211_S_AUTH:
    876 		ASSERT(ic->ic_opmode == IEEE80211_M_STA);
    877 		switch (ostate) {
    878 		case IEEE80211_S_INIT:
    879 		case IEEE80211_S_SCAN:
    880 			IEEE80211_UNLOCK(ic);
    881 			IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
    882 			    1);
    883 			return (0);
    884 		case IEEE80211_S_AUTH:
    885 		case IEEE80211_S_ASSOC:
    886 			switch (arg) {
    887 			case IEEE80211_FC0_SUBTYPE_AUTH:
    888 				IEEE80211_UNLOCK(ic);
    889 				IEEE80211_SEND_MGMT(ic, in,
    890 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
    891 				return (0);
    892 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
    893 				/* ignore and retry scan on timeout */
    894 				break;
    895 			}
    896 			break;
    897 		case IEEE80211_S_RUN:
    898 			switch (arg) {
    899 			case IEEE80211_FC0_SUBTYPE_AUTH:
    900 				ic->ic_state = ostate;	/* stay RUN */
    901 				IEEE80211_UNLOCK(ic);
    902 				IEEE80211_SEND_MGMT(ic, in,
    903 				    IEEE80211_FC0_SUBTYPE_AUTH, 2);
    904 				return (0);
    905 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
    906 				IEEE80211_UNLOCK(ic);
    907 				ieee80211_sta_leave(ic, in);
    908 				/* try to re-auth */
    909 				IEEE80211_SEND_MGMT(ic, in,
    910 				    IEEE80211_FC0_SUBTYPE_AUTH, 1);
    911 				return (0);
    912 			}
    913 			break;
    914 		}
    915 		break;
    916 	case IEEE80211_S_ASSOC:
    917 		ASSERT(ic->ic_opmode == IEEE80211_M_STA);
    918 		switch (ostate) {
    919 		case IEEE80211_S_INIT:
    920 		case IEEE80211_S_SCAN:
    921 		case IEEE80211_S_ASSOC:
    922 			ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_newstate: "
    923 			    "invalid transition\n");
    924 			break;
    925 		case IEEE80211_S_AUTH:
    926 			IEEE80211_UNLOCK(ic);
    927 			IEEE80211_SEND_MGMT(ic, in,
    928 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
    929 			return (0);
    930 		case IEEE80211_S_RUN:
    931 			IEEE80211_UNLOCK(ic);
    932 			ieee80211_sta_leave(ic, in);
    933 			IEEE80211_SEND_MGMT(ic, in,
    934 			    IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1);
    935 			return (0);
    936 		}
    937 		break;
    938 	case IEEE80211_S_RUN:
    939 		switch (ostate) {
    940 		case IEEE80211_S_INIT:
    941 			ieee80211_err("ieee80211_newstate: "
    942 			    "invalid transition\n");
    943 			break;
    944 		case IEEE80211_S_AUTH:
    945 			ieee80211_err("ieee80211_newstate: "
    946 			    "invalid transition\n");
    947 			break;
    948 		case IEEE80211_S_SCAN:		/* adhoc/hostap mode */
    949 		case IEEE80211_S_ASSOC:		/* infra mode */
    950 			ASSERT(in->in_txrate < in->in_rates.ir_nrates);
    951 			im->im_mgt_timer = 0;
    952 			ieee80211_notify_node_join(ic, in);
    953 
    954 			/*
    955 			 * We can send data now; update the fastpath with our
    956 			 * current associated BSSID and other relevant settings.
    957 			 */
    958 			wd.wd_secalloc = ieee80211_crypto_getciphertype(ic);
    959 			wd.wd_opmode = ic->ic_opmode;
    960 			IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid);
    961 			wd.wd_qospad = 0;
    962 			if (in->in_flags &
    963 			    (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) {
    964 				wd.wd_qospad = 2;
    965 				if (ic->ic_flags & IEEE80211_F_DATAPAD) {
    966 					wd.wd_qospad = roundup(wd.wd_qospad,
    967 					    sizeof (uint32_t));
    968 				}
    969 			}
    970 			(void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
    971 			break;
    972 		}
    973 
    974 		/*
    975 		 * When 802.1x is not in use mark the port authorized
    976 		 * at this point so traffic can flow.
    977 		 */
    978 		if (in->in_authmode != IEEE80211_AUTH_8021X)
    979 			ieee80211_node_authorize(in);
    980 		/*
    981 		 * Enable inactivity processing.
    982 		 */
    983 		ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT;
    984 		ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT;
    985 		break;	/* IEEE80211_S_RUN */
    986 	} /* switch nstate */
    987 	IEEE80211_UNLOCK(ic);
    988 
    989 	return (0);
    990 }
    991