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