11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 38a1b9b6aSSam Leffler * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting 41a1e1d21SSam Leffler * All rights reserved. 51a1e1d21SSam Leffler * 61a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 71a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 81a1e1d21SSam Leffler * are met: 91a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 107535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 117535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 137535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 147535e66aSSam Leffler * 3. The name of the author may not be used to endorse or promote products 157535e66aSSam Leffler * derived from this software without specific prior written permission. 161a1e1d21SSam Leffler * 171a1e1d21SSam Leffler * Alternatively, this software may be distributed under the terms of the 181a1e1d21SSam Leffler * GNU General Public License ("GPL") version 2 as published by the Free 191a1e1d21SSam Leffler * Software Foundation. 201a1e1d21SSam Leffler * 217535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 227535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 237535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 247535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 257535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 267535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 277535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 287535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 297535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 307535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 311a1e1d21SSam Leffler */ 321a1e1d21SSam Leffler 331a1e1d21SSam Leffler #include <sys/cdefs.h> 341a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 351a1e1d21SSam Leffler 361a1e1d21SSam Leffler /* 371a1e1d21SSam Leffler * IEEE 802.11 protocol support. 381a1e1d21SSam Leffler */ 391a1e1d21SSam Leffler 401a1e1d21SSam Leffler #include "opt_inet.h" 411a1e1d21SSam Leffler 421a1e1d21SSam Leffler #include <sys/param.h> 431a1e1d21SSam Leffler #include <sys/kernel.h> 448a1b9b6aSSam Leffler #include <sys/systm.h> 451a1e1d21SSam Leffler 468a1b9b6aSSam Leffler #include <sys/socket.h> 471a1e1d21SSam Leffler 481a1e1d21SSam Leffler #include <net/if.h> 491a1e1d21SSam Leffler #include <net/if_media.h> 508a1b9b6aSSam Leffler #include <net/ethernet.h> /* XXX for ether_sprintf */ 511a1e1d21SSam Leffler 521a1e1d21SSam Leffler #include <net80211/ieee80211_var.h> 531a1e1d21SSam Leffler 548a1b9b6aSSam Leffler /* XXX tunables */ 558a1b9b6aSSam Leffler #define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */ 568a1b9b6aSSam Leffler #define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */ 571a1e1d21SSam Leffler 581a1e1d21SSam Leffler #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 591a1e1d21SSam Leffler 601a1e1d21SSam Leffler const char *ieee80211_mgt_subtype_name[] = { 611a1e1d21SSam Leffler "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 621a1e1d21SSam Leffler "probe_req", "probe_resp", "reserved#6", "reserved#7", 631a1e1d21SSam Leffler "beacon", "atim", "disassoc", "auth", 641a1e1d21SSam Leffler "deauth", "reserved#13", "reserved#14", "reserved#15" 651a1e1d21SSam Leffler }; 668a1b9b6aSSam Leffler const char *ieee80211_ctl_subtype_name[] = { 678a1b9b6aSSam Leffler "reserved#0", "reserved#1", "reserved#2", "reserved#3", 688a1b9b6aSSam Leffler "reserved#3", "reserved#5", "reserved#6", "reserved#7", 698a1b9b6aSSam Leffler "reserved#8", "reserved#9", "ps_poll", "rts", 708a1b9b6aSSam Leffler "cts", "ack", "cf_end", "cf_end_ack" 718a1b9b6aSSam Leffler }; 72a11c9a5cSSam Leffler const char *ieee80211_state_name[IEEE80211_S_MAX] = { 73a11c9a5cSSam Leffler "INIT", /* IEEE80211_S_INIT */ 74a11c9a5cSSam Leffler "SCAN", /* IEEE80211_S_SCAN */ 75a11c9a5cSSam Leffler "AUTH", /* IEEE80211_S_AUTH */ 76a11c9a5cSSam Leffler "ASSOC", /* IEEE80211_S_ASSOC */ 77a11c9a5cSSam Leffler "RUN" /* IEEE80211_S_RUN */ 78a11c9a5cSSam Leffler }; 798a1b9b6aSSam Leffler const char *ieee80211_wme_acnames[] = { 808a1b9b6aSSam Leffler "WME_AC_BE", 818a1b9b6aSSam Leffler "WME_AC_BK", 828a1b9b6aSSam Leffler "WME_AC_VI", 838a1b9b6aSSam Leffler "WME_AC_VO", 848a1b9b6aSSam Leffler "WME_UPSD", 858a1b9b6aSSam Leffler }; 86a11c9a5cSSam Leffler 87a11c9a5cSSam Leffler static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 881a1e1d21SSam Leffler 891a1e1d21SSam Leffler void 908a1b9b6aSSam Leffler ieee80211_proto_attach(struct ieee80211com *ic) 911a1e1d21SSam Leffler { 928a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 931a1e1d21SSam Leffler 948a1b9b6aSSam Leffler /* XXX room for crypto */ 958a1b9b6aSSam Leffler ifp->if_hdrlen = sizeof(struct ieee80211_qosframe_addr4); 961a1e1d21SSam Leffler 971a1e1d21SSam Leffler #ifdef notdef 981a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 991a1e1d21SSam Leffler #else 1001a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 1011a1e1d21SSam Leffler #endif 1021a1e1d21SSam Leffler ic->ic_fragthreshold = 2346; /* XXX not used yet */ 1031a1e1d21SSam Leffler ic->ic_fixed_rate = -1; /* no fixed rate */ 1042e79ca97SSam Leffler ic->ic_protmode = IEEE80211_PROT_CTSONLY; 1058a1b9b6aSSam Leffler ic->ic_roaming = IEEE80211_ROAMING_AUTO; 1068a1b9b6aSSam Leffler 1078a1b9b6aSSam Leffler ic->ic_wme.wme_hipri_switch_hysteresis = 1088a1b9b6aSSam Leffler AGGRESSIVE_MODE_SWITCH_HYSTERESIS; 1091a1e1d21SSam Leffler 1109bf40edeSBrooks Davis mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_xname, "mgmt send q", MTX_DEF); 1111a1e1d21SSam Leffler 112a11c9a5cSSam Leffler /* protocol state change handler */ 113a11c9a5cSSam Leffler ic->ic_newstate = ieee80211_newstate; 114a11c9a5cSSam Leffler 1151a1e1d21SSam Leffler /* initialize management frame handlers */ 1161a1e1d21SSam Leffler ic->ic_recv_mgmt = ieee80211_recv_mgmt; 1171a1e1d21SSam Leffler ic->ic_send_mgmt = ieee80211_send_mgmt; 1181a1e1d21SSam Leffler } 1191a1e1d21SSam Leffler 1201a1e1d21SSam Leffler void 1218a1b9b6aSSam Leffler ieee80211_proto_detach(struct ieee80211com *ic) 1221a1e1d21SSam Leffler { 1238a1b9b6aSSam Leffler 1248a1b9b6aSSam Leffler /* 1258a1b9b6aSSam Leffler * This should not be needed as we detach when reseting 1268a1b9b6aSSam Leffler * the state but be conservative here since the 1278a1b9b6aSSam Leffler * authenticator may do things like spawn kernel threads. 1288a1b9b6aSSam Leffler */ 1298a1b9b6aSSam Leffler if (ic->ic_auth->ia_detach) 1308a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 1311a1e1d21SSam Leffler 1321a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 1331a1e1d21SSam Leffler mtx_destroy(&ic->ic_mgtq.ifq_mtx); 1348a1b9b6aSSam Leffler 1358a1b9b6aSSam Leffler /* 1368a1b9b6aSSam Leffler * Detach any ACL'ator. 1378a1b9b6aSSam Leffler */ 1388a1b9b6aSSam Leffler if (ic->ic_acl != NULL) 1398a1b9b6aSSam Leffler ic->ic_acl->iac_detach(ic); 1408a1b9b6aSSam Leffler } 1418a1b9b6aSSam Leffler 1428a1b9b6aSSam Leffler /* 1438a1b9b6aSSam Leffler * Simple-minded authenticator module support. 1448a1b9b6aSSam Leffler */ 1458a1b9b6aSSam Leffler 1468a1b9b6aSSam Leffler #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 1478a1b9b6aSSam Leffler /* XXX well-known names */ 1488a1b9b6aSSam Leffler static const char *auth_modnames[IEEE80211_AUTH_MAX] = { 1498a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_NONE */ 1508a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_OPEN */ 1518a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_SHARED */ 1528a1b9b6aSSam Leffler "wlan_xauth", /* IEEE80211_AUTH_8021X */ 1538a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_AUTO */ 1548a1b9b6aSSam Leffler "wlan_xauth", /* IEEE80211_AUTH_WPA */ 1558a1b9b6aSSam Leffler }; 1568a1b9b6aSSam Leffler static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 1578a1b9b6aSSam Leffler 1588a1b9b6aSSam Leffler static const struct ieee80211_authenticator auth_internal = { 1598a1b9b6aSSam Leffler .ia_name = "wlan_internal", 1608a1b9b6aSSam Leffler .ia_attach = NULL, 1618a1b9b6aSSam Leffler .ia_detach = NULL, 1628a1b9b6aSSam Leffler .ia_node_join = NULL, 1638a1b9b6aSSam Leffler .ia_node_leave = NULL, 1648a1b9b6aSSam Leffler }; 1658a1b9b6aSSam Leffler 1668a1b9b6aSSam Leffler /* 1678a1b9b6aSSam Leffler * Setup internal authenticators once; they are never unregistered. 1688a1b9b6aSSam Leffler */ 1698a1b9b6aSSam Leffler static void 1708a1b9b6aSSam Leffler ieee80211_auth_setup(void) 1718a1b9b6aSSam Leffler { 1728a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 1738a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 1748a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 1758a1b9b6aSSam Leffler } 1768a1b9b6aSSam Leffler SYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL); 1778a1b9b6aSSam Leffler 1788a1b9b6aSSam Leffler const struct ieee80211_authenticator * 1798a1b9b6aSSam Leffler ieee80211_authenticator_get(int auth) 1808a1b9b6aSSam Leffler { 1818a1b9b6aSSam Leffler if (auth >= IEEE80211_AUTH_MAX) 1828a1b9b6aSSam Leffler return NULL; 1838a1b9b6aSSam Leffler if (authenticators[auth] == NULL) 1848a1b9b6aSSam Leffler ieee80211_load_module(auth_modnames[auth]); 1858a1b9b6aSSam Leffler return authenticators[auth]; 1861a1e1d21SSam Leffler } 1871a1e1d21SSam Leffler 1881a1e1d21SSam Leffler void 1898a1b9b6aSSam Leffler ieee80211_authenticator_register(int type, 1908a1b9b6aSSam Leffler const struct ieee80211_authenticator *auth) 1911a1e1d21SSam Leffler { 1928a1b9b6aSSam Leffler if (type >= IEEE80211_AUTH_MAX) 1938a1b9b6aSSam Leffler return; 1948a1b9b6aSSam Leffler authenticators[type] = auth; 1958a1b9b6aSSam Leffler } 1968a1b9b6aSSam Leffler 1978a1b9b6aSSam Leffler void 1988a1b9b6aSSam Leffler ieee80211_authenticator_unregister(int type) 1998a1b9b6aSSam Leffler { 2008a1b9b6aSSam Leffler 2018a1b9b6aSSam Leffler if (type >= IEEE80211_AUTH_MAX) 2028a1b9b6aSSam Leffler return; 2038a1b9b6aSSam Leffler authenticators[type] = NULL; 2048a1b9b6aSSam Leffler } 2058a1b9b6aSSam Leffler 2068a1b9b6aSSam Leffler /* 2078a1b9b6aSSam Leffler * Very simple-minded ACL module support. 2088a1b9b6aSSam Leffler */ 2098a1b9b6aSSam Leffler /* XXX just one for now */ 2108a1b9b6aSSam Leffler static const struct ieee80211_aclator *acl = NULL; 2118a1b9b6aSSam Leffler 2128a1b9b6aSSam Leffler void 2138a1b9b6aSSam Leffler ieee80211_aclator_register(const struct ieee80211_aclator *iac) 2148a1b9b6aSSam Leffler { 2158a1b9b6aSSam Leffler printf("wlan: %s acl policy registered\n", iac->iac_name); 2168a1b9b6aSSam Leffler acl = iac; 2178a1b9b6aSSam Leffler } 2188a1b9b6aSSam Leffler 2198a1b9b6aSSam Leffler void 2208a1b9b6aSSam Leffler ieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 2218a1b9b6aSSam Leffler { 2228a1b9b6aSSam Leffler if (acl == iac) 2238a1b9b6aSSam Leffler acl = NULL; 2248a1b9b6aSSam Leffler printf("wlan: %s acl policy unregistered\n", iac->iac_name); 2258a1b9b6aSSam Leffler } 2268a1b9b6aSSam Leffler 2278a1b9b6aSSam Leffler const struct ieee80211_aclator * 2288a1b9b6aSSam Leffler ieee80211_aclator_get(const char *name) 2298a1b9b6aSSam Leffler { 2308a1b9b6aSSam Leffler if (acl == NULL) 2318a1b9b6aSSam Leffler ieee80211_load_module("wlan_acl"); 2328a1b9b6aSSam Leffler return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 2338a1b9b6aSSam Leffler } 2348a1b9b6aSSam Leffler 2358a1b9b6aSSam Leffler void 2368a1b9b6aSSam Leffler ieee80211_print_essid(const u_int8_t *essid, int len) 2378a1b9b6aSSam Leffler { 2388a1b9b6aSSam Leffler const u_int8_t *p; 2391a1e1d21SSam Leffler int i; 2401a1e1d21SSam Leffler 2411a1e1d21SSam Leffler if (len > IEEE80211_NWID_LEN) 2421a1e1d21SSam Leffler len = IEEE80211_NWID_LEN; 2431a1e1d21SSam Leffler /* determine printable or not */ 2441a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) { 2451a1e1d21SSam Leffler if (*p < ' ' || *p > 0x7e) 2461a1e1d21SSam Leffler break; 2471a1e1d21SSam Leffler } 2481a1e1d21SSam Leffler if (i == len) { 2491a1e1d21SSam Leffler printf("\""); 2501a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 2511a1e1d21SSam Leffler printf("%c", *p); 2521a1e1d21SSam Leffler printf("\""); 2531a1e1d21SSam Leffler } else { 2541a1e1d21SSam Leffler printf("0x"); 2551a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 2561a1e1d21SSam Leffler printf("%02x", *p); 2571a1e1d21SSam Leffler } 2581a1e1d21SSam Leffler } 2591a1e1d21SSam Leffler 2601a1e1d21SSam Leffler void 2618a1b9b6aSSam Leffler ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi) 2621a1e1d21SSam Leffler { 2638a1b9b6aSSam Leffler const struct ieee80211_frame *wh; 2641a1e1d21SSam Leffler int i; 2651a1e1d21SSam Leffler 2668a1b9b6aSSam Leffler wh = (const struct ieee80211_frame *)buf; 2671a1e1d21SSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 2681a1e1d21SSam Leffler case IEEE80211_FC1_DIR_NODS: 2691a1e1d21SSam Leffler printf("NODS %s", ether_sprintf(wh->i_addr2)); 2701a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 2711a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr3)); 2721a1e1d21SSam Leffler break; 2731a1e1d21SSam Leffler case IEEE80211_FC1_DIR_TODS: 2741a1e1d21SSam Leffler printf("TODS %s", ether_sprintf(wh->i_addr2)); 2751a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 2761a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr1)); 2771a1e1d21SSam Leffler break; 2781a1e1d21SSam Leffler case IEEE80211_FC1_DIR_FROMDS: 2791a1e1d21SSam Leffler printf("FRDS %s", ether_sprintf(wh->i_addr3)); 2801a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 2811a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr2)); 2821a1e1d21SSam Leffler break; 2831a1e1d21SSam Leffler case IEEE80211_FC1_DIR_DSTODS: 2848a1b9b6aSSam Leffler printf("DSDS %s", ether_sprintf((const u_int8_t *)&wh[1])); 2851a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 2861a1e1d21SSam Leffler printf("(%s", ether_sprintf(wh->i_addr2)); 2871a1e1d21SSam Leffler printf("->%s)", ether_sprintf(wh->i_addr1)); 2881a1e1d21SSam Leffler break; 2891a1e1d21SSam Leffler } 2901a1e1d21SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 2911a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_DATA: 2921a1e1d21SSam Leffler printf(" data"); 2931a1e1d21SSam Leffler break; 2941a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_MGT: 2951a1e1d21SSam Leffler printf(" %s", ieee80211_mgt_subtype_name[ 2961a1e1d21SSam Leffler (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 2971a1e1d21SSam Leffler >> IEEE80211_FC0_SUBTYPE_SHIFT]); 2981a1e1d21SSam Leffler break; 2991a1e1d21SSam Leffler default: 3001a1e1d21SSam Leffler printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 3011a1e1d21SSam Leffler break; 3021a1e1d21SSam Leffler } 3038a1b9b6aSSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 3048a1b9b6aSSam Leffler int i; 3058a1b9b6aSSam Leffler printf(" WEP [IV"); 3068a1b9b6aSSam Leffler for (i = 0; i < IEEE80211_WEP_IVLEN; i++) 3078a1b9b6aSSam Leffler printf(" %.02x", buf[sizeof(*wh)+i]); 3088a1b9b6aSSam Leffler printf(" KID %u]", buf[sizeof(*wh)+i] >> 6); 3098a1b9b6aSSam Leffler } 3101a1e1d21SSam Leffler if (rate >= 0) 3111a1e1d21SSam Leffler printf(" %dM", rate / 2); 3121a1e1d21SSam Leffler if (rssi >= 0) 3131a1e1d21SSam Leffler printf(" +%d", rssi); 3141a1e1d21SSam Leffler printf("\n"); 3151a1e1d21SSam Leffler if (len > 0) { 3161a1e1d21SSam Leffler for (i = 0; i < len; i++) { 3171a1e1d21SSam Leffler if ((i & 1) == 0) 3181a1e1d21SSam Leffler printf(" "); 3191a1e1d21SSam Leffler printf("%02x", buf[i]); 3201a1e1d21SSam Leffler } 3211a1e1d21SSam Leffler printf("\n"); 3221a1e1d21SSam Leffler } 3231a1e1d21SSam Leffler } 3241a1e1d21SSam Leffler 3251a1e1d21SSam Leffler int 3261a1e1d21SSam Leffler ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 3271a1e1d21SSam Leffler { 3281a1e1d21SSam Leffler #define RV(v) ((v) & IEEE80211_RATE_VAL) 3291a1e1d21SSam Leffler int i, j, ignore, error; 3308a1b9b6aSSam Leffler int okrate, badrate, fixedrate; 3311a1e1d21SSam Leffler struct ieee80211_rateset *srs, *nrs; 3321a1e1d21SSam Leffler u_int8_t r; 3331a1e1d21SSam Leffler 3348a1b9b6aSSam Leffler /* 3358a1b9b6aSSam Leffler * If the fixed rate check was requested but no 3368a1b9b6aSSam Leffler * fixed has been defined then just remove it. 3378a1b9b6aSSam Leffler */ 3388a1b9b6aSSam Leffler if ((flags & IEEE80211_F_DOFRATE) && ic->ic_fixed_rate < 0) 3398a1b9b6aSSam Leffler flags &= ~IEEE80211_F_DOFRATE; 3401a1e1d21SSam Leffler error = 0; 3418a1b9b6aSSam Leffler okrate = badrate = fixedrate = 0; 3421a1e1d21SSam Leffler srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 3431a1e1d21SSam Leffler nrs = &ni->ni_rates; 344ef39d4beSSam Leffler for (i = 0; i < nrs->rs_nrates; ) { 3451a1e1d21SSam Leffler ignore = 0; 3461a1e1d21SSam Leffler if (flags & IEEE80211_F_DOSORT) { 3471a1e1d21SSam Leffler /* 3481a1e1d21SSam Leffler * Sort rates. 3491a1e1d21SSam Leffler */ 3501a1e1d21SSam Leffler for (j = i + 1; j < nrs->rs_nrates; j++) { 3511a1e1d21SSam Leffler if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 3521a1e1d21SSam Leffler r = nrs->rs_rates[i]; 3531a1e1d21SSam Leffler nrs->rs_rates[i] = nrs->rs_rates[j]; 3541a1e1d21SSam Leffler nrs->rs_rates[j] = r; 3551a1e1d21SSam Leffler } 3561a1e1d21SSam Leffler } 3571a1e1d21SSam Leffler } 3581a1e1d21SSam Leffler r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 3591a1e1d21SSam Leffler badrate = r; 3601a1e1d21SSam Leffler if (flags & IEEE80211_F_DOFRATE) { 3611a1e1d21SSam Leffler /* 3628a1b9b6aSSam Leffler * Check any fixed rate is included. 3631a1e1d21SSam Leffler */ 3648a1b9b6aSSam Leffler if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) 3658a1b9b6aSSam Leffler fixedrate = r; 3661a1e1d21SSam Leffler } 3671a1e1d21SSam Leffler if (flags & IEEE80211_F_DONEGO) { 3681a1e1d21SSam Leffler /* 3691a1e1d21SSam Leffler * Check against supported rates. 3701a1e1d21SSam Leffler */ 3711a1e1d21SSam Leffler for (j = 0; j < srs->rs_nrates; j++) { 372fce2da8bSSam Leffler if (r == RV(srs->rs_rates[j])) { 373fce2da8bSSam Leffler /* 374fce2da8bSSam Leffler * Overwrite with the supported rate 375fce2da8bSSam Leffler * value so any basic rate bit is set. 376fce2da8bSSam Leffler * This insures that response we send 377fce2da8bSSam Leffler * to stations have the necessary basic 378fce2da8bSSam Leffler * rate bit set. 379fce2da8bSSam Leffler */ 380fce2da8bSSam Leffler nrs->rs_rates[i] = srs->rs_rates[j]; 3811a1e1d21SSam Leffler break; 3821a1e1d21SSam Leffler } 383fce2da8bSSam Leffler } 3841a1e1d21SSam Leffler if (j == srs->rs_nrates) { 385ef39d4beSSam Leffler /* 386ef39d4beSSam Leffler * A rate in the node's rate set is not 387ef39d4beSSam Leffler * supported. If this is a basic rate and we 388ef39d4beSSam Leffler * are operating as an AP then this is an error. 389ef39d4beSSam Leffler * Otherwise we just discard/ignore the rate. 390ef39d4beSSam Leffler * Note that this is important for 11b stations 391ef39d4beSSam Leffler * when they want to associate with an 11g AP. 392ef39d4beSSam Leffler */ 393ef39d4beSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 394ef39d4beSSam Leffler (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 3951a1e1d21SSam Leffler error++; 3961a1e1d21SSam Leffler ignore++; 3971a1e1d21SSam Leffler } 3981a1e1d21SSam Leffler } 3991a1e1d21SSam Leffler if (flags & IEEE80211_F_DODEL) { 4001a1e1d21SSam Leffler /* 4011a1e1d21SSam Leffler * Delete unacceptable rates. 4021a1e1d21SSam Leffler */ 4031a1e1d21SSam Leffler if (ignore) { 4041a1e1d21SSam Leffler nrs->rs_nrates--; 4051a1e1d21SSam Leffler for (j = i; j < nrs->rs_nrates; j++) 4061a1e1d21SSam Leffler nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 4071a1e1d21SSam Leffler nrs->rs_rates[j] = 0; 4081a1e1d21SSam Leffler continue; 4091a1e1d21SSam Leffler } 4101a1e1d21SSam Leffler } 4111a1e1d21SSam Leffler if (!ignore) 4121a1e1d21SSam Leffler okrate = nrs->rs_rates[i]; 4131a1e1d21SSam Leffler i++; 4141a1e1d21SSam Leffler } 4158a1b9b6aSSam Leffler if (okrate == 0 || error != 0 || 4168a1b9b6aSSam Leffler ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 4171a1e1d21SSam Leffler return badrate | IEEE80211_RATE_BASIC; 4181a1e1d21SSam Leffler else 4191a1e1d21SSam Leffler return RV(okrate); 4201a1e1d21SSam Leffler #undef RV 4211a1e1d21SSam Leffler } 4221a1e1d21SSam Leffler 4238a1b9b6aSSam Leffler /* 4248a1b9b6aSSam Leffler * Reset 11g-related state. 4258a1b9b6aSSam Leffler */ 4268a1b9b6aSSam Leffler void 4278a1b9b6aSSam Leffler ieee80211_reset_erp(struct ieee80211com *ic) 4281a1e1d21SSam Leffler { 4298a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_USEPROT; 4308a1b9b6aSSam Leffler ic->ic_nonerpsta = 0; 4318a1b9b6aSSam Leffler ic->ic_longslotsta = 0; 4328a1b9b6aSSam Leffler /* 4338a1b9b6aSSam Leffler * Short slot time is enabled only when operating in 11g 4348a1b9b6aSSam Leffler * and not in an IBSS. We must also honor whether or not 4358a1b9b6aSSam Leffler * the driver is capable of doing it. 4368a1b9b6aSSam Leffler */ 4378a1b9b6aSSam Leffler ieee80211_set_shortslottime(ic, 4388a1b9b6aSSam Leffler ic->ic_curmode == IEEE80211_MODE_11A || 4398a1b9b6aSSam Leffler (ic->ic_curmode == IEEE80211_MODE_11G && 4408a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_HOSTAP && 4418a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT))); 4428a1b9b6aSSam Leffler /* 4438a1b9b6aSSam Leffler * Set short preamble and ERP barker-preamble flags. 4448a1b9b6aSSam Leffler */ 4458a1b9b6aSSam Leffler if (ic->ic_curmode == IEEE80211_MODE_11A || 4468a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 4478a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 4488a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_USEBARKER; 4498a1b9b6aSSam Leffler } else { 4508a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 4518a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_USEBARKER; 4528a1b9b6aSSam Leffler } 4538a1b9b6aSSam Leffler } 4548a1b9b6aSSam Leffler 4558a1b9b6aSSam Leffler /* 4568a1b9b6aSSam Leffler * Set the short slot time state and notify the driver. 4578a1b9b6aSSam Leffler */ 4588a1b9b6aSSam Leffler void 4598a1b9b6aSSam Leffler ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 4608a1b9b6aSSam Leffler { 4618a1b9b6aSSam Leffler if (onoff) 4628a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_SHSLOT; 4638a1b9b6aSSam Leffler else 4648a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SHSLOT; 4658a1b9b6aSSam Leffler /* notify driver */ 4668a1b9b6aSSam Leffler if (ic->ic_updateslot != NULL) 4678a1b9b6aSSam Leffler ic->ic_updateslot(ic->ic_ifp); 4688a1b9b6aSSam Leffler } 4698a1b9b6aSSam Leffler 4708a1b9b6aSSam Leffler /* 4718a1b9b6aSSam Leffler * Check if the specified rate set supports ERP. 4728a1b9b6aSSam Leffler * NB: the rate set is assumed to be sorted. 4738a1b9b6aSSam Leffler */ 4748a1b9b6aSSam Leffler int 4758a1b9b6aSSam Leffler ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs) 4768a1b9b6aSSam Leffler { 4778a1b9b6aSSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 4788a1b9b6aSSam Leffler static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 4798a1b9b6aSSam Leffler int i, j; 4808a1b9b6aSSam Leffler 4818a1b9b6aSSam Leffler if (rs->rs_nrates < N(rates)) 4828a1b9b6aSSam Leffler return 0; 4838a1b9b6aSSam Leffler for (i = 0; i < N(rates); i++) { 4848a1b9b6aSSam Leffler for (j = 0; j < rs->rs_nrates; j++) { 4858a1b9b6aSSam Leffler int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 4868a1b9b6aSSam Leffler if (rates[i] == r) 4878a1b9b6aSSam Leffler goto next; 4888a1b9b6aSSam Leffler if (r > rates[i]) 4898a1b9b6aSSam Leffler return 0; 4908a1b9b6aSSam Leffler } 4918a1b9b6aSSam Leffler return 0; 4928a1b9b6aSSam Leffler next: 4938a1b9b6aSSam Leffler ; 4948a1b9b6aSSam Leffler } 4958a1b9b6aSSam Leffler return 1; 4968a1b9b6aSSam Leffler #undef N 4978a1b9b6aSSam Leffler } 4988a1b9b6aSSam Leffler 4998a1b9b6aSSam Leffler /* 5008a1b9b6aSSam Leffler * Mark the basic rates for the 11g rate table based on the 5018a1b9b6aSSam Leffler * operating mode. For real 11g we mark all the 11b rates 5028a1b9b6aSSam Leffler * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 5038a1b9b6aSSam Leffler * 11b rates. There's also a pseudo 11a-mode used to mark only 5048a1b9b6aSSam Leffler * the basic OFDM rates. 5058a1b9b6aSSam Leffler */ 5068a1b9b6aSSam Leffler void 5078a1b9b6aSSam Leffler ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 5088a1b9b6aSSam Leffler { 5098a1b9b6aSSam Leffler static const struct ieee80211_rateset basic[] = { 5108a1b9b6aSSam Leffler { 0 }, /* IEEE80211_MODE_AUTO */ 5118a1b9b6aSSam Leffler { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 5128a1b9b6aSSam Leffler { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ 5138a1b9b6aSSam Leffler { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */ 5148a1b9b6aSSam Leffler { 0 }, /* IEEE80211_MODE_FH */ 5158a1b9b6aSSam Leffler /* IEEE80211_MODE_PUREG (not yet) */ 5168a1b9b6aSSam Leffler { 7, { 2, 4, 11, 22, 12, 24, 48 } }, 5178a1b9b6aSSam Leffler }; 5188a1b9b6aSSam Leffler int i, j; 5198a1b9b6aSSam Leffler 5208a1b9b6aSSam Leffler for (i = 0; i < rs->rs_nrates; i++) { 5218a1b9b6aSSam Leffler rs->rs_rates[i] &= IEEE80211_RATE_VAL; 5228a1b9b6aSSam Leffler for (j = 0; j < basic[mode].rs_nrates; j++) 5238a1b9b6aSSam Leffler if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 5248a1b9b6aSSam Leffler rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 5258a1b9b6aSSam Leffler break; 5268a1b9b6aSSam Leffler } 5278a1b9b6aSSam Leffler } 5288a1b9b6aSSam Leffler } 5298a1b9b6aSSam Leffler 5308a1b9b6aSSam Leffler /* 5318a1b9b6aSSam Leffler * WME protocol support. The following parameters come from the spec. 5328a1b9b6aSSam Leffler */ 5338a1b9b6aSSam Leffler typedef struct phyParamType { 5348a1b9b6aSSam Leffler u_int8_t aifsn; 5358a1b9b6aSSam Leffler u_int8_t logcwmin; 5368a1b9b6aSSam Leffler u_int8_t logcwmax; 5378a1b9b6aSSam Leffler u_int16_t txopLimit; 5388a1b9b6aSSam Leffler u_int8_t acm; 5398a1b9b6aSSam Leffler } paramType; 5408a1b9b6aSSam Leffler 5418a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 5428a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_AUTO */ 5438a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_11A */ 5448a1b9b6aSSam Leffler { 3, 5, 7 }, /* IEEE80211_MODE_11B */ 5458a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_11G */ 5468a1b9b6aSSam Leffler { 3, 5, 7 }, /* IEEE80211_MODE_FH */ 5478a1b9b6aSSam Leffler { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */ 5488a1b9b6aSSam Leffler { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */ 5498a1b9b6aSSam Leffler }; 5508a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 5518a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_AUTO */ 5528a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_11A */ 5538a1b9b6aSSam Leffler { 7, 5, 10 }, /* IEEE80211_MODE_11B */ 5548a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_11G */ 5558a1b9b6aSSam Leffler { 7, 5, 10 }, /* IEEE80211_MODE_FH */ 5568a1b9b6aSSam Leffler { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 5578a1b9b6aSSam Leffler { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 5588a1b9b6aSSam Leffler }; 5598a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 5608a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 5618a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 5628a1b9b6aSSam Leffler { 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 5638a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 5648a1b9b6aSSam Leffler { 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 5658a1b9b6aSSam Leffler { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 5668a1b9b6aSSam Leffler { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 5678a1b9b6aSSam Leffler }; 5688a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 5698a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 5708a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 5718a1b9b6aSSam Leffler { 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 5728a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 5738a1b9b6aSSam Leffler { 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 5748a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 5758a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 5768a1b9b6aSSam Leffler }; 5778a1b9b6aSSam Leffler 5788a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 5798a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_AUTO */ 5808a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_11A */ 5818a1b9b6aSSam Leffler { 3, 5, 10 }, /* IEEE80211_MODE_11B */ 5828a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_11G */ 5838a1b9b6aSSam Leffler { 3, 5, 10 }, /* IEEE80211_MODE_FH */ 5848a1b9b6aSSam Leffler { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 5858a1b9b6aSSam Leffler { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 5868a1b9b6aSSam Leffler }; 5878a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 5888a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 5898a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 5908a1b9b6aSSam Leffler { 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 5918a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 5928a1b9b6aSSam Leffler { 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 5938a1b9b6aSSam Leffler { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 5948a1b9b6aSSam Leffler { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 5958a1b9b6aSSam Leffler }; 5968a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 5978a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 5988a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 5998a1b9b6aSSam Leffler { 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 6008a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 6018a1b9b6aSSam Leffler { 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 6028a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 6038a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 6048a1b9b6aSSam Leffler }; 6058a1b9b6aSSam Leffler 6068a1b9b6aSSam Leffler void 6078a1b9b6aSSam Leffler ieee80211_wme_initparams(struct ieee80211com *ic) 6088a1b9b6aSSam Leffler { 6098a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 6108a1b9b6aSSam Leffler const paramType *pPhyParam, *pBssPhyParam; 6118a1b9b6aSSam Leffler struct wmeParams *wmep; 6128a1b9b6aSSam Leffler int i; 6138a1b9b6aSSam Leffler 6148a1b9b6aSSam Leffler if ((ic->ic_caps & IEEE80211_C_WME) == 0) 6158a1b9b6aSSam Leffler return; 6168a1b9b6aSSam Leffler 6178a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 6188a1b9b6aSSam Leffler switch (i) { 6198a1b9b6aSSam Leffler case WME_AC_BK: 6208a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 6218a1b9b6aSSam Leffler pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 6228a1b9b6aSSam Leffler break; 6238a1b9b6aSSam Leffler case WME_AC_VI: 6248a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_VI[ic->ic_curmode]; 6258a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode]; 6268a1b9b6aSSam Leffler break; 6278a1b9b6aSSam Leffler case WME_AC_VO: 6288a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_VO[ic->ic_curmode]; 6298a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode]; 6308a1b9b6aSSam Leffler break; 6318a1b9b6aSSam Leffler case WME_AC_BE: 6328a1b9b6aSSam Leffler default: 6338a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_BE[ic->ic_curmode]; 6348a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode]; 6358a1b9b6aSSam Leffler break; 6368a1b9b6aSSam Leffler } 6378a1b9b6aSSam Leffler 6388a1b9b6aSSam Leffler wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 6398a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 6408a1b9b6aSSam Leffler wmep->wmep_acm = pPhyParam->acm; 6418a1b9b6aSSam Leffler wmep->wmep_aifsn = pPhyParam->aifsn; 6428a1b9b6aSSam Leffler wmep->wmep_logcwmin = pPhyParam->logcwmin; 6438a1b9b6aSSam Leffler wmep->wmep_logcwmax = pPhyParam->logcwmax; 6448a1b9b6aSSam Leffler wmep->wmep_txopLimit = pPhyParam->txopLimit; 6458a1b9b6aSSam Leffler } else { 6468a1b9b6aSSam Leffler wmep->wmep_acm = pBssPhyParam->acm; 6478a1b9b6aSSam Leffler wmep->wmep_aifsn = pBssPhyParam->aifsn; 6488a1b9b6aSSam Leffler wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 6498a1b9b6aSSam Leffler wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 6508a1b9b6aSSam Leffler wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 6518a1b9b6aSSam Leffler 6528a1b9b6aSSam Leffler } 6538a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 6548a1b9b6aSSam Leffler "%s: %s chan [acm %u aifsn %u log2(cwmin) %u " 6558a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 6568a1b9b6aSSam Leffler , ieee80211_wme_acnames[i] 6578a1b9b6aSSam Leffler , wmep->wmep_acm 6588a1b9b6aSSam Leffler , wmep->wmep_aifsn 6598a1b9b6aSSam Leffler , wmep->wmep_logcwmin 6608a1b9b6aSSam Leffler , wmep->wmep_logcwmax 6618a1b9b6aSSam Leffler , wmep->wmep_txopLimit 6628a1b9b6aSSam Leffler ); 6638a1b9b6aSSam Leffler 6648a1b9b6aSSam Leffler wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 6658a1b9b6aSSam Leffler wmep->wmep_acm = pBssPhyParam->acm; 6668a1b9b6aSSam Leffler wmep->wmep_aifsn = pBssPhyParam->aifsn; 6678a1b9b6aSSam Leffler wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 6688a1b9b6aSSam Leffler wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 6698a1b9b6aSSam Leffler wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 6708a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 6718a1b9b6aSSam Leffler "%s: %s bss [acm %u aifsn %u log2(cwmin) %u " 6728a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 6738a1b9b6aSSam Leffler , ieee80211_wme_acnames[i] 6748a1b9b6aSSam Leffler , wmep->wmep_acm 6758a1b9b6aSSam Leffler , wmep->wmep_aifsn 6768a1b9b6aSSam Leffler , wmep->wmep_logcwmin 6778a1b9b6aSSam Leffler , wmep->wmep_logcwmax 6788a1b9b6aSSam Leffler , wmep->wmep_txopLimit 6798a1b9b6aSSam Leffler ); 6808a1b9b6aSSam Leffler } 6818a1b9b6aSSam Leffler /* NB: check ic_bss to avoid NULL deref on initial attach */ 6828a1b9b6aSSam Leffler if (ic->ic_bss != NULL) { 6838a1b9b6aSSam Leffler /* 6848a1b9b6aSSam Leffler * Calculate agressive mode switching threshold based 6858a1b9b6aSSam Leffler * on beacon interval. This doesn't need locking since 6868a1b9b6aSSam Leffler * we're only called before entering the RUN state at 6878a1b9b6aSSam Leffler * which point we start sending beacon frames. 6888a1b9b6aSSam Leffler */ 6898a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh = 6908a1b9b6aSSam Leffler (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100; 6918a1b9b6aSSam Leffler ieee80211_wme_updateparams(ic); 6928a1b9b6aSSam Leffler } 6938a1b9b6aSSam Leffler } 6948a1b9b6aSSam Leffler 6958a1b9b6aSSam Leffler /* 6968a1b9b6aSSam Leffler * Update WME parameters for ourself and the BSS. 6978a1b9b6aSSam Leffler */ 6988a1b9b6aSSam Leffler void 6998a1b9b6aSSam Leffler ieee80211_wme_updateparams_locked(struct ieee80211com *ic) 7008a1b9b6aSSam Leffler { 7018a1b9b6aSSam Leffler static const paramType phyParam[IEEE80211_MODE_MAX] = { 7028a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */ 7038a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */ 7048a1b9b6aSSam Leffler { 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */ 7058a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */ 7068a1b9b6aSSam Leffler { 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */ 7078a1b9b6aSSam Leffler { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */ 7088a1b9b6aSSam Leffler { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */ 7098a1b9b6aSSam Leffler }; 7108a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 7118a1b9b6aSSam Leffler const struct wmeParams *wmep; 7128a1b9b6aSSam Leffler struct wmeParams *chanp, *bssp; 7138a1b9b6aSSam Leffler int i; 7148a1b9b6aSSam Leffler 7158a1b9b6aSSam Leffler /* set up the channel access parameters for the physical device */ 7168a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 7178a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[i]; 7188a1b9b6aSSam Leffler wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 7198a1b9b6aSSam Leffler chanp->wmep_aifsn = wmep->wmep_aifsn; 7208a1b9b6aSSam Leffler chanp->wmep_logcwmin = wmep->wmep_logcwmin; 7218a1b9b6aSSam Leffler chanp->wmep_logcwmax = wmep->wmep_logcwmax; 7228a1b9b6aSSam Leffler chanp->wmep_txopLimit = wmep->wmep_txopLimit; 7238a1b9b6aSSam Leffler 7248a1b9b6aSSam Leffler chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 7258a1b9b6aSSam Leffler wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 7268a1b9b6aSSam Leffler chanp->wmep_aifsn = wmep->wmep_aifsn; 7278a1b9b6aSSam Leffler chanp->wmep_logcwmin = wmep->wmep_logcwmin; 7288a1b9b6aSSam Leffler chanp->wmep_logcwmax = wmep->wmep_logcwmax; 7298a1b9b6aSSam Leffler chanp->wmep_txopLimit = wmep->wmep_txopLimit; 7308a1b9b6aSSam Leffler } 7318a1b9b6aSSam Leffler 7328a1b9b6aSSam Leffler /* 7338a1b9b6aSSam Leffler * This implements agressive mode as found in certain 7348a1b9b6aSSam Leffler * vendors' AP's. When there is significant high 7358a1b9b6aSSam Leffler * priority (VI/VO) traffic in the BSS throttle back BE 7368a1b9b6aSSam Leffler * traffic by using conservative parameters. Otherwise 7378a1b9b6aSSam Leffler * BE uses agressive params to optimize performance of 7388a1b9b6aSSam Leffler * legacy/non-QoS traffic. 7398a1b9b6aSSam Leffler */ 7408a1b9b6aSSam Leffler if ((ic->ic_opmode == IEEE80211_M_HOSTAP && 7418a1b9b6aSSam Leffler (wme->wme_flags & WME_F_AGGRMODE) == 0) || 7428a1b9b6aSSam Leffler (ic->ic_opmode != IEEE80211_M_HOSTAP && 7438a1b9b6aSSam Leffler (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || 7448a1b9b6aSSam Leffler (ic->ic_flags & IEEE80211_F_WME) == 0) { 7458a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 7468a1b9b6aSSam Leffler bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 7478a1b9b6aSSam Leffler 7488a1b9b6aSSam Leffler chanp->wmep_aifsn = bssp->wmep_aifsn = 7498a1b9b6aSSam Leffler phyParam[ic->ic_curmode].aifsn; 7508a1b9b6aSSam Leffler chanp->wmep_logcwmin = bssp->wmep_logcwmin = 7518a1b9b6aSSam Leffler phyParam[ic->ic_curmode].logcwmin; 7528a1b9b6aSSam Leffler chanp->wmep_logcwmax = bssp->wmep_logcwmax = 7538a1b9b6aSSam Leffler phyParam[ic->ic_curmode].logcwmax; 7548a1b9b6aSSam Leffler chanp->wmep_txopLimit = bssp->wmep_txopLimit = 7558a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_BURST) ? 7568a1b9b6aSSam Leffler phyParam[ic->ic_curmode].txopLimit : 0; 7578a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 7588a1b9b6aSSam Leffler "%s: %s [acm %u aifsn %u log2(cwmin) %u " 7598a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 7608a1b9b6aSSam Leffler , ieee80211_wme_acnames[WME_AC_BE] 7618a1b9b6aSSam Leffler , chanp->wmep_acm 7628a1b9b6aSSam Leffler , chanp->wmep_aifsn 7638a1b9b6aSSam Leffler , chanp->wmep_logcwmin 7648a1b9b6aSSam Leffler , chanp->wmep_logcwmax 7658a1b9b6aSSam Leffler , chanp->wmep_txopLimit 7668a1b9b6aSSam Leffler ); 7678a1b9b6aSSam Leffler } 7688a1b9b6aSSam Leffler 7698a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 7708a1b9b6aSSam Leffler ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) == 0) { 7718a1b9b6aSSam Leffler static const u_int8_t logCwMin[IEEE80211_MODE_MAX] = { 7728a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_AUTO */ 7738a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_11A */ 7748a1b9b6aSSam Leffler 4, /* IEEE80211_MODE_11B */ 7758a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_11G */ 7768a1b9b6aSSam Leffler 4, /* IEEE80211_MODE_FH */ 7778a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_TURBO_A */ 7788a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_TURBO_G */ 7798a1b9b6aSSam Leffler }; 7808a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 7818a1b9b6aSSam Leffler bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 7828a1b9b6aSSam Leffler 7838a1b9b6aSSam Leffler chanp->wmep_logcwmin = bssp->wmep_logcwmin = 7848a1b9b6aSSam Leffler logCwMin[ic->ic_curmode]; 7858a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 7868a1b9b6aSSam Leffler "%s: %s log2(cwmin) %u\n", __func__ 7878a1b9b6aSSam Leffler , ieee80211_wme_acnames[WME_AC_BE] 7888a1b9b6aSSam Leffler , chanp->wmep_logcwmin 7898a1b9b6aSSam Leffler ); 7908a1b9b6aSSam Leffler } 7918a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ 7928a1b9b6aSSam Leffler /* 7938a1b9b6aSSam Leffler * Arrange for a beacon update and bump the parameter 7948a1b9b6aSSam Leffler * set number so associated stations load the new values. 7958a1b9b6aSSam Leffler */ 7968a1b9b6aSSam Leffler wme->wme_bssChanParams.cap_info = 7978a1b9b6aSSam Leffler (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 7988a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_WMEUPDATE; 7998a1b9b6aSSam Leffler } 8008a1b9b6aSSam Leffler 8018a1b9b6aSSam Leffler wme->wme_update(ic); 8028a1b9b6aSSam Leffler 8038a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 8048a1b9b6aSSam Leffler "%s: WME params updated, cap_info 0x%x\n", __func__, 8058a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_STA ? 8068a1b9b6aSSam Leffler wme->wme_wmeChanParams.cap_info : 8078a1b9b6aSSam Leffler wme->wme_bssChanParams.cap_info); 8088a1b9b6aSSam Leffler } 8098a1b9b6aSSam Leffler 8108a1b9b6aSSam Leffler void 8118a1b9b6aSSam Leffler ieee80211_wme_updateparams(struct ieee80211com *ic) 8128a1b9b6aSSam Leffler { 8138a1b9b6aSSam Leffler 8148a1b9b6aSSam Leffler if (ic->ic_caps & IEEE80211_C_WME) { 8158a1b9b6aSSam Leffler IEEE80211_BEACON_LOCK(ic); 8168a1b9b6aSSam Leffler ieee80211_wme_updateparams_locked(ic); 8178a1b9b6aSSam Leffler IEEE80211_BEACON_UNLOCK(ic); 8188a1b9b6aSSam Leffler } 8198a1b9b6aSSam Leffler } 8208a1b9b6aSSam Leffler 8218a1b9b6aSSam Leffler static int 8228a1b9b6aSSam Leffler ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 8238a1b9b6aSSam Leffler { 8248a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 8258a1b9b6aSSam Leffler struct ieee80211_node_table *nt; 8261a1e1d21SSam Leffler struct ieee80211_node *ni; 827a11c9a5cSSam Leffler enum ieee80211_state ostate; 8281a1e1d21SSam Leffler 8291a1e1d21SSam Leffler ostate = ic->ic_state; 8308a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__, 8318a1b9b6aSSam Leffler ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 832a11c9a5cSSam Leffler ic->ic_state = nstate; /* state transition */ 8331a1e1d21SSam Leffler ni = ic->ic_bss; /* NB: no reference held */ 8341a1e1d21SSam Leffler switch (nstate) { 8351a1e1d21SSam Leffler case IEEE80211_S_INIT: 8361a1e1d21SSam Leffler switch (ostate) { 8371a1e1d21SSam Leffler case IEEE80211_S_INIT: 8381a1e1d21SSam Leffler break; 8391a1e1d21SSam Leffler case IEEE80211_S_RUN: 8401a1e1d21SSam Leffler switch (ic->ic_opmode) { 8411a1e1d21SSam Leffler case IEEE80211_M_STA: 8421a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8431a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 8441a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 8458a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 8461a1e1d21SSam Leffler break; 8471a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 8488a1b9b6aSSam Leffler nt = ic->ic_sta; 8498a1b9b6aSSam Leffler if (nt == NULL) { /* XXX cannot happen */ 8508a1b9b6aSSam Leffler if_printf(ifp, "no sta table (run)\n"); 8518a1b9b6aSSam Leffler break; 8528a1b9b6aSSam Leffler } 8538a1b9b6aSSam Leffler IEEE80211_NODE_LOCK(nt); 8548a1b9b6aSSam Leffler TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 8551a1e1d21SSam Leffler if (ni->ni_associd == 0) 8561a1e1d21SSam Leffler continue; 8571a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8581a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 8591a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 8601a1e1d21SSam Leffler } 8618a1b9b6aSSam Leffler IEEE80211_NODE_UNLOCK(nt); 8621a1e1d21SSam Leffler break; 8631a1e1d21SSam Leffler default: 8641a1e1d21SSam Leffler break; 8651a1e1d21SSam Leffler } 8668a1b9b6aSSam Leffler goto reset; 8671a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 8681a1e1d21SSam Leffler switch (ic->ic_opmode) { 8691a1e1d21SSam Leffler case IEEE80211_M_STA: 8701a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8711a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 8721a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 8731a1e1d21SSam Leffler break; 8741a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 8758a1b9b6aSSam Leffler nt = ic->ic_sta; 8768a1b9b6aSSam Leffler if (nt == NULL) { /* XXX cannot happen */ 8778a1b9b6aSSam Leffler if_printf(ifp, "no sta table (assoc)\n"); 8788a1b9b6aSSam Leffler break; 8798a1b9b6aSSam Leffler } 8808a1b9b6aSSam Leffler IEEE80211_NODE_LOCK(nt); 8818a1b9b6aSSam Leffler TAILQ_FOREACH(ni, &nt->nt_node, ni_list) { 8821a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8831a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 8841a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 8851a1e1d21SSam Leffler } 8868a1b9b6aSSam Leffler IEEE80211_NODE_UNLOCK(nt); 8871a1e1d21SSam Leffler break; 8881a1e1d21SSam Leffler default: 8891a1e1d21SSam Leffler break; 8901a1e1d21SSam Leffler } 8918a1b9b6aSSam Leffler goto reset; 8921a1e1d21SSam Leffler case IEEE80211_S_AUTH: 8931a1e1d21SSam Leffler case IEEE80211_S_SCAN: 8948a1b9b6aSSam Leffler reset: 8951a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 8961a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 8978a1b9b6aSSam Leffler ieee80211_reset_bss(ic); 8988a1b9b6aSSam Leffler ieee80211_crypto_delglobalkeys(ic); 8991a1e1d21SSam Leffler break; 9001a1e1d21SSam Leffler } 9018a1b9b6aSSam Leffler if (ic->ic_auth->ia_detach != NULL) 9028a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 9031a1e1d21SSam Leffler break; 9041a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9051a1e1d21SSam Leffler switch (ostate) { 9061a1e1d21SSam Leffler case IEEE80211_S_INIT: 9078a1b9b6aSSam Leffler if ((ic->ic_opmode == IEEE80211_M_HOSTAP || 9088a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_IBSS || 9098a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_AHDEMO) && 9101a1e1d21SSam Leffler ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 9111a1e1d21SSam Leffler /* 9121a1e1d21SSam Leffler * AP operation and we already have a channel; 9131a1e1d21SSam Leffler * bypass the scan and startup immediately. 9141a1e1d21SSam Leffler */ 9151a1e1d21SSam Leffler ieee80211_create_ibss(ic, ic->ic_des_chan); 9161a1e1d21SSam Leffler } else { 9178a1b9b6aSSam Leffler ieee80211_begin_scan(ic, arg); 9181a1e1d21SSam Leffler } 9191a1e1d21SSam Leffler break; 9201a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9218a1b9b6aSSam Leffler /* 9228a1b9b6aSSam Leffler * Scan next. If doing an active scan and the 9238a1b9b6aSSam Leffler * channel is not marked passive-only then send 9248a1b9b6aSSam Leffler * a probe request. Otherwise just listen for 9258a1b9b6aSSam Leffler * beacons on the channel. 9268a1b9b6aSSam Leffler */ 9278a1b9b6aSSam Leffler if ((ic->ic_flags & IEEE80211_F_ASCAN) && 9288a1b9b6aSSam Leffler (ni->ni_chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) { 9291a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9301a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 9311a1e1d21SSam Leffler } 9321a1e1d21SSam Leffler break; 9331a1e1d21SSam Leffler case IEEE80211_S_RUN: 9341a1e1d21SSam Leffler /* beacon miss */ 9358a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, 9368a1b9b6aSSam Leffler "no recent beacons from %s; rescanning\n", 9371a1e1d21SSam Leffler ether_sprintf(ic->ic_bss->ni_bssid)); 9388a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 9398a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */ 9401a1e1d21SSam Leffler /* FALLTHRU */ 9411a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9421a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9431a1e1d21SSam Leffler /* timeout restart scan */ 9448a1b9b6aSSam Leffler ni = ieee80211_find_node(&ic->ic_scan, 9458a1b9b6aSSam Leffler ic->ic_bss->ni_macaddr); 9461a1e1d21SSam Leffler if (ni != NULL) { 9471a1e1d21SSam Leffler ni->ni_fails++; 9481a1e1d21SSam Leffler ieee80211_unref_node(&ni); 9491a1e1d21SSam Leffler } 9508a1b9b6aSSam Leffler ieee80211_begin_scan(ic, arg); 9511a1e1d21SSam Leffler break; 9521a1e1d21SSam Leffler } 9531a1e1d21SSam Leffler break; 9541a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9551a1e1d21SSam Leffler switch (ostate) { 9561a1e1d21SSam Leffler case IEEE80211_S_INIT: 9571a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9581a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9591a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 9601a1e1d21SSam Leffler break; 9611a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9621a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9638a1b9b6aSSam Leffler switch (arg) { 9641a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 9651a1e1d21SSam Leffler /* ??? */ 9661a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9671a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 9681a1e1d21SSam Leffler break; 9691a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 9701a1e1d21SSam Leffler /* ignore and retry scan on timeout */ 9711a1e1d21SSam Leffler break; 9721a1e1d21SSam Leffler } 9731a1e1d21SSam Leffler break; 9741a1e1d21SSam Leffler case IEEE80211_S_RUN: 9758a1b9b6aSSam Leffler switch (arg) { 9761a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 9771a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9781a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 9791a1e1d21SSam Leffler ic->ic_state = ostate; /* stay RUN */ 9801a1e1d21SSam Leffler break; 9811a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 9821a1e1d21SSam Leffler /* try to reauth */ 9831a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9841a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 9858a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 9861a1e1d21SSam Leffler break; 9871a1e1d21SSam Leffler } 9881a1e1d21SSam Leffler break; 9891a1e1d21SSam Leffler } 9901a1e1d21SSam Leffler break; 9911a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9921a1e1d21SSam Leffler switch (ostate) { 9931a1e1d21SSam Leffler case IEEE80211_S_INIT: 9941a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9951a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9968a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 9978a1b9b6aSSam Leffler "%s: invalid transition\n", __func__); 9981a1e1d21SSam Leffler break; 9991a1e1d21SSam Leffler case IEEE80211_S_AUTH: 10001a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 10011a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 10021a1e1d21SSam Leffler break; 10031a1e1d21SSam Leffler case IEEE80211_S_RUN: 10041a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 10051a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 10068a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 10071a1e1d21SSam Leffler break; 10081a1e1d21SSam Leffler } 10091a1e1d21SSam Leffler break; 10101a1e1d21SSam Leffler case IEEE80211_S_RUN: 10118a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_WPA) { 10128a1b9b6aSSam Leffler /* XXX validate prerequisites */ 10138a1b9b6aSSam Leffler } 10141a1e1d21SSam Leffler switch (ostate) { 10151a1e1d21SSam Leffler case IEEE80211_S_INIT: 10168a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) 10178a1b9b6aSSam Leffler break; 10188a1b9b6aSSam Leffler /* fall thru... */ 10191a1e1d21SSam Leffler case IEEE80211_S_AUTH: 10201a1e1d21SSam Leffler case IEEE80211_S_RUN: 10218a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 10228a1b9b6aSSam Leffler "%s: invalid transition\n", __func__); 10231a1e1d21SSam Leffler break; 10241a1e1d21SSam Leffler case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 10251a1e1d21SSam Leffler case IEEE80211_S_ASSOC: /* infra mode */ 10261a1e1d21SSam Leffler KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 10271a1e1d21SSam Leffler ("%s: bogus xmit rate %u setup\n", __func__, 10281a1e1d21SSam Leffler ni->ni_txrate)); 10298a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 10308a1b9b6aSSam Leffler if (ieee80211_msg_debug(ic)) { 10311a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 10328a1b9b6aSSam Leffler if_printf(ifp, "associated "); 10331a1e1d21SSam Leffler else 10348a1b9b6aSSam Leffler if_printf(ifp, "synchronized "); 10351a1e1d21SSam Leffler printf("with %s ssid ", 10361a1e1d21SSam Leffler ether_sprintf(ni->ni_bssid)); 10371a1e1d21SSam Leffler ieee80211_print_essid(ic->ic_bss->ni_essid, 10381a1e1d21SSam Leffler ni->ni_esslen); 10391a1e1d21SSam Leffler printf(" channel %d start %uMb\n", 10401a1e1d21SSam Leffler ieee80211_chan2ieee(ic, ni->ni_chan), 10411a1e1d21SSam Leffler IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 10421a1e1d21SSam Leffler } 10438a1b9b6aSSam Leffler #endif 10441a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 10458a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 10468a1b9b6aSSam Leffler ieee80211_notify_node_join(ic, ni, 10478a1b9b6aSSam Leffler arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 10488a1b9b6aSSam Leffler if_start(ifp); /* XXX not authorized yet */ 10491a1e1d21SSam Leffler break; 10501a1e1d21SSam Leffler } 10518a1b9b6aSSam Leffler /* 10528a1b9b6aSSam Leffler * Start/stop the authenticator when operating as an 10538a1b9b6aSSam Leffler * AP. We delay until here to allow configuration to 10548a1b9b6aSSam Leffler * happen out of order. 10558a1b9b6aSSam Leffler */ 10568a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ 10578a1b9b6aSSam Leffler ic->ic_auth->ia_attach != NULL) { 10588a1b9b6aSSam Leffler /* XXX check failure */ 10598a1b9b6aSSam Leffler ic->ic_auth->ia_attach(ic); 10608a1b9b6aSSam Leffler } else if (ic->ic_auth->ia_detach != NULL) { 10618a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 10628a1b9b6aSSam Leffler } 10638a1b9b6aSSam Leffler /* 10648a1b9b6aSSam Leffler * When 802.1x is not in use mark the port authorized 10658a1b9b6aSSam Leffler * at this point so traffic can flow. 10668a1b9b6aSSam Leffler */ 10678a1b9b6aSSam Leffler if (ni->ni_authmode != IEEE80211_AUTH_8021X) 10688a1b9b6aSSam Leffler ieee80211_node_authorize(ic, ni); 10698a1b9b6aSSam Leffler /* 10708a1b9b6aSSam Leffler * Enable inactivity processing. 10718a1b9b6aSSam Leffler * XXX 10728a1b9b6aSSam Leffler */ 10738a1b9b6aSSam Leffler ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 10748a1b9b6aSSam Leffler if (ic->ic_sta != NULL) 10758a1b9b6aSSam Leffler ic->ic_sta->nt_inact_timer = IEEE80211_INACT_WAIT; 10761a1e1d21SSam Leffler break; 10771a1e1d21SSam Leffler } 10781a1e1d21SSam Leffler return 0; 10791a1e1d21SSam Leffler } 1080