11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 31f1d7810SSam Leffler * Copyright (c) 2002-2005 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 ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 9833acb1ceSSam Leffler ic->ic_fragthreshold = IEEE80211_FRAG_DEFAULT; 992c39b32cSSam Leffler ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE; 1002e79ca97SSam Leffler ic->ic_protmode = IEEE80211_PROT_CTSONLY; 1018a1b9b6aSSam Leffler ic->ic_roaming = IEEE80211_ROAMING_AUTO; 1028a1b9b6aSSam Leffler 1038a1b9b6aSSam Leffler ic->ic_wme.wme_hipri_switch_hysteresis = 1048a1b9b6aSSam Leffler AGGRESSIVE_MODE_SWITCH_HYSTERESIS; 1051a1e1d21SSam Leffler 1069bf40edeSBrooks Davis mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_xname, "mgmt send q", MTX_DEF); 1071a1e1d21SSam Leffler 108a11c9a5cSSam Leffler /* protocol state change handler */ 109a11c9a5cSSam Leffler ic->ic_newstate = ieee80211_newstate; 110a11c9a5cSSam Leffler 1111a1e1d21SSam Leffler /* initialize management frame handlers */ 1121a1e1d21SSam Leffler ic->ic_recv_mgmt = ieee80211_recv_mgmt; 1131a1e1d21SSam Leffler ic->ic_send_mgmt = ieee80211_send_mgmt; 1141a1e1d21SSam Leffler } 1151a1e1d21SSam Leffler 1161a1e1d21SSam Leffler void 1178a1b9b6aSSam Leffler ieee80211_proto_detach(struct ieee80211com *ic) 1181a1e1d21SSam Leffler { 1198a1b9b6aSSam Leffler 1208a1b9b6aSSam Leffler /* 1218a1b9b6aSSam Leffler * This should not be needed as we detach when reseting 1228a1b9b6aSSam Leffler * the state but be conservative here since the 1238a1b9b6aSSam Leffler * authenticator may do things like spawn kernel threads. 1248a1b9b6aSSam Leffler */ 1258a1b9b6aSSam Leffler if (ic->ic_auth->ia_detach) 1268a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 1271a1e1d21SSam Leffler 1281a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 1291a1e1d21SSam Leffler mtx_destroy(&ic->ic_mgtq.ifq_mtx); 1308a1b9b6aSSam Leffler 1318a1b9b6aSSam Leffler /* 1328a1b9b6aSSam Leffler * Detach any ACL'ator. 1338a1b9b6aSSam Leffler */ 1348a1b9b6aSSam Leffler if (ic->ic_acl != NULL) 1358a1b9b6aSSam Leffler ic->ic_acl->iac_detach(ic); 1368a1b9b6aSSam Leffler } 1378a1b9b6aSSam Leffler 1388a1b9b6aSSam Leffler /* 1398a1b9b6aSSam Leffler * Simple-minded authenticator module support. 1408a1b9b6aSSam Leffler */ 1418a1b9b6aSSam Leffler 1428a1b9b6aSSam Leffler #define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 1438a1b9b6aSSam Leffler /* XXX well-known names */ 1448a1b9b6aSSam Leffler static const char *auth_modnames[IEEE80211_AUTH_MAX] = { 1458a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_NONE */ 1468a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_OPEN */ 1478a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_SHARED */ 1488a1b9b6aSSam Leffler "wlan_xauth", /* IEEE80211_AUTH_8021X */ 1498a1b9b6aSSam Leffler "wlan_internal", /* IEEE80211_AUTH_AUTO */ 1508a1b9b6aSSam Leffler "wlan_xauth", /* IEEE80211_AUTH_WPA */ 1518a1b9b6aSSam Leffler }; 1528a1b9b6aSSam Leffler static const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 1538a1b9b6aSSam Leffler 1548a1b9b6aSSam Leffler static const struct ieee80211_authenticator auth_internal = { 1558a1b9b6aSSam Leffler .ia_name = "wlan_internal", 1568a1b9b6aSSam Leffler .ia_attach = NULL, 1578a1b9b6aSSam Leffler .ia_detach = NULL, 1588a1b9b6aSSam Leffler .ia_node_join = NULL, 1598a1b9b6aSSam Leffler .ia_node_leave = NULL, 1608a1b9b6aSSam Leffler }; 1618a1b9b6aSSam Leffler 1628a1b9b6aSSam Leffler /* 1638a1b9b6aSSam Leffler * Setup internal authenticators once; they are never unregistered. 1648a1b9b6aSSam Leffler */ 1658a1b9b6aSSam Leffler static void 1668a1b9b6aSSam Leffler ieee80211_auth_setup(void) 1678a1b9b6aSSam Leffler { 1688a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 1698a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 1708a1b9b6aSSam Leffler ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 1718a1b9b6aSSam Leffler } 1728a1b9b6aSSam Leffler SYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL); 1738a1b9b6aSSam Leffler 1748a1b9b6aSSam Leffler const struct ieee80211_authenticator * 1758a1b9b6aSSam Leffler ieee80211_authenticator_get(int auth) 1768a1b9b6aSSam Leffler { 1778a1b9b6aSSam Leffler if (auth >= IEEE80211_AUTH_MAX) 1788a1b9b6aSSam Leffler return NULL; 1798a1b9b6aSSam Leffler if (authenticators[auth] == NULL) 1808a1b9b6aSSam Leffler ieee80211_load_module(auth_modnames[auth]); 1818a1b9b6aSSam Leffler return authenticators[auth]; 1821a1e1d21SSam Leffler } 1831a1e1d21SSam Leffler 1841a1e1d21SSam Leffler void 1858a1b9b6aSSam Leffler ieee80211_authenticator_register(int type, 1868a1b9b6aSSam Leffler const struct ieee80211_authenticator *auth) 1871a1e1d21SSam Leffler { 1888a1b9b6aSSam Leffler if (type >= IEEE80211_AUTH_MAX) 1898a1b9b6aSSam Leffler return; 1908a1b9b6aSSam Leffler authenticators[type] = auth; 1918a1b9b6aSSam Leffler } 1928a1b9b6aSSam Leffler 1938a1b9b6aSSam Leffler void 1948a1b9b6aSSam Leffler ieee80211_authenticator_unregister(int type) 1958a1b9b6aSSam Leffler { 1968a1b9b6aSSam Leffler 1978a1b9b6aSSam Leffler if (type >= IEEE80211_AUTH_MAX) 1988a1b9b6aSSam Leffler return; 1998a1b9b6aSSam Leffler authenticators[type] = NULL; 2008a1b9b6aSSam Leffler } 2018a1b9b6aSSam Leffler 2028a1b9b6aSSam Leffler /* 2038a1b9b6aSSam Leffler * Very simple-minded ACL module support. 2048a1b9b6aSSam Leffler */ 2058a1b9b6aSSam Leffler /* XXX just one for now */ 2068a1b9b6aSSam Leffler static const struct ieee80211_aclator *acl = NULL; 2078a1b9b6aSSam Leffler 2088a1b9b6aSSam Leffler void 2098a1b9b6aSSam Leffler ieee80211_aclator_register(const struct ieee80211_aclator *iac) 2108a1b9b6aSSam Leffler { 2118a1b9b6aSSam Leffler printf("wlan: %s acl policy registered\n", iac->iac_name); 2128a1b9b6aSSam Leffler acl = iac; 2138a1b9b6aSSam Leffler } 2148a1b9b6aSSam Leffler 2158a1b9b6aSSam Leffler void 2168a1b9b6aSSam Leffler ieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 2178a1b9b6aSSam Leffler { 2188a1b9b6aSSam Leffler if (acl == iac) 2198a1b9b6aSSam Leffler acl = NULL; 2208a1b9b6aSSam Leffler printf("wlan: %s acl policy unregistered\n", iac->iac_name); 2218a1b9b6aSSam Leffler } 2228a1b9b6aSSam Leffler 2238a1b9b6aSSam Leffler const struct ieee80211_aclator * 2248a1b9b6aSSam Leffler ieee80211_aclator_get(const char *name) 2258a1b9b6aSSam Leffler { 2268a1b9b6aSSam Leffler if (acl == NULL) 2278a1b9b6aSSam Leffler ieee80211_load_module("wlan_acl"); 2288a1b9b6aSSam Leffler return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 2298a1b9b6aSSam Leffler } 2308a1b9b6aSSam Leffler 2318a1b9b6aSSam Leffler void 2328a1b9b6aSSam Leffler ieee80211_print_essid(const u_int8_t *essid, int len) 2338a1b9b6aSSam Leffler { 2348a1b9b6aSSam Leffler const u_int8_t *p; 2351a1e1d21SSam Leffler int i; 2361a1e1d21SSam Leffler 2371a1e1d21SSam Leffler if (len > IEEE80211_NWID_LEN) 2381a1e1d21SSam Leffler len = IEEE80211_NWID_LEN; 2391a1e1d21SSam Leffler /* determine printable or not */ 2401a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) { 2411a1e1d21SSam Leffler if (*p < ' ' || *p > 0x7e) 2421a1e1d21SSam Leffler break; 2431a1e1d21SSam Leffler } 2441a1e1d21SSam Leffler if (i == len) { 2451a1e1d21SSam Leffler printf("\""); 2461a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 2471a1e1d21SSam Leffler printf("%c", *p); 2481a1e1d21SSam Leffler printf("\""); 2491a1e1d21SSam Leffler } else { 2501a1e1d21SSam Leffler printf("0x"); 2511a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 2521a1e1d21SSam Leffler printf("%02x", *p); 2531a1e1d21SSam Leffler } 2541a1e1d21SSam Leffler } 2551a1e1d21SSam Leffler 2561a1e1d21SSam Leffler void 2578a1b9b6aSSam Leffler ieee80211_dump_pkt(const u_int8_t *buf, int len, int rate, int rssi) 2581a1e1d21SSam Leffler { 2598a1b9b6aSSam Leffler const struct ieee80211_frame *wh; 2601a1e1d21SSam Leffler int i; 2611a1e1d21SSam Leffler 2628a1b9b6aSSam Leffler wh = (const struct ieee80211_frame *)buf; 2631a1e1d21SSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 2641a1e1d21SSam Leffler case IEEE80211_FC1_DIR_NODS: 2651a1e1d21SSam Leffler printf("NODS %s", ether_sprintf(wh->i_addr2)); 2661a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 2671a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr3)); 2681a1e1d21SSam Leffler break; 2691a1e1d21SSam Leffler case IEEE80211_FC1_DIR_TODS: 2701a1e1d21SSam Leffler printf("TODS %s", ether_sprintf(wh->i_addr2)); 2711a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 2721a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr1)); 2731a1e1d21SSam Leffler break; 2741a1e1d21SSam Leffler case IEEE80211_FC1_DIR_FROMDS: 2751a1e1d21SSam Leffler printf("FRDS %s", ether_sprintf(wh->i_addr3)); 2761a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 2771a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr2)); 2781a1e1d21SSam Leffler break; 2791a1e1d21SSam Leffler case IEEE80211_FC1_DIR_DSTODS: 2808a1b9b6aSSam Leffler printf("DSDS %s", ether_sprintf((const u_int8_t *)&wh[1])); 2811a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 2821a1e1d21SSam Leffler printf("(%s", ether_sprintf(wh->i_addr2)); 2831a1e1d21SSam Leffler printf("->%s)", ether_sprintf(wh->i_addr1)); 2841a1e1d21SSam Leffler break; 2851a1e1d21SSam Leffler } 2861a1e1d21SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 2871a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_DATA: 2881a1e1d21SSam Leffler printf(" data"); 2891a1e1d21SSam Leffler break; 2901a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_MGT: 2911a1e1d21SSam Leffler printf(" %s", ieee80211_mgt_subtype_name[ 2921a1e1d21SSam Leffler (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 2931a1e1d21SSam Leffler >> IEEE80211_FC0_SUBTYPE_SHIFT]); 2941a1e1d21SSam Leffler break; 2951a1e1d21SSam Leffler default: 2961a1e1d21SSam Leffler printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 2971a1e1d21SSam Leffler break; 2981a1e1d21SSam Leffler } 2998a1b9b6aSSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 3008a1b9b6aSSam Leffler int i; 3018a1b9b6aSSam Leffler printf(" WEP [IV"); 3028a1b9b6aSSam Leffler for (i = 0; i < IEEE80211_WEP_IVLEN; i++) 3038a1b9b6aSSam Leffler printf(" %.02x", buf[sizeof(*wh)+i]); 3048a1b9b6aSSam Leffler printf(" KID %u]", buf[sizeof(*wh)+i] >> 6); 3058a1b9b6aSSam Leffler } 3061a1e1d21SSam Leffler if (rate >= 0) 3071a1e1d21SSam Leffler printf(" %dM", rate / 2); 3081a1e1d21SSam Leffler if (rssi >= 0) 3091a1e1d21SSam Leffler printf(" +%d", rssi); 3101a1e1d21SSam Leffler printf("\n"); 3111a1e1d21SSam Leffler if (len > 0) { 3121a1e1d21SSam Leffler for (i = 0; i < len; i++) { 3131a1e1d21SSam Leffler if ((i & 1) == 0) 3141a1e1d21SSam Leffler printf(" "); 3151a1e1d21SSam Leffler printf("%02x", buf[i]); 3161a1e1d21SSam Leffler } 3171a1e1d21SSam Leffler printf("\n"); 3181a1e1d21SSam Leffler } 3191a1e1d21SSam Leffler } 3201a1e1d21SSam Leffler 3211a1e1d21SSam Leffler int 3227d77cd53SSam Leffler ieee80211_fix_rate(struct ieee80211_node *ni, int flags) 3231a1e1d21SSam Leffler { 3241a1e1d21SSam Leffler #define RV(v) ((v) & IEEE80211_RATE_VAL) 3257d77cd53SSam Leffler struct ieee80211com *ic = ni->ni_ic; 3261a1e1d21SSam Leffler int i, j, ignore, error; 3278a1b9b6aSSam Leffler int okrate, badrate, fixedrate; 3281a1e1d21SSam Leffler struct ieee80211_rateset *srs, *nrs; 3291a1e1d21SSam Leffler u_int8_t r; 3301a1e1d21SSam Leffler 3318a1b9b6aSSam Leffler /* 3328a1b9b6aSSam Leffler * If the fixed rate check was requested but no 3338a1b9b6aSSam Leffler * fixed has been defined then just remove it. 3348a1b9b6aSSam Leffler */ 3352c39b32cSSam Leffler if ((flags & IEEE80211_F_DOFRATE) && 3362c39b32cSSam Leffler ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) 3378a1b9b6aSSam Leffler flags &= ~IEEE80211_F_DOFRATE; 3381a1e1d21SSam Leffler error = 0; 3398a1b9b6aSSam Leffler okrate = badrate = fixedrate = 0; 3401a1e1d21SSam Leffler srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 3411a1e1d21SSam Leffler nrs = &ni->ni_rates; 342ef39d4beSSam Leffler for (i = 0; i < nrs->rs_nrates; ) { 3431a1e1d21SSam Leffler ignore = 0; 3441a1e1d21SSam Leffler if (flags & IEEE80211_F_DOSORT) { 3451a1e1d21SSam Leffler /* 3461a1e1d21SSam Leffler * Sort rates. 3471a1e1d21SSam Leffler */ 3481a1e1d21SSam Leffler for (j = i + 1; j < nrs->rs_nrates; j++) { 3491a1e1d21SSam Leffler if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 3501a1e1d21SSam Leffler r = nrs->rs_rates[i]; 3511a1e1d21SSam Leffler nrs->rs_rates[i] = nrs->rs_rates[j]; 3521a1e1d21SSam Leffler nrs->rs_rates[j] = r; 3531a1e1d21SSam Leffler } 3541a1e1d21SSam Leffler } 3551a1e1d21SSam Leffler } 3561a1e1d21SSam Leffler r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 3571a1e1d21SSam Leffler badrate = r; 3581a1e1d21SSam Leffler if (flags & IEEE80211_F_DOFRATE) { 3591a1e1d21SSam Leffler /* 3608a1b9b6aSSam Leffler * Check any fixed rate is included. 3611a1e1d21SSam Leffler */ 3628a1b9b6aSSam Leffler if (r == RV(srs->rs_rates[ic->ic_fixed_rate])) 3638a1b9b6aSSam Leffler fixedrate = r; 3641a1e1d21SSam Leffler } 3651a1e1d21SSam Leffler if (flags & IEEE80211_F_DONEGO) { 3661a1e1d21SSam Leffler /* 3671a1e1d21SSam Leffler * Check against supported rates. 3681a1e1d21SSam Leffler */ 3691a1e1d21SSam Leffler for (j = 0; j < srs->rs_nrates; j++) { 370fce2da8bSSam Leffler if (r == RV(srs->rs_rates[j])) { 371fce2da8bSSam Leffler /* 372fce2da8bSSam Leffler * Overwrite with the supported rate 373fce2da8bSSam Leffler * value so any basic rate bit is set. 374fce2da8bSSam Leffler * This insures that response we send 375fce2da8bSSam Leffler * to stations have the necessary basic 376fce2da8bSSam Leffler * rate bit set. 377fce2da8bSSam Leffler */ 378fce2da8bSSam Leffler nrs->rs_rates[i] = srs->rs_rates[j]; 3791a1e1d21SSam Leffler break; 3801a1e1d21SSam Leffler } 381fce2da8bSSam Leffler } 3821a1e1d21SSam Leffler if (j == srs->rs_nrates) { 383ef39d4beSSam Leffler /* 384ef39d4beSSam Leffler * A rate in the node's rate set is not 385ef39d4beSSam Leffler * supported. If this is a basic rate and we 386ef39d4beSSam Leffler * are operating as an AP then this is an error. 387ef39d4beSSam Leffler * Otherwise we just discard/ignore the rate. 388ef39d4beSSam Leffler * Note that this is important for 11b stations 389ef39d4beSSam Leffler * when they want to associate with an 11g AP. 390ef39d4beSSam Leffler */ 391ef39d4beSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 392ef39d4beSSam Leffler (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 3931a1e1d21SSam Leffler error++; 3941a1e1d21SSam Leffler ignore++; 3951a1e1d21SSam Leffler } 3961a1e1d21SSam Leffler } 3971a1e1d21SSam Leffler if (flags & IEEE80211_F_DODEL) { 3981a1e1d21SSam Leffler /* 3991a1e1d21SSam Leffler * Delete unacceptable rates. 4001a1e1d21SSam Leffler */ 4011a1e1d21SSam Leffler if (ignore) { 4021a1e1d21SSam Leffler nrs->rs_nrates--; 4031a1e1d21SSam Leffler for (j = i; j < nrs->rs_nrates; j++) 4041a1e1d21SSam Leffler nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 4051a1e1d21SSam Leffler nrs->rs_rates[j] = 0; 4061a1e1d21SSam Leffler continue; 4071a1e1d21SSam Leffler } 4081a1e1d21SSam Leffler } 4091a1e1d21SSam Leffler if (!ignore) 4101a1e1d21SSam Leffler okrate = nrs->rs_rates[i]; 4111a1e1d21SSam Leffler i++; 4121a1e1d21SSam Leffler } 4138a1b9b6aSSam Leffler if (okrate == 0 || error != 0 || 4148a1b9b6aSSam Leffler ((flags & IEEE80211_F_DOFRATE) && fixedrate == 0)) 4151a1e1d21SSam Leffler return badrate | IEEE80211_RATE_BASIC; 4161a1e1d21SSam Leffler else 4171a1e1d21SSam Leffler return RV(okrate); 4181a1e1d21SSam Leffler #undef RV 4191a1e1d21SSam Leffler } 4201a1e1d21SSam Leffler 4218a1b9b6aSSam Leffler /* 4228a1b9b6aSSam Leffler * Reset 11g-related state. 4238a1b9b6aSSam Leffler */ 4248a1b9b6aSSam Leffler void 4258a1b9b6aSSam Leffler ieee80211_reset_erp(struct ieee80211com *ic) 4261a1e1d21SSam Leffler { 4278a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_USEPROT; 4288a1b9b6aSSam Leffler ic->ic_nonerpsta = 0; 4298a1b9b6aSSam Leffler ic->ic_longslotsta = 0; 4308a1b9b6aSSam Leffler /* 4318a1b9b6aSSam Leffler * Short slot time is enabled only when operating in 11g 4328a1b9b6aSSam Leffler * and not in an IBSS. We must also honor whether or not 4338a1b9b6aSSam Leffler * the driver is capable of doing it. 4348a1b9b6aSSam Leffler */ 4358a1b9b6aSSam Leffler ieee80211_set_shortslottime(ic, 4368a1b9b6aSSam Leffler ic->ic_curmode == IEEE80211_MODE_11A || 4378a1b9b6aSSam Leffler (ic->ic_curmode == IEEE80211_MODE_11G && 4388a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_HOSTAP && 4398a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT))); 4408a1b9b6aSSam Leffler /* 4418a1b9b6aSSam Leffler * Set short preamble and ERP barker-preamble flags. 4428a1b9b6aSSam Leffler */ 4438a1b9b6aSSam Leffler if (ic->ic_curmode == IEEE80211_MODE_11A || 4448a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 4458a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 4468a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_USEBARKER; 4478a1b9b6aSSam Leffler } else { 4488a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 4498a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_USEBARKER; 4508a1b9b6aSSam Leffler } 4518a1b9b6aSSam Leffler } 4528a1b9b6aSSam Leffler 4538a1b9b6aSSam Leffler /* 4548a1b9b6aSSam Leffler * Set the short slot time state and notify the driver. 4558a1b9b6aSSam Leffler */ 4568a1b9b6aSSam Leffler void 4578a1b9b6aSSam Leffler ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 4588a1b9b6aSSam Leffler { 4598a1b9b6aSSam Leffler if (onoff) 4608a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_SHSLOT; 4618a1b9b6aSSam Leffler else 4628a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SHSLOT; 4638a1b9b6aSSam Leffler /* notify driver */ 4648a1b9b6aSSam Leffler if (ic->ic_updateslot != NULL) 4658a1b9b6aSSam Leffler ic->ic_updateslot(ic->ic_ifp); 4668a1b9b6aSSam Leffler } 4678a1b9b6aSSam Leffler 4688a1b9b6aSSam Leffler /* 4698a1b9b6aSSam Leffler * Check if the specified rate set supports ERP. 4708a1b9b6aSSam Leffler * NB: the rate set is assumed to be sorted. 4718a1b9b6aSSam Leffler */ 4728a1b9b6aSSam Leffler int 4738a1b9b6aSSam Leffler ieee80211_iserp_rateset(struct ieee80211com *ic, struct ieee80211_rateset *rs) 4748a1b9b6aSSam Leffler { 4758a1b9b6aSSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 4768a1b9b6aSSam Leffler static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 4778a1b9b6aSSam Leffler int i, j; 4788a1b9b6aSSam Leffler 4798a1b9b6aSSam Leffler if (rs->rs_nrates < N(rates)) 4808a1b9b6aSSam Leffler return 0; 4818a1b9b6aSSam Leffler for (i = 0; i < N(rates); i++) { 4828a1b9b6aSSam Leffler for (j = 0; j < rs->rs_nrates; j++) { 4838a1b9b6aSSam Leffler int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 4848a1b9b6aSSam Leffler if (rates[i] == r) 4858a1b9b6aSSam Leffler goto next; 4868a1b9b6aSSam Leffler if (r > rates[i]) 4878a1b9b6aSSam Leffler return 0; 4888a1b9b6aSSam Leffler } 4898a1b9b6aSSam Leffler return 0; 4908a1b9b6aSSam Leffler next: 4918a1b9b6aSSam Leffler ; 4928a1b9b6aSSam Leffler } 4938a1b9b6aSSam Leffler return 1; 4948a1b9b6aSSam Leffler #undef N 4958a1b9b6aSSam Leffler } 4968a1b9b6aSSam Leffler 4978a1b9b6aSSam Leffler /* 4988a1b9b6aSSam Leffler * Mark the basic rates for the 11g rate table based on the 4998a1b9b6aSSam Leffler * operating mode. For real 11g we mark all the 11b rates 5008a1b9b6aSSam Leffler * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 5018a1b9b6aSSam Leffler * 11b rates. There's also a pseudo 11a-mode used to mark only 5028a1b9b6aSSam Leffler * the basic OFDM rates. 5038a1b9b6aSSam Leffler */ 5048a1b9b6aSSam Leffler void 5058a1b9b6aSSam Leffler ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 5068a1b9b6aSSam Leffler { 5078a1b9b6aSSam Leffler static const struct ieee80211_rateset basic[] = { 5088a1b9b6aSSam Leffler { 0 }, /* IEEE80211_MODE_AUTO */ 5098a1b9b6aSSam Leffler { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 5108a1b9b6aSSam Leffler { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */ 5118a1b9b6aSSam Leffler { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G (mixed b/g) */ 5128a1b9b6aSSam Leffler { 0 }, /* IEEE80211_MODE_FH */ 5138a1b9b6aSSam Leffler /* IEEE80211_MODE_PUREG (not yet) */ 5148a1b9b6aSSam Leffler { 7, { 2, 4, 11, 22, 12, 24, 48 } }, 5158a1b9b6aSSam Leffler }; 5168a1b9b6aSSam Leffler int i, j; 5178a1b9b6aSSam Leffler 5188a1b9b6aSSam Leffler for (i = 0; i < rs->rs_nrates; i++) { 5198a1b9b6aSSam Leffler rs->rs_rates[i] &= IEEE80211_RATE_VAL; 5208a1b9b6aSSam Leffler for (j = 0; j < basic[mode].rs_nrates; j++) 5218a1b9b6aSSam Leffler if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 5228a1b9b6aSSam Leffler rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 5238a1b9b6aSSam Leffler break; 5248a1b9b6aSSam Leffler } 5258a1b9b6aSSam Leffler } 5268a1b9b6aSSam Leffler } 5278a1b9b6aSSam Leffler 5288a1b9b6aSSam Leffler /* 5298a1b9b6aSSam Leffler * WME protocol support. The following parameters come from the spec. 5308a1b9b6aSSam Leffler */ 5318a1b9b6aSSam Leffler typedef struct phyParamType { 5328a1b9b6aSSam Leffler u_int8_t aifsn; 5338a1b9b6aSSam Leffler u_int8_t logcwmin; 5348a1b9b6aSSam Leffler u_int8_t logcwmax; 5358a1b9b6aSSam Leffler u_int16_t txopLimit; 5368a1b9b6aSSam Leffler u_int8_t acm; 5378a1b9b6aSSam Leffler } paramType; 5388a1b9b6aSSam Leffler 5398a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 5408a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_AUTO */ 5418a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_11A */ 5428a1b9b6aSSam Leffler { 3, 5, 7 }, /* IEEE80211_MODE_11B */ 5438a1b9b6aSSam Leffler { 3, 4, 6 }, /* IEEE80211_MODE_11G */ 5448a1b9b6aSSam Leffler { 3, 5, 7 }, /* IEEE80211_MODE_FH */ 5458a1b9b6aSSam Leffler { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_A */ 5468a1b9b6aSSam Leffler { 2, 3, 5 }, /* IEEE80211_MODE_TURBO_G */ 5478a1b9b6aSSam Leffler }; 5488a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 5498a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_AUTO */ 5508a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_11A */ 5518a1b9b6aSSam Leffler { 7, 5, 10 }, /* IEEE80211_MODE_11B */ 5528a1b9b6aSSam Leffler { 7, 4, 10 }, /* IEEE80211_MODE_11G */ 5538a1b9b6aSSam Leffler { 7, 5, 10 }, /* IEEE80211_MODE_FH */ 5548a1b9b6aSSam Leffler { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 5558a1b9b6aSSam Leffler { 7, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 5568a1b9b6aSSam Leffler }; 5578a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 5588a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 5598a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 5608a1b9b6aSSam Leffler { 1, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 5618a1b9b6aSSam Leffler { 1, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 5628a1b9b6aSSam Leffler { 1, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 5638a1b9b6aSSam Leffler { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 5648a1b9b6aSSam Leffler { 1, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 5658a1b9b6aSSam Leffler }; 5668a1b9b6aSSam Leffler static const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 5678a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 5688a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 5698a1b9b6aSSam Leffler { 1, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 5708a1b9b6aSSam Leffler { 1, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 5718a1b9b6aSSam Leffler { 1, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 5728a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 5738a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 5748a1b9b6aSSam Leffler }; 5758a1b9b6aSSam Leffler 5768a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 5778a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_AUTO */ 5788a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_11A */ 5798a1b9b6aSSam Leffler { 3, 5, 10 }, /* IEEE80211_MODE_11B */ 5808a1b9b6aSSam Leffler { 3, 4, 10 }, /* IEEE80211_MODE_11G */ 5818a1b9b6aSSam Leffler { 3, 5, 10 }, /* IEEE80211_MODE_FH */ 5828a1b9b6aSSam Leffler { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_A */ 5838a1b9b6aSSam Leffler { 2, 3, 10 }, /* IEEE80211_MODE_TURBO_G */ 5848a1b9b6aSSam Leffler }; 5858a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 5868a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_AUTO */ 5878a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_11A */ 5888a1b9b6aSSam Leffler { 2, 4, 5, 188 }, /* IEEE80211_MODE_11B */ 5898a1b9b6aSSam Leffler { 2, 3, 4, 94 }, /* IEEE80211_MODE_11G */ 5908a1b9b6aSSam Leffler { 2, 4, 5, 188 }, /* IEEE80211_MODE_FH */ 5918a1b9b6aSSam Leffler { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_A */ 5928a1b9b6aSSam Leffler { 2, 2, 3, 94 }, /* IEEE80211_MODE_TURBO_G */ 5938a1b9b6aSSam Leffler }; 5948a1b9b6aSSam Leffler static const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 5958a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_AUTO */ 5968a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_11A */ 5978a1b9b6aSSam Leffler { 2, 3, 4, 102 }, /* IEEE80211_MODE_11B */ 5988a1b9b6aSSam Leffler { 2, 2, 3, 47 }, /* IEEE80211_MODE_11G */ 5998a1b9b6aSSam Leffler { 2, 3, 4, 102 }, /* IEEE80211_MODE_FH */ 6008a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_A */ 6018a1b9b6aSSam Leffler { 1, 2, 2, 47 }, /* IEEE80211_MODE_TURBO_G */ 6028a1b9b6aSSam Leffler }; 6038a1b9b6aSSam Leffler 6048a1b9b6aSSam Leffler void 6058a1b9b6aSSam Leffler ieee80211_wme_initparams(struct ieee80211com *ic) 6068a1b9b6aSSam Leffler { 6078a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 6088a1b9b6aSSam Leffler const paramType *pPhyParam, *pBssPhyParam; 6098a1b9b6aSSam Leffler struct wmeParams *wmep; 6108a1b9b6aSSam Leffler int i; 6118a1b9b6aSSam Leffler 6128a1b9b6aSSam Leffler if ((ic->ic_caps & IEEE80211_C_WME) == 0) 6138a1b9b6aSSam Leffler return; 6148a1b9b6aSSam Leffler 6158a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 6168a1b9b6aSSam Leffler switch (i) { 6178a1b9b6aSSam Leffler case WME_AC_BK: 6188a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 6198a1b9b6aSSam Leffler pBssPhyParam = &phyParamForAC_BK[ic->ic_curmode]; 6208a1b9b6aSSam Leffler break; 6218a1b9b6aSSam Leffler case WME_AC_VI: 6228a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_VI[ic->ic_curmode]; 6238a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_VI[ic->ic_curmode]; 6248a1b9b6aSSam Leffler break; 6258a1b9b6aSSam Leffler case WME_AC_VO: 6268a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_VO[ic->ic_curmode]; 6278a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_VO[ic->ic_curmode]; 6288a1b9b6aSSam Leffler break; 6298a1b9b6aSSam Leffler case WME_AC_BE: 6308a1b9b6aSSam Leffler default: 6318a1b9b6aSSam Leffler pPhyParam = &phyParamForAC_BE[ic->ic_curmode]; 6328a1b9b6aSSam Leffler pBssPhyParam = &bssPhyParamForAC_BE[ic->ic_curmode]; 6338a1b9b6aSSam Leffler break; 6348a1b9b6aSSam Leffler } 6358a1b9b6aSSam Leffler 6368a1b9b6aSSam Leffler wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 6378a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 6388a1b9b6aSSam Leffler wmep->wmep_acm = pPhyParam->acm; 6398a1b9b6aSSam Leffler wmep->wmep_aifsn = pPhyParam->aifsn; 6408a1b9b6aSSam Leffler wmep->wmep_logcwmin = pPhyParam->logcwmin; 6418a1b9b6aSSam Leffler wmep->wmep_logcwmax = pPhyParam->logcwmax; 6428a1b9b6aSSam Leffler wmep->wmep_txopLimit = pPhyParam->txopLimit; 6438a1b9b6aSSam Leffler } else { 6448a1b9b6aSSam Leffler wmep->wmep_acm = pBssPhyParam->acm; 6458a1b9b6aSSam Leffler wmep->wmep_aifsn = pBssPhyParam->aifsn; 6468a1b9b6aSSam Leffler wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 6478a1b9b6aSSam Leffler wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 6488a1b9b6aSSam Leffler wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 6498a1b9b6aSSam Leffler 6508a1b9b6aSSam Leffler } 6518a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 6528a1b9b6aSSam Leffler "%s: %s chan [acm %u aifsn %u log2(cwmin) %u " 6538a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 6548a1b9b6aSSam Leffler , ieee80211_wme_acnames[i] 6558a1b9b6aSSam Leffler , wmep->wmep_acm 6568a1b9b6aSSam Leffler , wmep->wmep_aifsn 6578a1b9b6aSSam Leffler , wmep->wmep_logcwmin 6588a1b9b6aSSam Leffler , wmep->wmep_logcwmax 6598a1b9b6aSSam Leffler , wmep->wmep_txopLimit 6608a1b9b6aSSam Leffler ); 6618a1b9b6aSSam Leffler 6628a1b9b6aSSam Leffler wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 6638a1b9b6aSSam Leffler wmep->wmep_acm = pBssPhyParam->acm; 6648a1b9b6aSSam Leffler wmep->wmep_aifsn = pBssPhyParam->aifsn; 6658a1b9b6aSSam Leffler wmep->wmep_logcwmin = pBssPhyParam->logcwmin; 6668a1b9b6aSSam Leffler wmep->wmep_logcwmax = pBssPhyParam->logcwmax; 6678a1b9b6aSSam Leffler wmep->wmep_txopLimit = pBssPhyParam->txopLimit; 6688a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 6698a1b9b6aSSam Leffler "%s: %s bss [acm %u aifsn %u log2(cwmin) %u " 6708a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 6718a1b9b6aSSam Leffler , ieee80211_wme_acnames[i] 6728a1b9b6aSSam Leffler , wmep->wmep_acm 6738a1b9b6aSSam Leffler , wmep->wmep_aifsn 6748a1b9b6aSSam Leffler , wmep->wmep_logcwmin 6758a1b9b6aSSam Leffler , wmep->wmep_logcwmax 6768a1b9b6aSSam Leffler , wmep->wmep_txopLimit 6778a1b9b6aSSam Leffler ); 6788a1b9b6aSSam Leffler } 6798a1b9b6aSSam Leffler /* NB: check ic_bss to avoid NULL deref on initial attach */ 6808a1b9b6aSSam Leffler if (ic->ic_bss != NULL) { 6818a1b9b6aSSam Leffler /* 6828a1b9b6aSSam Leffler * Calculate agressive mode switching threshold based 6838a1b9b6aSSam Leffler * on beacon interval. This doesn't need locking since 6848a1b9b6aSSam Leffler * we're only called before entering the RUN state at 6858a1b9b6aSSam Leffler * which point we start sending beacon frames. 6868a1b9b6aSSam Leffler */ 6878a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh = 6888a1b9b6aSSam Leffler (HIGH_PRI_SWITCH_THRESH * ic->ic_bss->ni_intval) / 100; 6898a1b9b6aSSam Leffler ieee80211_wme_updateparams(ic); 6908a1b9b6aSSam Leffler } 6918a1b9b6aSSam Leffler } 6928a1b9b6aSSam Leffler 6938a1b9b6aSSam Leffler /* 6948a1b9b6aSSam Leffler * Update WME parameters for ourself and the BSS. 6958a1b9b6aSSam Leffler */ 6968a1b9b6aSSam Leffler void 6978a1b9b6aSSam Leffler ieee80211_wme_updateparams_locked(struct ieee80211com *ic) 6988a1b9b6aSSam Leffler { 6998a1b9b6aSSam Leffler static const paramType phyParam[IEEE80211_MODE_MAX] = { 7008a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_AUTO */ 7018a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_11A */ 7028a1b9b6aSSam Leffler { 2, 5, 10, 64 }, /* IEEE80211_MODE_11B */ 7038a1b9b6aSSam Leffler { 2, 4, 10, 64 }, /* IEEE80211_MODE_11G */ 7048a1b9b6aSSam Leffler { 2, 5, 10, 64 }, /* IEEE80211_MODE_FH */ 7058a1b9b6aSSam Leffler { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_A */ 7068a1b9b6aSSam Leffler { 1, 3, 10, 64 }, /* IEEE80211_MODE_TURBO_G */ 7078a1b9b6aSSam Leffler }; 7088a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 7098a1b9b6aSSam Leffler const struct wmeParams *wmep; 7108a1b9b6aSSam Leffler struct wmeParams *chanp, *bssp; 7118a1b9b6aSSam Leffler int i; 7128a1b9b6aSSam Leffler 7138a1b9b6aSSam Leffler /* set up the channel access parameters for the physical device */ 7148a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 7158a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[i]; 7168a1b9b6aSSam Leffler wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 7178a1b9b6aSSam Leffler chanp->wmep_aifsn = wmep->wmep_aifsn; 7188a1b9b6aSSam Leffler chanp->wmep_logcwmin = wmep->wmep_logcwmin; 7198a1b9b6aSSam Leffler chanp->wmep_logcwmax = wmep->wmep_logcwmax; 7208a1b9b6aSSam Leffler chanp->wmep_txopLimit = wmep->wmep_txopLimit; 7218a1b9b6aSSam Leffler 7228a1b9b6aSSam Leffler chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 7238a1b9b6aSSam Leffler wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 7248a1b9b6aSSam Leffler chanp->wmep_aifsn = wmep->wmep_aifsn; 7258a1b9b6aSSam Leffler chanp->wmep_logcwmin = wmep->wmep_logcwmin; 7268a1b9b6aSSam Leffler chanp->wmep_logcwmax = wmep->wmep_logcwmax; 7278a1b9b6aSSam Leffler chanp->wmep_txopLimit = wmep->wmep_txopLimit; 7288a1b9b6aSSam Leffler } 7298a1b9b6aSSam Leffler 7308a1b9b6aSSam Leffler /* 7318a1b9b6aSSam Leffler * This implements agressive mode as found in certain 7328a1b9b6aSSam Leffler * vendors' AP's. When there is significant high 7338a1b9b6aSSam Leffler * priority (VI/VO) traffic in the BSS throttle back BE 7348a1b9b6aSSam Leffler * traffic by using conservative parameters. Otherwise 7358a1b9b6aSSam Leffler * BE uses agressive params to optimize performance of 7368a1b9b6aSSam Leffler * legacy/non-QoS traffic. 7378a1b9b6aSSam Leffler */ 7388a1b9b6aSSam Leffler if ((ic->ic_opmode == IEEE80211_M_HOSTAP && 7398a1b9b6aSSam Leffler (wme->wme_flags & WME_F_AGGRMODE) == 0) || 7408a1b9b6aSSam Leffler (ic->ic_opmode != IEEE80211_M_HOSTAP && 7418a1b9b6aSSam Leffler (ic->ic_bss->ni_flags & IEEE80211_NODE_QOS) == 0) || 7428a1b9b6aSSam Leffler (ic->ic_flags & IEEE80211_F_WME) == 0) { 7438a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 7448a1b9b6aSSam Leffler bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 7458a1b9b6aSSam Leffler 7468a1b9b6aSSam Leffler chanp->wmep_aifsn = bssp->wmep_aifsn = 7478a1b9b6aSSam Leffler phyParam[ic->ic_curmode].aifsn; 7488a1b9b6aSSam Leffler chanp->wmep_logcwmin = bssp->wmep_logcwmin = 7498a1b9b6aSSam Leffler phyParam[ic->ic_curmode].logcwmin; 7508a1b9b6aSSam Leffler chanp->wmep_logcwmax = bssp->wmep_logcwmax = 7518a1b9b6aSSam Leffler phyParam[ic->ic_curmode].logcwmax; 7528a1b9b6aSSam Leffler chanp->wmep_txopLimit = bssp->wmep_txopLimit = 7538a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_BURST) ? 7548a1b9b6aSSam Leffler phyParam[ic->ic_curmode].txopLimit : 0; 7558a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 7568a1b9b6aSSam Leffler "%s: %s [acm %u aifsn %u log2(cwmin) %u " 7578a1b9b6aSSam Leffler "log2(cwmax) %u txpoLimit %u]\n", __func__ 7588a1b9b6aSSam Leffler , ieee80211_wme_acnames[WME_AC_BE] 7598a1b9b6aSSam Leffler , chanp->wmep_acm 7608a1b9b6aSSam Leffler , chanp->wmep_aifsn 7618a1b9b6aSSam Leffler , chanp->wmep_logcwmin 7628a1b9b6aSSam Leffler , chanp->wmep_logcwmax 7638a1b9b6aSSam Leffler , chanp->wmep_txopLimit 7648a1b9b6aSSam Leffler ); 7658a1b9b6aSSam Leffler } 7668a1b9b6aSSam Leffler 7678a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 7688a1b9b6aSSam Leffler ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) == 0) { 7698a1b9b6aSSam Leffler static const u_int8_t logCwMin[IEEE80211_MODE_MAX] = { 7708a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_AUTO */ 7718a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_11A */ 7728a1b9b6aSSam Leffler 4, /* IEEE80211_MODE_11B */ 7738a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_11G */ 7748a1b9b6aSSam Leffler 4, /* IEEE80211_MODE_FH */ 7758a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_TURBO_A */ 7768a1b9b6aSSam Leffler 3, /* IEEE80211_MODE_TURBO_G */ 7778a1b9b6aSSam Leffler }; 7788a1b9b6aSSam Leffler chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 7798a1b9b6aSSam Leffler bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 7808a1b9b6aSSam Leffler 7818a1b9b6aSSam Leffler chanp->wmep_logcwmin = bssp->wmep_logcwmin = 7828a1b9b6aSSam Leffler logCwMin[ic->ic_curmode]; 7838a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 7848a1b9b6aSSam Leffler "%s: %s log2(cwmin) %u\n", __func__ 7858a1b9b6aSSam Leffler , ieee80211_wme_acnames[WME_AC_BE] 7868a1b9b6aSSam Leffler , chanp->wmep_logcwmin 7878a1b9b6aSSam Leffler ); 7888a1b9b6aSSam Leffler } 7898a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP) { /* XXX ibss? */ 7908a1b9b6aSSam Leffler /* 7918a1b9b6aSSam Leffler * Arrange for a beacon update and bump the parameter 7928a1b9b6aSSam Leffler * set number so associated stations load the new values. 7938a1b9b6aSSam Leffler */ 7948a1b9b6aSSam Leffler wme->wme_bssChanParams.cap_info = 7958a1b9b6aSSam Leffler (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 7968a1b9b6aSSam Leffler ic->ic_flags |= IEEE80211_F_WMEUPDATE; 7978a1b9b6aSSam Leffler } 7988a1b9b6aSSam Leffler 7998a1b9b6aSSam Leffler wme->wme_update(ic); 8008a1b9b6aSSam Leffler 8018a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_WME, 8028a1b9b6aSSam Leffler "%s: WME params updated, cap_info 0x%x\n", __func__, 8038a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_STA ? 8048a1b9b6aSSam Leffler wme->wme_wmeChanParams.cap_info : 8058a1b9b6aSSam Leffler wme->wme_bssChanParams.cap_info); 8068a1b9b6aSSam Leffler } 8078a1b9b6aSSam Leffler 8088a1b9b6aSSam Leffler void 8098a1b9b6aSSam Leffler ieee80211_wme_updateparams(struct ieee80211com *ic) 8108a1b9b6aSSam Leffler { 8118a1b9b6aSSam Leffler 8128a1b9b6aSSam Leffler if (ic->ic_caps & IEEE80211_C_WME) { 8138a1b9b6aSSam Leffler IEEE80211_BEACON_LOCK(ic); 8148a1b9b6aSSam Leffler ieee80211_wme_updateparams_locked(ic); 8158a1b9b6aSSam Leffler IEEE80211_BEACON_UNLOCK(ic); 8168a1b9b6aSSam Leffler } 8178a1b9b6aSSam Leffler } 8188a1b9b6aSSam Leffler 8197edb8cf9SSam Leffler static void 8207edb8cf9SSam Leffler sta_disassoc(void *arg, struct ieee80211_node *ni) 8217edb8cf9SSam Leffler { 8227edb8cf9SSam Leffler struct ieee80211com *ic = arg; 8237edb8cf9SSam Leffler 8247edb8cf9SSam Leffler if (ni->ni_associd != 0) { 8257edb8cf9SSam Leffler IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DISASSOC, 8267edb8cf9SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 8277edb8cf9SSam Leffler ieee80211_node_leave(ic, ni); 8287edb8cf9SSam Leffler } 8297edb8cf9SSam Leffler } 8307edb8cf9SSam Leffler 8317edb8cf9SSam Leffler static void 8327edb8cf9SSam Leffler sta_deauth(void *arg, struct ieee80211_node *ni) 8337edb8cf9SSam Leffler { 8347edb8cf9SSam Leffler struct ieee80211com *ic = arg; 8357edb8cf9SSam Leffler 8367edb8cf9SSam Leffler IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH, 8377edb8cf9SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 8387edb8cf9SSam Leffler } 8397edb8cf9SSam Leffler 8408a1b9b6aSSam Leffler static int 8418a1b9b6aSSam Leffler ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) 8428a1b9b6aSSam Leffler { 8438a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 8441a1e1d21SSam Leffler struct ieee80211_node *ni; 845a11c9a5cSSam Leffler enum ieee80211_state ostate; 8461a1e1d21SSam Leffler 8471a1e1d21SSam Leffler ostate = ic->ic_state; 8488a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__, 8498a1b9b6aSSam Leffler ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 850a11c9a5cSSam Leffler ic->ic_state = nstate; /* state transition */ 8511a1e1d21SSam Leffler ni = ic->ic_bss; /* NB: no reference held */ 8521a1e1d21SSam Leffler switch (nstate) { 8531a1e1d21SSam Leffler case IEEE80211_S_INIT: 8541a1e1d21SSam Leffler switch (ostate) { 8551a1e1d21SSam Leffler case IEEE80211_S_INIT: 8561a1e1d21SSam Leffler break; 8571a1e1d21SSam Leffler case IEEE80211_S_RUN: 8581a1e1d21SSam Leffler switch (ic->ic_opmode) { 8591a1e1d21SSam Leffler case IEEE80211_M_STA: 8601a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8611a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 8621a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 8638a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 8641a1e1d21SSam Leffler break; 8651a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 8667edb8cf9SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, 8677edb8cf9SSam Leffler sta_disassoc, ic); 8681a1e1d21SSam Leffler break; 8691a1e1d21SSam Leffler default: 8701a1e1d21SSam Leffler break; 8711a1e1d21SSam Leffler } 8728a1b9b6aSSam Leffler goto reset; 8731a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 8741a1e1d21SSam Leffler switch (ic->ic_opmode) { 8751a1e1d21SSam Leffler case IEEE80211_M_STA: 8761a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 8771a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 8781a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 8791a1e1d21SSam Leffler break; 8801a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 8817edb8cf9SSam Leffler ieee80211_iterate_nodes(&ic->ic_sta, 8827edb8cf9SSam Leffler sta_deauth, ic); 8831a1e1d21SSam Leffler break; 8841a1e1d21SSam Leffler default: 8851a1e1d21SSam Leffler break; 8861a1e1d21SSam Leffler } 8878a1b9b6aSSam Leffler goto reset; 8881a1e1d21SSam Leffler case IEEE80211_S_SCAN: 889c75ac469SSam Leffler ieee80211_cancel_scan(ic); 890c75ac469SSam Leffler goto reset; 891c75ac469SSam Leffler case IEEE80211_S_AUTH: 8928a1b9b6aSSam Leffler reset: 8931a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 8941a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 8958a1b9b6aSSam Leffler ieee80211_reset_bss(ic); 8961a1e1d21SSam Leffler break; 8971a1e1d21SSam Leffler } 8988a1b9b6aSSam Leffler if (ic->ic_auth->ia_detach != NULL) 8998a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 9001a1e1d21SSam Leffler break; 9011a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9021a1e1d21SSam Leffler switch (ostate) { 9031a1e1d21SSam Leffler case IEEE80211_S_INIT: 9048a1b9b6aSSam Leffler if ((ic->ic_opmode == IEEE80211_M_HOSTAP || 9058a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_IBSS || 9068a1b9b6aSSam Leffler ic->ic_opmode == IEEE80211_M_AHDEMO) && 9071a1e1d21SSam Leffler ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 9081a1e1d21SSam Leffler /* 9091a1e1d21SSam Leffler * AP operation and we already have a channel; 9101a1e1d21SSam Leffler * bypass the scan and startup immediately. 9111a1e1d21SSam Leffler */ 9121a1e1d21SSam Leffler ieee80211_create_ibss(ic, ic->ic_des_chan); 9131a1e1d21SSam Leffler } else { 9148a1b9b6aSSam Leffler ieee80211_begin_scan(ic, arg); 9151a1e1d21SSam Leffler } 9161a1e1d21SSam Leffler break; 9171a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9188a1b9b6aSSam Leffler /* 9198a1b9b6aSSam Leffler * Scan next. If doing an active scan and the 9208a1b9b6aSSam Leffler * channel is not marked passive-only then send 9218a1b9b6aSSam Leffler * a probe request. Otherwise just listen for 9228a1b9b6aSSam Leffler * beacons on the channel. 9238a1b9b6aSSam Leffler */ 9248a1b9b6aSSam Leffler if ((ic->ic_flags & IEEE80211_F_ASCAN) && 9258a1b9b6aSSam Leffler (ni->ni_chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) { 9261a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9271a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 9281a1e1d21SSam Leffler } 9291a1e1d21SSam Leffler break; 9301a1e1d21SSam Leffler case IEEE80211_S_RUN: 9311a1e1d21SSam Leffler /* beacon miss */ 9328a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_STATE, 9338a1b9b6aSSam Leffler "no recent beacons from %s; rescanning\n", 9341a1e1d21SSam Leffler ether_sprintf(ic->ic_bss->ni_bssid)); 9358a1b9b6aSSam Leffler ieee80211_sta_leave(ic, ni); 9368a1b9b6aSSam Leffler ic->ic_flags &= ~IEEE80211_F_SIBSS; /* XXX */ 9371a1e1d21SSam Leffler /* FALLTHRU */ 9381a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9391a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9401a1e1d21SSam Leffler /* timeout restart scan */ 9418a1b9b6aSSam Leffler ni = ieee80211_find_node(&ic->ic_scan, 9428a1b9b6aSSam Leffler ic->ic_bss->ni_macaddr); 9431a1e1d21SSam Leffler if (ni != NULL) { 9441a1e1d21SSam Leffler ni->ni_fails++; 9451a1e1d21SSam Leffler ieee80211_unref_node(&ni); 9461a1e1d21SSam Leffler } 947ae8880fdSSam Leffler if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) 9488a1b9b6aSSam Leffler ieee80211_begin_scan(ic, arg); 9491a1e1d21SSam Leffler break; 9501a1e1d21SSam Leffler } 9511a1e1d21SSam Leffler break; 9521a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9531a1e1d21SSam Leffler switch (ostate) { 9541a1e1d21SSam Leffler case IEEE80211_S_INIT: 9551a1e1d21SSam Leffler case IEEE80211_S_SCAN: 9561a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9571a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 9581a1e1d21SSam Leffler break; 9591a1e1d21SSam Leffler case IEEE80211_S_AUTH: 9601a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 9618a1b9b6aSSam Leffler switch (arg) { 9621a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 9631a1e1d21SSam Leffler /* ??? */ 9641a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9651a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 9661a1e1d21SSam Leffler break; 9671a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 9681a1e1d21SSam Leffler /* ignore and retry scan on timeout */ 9691a1e1d21SSam Leffler break; 9701a1e1d21SSam Leffler } 9711a1e1d21SSam Leffler break; 9721a1e1d21SSam Leffler case IEEE80211_S_RUN: 9738a1b9b6aSSam Leffler switch (arg) { 9741a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 9751a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9761a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 9771a1e1d21SSam Leffler ic->ic_state = ostate; /* stay RUN */ 9781a1e1d21SSam Leffler break; 9791a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 980ae8880fdSSam Leffler ieee80211_sta_leave(ic, ni); 981ae8880fdSSam Leffler if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 9821a1e1d21SSam Leffler /* try to reauth */ 9831a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 9841a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 985ae8880fdSSam Leffler } 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: 1004ae8880fdSSam Leffler ieee80211_sta_leave(ic, ni); 1005ae8880fdSSam Leffler if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) { 10061a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 10071a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 1008ae8880fdSSam Leffler } 10091a1e1d21SSam Leffler break; 10101a1e1d21SSam Leffler } 10111a1e1d21SSam Leffler break; 10121a1e1d21SSam Leffler case IEEE80211_S_RUN: 10138a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_WPA) { 10148a1b9b6aSSam Leffler /* XXX validate prerequisites */ 10158a1b9b6aSSam Leffler } 10161a1e1d21SSam Leffler switch (ostate) { 10171a1e1d21SSam Leffler case IEEE80211_S_INIT: 10188a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_MONITOR) 10198a1b9b6aSSam Leffler break; 10208a1b9b6aSSam Leffler /* fall thru... */ 10211a1e1d21SSam Leffler case IEEE80211_S_AUTH: 10228a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY, 10238a1b9b6aSSam Leffler "%s: invalid transition\n", __func__); 10242c21ffc8SSam Leffler /* fall thru... */ 10252c21ffc8SSam Leffler case IEEE80211_S_RUN: 10261a1e1d21SSam Leffler break; 10271a1e1d21SSam Leffler case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 10281a1e1d21SSam Leffler case IEEE80211_S_ASSOC: /* infra mode */ 10291a1e1d21SSam Leffler KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 10301a1e1d21SSam Leffler ("%s: bogus xmit rate %u setup\n", __func__, 10311a1e1d21SSam Leffler ni->ni_txrate)); 10328a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 10338a1b9b6aSSam Leffler if (ieee80211_msg_debug(ic)) { 10341a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 10358a1b9b6aSSam Leffler if_printf(ifp, "associated "); 10361a1e1d21SSam Leffler else 10378a1b9b6aSSam Leffler if_printf(ifp, "synchronized "); 10381a1e1d21SSam Leffler printf("with %s ssid ", 10391a1e1d21SSam Leffler ether_sprintf(ni->ni_bssid)); 10401a1e1d21SSam Leffler ieee80211_print_essid(ic->ic_bss->ni_essid, 10411a1e1d21SSam Leffler ni->ni_esslen); 10421a1e1d21SSam Leffler printf(" channel %d start %uMb\n", 10431a1e1d21SSam Leffler ieee80211_chan2ieee(ic, ni->ni_chan), 10441a1e1d21SSam Leffler IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 10451a1e1d21SSam Leffler } 10468a1b9b6aSSam Leffler #endif 10471a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 10488a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 10498a1b9b6aSSam Leffler ieee80211_notify_node_join(ic, ni, 10508a1b9b6aSSam Leffler arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP); 10518a1b9b6aSSam Leffler if_start(ifp); /* XXX not authorized yet */ 10521a1e1d21SSam Leffler break; 10531a1e1d21SSam Leffler } 10548a1b9b6aSSam Leffler /* 10558a1b9b6aSSam Leffler * Start/stop the authenticator when operating as an 10568a1b9b6aSSam Leffler * AP. We delay until here to allow configuration to 10578a1b9b6aSSam Leffler * happen out of order. 10588a1b9b6aSSam Leffler */ 10598a1b9b6aSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */ 10608a1b9b6aSSam Leffler ic->ic_auth->ia_attach != NULL) { 10618a1b9b6aSSam Leffler /* XXX check failure */ 10628a1b9b6aSSam Leffler ic->ic_auth->ia_attach(ic); 10638a1b9b6aSSam Leffler } else if (ic->ic_auth->ia_detach != NULL) { 10648a1b9b6aSSam Leffler ic->ic_auth->ia_detach(ic); 10658a1b9b6aSSam Leffler } 10668a1b9b6aSSam Leffler /* 10678a1b9b6aSSam Leffler * When 802.1x is not in use mark the port authorized 10688a1b9b6aSSam Leffler * at this point so traffic can flow. 10698a1b9b6aSSam Leffler */ 10708a1b9b6aSSam Leffler if (ni->ni_authmode != IEEE80211_AUTH_8021X) 10718a1b9b6aSSam Leffler ieee80211_node_authorize(ic, ni); 10728a1b9b6aSSam Leffler /* 10738a1b9b6aSSam Leffler * Enable inactivity processing. 10748a1b9b6aSSam Leffler * XXX 10758a1b9b6aSSam Leffler */ 10768a1b9b6aSSam Leffler ic->ic_scan.nt_inact_timer = IEEE80211_INACT_WAIT; 1077acc4f7f5SSam Leffler ic->ic_sta.nt_inact_timer = IEEE80211_INACT_WAIT; 10781a1e1d21SSam Leffler break; 10791a1e1d21SSam Leffler } 10801a1e1d21SSam Leffler return 0; 10811a1e1d21SSam Leffler } 1082