1 /* $NetBSD: ieee80211_proto.c,v 1.23 2005/11/18 16:40:09 skrll Exp $ */ 2 /*- 3 * Copyright (c) 2001 Atsushi Onoe 4 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * Alternatively, this software may be distributed under the terms of the 19 * GNU General Public License ("GPL") version 2 as published by the Free 20 * Software Foundation. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #ifdef __FreeBSD__ 36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.23 2005/08/10 16:22:29 sam Exp $"); 37 #endif 38 #ifdef __NetBSD__ 39 __KERNEL_RCSID(0, "$NetBSD: ieee80211_proto.c,v 1.23 2005/11/18 16:40:09 skrll Exp $"); 40 #endif 41 42 /* 43 * IEEE 802.11 protocol support. 44 */ 45 46 #include "opt_inet.h" 47 48 #include <sys/param.h> 49 #include <sys/kernel.h> 50 #include <sys/systm.h> 51 52 #include <sys/socket.h> 53 #include <sys/sockio.h> 54 #include <sys/endian.h> 55 #include <sys/errno.h> 56 #include <sys/proc.h> 57 #include <sys/sysctl.h> 58 59 #include <net/if.h> 60 #include <net/if_media.h> 61 #include <net/if_arp.h> 62 #include <net/if_ether.h> 63 #include <net/if_llc.h> 64 65 #include <net80211/ieee80211_netbsd.h> 66 #include <net80211/ieee80211_var.h> 67 68 #include <net/bpf.h> 69 70 #ifdef INET 71 #include <netinet/in.h> 72 #include <net/if_ether.h> 73 #endif 74 75 #include <net/route.h> 76 /* XXX tunables */ 77 #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */ 78 #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */ 79 80 #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 81 82 const char *ieee80211_mgt_subtype_name[] = { 83 "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 84 "probe_req", "probe_resp", "reserved#6", "reserved#7", 85 "beacon", "atim", "disassoc", "auth", 86 "deauth", "reserved#13", "reserved#14", "reserved#15" 87 }; 88 const char *ieee80211_ctl_subtype_name[] = { 89 "reserved#0", "reserved#1", "reserved#2", "reserved#3", 90 "reserved#3", "reserved#5", "reserved#6", "reserved#7", 91 "reserved#8", "reserved#9", "ps_poll", "rts", 92 "cts", "ack", "cf_end", "cf_end_ack" 93 }; 94 const char *ieee80211_state_name[IEEE80211_S_MAX] = { 95 "INIT", /* IEEE80211_S_INIT */ 96 "SCAN", /* IEEE80211_S_SCAN */ 97 "AUTH", /* IEEE80211_S_AUTH */ 98 "ASSOC", /* IEEE80211_S_ASSOC */ 99 "RUN" /* IEEE80211_S_RUN */ 100 }; 101 const char *ieee80211_wme_acnames[] = { 102 "WME_AC_BE", 103 "WME_AC_BK", 104 "WME_AC_VI", 105 "WME_AC_VO", 106 "WME_UPSD", 107 }; 108 109 static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 110 111 void 112 ieee80211_proto_attach(struct ieee80211com *ic) 113 { 114 struct ifnet *ifp = ic->ic_ifp; 115 116 /* XXX room for crypto */ 117 ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4); 118 119 ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 120 ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT; 121 ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 122 ic->ic_protmode = IEEE80211_PROT_CTSONLY; 123 ic->ic_roaming = IEEE80211_ROAMING_AUTO; 124 125 ic->ic_wme.wme_hipri_switch_hysteresis = 126 AGGRESSIVE_MODE_SWITCH_HYSTERESIS; 127 128 /* protocol state change handler */ 129 ic->ic_newstate = ieee80211_newstate; 130 131 /* initialize management frame handlers */ 132 ic->ic_recv_mgmt = ieee80211_recv_mgmt; 133 ic->ic_send_mgmt = ieee80211_send_mgmt; 134 } 135 136 void 137 ieee80211_proto_detach(struct ieee80211com *ic) 138 { 139 140 /* 141 * This should not be needed as we detach when reseting 142 * the state but be conservative here since the 143 * authenticator may do things like spawn kernel threads. 144 */ 145 if (ic->ic_auth->ia_detach) 146 ic->ic_auth->ia_detach(ic); 147 148 IF_PURGE(&ic->ic_mgtq); 149 150 /* 151 * Detach any ACL'ator. 152 */ 153 if (ic->ic_acl != NULL) 154 ic->ic_acl->iac_detach(ic); 155 } 156 157 /* 158 * Simple-minded authenticator module support. 159 */ 160 161 #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 162 /* XXX well-known names */ 163 static const char *auth_modnames[IEEE80211_AUTH_MAX] = { 164 "wlan_internal", /* IEEE80211_AUTH_NONE */ 165 "wlan_internal", /* IEEE80211_AUTH_OPEN */ 166 "wlan_internal", /* IEEE80211_AUTH_SHARED */ 167 "wlan_xauth", /* IEEE80211_AUTH_8021X */ 168 "wlan_internal", /* IEEE80211_AUTH_AUTO */ 169 "wlan_xauth", /* IEEE80211_AUTH_WPA */ 170 }; 171 static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 172 173 static const struct ieee80211_authenticator auth_internal = { 174 .ia_name = "wlan_internal", 175 .ia_attach = NULL, 176 .ia_detach = NULL, 177 .ia_node_join = NULL, 178 .ia_node_leave = NULL, 179 }; 180 181 /* 182 * Setup internal authenticators once; they are never unregistered. 183 */ 184 static void 185 ieee80211_auth_setup(void) 186 { 187 ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 188 ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 189 ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 190 } 191 192 const struct ieee80211_authenticator * 193 ieee80211_authenticator_get(int auth) 194 { 195 static int initialized = 0; 196 if (!initialized) { 197 ieee80211_auth_setup(); 198 initialized = 1; 199 } 200 if (auth >= IEEE80211_AUTH_MAX) 201 return NULL; 202 if (authenticators[auth] == NULL) 203 ieee80211_load_module(auth_modnames[auth]); 204 return authenticators[auth]; 205 } 206 207 void 208 ieee80211_authenticator_register(int type, 209 const struct ieee80211_authenticator *auth) 210 { 211 if (type >= IEEE80211_AUTH_MAX) 212 return; 213 authenticators[type] = auth; 214 } 215 216 void 217 ieee80211_authenticator_unregister(int type) 218 { 219 220 if (type >= IEEE80211_AUTH_MAX) 221 return; 222 authenticators[type] = NULL; 223 } 224 225 /* 226 * Very simple-minded ACL module support. 227 */ 228 /* XXX just one for now */ 229 static const struct ieee80211_aclator *acl = NULL; 230 231 void 232 ieee80211_aclator_register(const struct ieee80211_aclator *iac) 233 { 234 printf("wlan: %s acl policy registered\n", iac->iac_name); 235 acl = iac; 236 } 237 238 void 239 ieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 240 { 241 if (acl == iac) 242 acl = NULL; 243 printf("wlan: %s acl policy unregistered\n", iac->iac_name); 244 } 245 246 const struct ieee80211_aclator * 247 ieee80211_aclator_get(const char *name) 248 { 249 if (acl == NULL) 250 ieee80211_load_module("wlan_acl"); 251 return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 252 } 253 254 void 255 ieee80211_print_essid(const u_int8_t *essid, int len) 256 { 257 const u_int8_t *p; 258 int i; 259 260 if (len > IEEE80211_NWID_LEN) 261 len = IEEE80211_NWID_LEN; 262 /* determine printable or not */ 263 for (i = 0, p = essid; i < len; i++, p++) { 264 if (*p < ' ' || *p > 0x7e) 265 break; 266 } 267 if (i == len) { 268 printf("\""); 269 for (i = 0, p = essid; i < len; i++, p++) 270 printf("%c", *p); 271 printf("\""); 272 } else { 273 printf("0x"); 274 for (i = 0, p = essid; i < len; i++, p++) 275 printf("%02x", *p); 276 } 277 } 278 279 void 280 ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi) 281 { 282 const struct ieee80211_frame *wh; 283 int i; 284 285 wh = (const struct ieee80211_frame *)buf; 286 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 287 case IEEE80211_FC1_DIR_NODS: 288 printf("NODS %s", ether_sprintf(wh->i_addr2)); 289 printf("->%s", ether_sprintf(wh->i_addr1)); 290 printf("(%s)", ether_sprintf(wh->i_addr3)); 291 break; 292 case IEEE80211_FC1_DIR_TODS: 293 printf("TODS %s", ether_sprintf(wh->i_addr2)); 294 printf("->%s", ether_sprintf(wh->i_addr3)); 295 printf("(%s)", ether_sprintf(wh->i_addr1)); 296 break; 297 case IEEE80211_FC1_DIR_FROMDS: 298 printf("FRDS %s", ether_sprintf(wh->i_addr3)); 299 printf("->%s", ether_sprintf(wh->i_addr1)); 300 printf("(%s)", ether_sprintf(wh->i_addr2)); 301 break; 302 case IEEE80211_FC1_DIR_DSTODS: 303 printf("DSDS %s", ether_sprintf((const u_int8_t *)&wh[1])); 304 printf("->%s", ether_sprintf(wh->i_addr3)); 305 printf("(%s", ether_sprintf(wh->i_addr2)); 306 printf("->%s)", ether_sprintf(wh->i_addr1)); 307 break; 308 } 309 switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 310 case IEEE80211_FC0_TYPE_DATA: 311 printf(" data"); 312 break; 313 case IEEE80211_FC0_TYPE_MGT: 314 printf(" %s", ieee80211_mgt_subtype_name[ 315 (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 316 >> IEEE80211_FC0_SUBTYPE_SHIFT]); 317 break; 318 default: 319 printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 320 break; 321 } 322 if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 323 printf(" WEP [IV"); 324 for (i = 0; i < IEEE80211_WEP_IVLEN; i++) 325 printf(" %.02x", buf[sizeof(*wh)+i]); 326 printf(" KID %u]", buf[sizeof(*wh)+i] >> 6); 327 } 328 if (rate >= 0) 329 printf(" %dM", rate / 2); 330 if (rssi >= 0) 331 printf(" +%d", rssi); 332 printf("\n"); 333 if (len > 0) { 334 for (i = 0; i < len; i++) { 335 if ((i & 1) == 0) 336 printf(" "); 337 printf("%02x", buf[i]); 338 } 339 printf("\n"); 340 } 341 } 342 343 int 344 ieee80211_fix_rate(struct ieee80211_node *ni, int flags) 345 { 346 #define RV(v) ((v) & IEEE80211_RATE_VAL) 347 struct ieee80211com *ic = ni->ni_ic; 348 int i, j, ignore, error; 349 int okrate, badrate, fixedrate; 350 struct ieee80211_rateset *srs, *nrs; 351 u_int8_t r; 352 353 /* 354 * If the fixed rate check was requested but no 355 * fixed has been defined then just remove it. 356 */ 357 if ((flags & IEEE80211_F_DOFRATE) && 358 ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 359 flags &= ~IEEE80211_F_DOFRATE; 360 error = 0; 361 okrate = badrate = fixedrate = 0; 362 srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 363 nrs = &ni->ni_rates; 364 for (i = 0; i < nrs->rs_nrates; ) { 365 ignore = 0; 366 if (flags & IEEE80211_F_DOSORT) { 367 /* 368 * Sort rates. 369 */ 370 for (j = i + 1; j < nrs->rs_nrates; j++) { 371 if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 372 r = nrs->rs_rates[i]; 373 nrs->rs_rates[i] = nrs->rs_rates[j]; 374 nrs->rs_rates[j] = r; 375 } 376 } 377 } 378 r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 379 badrate = r; 380 if (flags & IEEE80211_F_DOFRATE) { 381 /* 382 * Check any fixed rate is included. 383 */ 384 if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) 385 fixedrate = r; 386 } 387 if (flags & IEEE80211_F_DONEGO) { 388 /* 389 * Check against supported rates. 390 */ 391 for (j = 0; j < srs->rs_nrates; j++) { 392 if (r == RV(srs->rs_rates[j])) { 393 /* 394 * Overwrite with the supported rate 395 * value so any basic rate bit is set. 396 * This insures that response we send 397 * to stations have the necessary basic 398 * rate bit set. 399 */ 400 nrs->rs_rates[i] = srs->rs_rates[j]; 401 break; 402 } 403 } 404 if (j == srs->rs_nrates) { 405 /* 406 * A rate in the node's rate set is not 407 * supported. If this is a basic rate and we 408 * are operating as an AP then this is an error. 409 * Otherwise we just discard/ignore the rate. 410 * Note that this is important for 11b stations 411 * when they want to associate with an 11g AP. 412 */ 413 #ifndef IEEE80211_NO_HOSTAP 414 if (ic->ic_opmode == IEEE80211_M_HOSTAP && 415 (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 416 error++; 417 #endif /* !IEEE80211_NO_HOSTAP */ 418 ignore++; 419 } 420 } 421 if (flags & IEEE80211_F_DODEL) { 422 /* 423 * Delete unacceptable rates. 424 */ 425 if (ignore) { 426 nrs->rs_nrates--; 427 for (j = i; j < nrs->rs_nrates; j++) 428 nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 429 nrs->rs_rates[j] = 0; 430 continue; 431 } 432 } 433 if (!ignore) { 434 okrate = nrs->rs_rates[i]; 435 ni->ni_txrate = i; 436 } 437 i++; 438 } 439 if (okrate == 0 || error != 0 || 440 ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 441 return badrate | IEEE80211_RATE_BASIC; 442 else 443 return RV(okrate); 444 #undef RV 445 } 446 447 /* 448 * Reset 11g-related state. 449 */ 450 void 451 ieee80211_reset_erp(struct ieee80211com *ic) 452 { 453 ic->ic_flags &= ~IEEE80211_F_USEPROT; 454 ic->ic_nonerpsta = 0; 455 ic->ic_longslotsta = 0; 456 /* 457 * Short slot time is enabled only when operating in 11g 458 * and not in an IBSS. We must also honor whether or not 459 * the driver is capable of doing it. 460 */ 461 ieee80211_set_shortslottime(ic, 462 ic->ic_curmode == IEEE80211_MODE_11A || 463 (ic->ic_curmode == IEEE80211_MODE_11G && 464 ic->ic_opmode == IEEE80211_M_HOSTAP && 465 (ic->ic_caps & IEEE80211_C_SHSLOT))); 466 /* 467 * Set short preamble and ERP barker-preamble flags. 468 */ 469 if (ic->ic_curmode == IEEE80211_MODE_11A || 470 (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 471 ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 472 ic->ic_flags &= ~IEEE80211_F_USEBARKER; 473 } else { 474 ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 475 ic->ic_flags |= IEEE80211_F_USEBARKER; 476 } 477 } 478 479 /* 480 * Set the short slot time state and notify the driver. 481 */ 482 void 483 ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 484 { 485 if (onoff) 486 ic->ic_flags |= IEEE80211_F_SHSLOT; 487 else 488 ic->ic_flags &= ~IEEE80211_F_SHSLOT; 489 /* notify driver */ 490 if (ic->ic_updateslot != NULL) 491 ic->ic_updateslot(ic->ic_ifp); 492 } 493 494 /* 495 * Check if the specified rate set supports ERP. 496 * NB: the rate set is assumed to be sorted. 497 */ 498 int 499 ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs) 500 { 501 #define N(a) (sizeof(a) / sizeof(a[0])) 502 static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 503 int i, j; 504 505 if (rs->rs_nrates < N(rates)) 506 return 0; 507 for (i = 0; i < N(rates); i++) { 508 for (j = 0; j < rs->rs_nrates; j++) { 509 int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 510 if (rates[i] == r) 511 goto next; 512 if (r > rates[i]) 513 return 0; 514 } 515 return 0; 516 next: 517 ; 518 } 519 return 1; 520 #undef N 521 } 522 523 /* 524 * Mark the basic rates for the 11g rate table based on the 525 * operating mode. For real 11g we mark all the 11b rates 526 * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 527 * 11b rates. There's also a pseudo 11a-mode used to mark only 528 * the basic OFDM rates. 529 */ 530 void 531 ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 532 { 533 static const struct ieee80211_rateset basic[] = { 534 { 0 }, /* IEEE80211_MODE_AUTO */ 535 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 536 { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ 537 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */ 538 { 0 }, /* IEEE80211_MODE_FH */ 539 /* IEEE80211_MODE_PUREG (not yet) */ 540 { 7, { 2, 4, 11, 22, 12, 24, 48 } }, 541 }; 542 int i, j; 543 544 for (i = 0; i < rs->rs_nrates; i++) { 545 rs->rs_rates[i] &= IEEE80211_RATE_VAL; 546 for (j = 0; j < basic[mode].rs_nrates; j++) 547 if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 548 rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 549 break; 550 } 551 } 552 } 553 554 /* 555 * WME protocol support. The following parameters come from the spec. 556 */ 557 typedef struct phyParamType { 558 u_int8_t aifsn; 559 u_int8_t logcwmin; 560 u_int8_t logcwmax; 561 u_int16_t txopLimit; 562 u_int8_t acm; 563 } paramType; 564 565 static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 566 { 3, 4, 6 }, /* IEEE80211_MODE_AUTO */ 567 { 3, 4, 6 }, /* IEEE80211_MODE_11A */ 568 { 3, 5, 7 }, /* IEEE80211_MODE_11B */ 569 { 3, 4, 6 }, /* IEEE80211_MODE_11G */ 570 { 3, 5, 7 }, /* IEEE80211_MODE_FH */ 571 { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */ 572 { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */ 573 }; 574 static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 575 { 7, 4, 10 }, /* IEEE80211_MODE_AUTO */ 576 { 7, 4, 10 }, /* IEEE80211_MODE_11A */ 577 { 7, 5, 10 }, /* IEEE80211_MODE_11B */ 578 { 7, 4, 10 }, /* IEEE80211_MODE_11G */ 579 { 7, 5, 10 }, /* IEEE80211_MODE_FH */ 580 { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 581 { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 582 }; 583 static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 584 { 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 585 { 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 586 { 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 587 { 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 588 { 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 589 { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 590 { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 591 }; 592 static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 593 { 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 594 { 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 595 { 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 596 { 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 597 { 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 598 { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 599 { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 600 }; 601 602 static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 603 { 3, 4, 10 }, /* IEEE80211_MODE_AUTO */ 604 { 3, 4, 10 }, /* IEEE80211_MODE_11A */ 605 { 3, 5, 10 }, /* IEEE80211_MODE_11B */ 606 { 3, 4, 10 }, /* IEEE80211_MODE_11G */ 607 { 3, 5, 10 }, /* IEEE80211_MODE_FH */ 608 { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 609 { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 610 }; 611 static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 612 { 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 613 { 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 614 { 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 615 { 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 616 { 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 617 { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 618 { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 619 }; 620 static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 621 { 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 622 { 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 623 { 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 624 { 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 625 { 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 626 { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 627 { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 628 }; 629 630 void 631 ieee80211_wme_initparams(struct ieee80211com *ic) 632 { 633 struct ieee80211_wme_state *wme = &ic->ic_wme; 634 const paramType *pPhyParam, *pBssPhyParam; 635 struct wmeParams *wmep; 636 int i; 637 638 if ((ic->ic_caps & IEEE80211_C_WME) == 0) 639 return; 640 641 for (i = 0; i < WME_NUM_AC; i++) { 642 switch (i) { 643 case WME_AC_BK: 644 pPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 645 pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 646 break; 647 case WME_AC_VI: 648 pPhyParam = &phyParamForAC_VI[ic->ic_curmode]; 649 pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode]; 650 break; 651 case WME_AC_VO: 652 pPhyParam = &phyParamForAC_VO[ic->ic_curmode]; 653 pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode]; 654 break; 655 case WME_AC_BE: 656 default: 657 pPhyParam = &phyParamForAC_BE[ic->ic_curmode]; 658 pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode]; 659 break; 660 } 661 662 wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 663 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 664 wmep->wmep_acm = pPhyParam->acm; 665 wmep->wmep_aifsn = pPhyParam->aifsn; 666 wmep->wmep_logcwmin = pPhyParam->logcwmin; 667 wmep->wmep_logcwmax = pPhyParam->logcwmax; 668 wmep->wmep_txopLimit = pPhyParam->txopLimit; 669 } else { 670 wmep->wmep_acm = pBssPhyParam->acm; 671 wmep->wmep_aifsn = pBssPhyParam->aifsn; 672 wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 673 wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 674 wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 675 676 } 677 IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 678 "%s: %s chan [acm %u aifsn %u log2(cwmin) %u " 679 "log2(cwmax) %u txpoLimit %u]\n", __func__ 680 , ieee80211_wme_acnames[i] 681 , wmep->wmep_acm 682 , wmep->wmep_aifsn 683 , wmep->wmep_logcwmin 684 , wmep->wmep_logcwmax 685 , wmep->wmep_txopLimit 686 ); 687 688 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 689 wmep->wmep_acm = pBssPhyParam->acm; 690 wmep->wmep_aifsn = pBssPhyParam->aifsn; 691 wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 692 wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 693 wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 694 IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 695 "%s: %s bss [acm %u aifsn %u log2(cwmin) %u " 696 "log2(cwmax) %u txpoLimit %u]\n", __func__ 697 , ieee80211_wme_acnames[i] 698 , wmep->wmep_acm 699 , wmep->wmep_aifsn 700 , wmep->wmep_logcwmin 701 , wmep->wmep_logcwmax 702 , wmep->wmep_txopLimit 703 ); 704 } 705 /* NB: check ic_bss to avoid NULL deref on initial attach */ 706 if (ic->ic_bss != NULL) { 707 /* 708 * Calculate agressive mode switching threshold based 709 * on beacon interval. This doesn't need locking since 710 * we're only called before entering the RUN state at 711 * which point we start sending beacon frames. 712 */ 713 wme->wme_hipri_switch_thresh = 714 (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100; 715 ieee80211_wme_updateparams(ic); 716 } 717 } 718 719 /* 720 * Update WME parameters for ourself and the BSS. 721 */ 722 void 723 ieee80211_wme_updateparams_locked(struct ieee80211com *ic) 724 { 725 static const paramType phyParam[IEEE80211_MODE_MAX] = { 726 { 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */ 727 { 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */ 728 { 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */ 729 { 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */ 730 { 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */ 731 { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */ 732 { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */ 733 }; 734 struct ieee80211_wme_state *wme = &ic->ic_wme; 735 const struct wmeParams *wmep; 736 struct wmeParams *chanp, *bssp; 737 int i; 738 739 /* set up the channel access parameters for the physical device */ 740 for (i = 0; i < WME_NUM_AC; i++) { 741 chanp = &wme->wme_chanParams.cap_wmeParams[i]; 742 wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 743 chanp->wmep_aifsn = wmep->wmep_aifsn; 744 chanp->wmep_logcwmin = wmep->wmep_logcwmin; 745 chanp->wmep_logcwmax = wmep->wmep_logcwmax; 746 chanp->wmep_txopLimit = wmep->wmep_txopLimit; 747 748 chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 749 wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 750 chanp->wmep_aifsn = wmep->wmep_aifsn; 751 chanp->wmep_logcwmin = wmep->wmep_logcwmin; 752 chanp->wmep_logcwmax = wmep->wmep_logcwmax; 753 chanp->wmep_txopLimit = wmep->wmep_txopLimit; 754 } 755 756 /* 757 * This implements agressive mode as found in certain 758 * vendors' AP's. When there is significant high 759 * priority (VI/VO) traffic in the BSS throttle back BE 760 * traffic by using conservative parameters. Otherwise 761 * BE uses agressive params to optimize performance of 762 * legacy/non-QoS traffic. 763 */ 764 if ((ic->ic_opmode == IEEE80211_M_HOSTAP && 765 (wme->wme_flags & WME_F_AGGRMODE) == 0) || 766 (ic->ic_opmode != IEEE80211_M_HOSTAP && 767 (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || 768 (ic->ic_flags & IEEE80211_F_WME) == 0) { 769 chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 770 bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 771 772 chanp->wmep_aifsn = bssp->wmep_aifsn = 773 phyParam[ic->ic_curmode].aifsn; 774 chanp->wmep_logcwmin = bssp->wmep_logcwmin = 775 phyParam[ic->ic_curmode].logcwmin; 776 chanp->wmep_logcwmax = bssp->wmep_logcwmax = 777 phyParam[ic->ic_curmode].logcwmax; 778 chanp->wmep_txopLimit = bssp->wmep_txopLimit = 779 (ic->ic_caps & IEEE80211_C_BURST) ? 780 phyParam[ic->ic_curmode].txopLimit : 0; 781 IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 782 "%s: %s [acm %u aifsn %u log2(cwmin) %u " 783 "log2(cwmax) %u txpoLimit %u]\n", __func__ 784 , ieee80211_wme_acnames[WME_AC_BE] 785 , chanp->wmep_acm 786 , chanp->wmep_aifsn 787 , chanp->wmep_logcwmin 788 , chanp->wmep_logcwmax 789 , chanp->wmep_txopLimit 790 ); 791 } 792 793 #ifndef IEEE80211_NO_HOSTAP 794 if (ic->ic_opmode == IEEE80211_M_HOSTAP && 795 ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) == 0) { 796 static const u_int8_t logCwMin[IEEE80211_MODE_MAX] = { 797 3, /* IEEE80211_MODE_AUTO */ 798 3, /* IEEE80211_MODE_11A */ 799 4, /* IEEE80211_MODE_11B */ 800 3, /* IEEE80211_MODE_11G */ 801 4, /* IEEE80211_MODE_FH */ 802 3, /* IEEE80211_MODE_TURBO_A */ 803 3, /* IEEE80211_MODE_TURBO_G */ 804 }; 805 chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 806 bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 807 808 chanp->wmep_logcwmin = bssp->wmep_logcwmin = 809 logCwMin[ic->ic_curmode]; 810 IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 811 "%s: %s log2(cwmin) %u\n", __func__ 812 , ieee80211_wme_acnames[WME_AC_BE] 813 , chanp->wmep_logcwmin 814 ); 815 } 816 if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ 817 /* 818 * Arrange for a beacon update and bump the parameter 819 * set number so associated stations load the new values. 820 */ 821 wme->wme_bssChanParams.cap_info = 822 (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 823 ic->ic_flags |= IEEE80211_F_WMEUPDATE; 824 } 825 #endif /* !IEEE80211_NO_HOSTAP */ 826 827 wme->wme_update(ic); 828 829 IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 830 "%s: WME params updated, cap_info 0x%x\n", __func__, 831 ic->ic_opmode == IEEE80211_M_STA ? 832 wme->wme_wmeChanParams.cap_info : 833 wme->wme_bssChanParams.cap_info); 834 } 835 836 void 837 ieee80211_wme_updateparams(struct ieee80211com *ic) 838 { 839 840 if (ic->ic_caps & IEEE80211_C_WME) { 841 IEEE80211_BEACON_LOCK(ic); 842 ieee80211_wme_updateparams_locked(ic); 843 IEEE80211_BEACON_UNLOCK(ic); 844 } 845 } 846 847 #ifndef IEEE80211_NO_HOSTAP 848 static void 849 sta_disassoc(void *arg, struct ieee80211_node *ni) 850 { 851 struct ieee80211com *ic = arg; 852 853 if (ni->ni_associd != 0) { 854 IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, 855 IEEE80211_REASON_ASSOC_LEAVE); 856 ieee80211_node_leave(ic, ni); 857 } 858 } 859 860 static void 861 sta_deauth(void *arg, struct ieee80211_node *ni) 862 { 863 struct ieee80211com *ic = arg; 864 865 IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, 866 IEEE80211_REASON_ASSOC_LEAVE); 867 } 868 #endif /* !IEEE80211_NO_HOSTAP */ 869 870 static int 871 ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 872 { 873 struct ifnet *ifp = ic->ic_ifp; 874 struct ieee80211_node *ni; 875 enum ieee80211_state ostate; 876 877 ostate = ic->ic_state; 878 IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__, 879 ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 880 ic->ic_state = nstate; /* state transition */ 881 ni = ic->ic_bss; /* NB: no reference held */ 882 switch (nstate) { 883 case IEEE80211_S_INIT: 884 switch (ostate) { 885 case IEEE80211_S_INIT: 886 break; 887 case IEEE80211_S_RUN: 888 switch (ic->ic_opmode) { 889 case IEEE80211_M_STA: 890 IEEE80211_SEND_MGMT(ic, ni, 891 IEEE80211_FC0_SUBTYPE_DISASSOC, 892 IEEE80211_REASON_ASSOC_LEAVE); 893 ieee80211_sta_leave(ic, ni); 894 break; 895 case IEEE80211_M_HOSTAP: 896 #ifndef IEEE80211_NO_HOSTAP 897 ieee80211_iterate_nodes(&ic->ic_sta, 898 sta_disassoc, ic); 899 #endif /* !IEEE80211_NO_HOSTAP */ 900 break; 901 default: 902 break; 903 } 904 goto reset; 905 case IEEE80211_S_ASSOC: 906 switch (ic->ic_opmode) { 907 case IEEE80211_M_STA: 908 IEEE80211_SEND_MGMT(ic, ni, 909 IEEE80211_FC0_SUBTYPE_DEAUTH, 910 IEEE80211_REASON_AUTH_LEAVE); 911 break; 912 case IEEE80211_M_HOSTAP: 913 #ifndef IEEE80211_NO_HOSTAP 914 ieee80211_iterate_nodes(&ic->ic_sta, 915 sta_deauth, ic); 916 #endif /* !IEEE80211_NO_HOSTAP */ 917 break; 918 default: 919 break; 920 } 921 goto reset; 922 case IEEE80211_S_SCAN: 923 ieee80211_cancel_scan(ic); 924 goto reset; 925 case IEEE80211_S_AUTH: 926 reset: 927 ic->ic_mgt_timer = 0; 928 IF_PURGE(&ic->ic_mgtq); 929 ieee80211_reset_bss(ic); 930 break; 931 } 932 if (ic->ic_auth->ia_detach != NULL) 933 ic->ic_auth->ia_detach(ic); 934 break; 935 case IEEE80211_S_SCAN: 936 switch (ostate) { 937 case IEEE80211_S_INIT: 938 if ((ic->ic_opmode == IEEE80211_M_HOSTAP || 939 ic->ic_opmode == IEEE80211_M_IBSS || 940 ic->ic_opmode == IEEE80211_M_AHDEMO) && 941 ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 942 /* 943 * AP operation and we already have a channel; 944 * bypass the scan and startup immediately. 945 */ 946 ieee80211_create_ibss(ic, ic->ic_des_chan); 947 } else { 948 ieee80211_begin_scan(ic, arg); 949 } 950 break; 951 case IEEE80211_S_SCAN: 952 /* 953 * Scan next. If doing an active scan and the 954 * channel is not marked passive-only then send 955 * a probe request. Otherwise just listen for 956 * beacons on the channel. 957 */ 958 if ((ic->ic_flags & IEEE80211_F_ASCAN) && 959 (ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) { 960 ieee80211_send_probereq(ni, 961 ic->ic_myaddr, ifp->if_broadcastaddr, 962 ifp->if_broadcastaddr, 963 ic->ic_des_essid, ic->ic_des_esslen, 964 ic->ic_opt_ie, ic->ic_opt_ie_len); 965 } 966 break; 967 case IEEE80211_S_RUN: 968 /* beacon miss */ 969 IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, 970 "no recent beacons from %s; rescanning\n", 971 ether_sprintf(ic->ic_bss->ni_bssid)); 972 ieee80211_sta_leave(ic, ni); 973 ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */ 974 /* FALLTHRU */ 975 case IEEE80211_S_AUTH: 976 case IEEE80211_S_ASSOC: 977 /* timeout restart scan */ 978 ni = ieee80211_find_node(&ic->ic_scan, 979 ic->ic_bss->ni_macaddr); 980 if (ni != NULL) { 981 ni->ni_fails++; 982 ieee80211_unref_node(&ni); 983 } 984 if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) 985 ieee80211_begin_scan(ic, arg); 986 break; 987 } 988 break; 989 case IEEE80211_S_AUTH: 990 switch (ostate) { 991 case IEEE80211_S_INIT: 992 case IEEE80211_S_SCAN: 993 IEEE80211_SEND_MGMT(ic, ni, 994 IEEE80211_FC0_SUBTYPE_AUTH, 1); 995 break; 996 case IEEE80211_S_AUTH: 997 case IEEE80211_S_ASSOC: 998 switch (arg) { 999 case IEEE80211_FC0_SUBTYPE_AUTH: 1000 /* ??? */ 1001 IEEE80211_SEND_MGMT(ic, ni, 1002 IEEE80211_FC0_SUBTYPE_AUTH, 2); 1003 break; 1004 case IEEE80211_FC0_SUBTYPE_DEAUTH: 1005 /* ignore and retry scan on timeout */ 1006 break; 1007 } 1008 break; 1009 case IEEE80211_S_RUN: 1010 switch (arg) { 1011 case IEEE80211_FC0_SUBTYPE_AUTH: 1012 IEEE80211_SEND_MGMT(ic, ni, 1013 IEEE80211_FC0_SUBTYPE_AUTH, 2); 1014 ic->ic_state = ostate; /* stay RUN */ 1015 break; 1016 case IEEE80211_FC0_SUBTYPE_DEAUTH: 1017 ieee80211_sta_leave(ic, ni); 1018 if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1019 /* try to reauth */ 1020 IEEE80211_SEND_MGMT(ic, ni, 1021 IEEE80211_FC0_SUBTYPE_AUTH, 1); 1022 } 1023 break; 1024 } 1025 break; 1026 } 1027 break; 1028 case IEEE80211_S_ASSOC: 1029 switch (ostate) { 1030 case IEEE80211_S_INIT: 1031 case IEEE80211_S_SCAN: 1032 case IEEE80211_S_ASSOC: 1033 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1034 "%s: invalid transition\n", __func__); 1035 break; 1036 case IEEE80211_S_AUTH: 1037 IEEE80211_SEND_MGMT(ic, ni, 1038 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 1039 break; 1040 case IEEE80211_S_RUN: 1041 ieee80211_sta_leave(ic, ni); 1042 if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 1043 IEEE80211_SEND_MGMT(ic, ni, 1044 IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 1045 } 1046 break; 1047 } 1048 break; 1049 case IEEE80211_S_RUN: 1050 if (ic->ic_flags & IEEE80211_F_WPA) { 1051 /* XXX validate prerequisites */ 1052 } 1053 switch (ostate) { 1054 case IEEE80211_S_INIT: 1055 if (ic->ic_opmode == IEEE80211_M_MONITOR) 1056 break; 1057 /* fall thru... */ 1058 case IEEE80211_S_AUTH: 1059 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 1060 "%s: invalid transition\n", __func__); 1061 /* fall thru... */ 1062 case IEEE80211_S_RUN: 1063 break; 1064 case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 1065 case IEEE80211_S_ASSOC: /* infra mode */ 1066 IASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 1067 ("%s: bogus xmit rate %u setup\n", __func__, 1068 ni->ni_txrate)); 1069 #ifdef IEEE80211_DEBUG 1070 if (ieee80211_msg_debug(ic)) { 1071 if (ic->ic_opmode == IEEE80211_M_STA) 1072 if_printf(ifp, "associated "); 1073 else 1074 if_printf(ifp, "synchronized "); 1075 printf("with %s ssid ", 1076 ether_sprintf(ni->ni_bssid)); 1077 ieee80211_print_essid(ic->ic_bss->ni_essid, 1078 ni->ni_esslen); 1079 printf(" channel %d start %uMb\n", 1080 ieee80211_chan2ieee(ic, ic->ic_curchan), 1081 IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 1082 } 1083 #endif 1084 ic->ic_mgt_timer = 0; 1085 if (ic->ic_opmode == IEEE80211_M_STA) 1086 ieee80211_notify_node_join(ic, ni, 1087 arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 1088 (*ifp->if_start)(ifp); /* XXX not authorized yet */ 1089 break; 1090 } 1091 /* 1092 * Start/stop the authenticator when operating as an 1093 * AP. We delay until here to allow configuration to 1094 * happen out of order. 1095 */ 1096 if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ 1097 ic->ic_auth->ia_attach != NULL) { 1098 /* XXX check failure */ 1099 ic->ic_auth->ia_attach(ic); 1100 } else if (ic->ic_auth->ia_detach != NULL) { 1101 ic->ic_auth->ia_detach(ic); 1102 } 1103 /* 1104 * When 802.1x is not in use mark the port authorized 1105 * at this point so traffic can flow. 1106 */ 1107 if (ni->ni_authmode != IEEE80211_AUTH_8021X) 1108 ieee80211_node_authorize(ni); 1109 /* 1110 * Enable inactivity processing. 1111 * XXX 1112 */ 1113 ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 1114 ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT; 1115 break; 1116 } 1117 return 0; 1118 } 1119