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