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 const char *ieee80211_mgt_subtype_name[] = { 45 "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 46 "probe_req", "probe_resp", "reserved#6", "reserved#7", 47 "beacon", "atim", "disassoc", "auth", 48 "deauth", "reserved#13", "reserved#14", "reserved#15" 49 }; 50 const char *ieee80211_ctl_subtype_name[] = { 51 "reserved#0", "reserved#1", "reserved#2", "reserved#3", 52 "reserved#3", "reserved#5", "reserved#6", "reserved#7", 53 "reserved#8", "reserved#9", "ps_poll", "rts", 54 "cts", "ack", "cf_end", "cf_end_ack" 55 }; 56 const char *ieee80211_state_name[IEEE80211_S_MAX] = { 57 "INIT", /* IEEE80211_S_INIT */ 58 "SCAN", /* IEEE80211_S_SCAN */ 59 "AUTH", /* IEEE80211_S_AUTH */ 60 "ASSOC", /* IEEE80211_S_ASSOC */ 61 "RUN" /* IEEE80211_S_RUN */ 62 }; 63 64 static int ieee80211_newstate(ieee80211com_t *, enum ieee80211_state, int); 65 66 /* 67 * Initialize the interface softc, ic, with protocol management 68 * related data structures and functions. 69 */ 70 void 71 ieee80211_proto_attach(ieee80211com_t *ic) 72 { 73 struct ieee80211_impl *im = ic->ic_private; 74 75 ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 76 ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT; 77 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 78 ic->ic_mcast_rate = IEEE80211_MCAST_RATE_DEFAULT; 79 ic->ic_protmode = IEEE80211_PROT_CTSONLY; 80 im->im_bmiss_max = IEEE80211_BMISS_MAX; 81 82 /* protocol state change handler */ 83 ic->ic_newstate = ieee80211_newstate; 84 85 /* initialize management frame handlers */ 86 ic->ic_recv_mgmt = ieee80211_recv_mgmt; 87 ic->ic_send_mgmt = ieee80211_send_mgmt; 88 } 89 90 /* 91 * Print a 802.11 frame header 92 */ 93 void 94 ieee80211_dump_pkt(const uint8_t *buf, int32_t len, int32_t rate, int32_t rssi) 95 { 96 struct ieee80211_frame *wh; 97 int8_t buf1[100]; 98 int8_t buf2[25]; 99 int i; 100 101 bzero(buf1, sizeof (buf1)); 102 bzero(buf2, sizeof (buf2)); 103 wh = (struct ieee80211_frame *)buf; 104 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 105 case IEEE80211_FC1_DIR_NODS: 106 (void) snprintf(buf2, sizeof (buf2), "NODS %s", 107 ieee80211_macaddr_sprintf(wh->i_addr2)); 108 (void) strncat(buf1, buf2, sizeof (buf2)); 109 (void) snprintf(buf2, sizeof (buf2), "->%s", 110 ieee80211_macaddr_sprintf(wh->i_addr1)); 111 (void) strncat(buf1, buf2, sizeof (buf2)); 112 (void) snprintf(buf2, sizeof (buf2), "(%s)", 113 ieee80211_macaddr_sprintf(wh->i_addr3)); 114 (void) strncat(buf1, buf2, sizeof (buf2)); 115 break; 116 case IEEE80211_FC1_DIR_TODS: 117 (void) snprintf(buf2, sizeof (buf2), "TODS %s", 118 ieee80211_macaddr_sprintf(wh->i_addr2)); 119 (void) strncat(buf1, buf2, sizeof (buf2)); 120 (void) snprintf(buf2, sizeof (buf2), "->%s", 121 ieee80211_macaddr_sprintf(wh->i_addr3)); 122 (void) strncat(buf1, buf2, sizeof (buf2)); 123 (void) snprintf(buf2, sizeof (buf2), "(%s)", 124 ieee80211_macaddr_sprintf(wh->i_addr1)); 125 (void) strncat(buf1, buf2, sizeof (buf2)); 126 break; 127 case IEEE80211_FC1_DIR_FROMDS: 128 (void) snprintf(buf2, sizeof (buf2), "FRDS %s", 129 ieee80211_macaddr_sprintf(wh->i_addr3)); 130 (void) strncat(buf1, buf2, sizeof (buf2)); 131 (void) snprintf(buf2, sizeof (buf2), "->%s", 132 ieee80211_macaddr_sprintf(wh->i_addr1)); 133 (void) strncat(buf1, buf2, sizeof (buf2)); 134 (void) snprintf(buf2, sizeof (buf2), "(%s)", 135 ieee80211_macaddr_sprintf(wh->i_addr2)); 136 (void) strncat(buf1, buf2, sizeof (buf2)); 137 break; 138 case IEEE80211_FC1_DIR_DSTODS: 139 (void) snprintf(buf2, sizeof (buf2), "DSDS %s", 140 ieee80211_macaddr_sprintf((uint8_t *)&wh[1])); 141 (void) strncat(buf1, buf2, sizeof (buf2)); 142 (void) snprintf(buf2, sizeof (buf2), "->%s ", 143 ieee80211_macaddr_sprintf(wh->i_addr3)); 144 (void) strncat(buf1, buf2, sizeof (buf2)); 145 (void) snprintf(buf2, sizeof (buf2), "%s", 146 ieee80211_macaddr_sprintf(wh->i_addr2)); 147 (void) strncat(buf1, buf2, sizeof (buf2)); 148 (void) snprintf(buf2, sizeof (buf2), "->%s", 149 ieee80211_macaddr_sprintf(wh->i_addr1)); 150 (void) strncat(buf1, buf2, sizeof (buf2)); 151 break; 152 } 153 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1); 154 bzero(buf1, sizeof (buf1)); 155 156 switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 157 case IEEE80211_FC0_TYPE_DATA: 158 (void) sprintf(buf2, "data"); 159 break; 160 case IEEE80211_FC0_TYPE_MGT: 161 (void) snprintf(buf2, sizeof (buf2), "%s", 162 ieee80211_mgt_subtype_name[ 163 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 164 >> IEEE80211_FC0_SUBTYPE_SHIFT]); 165 break; 166 default: 167 (void) snprintf(buf2, sizeof (buf2), "type#%d", 168 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 169 break; 170 } 171 (void) strncat(buf1, buf2, sizeof (buf2)); 172 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 173 (void) sprintf(buf2, " WEP"); 174 (void) strcat(buf1, buf2); 175 } 176 if (rate >= 0) { 177 (void) snprintf(buf2, sizeof (buf2), " %dM", rate / 2); 178 (void) strncat(buf1, buf2, sizeof (buf2)); 179 } 180 if (rssi >= 0) { 181 (void) snprintf(buf2, sizeof (buf2), " +%d", rssi); 182 (void) strncat(buf1, buf2, sizeof (buf2)); 183 } 184 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", buf1); 185 bzero(buf1, sizeof (buf1)); 186 187 if (len > 0) { 188 for (i = 0; i < (len > 40 ? 40 : len); i++) { 189 if ((i & 0x03) == 0) 190 (void) strcat(buf1, " "); 191 (void) snprintf(buf2, 3, "%02x", buf[i]); 192 (void) strncat(buf1, buf2, 3); 193 } 194 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_dump_pkt(): %s", 195 buf1); 196 } 197 } 198 199 /* 200 * Adjust/Fix the specified node's rate table 201 * 202 * in node 203 * flag IEEE80211_F_DOSORT : sort the node's rate table 204 * IEEE80211_F_DONEGO : mark a rate as basic rate if it is 205 * a device's basic rate 206 * IEEE80211_F_DODEL : delete rates not supported by the device 207 * IEEE80211_F_DOFRATE: check if the fixed rate is supported by 208 * the device 209 * 210 * The highest bit of returned rate value is set to 1 on failure. 211 */ 212 int 213 ieee80211_fix_rate(ieee80211_node_t *in, int flags) 214 { 215 ieee80211com_t *ic = in->in_ic; 216 struct ieee80211_rateset *srs; 217 struct ieee80211_rateset *nrs; 218 boolean_t ignore; 219 int i; 220 int okrate; 221 int badrate; 222 int fixedrate; 223 uint8_t r; 224 225 /* 226 * If the fixed rate check was requested but no 227 * fixed has been defined then just remove it. 228 */ 229 if ((flags & IEEE80211_F_DOFRATE) && 230 (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE)) { 231 flags &= ~IEEE80211_F_DOFRATE; 232 } 233 if (in->in_chan == IEEE80211_CHAN_ANYC) { 234 return (IEEE80211_RATE_BASIC); 235 } 236 okrate = badrate = fixedrate = 0; 237 srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, in->in_chan)]; 238 nrs = &in->in_rates; 239 for (i = 0; i < nrs->ir_nrates; ) { 240 int j; 241 242 ignore = B_FALSE; 243 if (flags & IEEE80211_F_DOSORT) { 244 /* 245 * Sort rates. 246 */ 247 for (j = i + 1; j < nrs->ir_nrates; j++) { 248 if (IEEE80211_RV(nrs->ir_rates[i]) > 249 IEEE80211_RV(nrs->ir_rates[j])) { 250 r = nrs->ir_rates[i]; 251 nrs->ir_rates[i] = nrs->ir_rates[j]; 252 nrs->ir_rates[j] = r; 253 } 254 } 255 } 256 r = IEEE80211_RV(nrs->ir_rates[i]); 257 badrate = r; 258 259 /* 260 * Check against supported rates. 261 */ 262 for (j = 0; j < srs->ir_nrates; j++) { 263 if (r == IEEE80211_RV(srs->ir_rates[j])) { 264 /* 265 * Overwrite with the supported rate 266 * value so any basic rate bit is set. 267 * This insures that response we send 268 * to stations have the necessary basic 269 * rate bit set. 270 */ 271 if (flags & IEEE80211_F_DONEGO) 272 nrs->ir_rates[i] = srs->ir_rates[j]; 273 break; 274 } 275 } 276 if (j == srs->ir_nrates) { 277 /* 278 * A rate in the node's rate set is not 279 * supported. We just discard/ignore the rate. 280 * Note that this is important for 11b stations 281 * when they want to associate with an 11g AP. 282 */ 283 ignore = B_TRUE; 284 } 285 286 if (flags & IEEE80211_F_DODEL) { 287 /* 288 * Delete unacceptable rates. 289 */ 290 if (ignore) { 291 nrs->ir_nrates--; 292 for (j = i; j < nrs->ir_nrates; j++) 293 nrs->ir_rates[j] = nrs->ir_rates[j + 1]; 294 nrs->ir_rates[j] = 0; 295 continue; 296 } 297 } 298 if (flags & IEEE80211_F_DOFRATE) { 299 /* 300 * Check any fixed rate is included. 301 */ 302 if (r == ic->ic_fixed_rate) 303 fixedrate = r; 304 } 305 if (!ignore) 306 okrate = nrs->ir_rates[i]; 307 i++; 308 } 309 if (okrate == 0 || ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 310 return (badrate | IEEE80211_RATE_BASIC); 311 else 312 return (IEEE80211_RV(okrate)); 313 } 314 315 /* 316 * Reset 11g-related state. 317 */ 318 void 319 ieee80211_reset_erp(ieee80211com_t *ic) 320 { 321 ic->ic_flags &= ~IEEE80211_F_USEPROT; 322 /* 323 * Short slot time is enabled only when operating in 11g 324 * and not in an IBSS. We must also honor whether or not 325 * the driver is capable of doing it. 326 */ 327 ieee80211_set_shortslottime(ic, 328 ic->ic_curmode == IEEE80211_MODE_11A); 329 /* 330 * Set short preamble and ERP barker-preamble flags. 331 */ 332 if (ic->ic_curmode == IEEE80211_MODE_11A || 333 (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 334 ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 335 ic->ic_flags &= ~IEEE80211_F_USEBARKER; 336 } else { 337 ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 338 ic->ic_flags |= IEEE80211_F_USEBARKER; 339 } 340 } 341 342 /* 343 * Change current channel to be the next available channel 344 */ 345 void 346 ieee80211_reset_chan(ieee80211com_t *ic) 347 { 348 struct ieee80211_channel *ch = ic->ic_curchan; 349 350 IEEE80211_LOCK(ic); 351 do { 352 if (++ch > &ic->ic_sup_channels[IEEE80211_CHAN_MAX]) 353 ch = &ic->ic_sup_channels[0]; 354 if (ieee80211_isset(ic->ic_chan_active, 355 ieee80211_chan2ieee(ic, ch))) { 356 break; 357 } 358 } while (ch != ic->ic_curchan); 359 ic->ic_curchan = ch; 360 IEEE80211_UNLOCK(ic); 361 } 362 363 /* 364 * Set the short slot time state and notify the driver. 365 */ 366 void 367 ieee80211_set_shortslottime(ieee80211com_t *ic, boolean_t on) 368 { 369 if (on) 370 ic->ic_flags |= IEEE80211_F_SHSLOT; 371 else 372 ic->ic_flags &= ~IEEE80211_F_SHSLOT; 373 /* notify driver */ 374 if (ic->ic_set_shortslot != NULL) 375 ic->ic_set_shortslot(ic, on); 376 } 377 378 /* 379 * Mark the basic rates for the 11g rate table based on the 380 * operating mode. For real 11g we mark all the 11b rates 381 * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 382 * 11b rates. There's also a pseudo 11a-mode used to mark only 383 * the basic OFDM rates. 384 */ 385 void 386 ieee80211_setbasicrates(struct ieee80211_rateset *rs, 387 enum ieee80211_phymode mode) 388 { 389 static const struct ieee80211_rateset basic[] = { 390 { 0 }, /* IEEE80211_MODE_AUTO */ 391 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 392 { 2, { 2, 4} }, /* IEEE80211_MODE_11B */ 393 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G mixed b/g */ 394 { 0 }, /* IEEE80211_MODE_FH */ 395 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_TURBO_A */ 396 { 4, { 2, 4, 11, 22 } } /* IEEE80211_MODE_TURBO_G (mixed b/g) */ 397 }; 398 int i, j; 399 400 ASSERT(mode < IEEE80211_MODE_MAX); 401 for (i = 0; i < rs->ir_nrates; i++) { 402 rs->ir_rates[i] &= IEEE80211_RATE_VAL; 403 for (j = 0; j < basic[mode].ir_nrates; j++) { 404 if (basic[mode].ir_rates[j] == rs->ir_rates[i]) { 405 rs->ir_rates[i] |= IEEE80211_RATE_BASIC; 406 break; 407 } 408 } 409 } 410 } 411 412 /* 413 * Process STA mode beacon miss events. Send a direct probe request 414 * frame to the current ap bmiss_max times (w/o answer) before 415 * scanning for a new ap. 416 */ 417 void 418 ieee80211_beacon_miss(ieee80211com_t *ic) 419 { 420 ieee80211_impl_t *im = ic->ic_private; 421 422 if (ic->ic_flags & IEEE80211_F_SCAN) 423 return; 424 ieee80211_dbg(IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 425 "%s\n", "beacon miss"); 426 427 /* 428 * Our handling is only meaningful for stations that are 429 * associated; any other conditions else will be handled 430 * through different means (e.g. the tx timeout on mgt frames). 431 */ 432 if (ic->ic_opmode != IEEE80211_M_STA || 433 ic->ic_state != IEEE80211_S_RUN) { 434 return; 435 } 436 437 IEEE80211_LOCK(ic); 438 if (++im->im_bmiss_count < im->im_bmiss_max) { 439 /* 440 * Send a directed probe req before falling back to a scan; 441 * if we receive a response ic_bmiss_count will be reset. 442 * Some cards mistakenly report beacon miss so this avoids 443 * the expensive scan if the ap is still there. 444 */ 445 IEEE80211_UNLOCK(ic); 446 (void) ieee80211_send_probereq(ic->ic_bss, ic->ic_macaddr, 447 ic->ic_bss->in_bssid, ic->ic_bss->in_bssid, 448 ic->ic_bss->in_essid, ic->ic_bss->in_esslen, 449 ic->ic_opt_ie, ic->ic_opt_ie_len); 450 return; 451 } 452 im->im_bmiss_count = 0; 453 IEEE80211_UNLOCK(ic); 454 ieee80211_new_state(ic, IEEE80211_S_SCAN, 0); 455 } 456 457 /* 458 * Manage state transition between INIT | AUTH | ASSOC | RUN. 459 */ 460 static int 461 ieee80211_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg) 462 { 463 struct ieee80211_impl *im = ic->ic_private; 464 ieee80211_node_t *in; 465 enum ieee80211_state ostate; 466 wifi_data_t wd = { 0 }; 467 468 IEEE80211_LOCK(ic); 469 ostate = ic->ic_state; 470 ieee80211_dbg(IEEE80211_MSG_STATE, "ieee80211_newstate(): " 471 "%s -> %s\n", 472 ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 473 ic->ic_state = nstate; 474 in = ic->ic_bss; 475 im->im_swbmiss_period = 0; /* Reset software beacon miss period */ 476 477 switch (nstate) { 478 case IEEE80211_S_INIT: 479 IEEE80211_UNLOCK(ic); 480 switch (ostate) { 481 case IEEE80211_S_INIT: 482 return (0); 483 case IEEE80211_S_SCAN: 484 ieee80211_cancel_scan(ic); 485 break; 486 case IEEE80211_S_AUTH: 487 break; 488 case IEEE80211_S_ASSOC: 489 if (ic->ic_opmode == IEEE80211_M_STA) { 490 IEEE80211_SEND_MGMT(ic, in, 491 IEEE80211_FC0_SUBTYPE_DEAUTH, 492 IEEE80211_REASON_AUTH_LEAVE); 493 } 494 break; 495 case IEEE80211_S_RUN: 496 switch (ic->ic_opmode) { 497 case IEEE80211_M_STA: 498 IEEE80211_SEND_MGMT(ic, in, 499 IEEE80211_FC0_SUBTYPE_DISASSOC, 500 IEEE80211_REASON_ASSOC_LEAVE); 501 ieee80211_sta_leave(ic, in); 502 break; 503 case IEEE80211_M_IBSS: 504 ieee80211_notify_node_leave(ic, in); 505 break; 506 default: 507 break; 508 } 509 break; 510 } 511 IEEE80211_LOCK(ic); 512 im->im_mgt_timer = 0; 513 ieee80211_reset_bss(ic); 514 break; 515 case IEEE80211_S_SCAN: 516 switch (ostate) { 517 case IEEE80211_S_INIT: 518 IEEE80211_UNLOCK(ic); 519 ieee80211_begin_scan(ic, (arg == 0) ? B_FALSE : B_TRUE); 520 return (0); 521 case IEEE80211_S_SCAN: 522 /* 523 * Scan next. If doing an active scan and the 524 * channel is not marked passive-only then send 525 * a probe request. Otherwise just listen for 526 * beacons on the channel. 527 */ 528 if ((ic->ic_flags & IEEE80211_F_ASCAN) && 529 !IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) { 530 IEEE80211_UNLOCK(ic); 531 (void) ieee80211_send_probereq(in, 532 ic->ic_macaddr, wifi_bcastaddr, 533 wifi_bcastaddr, 534 ic->ic_des_essid, ic->ic_des_esslen, 535 ic->ic_opt_ie, ic->ic_opt_ie_len); 536 return (0); 537 } 538 break; 539 case IEEE80211_S_RUN: 540 /* beacon miss */ 541 ieee80211_dbg(IEEE80211_MSG_STATE, 542 "no recent beacons from %s, rescanning\n", 543 ieee80211_macaddr_sprintf(in->in_macaddr)); 544 IEEE80211_UNLOCK(ic); 545 ieee80211_sta_leave(ic, in); 546 IEEE80211_LOCK(ic); 547 ic->ic_flags &= ~IEEE80211_F_SIBSS; 548 /* FALLTHRU */ 549 case IEEE80211_S_AUTH: 550 case IEEE80211_S_ASSOC: 551 /* timeout restart scan */ 552 in = ieee80211_find_node(&ic->ic_scan, 553 ic->ic_bss->in_macaddr); 554 if (in != NULL) { 555 in->in_fails++; 556 ieee80211_unref_node(&in); 557 } 558 break; 559 } 560 break; 561 case IEEE80211_S_AUTH: 562 ASSERT(ic->ic_opmode == IEEE80211_M_STA); 563 switch (ostate) { 564 case IEEE80211_S_INIT: 565 case IEEE80211_S_SCAN: 566 IEEE80211_UNLOCK(ic); 567 IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH, 568 1); 569 return (0); 570 case IEEE80211_S_AUTH: 571 case IEEE80211_S_ASSOC: 572 switch (arg) { 573 case IEEE80211_FC0_SUBTYPE_AUTH: 574 IEEE80211_UNLOCK(ic); 575 IEEE80211_SEND_MGMT(ic, in, 576 IEEE80211_FC0_SUBTYPE_AUTH, 2); 577 return (0); 578 case IEEE80211_FC0_SUBTYPE_DEAUTH: 579 /* ignore and retry scan on timeout */ 580 break; 581 } 582 break; 583 case IEEE80211_S_RUN: 584 switch (arg) { 585 case IEEE80211_FC0_SUBTYPE_AUTH: 586 ic->ic_state = ostate; /* stay RUN */ 587 IEEE80211_UNLOCK(ic); 588 IEEE80211_SEND_MGMT(ic, in, 589 IEEE80211_FC0_SUBTYPE_AUTH, 2); 590 return (0); 591 case IEEE80211_FC0_SUBTYPE_DEAUTH: 592 IEEE80211_UNLOCK(ic); 593 ieee80211_sta_leave(ic, in); 594 /* try to re-auth */ 595 IEEE80211_SEND_MGMT(ic, in, 596 IEEE80211_FC0_SUBTYPE_AUTH, 1); 597 return (0); 598 } 599 break; 600 } 601 break; 602 case IEEE80211_S_ASSOC: 603 ASSERT(ic->ic_opmode == IEEE80211_M_STA); 604 switch (ostate) { 605 case IEEE80211_S_INIT: 606 case IEEE80211_S_SCAN: 607 case IEEE80211_S_ASSOC: 608 ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_newstate: " 609 "invalid transition\n"); 610 break; 611 case IEEE80211_S_AUTH: 612 IEEE80211_UNLOCK(ic); 613 IEEE80211_SEND_MGMT(ic, in, 614 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 615 return (0); 616 case IEEE80211_S_RUN: 617 IEEE80211_UNLOCK(ic); 618 ieee80211_sta_leave(ic, in); 619 IEEE80211_SEND_MGMT(ic, in, 620 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 621 return (0); 622 } 623 break; 624 case IEEE80211_S_RUN: 625 switch (ostate) { 626 case IEEE80211_S_INIT: 627 ieee80211_err("ieee80211_newstate: " 628 "invalid transition\n"); 629 break; 630 case IEEE80211_S_AUTH: 631 ieee80211_err("ieee80211_newstate: " 632 "invalid transition\n"); 633 break; 634 case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 635 case IEEE80211_S_ASSOC: /* infra mode */ 636 ASSERT(in->in_txrate < in->in_rates.ir_nrates); 637 im->im_mgt_timer = 0; 638 ieee80211_notify_node_join(ic, in); 639 640 /* 641 * We can send data now; update the fastpath with our 642 * current associated BSSID and other relevant settings. 643 */ 644 wd.wd_secalloc = ieee80211_crypto_getciphertype(ic); 645 wd.wd_opmode = ic->ic_opmode; 646 IEEE80211_ADDR_COPY(wd.wd_bssid, in->in_bssid); 647 (void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd)); 648 break; 649 } 650 651 /* 652 * When 802.1x is not in use mark the port authorized 653 * at this point so traffic can flow. 654 */ 655 if (in->in_authmode != IEEE80211_AUTH_8021X) 656 ieee80211_node_authorize(in); 657 /* 658 * Enable inactivity processing. 659 */ 660 ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 661 ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT; 662 break; /* IEEE80211_S_RUN */ 663 } /* switch nstate */ 664 IEEE80211_UNLOCK(ic); 665 666 return (0); 667 } 668