ieee80211_proto.c revision 244062
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3178354Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116904Ssam * notice, this list of conditions and the following disclaimer. 11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116904Ssam * notice, this list of conditions and the following disclaimer in the 13116904Ssam * documentation and/or other materials provided with the distribution. 14116742Ssam * 15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116742Ssam */ 26116742Ssam 27116742Ssam#include <sys/cdefs.h> 28116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_proto.c 244062 2012-12-10 00:16:38Z adrian $"); 29116742Ssam 30116742Ssam/* 31116742Ssam * IEEE 802.11 protocol support. 32116742Ssam */ 33116742Ssam 34116742Ssam#include "opt_inet.h" 35178354Ssam#include "opt_wlan.h" 36116742Ssam 37116742Ssam#include <sys/param.h> 38138568Ssam#include <sys/kernel.h> 39170530Ssam#include <sys/systm.h> 40170530Ssam 41116742Ssam#include <sys/socket.h> 42178354Ssam#include <sys/sockio.h> 43116742Ssam 44116742Ssam#include <net/if.h> 45116742Ssam#include <net/if_media.h> 46138568Ssam#include <net/ethernet.h> /* XXX for ether_sprintf */ 47116742Ssam 48116742Ssam#include <net80211/ieee80211_var.h> 49178354Ssam#include <net80211/ieee80211_adhoc.h> 50178354Ssam#include <net80211/ieee80211_sta.h> 51178354Ssam#include <net80211/ieee80211_hostap.h> 52178354Ssam#include <net80211/ieee80211_wds.h> 53195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 54195618Srpaulo#include <net80211/ieee80211_mesh.h> 55195618Srpaulo#endif 56178354Ssam#include <net80211/ieee80211_monitor.h> 57178354Ssam#include <net80211/ieee80211_input.h> 58116742Ssam 59138568Ssam/* XXX tunables */ 60138568Ssam#define AGGRESSIVE_MODE_SWITCH_HYSTERESIS 3 /* pkts / 100ms */ 61138568Ssam#define HIGH_PRI_SWITCH_THRESH 10 /* pkts / 100ms */ 62116742Ssam 63116742Ssamconst char *ieee80211_mgt_subtype_name[] = { 64116742Ssam "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 65116742Ssam "probe_req", "probe_resp", "reserved#6", "reserved#7", 66116742Ssam "beacon", "atim", "disassoc", "auth", 67218927Sbschmidt "deauth", "action", "action_noack", "reserved#15" 68116742Ssam}; 69138568Ssamconst char *ieee80211_ctl_subtype_name[] = { 70138568Ssam "reserved#0", "reserved#1", "reserved#2", "reserved#3", 71138568Ssam "reserved#3", "reserved#5", "reserved#6", "reserved#7", 72138568Ssam "reserved#8", "reserved#9", "ps_poll", "rts", 73138568Ssam "cts", "ack", "cf_end", "cf_end_ack" 74138568Ssam}; 75167283Ssamconst char *ieee80211_opmode_name[IEEE80211_OPMODE_MAX] = { 76167283Ssam "IBSS", /* IEEE80211_M_IBSS */ 77167283Ssam "STA", /* IEEE80211_M_STA */ 78178354Ssam "WDS", /* IEEE80211_M_WDS */ 79167283Ssam "AHDEMO", /* IEEE80211_M_AHDEMO */ 80167283Ssam "HOSTAP", /* IEEE80211_M_HOSTAP */ 81195618Srpaulo "MONITOR", /* IEEE80211_M_MONITOR */ 82195618Srpaulo "MBSS" /* IEEE80211_M_MBSS */ 83167283Ssam}; 84117811Ssamconst char *ieee80211_state_name[IEEE80211_S_MAX] = { 85117811Ssam "INIT", /* IEEE80211_S_INIT */ 86117811Ssam "SCAN", /* IEEE80211_S_SCAN */ 87117811Ssam "AUTH", /* IEEE80211_S_AUTH */ 88117811Ssam "ASSOC", /* IEEE80211_S_ASSOC */ 89172058Ssam "CAC", /* IEEE80211_S_CAC */ 90172058Ssam "RUN", /* IEEE80211_S_RUN */ 91172058Ssam "CSA", /* IEEE80211_S_CSA */ 92172058Ssam "SLEEP", /* IEEE80211_S_SLEEP */ 93117811Ssam}; 94138568Ssamconst char *ieee80211_wme_acnames[] = { 95138568Ssam "WME_AC_BE", 96138568Ssam "WME_AC_BK", 97138568Ssam "WME_AC_VI", 98138568Ssam "WME_AC_VO", 99138568Ssam "WME_UPSD", 100138568Ssam}; 101116742Ssam 102191746Sthompsastatic void beacon_miss(void *, int); 103191746Sthompsastatic void beacon_swmiss(void *, int); 104178354Ssamstatic void parent_updown(void *, int); 105191746Sthompsastatic void update_mcast(void *, int); 106191746Sthompsastatic void update_promisc(void *, int); 107191746Sthompsastatic void update_channel(void *, int); 108233452Sadrianstatic void update_chw(void *, int); 109191746Sthompsastatic void ieee80211_newstate_cb(void *, int); 110178354Ssamstatic int ieee80211_new_state_locked(struct ieee80211vap *, 111178354Ssam enum ieee80211_state, int); 112117811Ssam 113178354Ssamstatic int 114178354Ssamnull_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, 115178354Ssam const struct ieee80211_bpf_params *params) 116172211Ssam{ 117178354Ssam struct ifnet *ifp = ni->ni_ic->ic_ifp; 118178354Ssam 119178354Ssam if_printf(ifp, "missing ic_raw_xmit callback, drop frame\n"); 120178354Ssam m_freem(m); 121178354Ssam return ENETDOWN; 122172211Ssam} 123172211Ssam 124116742Ssamvoid 125138568Ssamieee80211_proto_attach(struct ieee80211com *ic) 126116742Ssam{ 127138568Ssam struct ifnet *ifp = ic->ic_ifp; 128116742Ssam 129178354Ssam /* override the 802.3 setting */ 130178354Ssam ifp->if_hdrlen = ic->ic_headroom 131178354Ssam + sizeof(struct ieee80211_qosframe_addr4) 132178354Ssam + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN 133178354Ssam + IEEE80211_WEP_EXTIVLEN; 134178354Ssam /* XXX no way to recalculate on ifdetach */ 135178354Ssam if (ALIGN(ifp->if_hdrlen) > max_linkhdr) { 136178354Ssam /* XXX sanity check... */ 137178354Ssam max_linkhdr = ALIGN(ifp->if_hdrlen); 138178354Ssam max_hdr = max_linkhdr + max_protohdr; 139178354Ssam max_datalen = MHLEN - max_hdr; 140178354Ssam } 141127648Ssam ic->ic_protmode = IEEE80211_PROT_CTSONLY; 142116742Ssam 143178354Ssam TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ifp); 144191746Sthompsa TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic); 145191746Sthompsa TASK_INIT(&ic->ic_promisc_task, 0, update_promisc, ic); 146191746Sthompsa TASK_INIT(&ic->ic_chan_task, 0, update_channel, ic); 147191746Sthompsa TASK_INIT(&ic->ic_bmiss_task, 0, beacon_miss, ic); 148233452Sadrian TASK_INIT(&ic->ic_chw_task, 0, update_chw, ic); 149178354Ssam 150138568Ssam ic->ic_wme.wme_hipri_switch_hysteresis = 151138568Ssam AGGRESSIVE_MODE_SWITCH_HYSTERESIS; 152138568Ssam 153116742Ssam /* initialize management frame handlers */ 154116742Ssam ic->ic_send_mgmt = ieee80211_send_mgmt; 155178354Ssam ic->ic_raw_xmit = null_raw_xmit; 156178354Ssam 157178354Ssam ieee80211_adhoc_attach(ic); 158178354Ssam ieee80211_sta_attach(ic); 159178354Ssam ieee80211_wds_attach(ic); 160178354Ssam ieee80211_hostap_attach(ic); 161195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 162195618Srpaulo ieee80211_mesh_attach(ic); 163195618Srpaulo#endif 164178354Ssam ieee80211_monitor_attach(ic); 165116742Ssam} 166116742Ssam 167116742Ssamvoid 168138568Ssamieee80211_proto_detach(struct ieee80211com *ic) 169116742Ssam{ 170178354Ssam ieee80211_monitor_detach(ic); 171195618Srpaulo#ifdef IEEE80211_SUPPORT_MESH 172195618Srpaulo ieee80211_mesh_detach(ic); 173195618Srpaulo#endif 174178354Ssam ieee80211_hostap_detach(ic); 175178354Ssam ieee80211_wds_detach(ic); 176178354Ssam ieee80211_adhoc_detach(ic); 177178354Ssam ieee80211_sta_detach(ic); 178178354Ssam} 179116742Ssam 180178354Ssamstatic void 181178354Ssamnull_update_beacon(struct ieee80211vap *vap, int item) 182178354Ssam{ 183178354Ssam} 184178354Ssam 185178354Ssamvoid 186178354Ssamieee80211_proto_vattach(struct ieee80211vap *vap) 187178354Ssam{ 188178354Ssam struct ieee80211com *ic = vap->iv_ic; 189178354Ssam struct ifnet *ifp = vap->iv_ifp; 190178354Ssam int i; 191178354Ssam 192178354Ssam /* override the 802.3 setting */ 193178354Ssam ifp->if_hdrlen = ic->ic_ifp->if_hdrlen; 194178354Ssam 195178354Ssam vap->iv_rtsthreshold = IEEE80211_RTS_DEFAULT; 196178354Ssam vap->iv_fragthreshold = IEEE80211_FRAG_DEFAULT; 197178354Ssam vap->iv_bmiss_max = IEEE80211_BMISS_MAX; 198225913Sadrian callout_init_mtx(&vap->iv_swbmiss, IEEE80211_LOCK_OBJ(ic), 0); 199178354Ssam callout_init(&vap->iv_mgtsend, CALLOUT_MPSAFE); 200191746Sthompsa TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, vap); 201191746Sthompsa TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap); 202138568Ssam /* 203178354Ssam * Install default tx rate handling: no fixed rate, lowest 204178354Ssam * supported rate for mgmt and multicast frames. Default 205178354Ssam * max retry count. These settings can be changed by the 206178354Ssam * driver and/or user applications. 207178354Ssam */ 208188779Ssam for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) { 209178354Ssam const struct ieee80211_rateset *rs = &ic->ic_sup_rates[i]; 210178354Ssam 211178354Ssam vap->iv_txparms[i].ucastrate = IEEE80211_FIXED_RATE_NONE; 212218916Sadrian 213218916Sadrian /* 214218916Sadrian * Setting the management rate to MCS 0 assumes that the 215218916Sadrian * BSS Basic rate set is empty and the BSS Basic MCS set 216218916Sadrian * is not. 217218916Sadrian * 218218916Sadrian * Since we're not checking this, default to the lowest 219218916Sadrian * defined rate for this mode. 220218916Sadrian * 221218916Sadrian * At least one 11n AP (DLINK DIR-825) is reported to drop 222218916Sadrian * some MCS management traffic (eg BA response frames.) 223218916Sadrian * 224218916Sadrian * See also: 9.6.0 of the 802.11n-2009 specification. 225218916Sadrian */ 226218916Sadrian#ifdef NOTYET 227188779Ssam if (i == IEEE80211_MODE_11NA || i == IEEE80211_MODE_11NG) { 228188779Ssam vap->iv_txparms[i].mgmtrate = 0 | IEEE80211_RATE_MCS; 229188779Ssam vap->iv_txparms[i].mcastrate = 0 | IEEE80211_RATE_MCS; 230188779Ssam } else { 231188779Ssam vap->iv_txparms[i].mgmtrate = 232188779Ssam rs->rs_rates[0] & IEEE80211_RATE_VAL; 233188779Ssam vap->iv_txparms[i].mcastrate = 234188779Ssam rs->rs_rates[0] & IEEE80211_RATE_VAL; 235188779Ssam } 236218916Sadrian#endif 237218916Sadrian vap->iv_txparms[i].mgmtrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; 238218916Sadrian vap->iv_txparms[i].mcastrate = rs->rs_rates[0] & IEEE80211_RATE_VAL; 239178354Ssam vap->iv_txparms[i].maxretry = IEEE80211_TXMAX_DEFAULT; 240178354Ssam } 241178354Ssam vap->iv_roaming = IEEE80211_ROAMING_AUTO; 242178354Ssam 243178354Ssam vap->iv_update_beacon = null_update_beacon; 244178354Ssam vap->iv_deliver_data = ieee80211_deliver_data; 245178354Ssam 246178354Ssam /* attach support for operating mode */ 247178354Ssam ic->ic_vattach[vap->iv_opmode](vap); 248178354Ssam} 249178354Ssam 250178354Ssamvoid 251178354Ssamieee80211_proto_vdetach(struct ieee80211vap *vap) 252178354Ssam{ 253178354Ssam#define FREEAPPIE(ie) do { \ 254178354Ssam if (ie != NULL) \ 255186302Ssam free(ie, M_80211_NODE_IE); \ 256178354Ssam} while (0) 257178354Ssam /* 258178354Ssam * Detach operating mode module. 259178354Ssam */ 260178354Ssam if (vap->iv_opdetach != NULL) 261178354Ssam vap->iv_opdetach(vap); 262178354Ssam /* 263138568Ssam * This should not be needed as we detach when reseting 264138568Ssam * the state but be conservative here since the 265138568Ssam * authenticator may do things like spawn kernel threads. 266138568Ssam */ 267178354Ssam if (vap->iv_auth->ia_detach != NULL) 268178354Ssam vap->iv_auth->ia_detach(vap); 269138568Ssam /* 270138568Ssam * Detach any ACL'ator. 271138568Ssam */ 272178354Ssam if (vap->iv_acl != NULL) 273178354Ssam vap->iv_acl->iac_detach(vap); 274178354Ssam 275178354Ssam FREEAPPIE(vap->iv_appie_beacon); 276178354Ssam FREEAPPIE(vap->iv_appie_probereq); 277178354Ssam FREEAPPIE(vap->iv_appie_proberesp); 278178354Ssam FREEAPPIE(vap->iv_appie_assocreq); 279178354Ssam FREEAPPIE(vap->iv_appie_assocresp); 280178354Ssam FREEAPPIE(vap->iv_appie_wpa); 281178354Ssam#undef FREEAPPIE 282116742Ssam} 283116742Ssam 284138568Ssam/* 285138568Ssam * Simple-minded authenticator module support. 286138568Ssam */ 287138568Ssam 288138568Ssam#define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WPA+1) 289138568Ssam/* XXX well-known names */ 290138568Ssamstatic const char *auth_modnames[IEEE80211_AUTH_MAX] = { 291138568Ssam "wlan_internal", /* IEEE80211_AUTH_NONE */ 292138568Ssam "wlan_internal", /* IEEE80211_AUTH_OPEN */ 293138568Ssam "wlan_internal", /* IEEE80211_AUTH_SHARED */ 294138568Ssam "wlan_xauth", /* IEEE80211_AUTH_8021X */ 295138568Ssam "wlan_internal", /* IEEE80211_AUTH_AUTO */ 296138568Ssam "wlan_xauth", /* IEEE80211_AUTH_WPA */ 297138568Ssam}; 298138568Ssamstatic const struct ieee80211_authenticator *authenticators[IEEE80211_AUTH_MAX]; 299138568Ssam 300138568Ssamstatic const struct ieee80211_authenticator auth_internal = { 301138568Ssam .ia_name = "wlan_internal", 302138568Ssam .ia_attach = NULL, 303138568Ssam .ia_detach = NULL, 304138568Ssam .ia_node_join = NULL, 305138568Ssam .ia_node_leave = NULL, 306138568Ssam}; 307138568Ssam 308138568Ssam/* 309138568Ssam * Setup internal authenticators once; they are never unregistered. 310138568Ssam */ 311138568Ssamstatic void 312138568Ssamieee80211_auth_setup(void) 313138568Ssam{ 314138568Ssam ieee80211_authenticator_register(IEEE80211_AUTH_OPEN, &auth_internal); 315138568Ssam ieee80211_authenticator_register(IEEE80211_AUTH_SHARED, &auth_internal); 316138568Ssam ieee80211_authenticator_register(IEEE80211_AUTH_AUTO, &auth_internal); 317138568Ssam} 318138568SsamSYSINIT(wlan_auth, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_auth_setup, NULL); 319138568Ssam 320138568Ssamconst struct ieee80211_authenticator * 321138568Ssamieee80211_authenticator_get(int auth) 322138568Ssam{ 323138568Ssam if (auth >= IEEE80211_AUTH_MAX) 324138568Ssam return NULL; 325138568Ssam if (authenticators[auth] == NULL) 326138568Ssam ieee80211_load_module(auth_modnames[auth]); 327138568Ssam return authenticators[auth]; 328138568Ssam} 329138568Ssam 330116742Ssamvoid 331138568Ssamieee80211_authenticator_register(int type, 332138568Ssam const struct ieee80211_authenticator *auth) 333116742Ssam{ 334138568Ssam if (type >= IEEE80211_AUTH_MAX) 335138568Ssam return; 336138568Ssam authenticators[type] = auth; 337138568Ssam} 338138568Ssam 339138568Ssamvoid 340138568Ssamieee80211_authenticator_unregister(int type) 341138568Ssam{ 342138568Ssam 343138568Ssam if (type >= IEEE80211_AUTH_MAX) 344138568Ssam return; 345138568Ssam authenticators[type] = NULL; 346138568Ssam} 347138568Ssam 348138568Ssam/* 349138568Ssam * Very simple-minded ACL module support. 350138568Ssam */ 351138568Ssam/* XXX just one for now */ 352138568Ssamstatic const struct ieee80211_aclator *acl = NULL; 353138568Ssam 354138568Ssamvoid 355138568Ssamieee80211_aclator_register(const struct ieee80211_aclator *iac) 356138568Ssam{ 357138568Ssam printf("wlan: %s acl policy registered\n", iac->iac_name); 358138568Ssam acl = iac; 359138568Ssam} 360138568Ssam 361138568Ssamvoid 362138568Ssamieee80211_aclator_unregister(const struct ieee80211_aclator *iac) 363138568Ssam{ 364138568Ssam if (acl == iac) 365138568Ssam acl = NULL; 366138568Ssam printf("wlan: %s acl policy unregistered\n", iac->iac_name); 367138568Ssam} 368138568Ssam 369138568Ssamconst struct ieee80211_aclator * 370138568Ssamieee80211_aclator_get(const char *name) 371138568Ssam{ 372138568Ssam if (acl == NULL) 373138568Ssam ieee80211_load_module("wlan_acl"); 374138568Ssam return acl != NULL && strcmp(acl->iac_name, name) == 0 ? acl : NULL; 375138568Ssam} 376138568Ssam 377138568Ssamvoid 378170530Ssamieee80211_print_essid(const uint8_t *essid, int len) 379138568Ssam{ 380170530Ssam const uint8_t *p; 381116742Ssam int i; 382116742Ssam 383116742Ssam if (len > IEEE80211_NWID_LEN) 384116742Ssam len = IEEE80211_NWID_LEN; 385116742Ssam /* determine printable or not */ 386116742Ssam for (i = 0, p = essid; i < len; i++, p++) { 387116742Ssam if (*p < ' ' || *p > 0x7e) 388116742Ssam break; 389116742Ssam } 390116742Ssam if (i == len) { 391116742Ssam printf("\""); 392116742Ssam for (i = 0, p = essid; i < len; i++, p++) 393116742Ssam printf("%c", *p); 394116742Ssam printf("\""); 395116742Ssam } else { 396116742Ssam printf("0x"); 397116742Ssam for (i = 0, p = essid; i < len; i++, p++) 398116742Ssam printf("%02x", *p); 399116742Ssam } 400116742Ssam} 401116742Ssam 402116742Ssamvoid 403170530Ssamieee80211_dump_pkt(struct ieee80211com *ic, 404170530Ssam const uint8_t *buf, int len, int rate, int rssi) 405116742Ssam{ 406138568Ssam const struct ieee80211_frame *wh; 407116742Ssam int i; 408116742Ssam 409138568Ssam wh = (const struct ieee80211_frame *)buf; 410116742Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 411116742Ssam case IEEE80211_FC1_DIR_NODS: 412116742Ssam printf("NODS %s", ether_sprintf(wh->i_addr2)); 413116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 414116742Ssam printf("(%s)", ether_sprintf(wh->i_addr3)); 415116742Ssam break; 416116742Ssam case IEEE80211_FC1_DIR_TODS: 417116742Ssam printf("TODS %s", ether_sprintf(wh->i_addr2)); 418116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 419116742Ssam printf("(%s)", ether_sprintf(wh->i_addr1)); 420116742Ssam break; 421116742Ssam case IEEE80211_FC1_DIR_FROMDS: 422116742Ssam printf("FRDS %s", ether_sprintf(wh->i_addr3)); 423116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 424116742Ssam printf("(%s)", ether_sprintf(wh->i_addr2)); 425116742Ssam break; 426116742Ssam case IEEE80211_FC1_DIR_DSTODS: 427170530Ssam printf("DSDS %s", ether_sprintf((const uint8_t *)&wh[1])); 428116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 429116742Ssam printf("(%s", ether_sprintf(wh->i_addr2)); 430116742Ssam printf("->%s)", ether_sprintf(wh->i_addr1)); 431116742Ssam break; 432116742Ssam } 433116742Ssam switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 434116742Ssam case IEEE80211_FC0_TYPE_DATA: 435116742Ssam printf(" data"); 436116742Ssam break; 437116742Ssam case IEEE80211_FC0_TYPE_MGT: 438116742Ssam printf(" %s", ieee80211_mgt_subtype_name[ 439116742Ssam (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 440116742Ssam >> IEEE80211_FC0_SUBTYPE_SHIFT]); 441116742Ssam break; 442116742Ssam default: 443116742Ssam printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 444116742Ssam break; 445116742Ssam } 446170530Ssam if (IEEE80211_QOS_HAS_SEQ(wh)) { 447170530Ssam const struct ieee80211_qosframe *qwh = 448170530Ssam (const struct ieee80211_qosframe *)buf; 449170530Ssam printf(" QoS [TID %u%s]", qwh->i_qos[0] & IEEE80211_QOS_TID, 450170530Ssam qwh->i_qos[0] & IEEE80211_QOS_ACKPOLICY ? " ACM" : ""); 451170530Ssam } 452138568Ssam if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 453170530Ssam int off; 454170530Ssam 455170530Ssam off = ieee80211_anyhdrspace(ic, wh); 456170530Ssam printf(" WEP [IV %.02x %.02x %.02x", 457170530Ssam buf[off+0], buf[off+1], buf[off+2]); 458170530Ssam if (buf[off+IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV) 459170530Ssam printf(" %.02x %.02x %.02x", 460170530Ssam buf[off+4], buf[off+5], buf[off+6]); 461170530Ssam printf(" KID %u]", buf[off+IEEE80211_WEP_IVLEN] >> 6); 462138568Ssam } 463116742Ssam if (rate >= 0) 464116742Ssam printf(" %dM", rate / 2); 465116742Ssam if (rssi >= 0) 466116742Ssam printf(" +%d", rssi); 467116742Ssam printf("\n"); 468116742Ssam if (len > 0) { 469116742Ssam for (i = 0; i < len; i++) { 470116742Ssam if ((i & 1) == 0) 471116742Ssam printf(" "); 472116742Ssam printf("%02x", buf[i]); 473116742Ssam } 474116742Ssam printf("\n"); 475116742Ssam } 476116742Ssam} 477116742Ssam 478165887Ssamstatic __inline int 479165887Ssamfindrix(const struct ieee80211_rateset *rs, int r) 480165887Ssam{ 481165887Ssam int i; 482165887Ssam 483165887Ssam for (i = 0; i < rs->rs_nrates; i++) 484165887Ssam if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == r) 485165887Ssam return i; 486165887Ssam return -1; 487165887Ssam} 488165887Ssam 489116742Ssamint 490167442Ssamieee80211_fix_rate(struct ieee80211_node *ni, 491167442Ssam struct ieee80211_rateset *nrs, int flags) 492116742Ssam{ 493116742Ssam#define RV(v) ((v) & IEEE80211_RATE_VAL) 494178354Ssam struct ieee80211vap *vap = ni->ni_vap; 495148299Ssam struct ieee80211com *ic = ni->ni_ic; 496165887Ssam int i, j, rix, error; 497178354Ssam int okrate, badrate, fixedrate, ucastrate; 498165569Ssam const struct ieee80211_rateset *srs; 499170530Ssam uint8_t r; 500116742Ssam 501116742Ssam error = 0; 502170530Ssam okrate = badrate = 0; 503178354Ssam ucastrate = vap->iv_txparms[ieee80211_chan2mode(ni->ni_chan)].ucastrate; 504178354Ssam if (ucastrate != IEEE80211_FIXED_RATE_NONE) { 505178354Ssam /* 506178354Ssam * Workaround awkwardness with fixed rate. We are called 507178354Ssam * to check both the legacy rate set and the HT rate set 508178354Ssam * but we must apply any legacy fixed rate check only to the 509178354Ssam * legacy rate set and vice versa. We cannot tell what type 510178354Ssam * of rate set we've been given (legacy or HT) but we can 511178354Ssam * distinguish the fixed rate type (MCS have 0x80 set). 512178354Ssam * So to deal with this the caller communicates whether to 513178354Ssam * check MCS or legacy rate using the flags and we use the 514178354Ssam * type of any fixed rate to avoid applying an MCS to a 515178354Ssam * legacy rate and vice versa. 516178354Ssam */ 517178354Ssam if (ucastrate & 0x80) { 518178354Ssam if (flags & IEEE80211_F_DOFRATE) 519178354Ssam flags &= ~IEEE80211_F_DOFRATE; 520178354Ssam } else if ((ucastrate & 0x80) == 0) { 521178354Ssam if (flags & IEEE80211_F_DOFMCS) 522178354Ssam flags &= ~IEEE80211_F_DOFMCS; 523178354Ssam } 524178354Ssam /* NB: required to make MCS match below work */ 525178354Ssam ucastrate &= IEEE80211_RATE_VAL; 526178354Ssam } 527170530Ssam fixedrate = IEEE80211_FIXED_RATE_NONE; 528178354Ssam /* 529178354Ssam * XXX we are called to process both MCS and legacy rates; 530178354Ssam * we must use the appropriate basic rate set or chaos will 531178354Ssam * ensue; for now callers that want MCS must supply 532178354Ssam * IEEE80211_F_DOBRS; at some point we'll need to split this 533178354Ssam * function so there are two variants, one for MCS and one 534178354Ssam * for legacy rates. 535178354Ssam */ 536178354Ssam if (flags & IEEE80211_F_DOBRS) 537178354Ssam srs = (const struct ieee80211_rateset *) 538178354Ssam ieee80211_get_suphtrates(ic, ni->ni_chan); 539178354Ssam else 540178354Ssam srs = ieee80211_get_suprates(ic, ni->ni_chan); 541120482Ssam for (i = 0; i < nrs->rs_nrates; ) { 542116742Ssam if (flags & IEEE80211_F_DOSORT) { 543116742Ssam /* 544116742Ssam * Sort rates. 545116742Ssam */ 546116742Ssam for (j = i + 1; j < nrs->rs_nrates; j++) { 547116742Ssam if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 548116742Ssam r = nrs->rs_rates[i]; 549116742Ssam nrs->rs_rates[i] = nrs->rs_rates[j]; 550116742Ssam nrs->rs_rates[j] = r; 551116742Ssam } 552116742Ssam } 553116742Ssam } 554116742Ssam r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 555116742Ssam badrate = r; 556165887Ssam /* 557170530Ssam * Check for fixed rate. 558170530Ssam */ 559178354Ssam if (r == ucastrate) 560170530Ssam fixedrate = r; 561170530Ssam /* 562165887Ssam * Check against supported rates. 563165887Ssam */ 564165887Ssam rix = findrix(srs, r); 565116742Ssam if (flags & IEEE80211_F_DONEGO) { 566165887Ssam if (rix < 0) { 567120482Ssam /* 568120482Ssam * A rate in the node's rate set is not 569120482Ssam * supported. If this is a basic rate and we 570165887Ssam * are operating as a STA then this is an error. 571120482Ssam * Otherwise we just discard/ignore the rate. 572120482Ssam */ 573165887Ssam if ((flags & IEEE80211_F_JOIN) && 574120482Ssam (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 575116742Ssam error++; 576165887Ssam } else if ((flags & IEEE80211_F_JOIN) == 0) { 577165887Ssam /* 578165887Ssam * Overwrite with the supported rate 579165887Ssam * value so any basic rate bit is set. 580165887Ssam */ 581165887Ssam nrs->rs_rates[i] = srs->rs_rates[rix]; 582116742Ssam } 583116742Ssam } 584165887Ssam if ((flags & IEEE80211_F_DODEL) && rix < 0) { 585116742Ssam /* 586116742Ssam * Delete unacceptable rates. 587116742Ssam */ 588165887Ssam nrs->rs_nrates--; 589165887Ssam for (j = i; j < nrs->rs_nrates; j++) 590165887Ssam nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 591165887Ssam nrs->rs_rates[j] = 0; 592165887Ssam continue; 593116742Ssam } 594165887Ssam if (rix >= 0) 595116742Ssam okrate = nrs->rs_rates[i]; 596116742Ssam i++; 597116742Ssam } 598138568Ssam if (okrate == 0 || error != 0 || 599178354Ssam ((flags & (IEEE80211_F_DOFRATE|IEEE80211_F_DOFMCS)) && 600178354Ssam fixedrate != ucastrate)) { 601178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni, 602178354Ssam "%s: flags 0x%x okrate %d error %d fixedrate 0x%x " 603178354Ssam "ucastrate %x\n", __func__, fixedrate, ucastrate, flags); 604116742Ssam return badrate | IEEE80211_RATE_BASIC; 605178354Ssam } else 606116742Ssam return RV(okrate); 607116742Ssam#undef RV 608116742Ssam} 609116742Ssam 610138568Ssam/* 611138568Ssam * Reset 11g-related state. 612138568Ssam */ 613138568Ssamvoid 614138568Ssamieee80211_reset_erp(struct ieee80211com *ic) 615138568Ssam{ 616138568Ssam ic->ic_flags &= ~IEEE80211_F_USEPROT; 617138568Ssam ic->ic_nonerpsta = 0; 618138568Ssam ic->ic_longslotsta = 0; 619138568Ssam /* 620138568Ssam * Short slot time is enabled only when operating in 11g 621138568Ssam * and not in an IBSS. We must also honor whether or not 622138568Ssam * the driver is capable of doing it. 623138568Ssam */ 624138568Ssam ieee80211_set_shortslottime(ic, 625170530Ssam IEEE80211_IS_CHAN_A(ic->ic_curchan) || 626170530Ssam IEEE80211_IS_CHAN_HT(ic->ic_curchan) || 627170530Ssam (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 628138568Ssam ic->ic_opmode == IEEE80211_M_HOSTAP && 629138568Ssam (ic->ic_caps & IEEE80211_C_SHSLOT))); 630138568Ssam /* 631138568Ssam * Set short preamble and ERP barker-preamble flags. 632138568Ssam */ 633170530Ssam if (IEEE80211_IS_CHAN_A(ic->ic_curchan) || 634138568Ssam (ic->ic_caps & IEEE80211_C_SHPREAMBLE)) { 635138568Ssam ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 636138568Ssam ic->ic_flags &= ~IEEE80211_F_USEBARKER; 637138568Ssam } else { 638138568Ssam ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE; 639138568Ssam ic->ic_flags |= IEEE80211_F_USEBARKER; 640138568Ssam } 641138568Ssam} 642138568Ssam 643138568Ssam/* 644138568Ssam * Set the short slot time state and notify the driver. 645138568Ssam */ 646138568Ssamvoid 647138568Ssamieee80211_set_shortslottime(struct ieee80211com *ic, int onoff) 648138568Ssam{ 649138568Ssam if (onoff) 650138568Ssam ic->ic_flags |= IEEE80211_F_SHSLOT; 651138568Ssam else 652138568Ssam ic->ic_flags &= ~IEEE80211_F_SHSLOT; 653138568Ssam /* notify driver */ 654138568Ssam if (ic->ic_updateslot != NULL) 655138568Ssam ic->ic_updateslot(ic->ic_ifp); 656138568Ssam} 657138568Ssam 658138568Ssam/* 659138568Ssam * Check if the specified rate set supports ERP. 660138568Ssam * NB: the rate set is assumed to be sorted. 661138568Ssam */ 662138568Ssamint 663178354Ssamieee80211_iserp_rateset(const struct ieee80211_rateset *rs) 664138568Ssam{ 665138568Ssam#define N(a) (sizeof(a) / sizeof(a[0])) 666138568Ssam static const int rates[] = { 2, 4, 11, 22, 12, 24, 48 }; 667138568Ssam int i, j; 668138568Ssam 669138568Ssam if (rs->rs_nrates < N(rates)) 670138568Ssam return 0; 671138568Ssam for (i = 0; i < N(rates); i++) { 672138568Ssam for (j = 0; j < rs->rs_nrates; j++) { 673138568Ssam int r = rs->rs_rates[j] & IEEE80211_RATE_VAL; 674138568Ssam if (rates[i] == r) 675138568Ssam goto next; 676138568Ssam if (r > rates[i]) 677138568Ssam return 0; 678138568Ssam } 679138568Ssam return 0; 680138568Ssam next: 681138568Ssam ; 682138568Ssam } 683138568Ssam return 1; 684138568Ssam#undef N 685138568Ssam} 686138568Ssam 687138568Ssam/* 688178354Ssam * Mark the basic rates for the rate table based on the 689138568Ssam * operating mode. For real 11g we mark all the 11b rates 690138568Ssam * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 691138568Ssam * 11b rates. There's also a pseudo 11a-mode used to mark only 692138568Ssam * the basic OFDM rates. 693138568Ssam */ 694178354Ssamstatic void 695178354Ssamsetbasicrates(struct ieee80211_rateset *rs, 696178354Ssam enum ieee80211_phymode mode, int add) 697138568Ssam{ 698170530Ssam static const struct ieee80211_rateset basic[IEEE80211_MODE_MAX] = { 699188780Ssam [IEEE80211_MODE_11A] = { 3, { 12, 24, 48 } }, 700188780Ssam [IEEE80211_MODE_11B] = { 2, { 2, 4 } }, 701188780Ssam /* NB: mixed b/g */ 702188780Ssam [IEEE80211_MODE_11G] = { 4, { 2, 4, 11, 22 } }, 703188780Ssam [IEEE80211_MODE_TURBO_A] = { 3, { 12, 24, 48 } }, 704188780Ssam [IEEE80211_MODE_TURBO_G] = { 4, { 2, 4, 11, 22 } }, 705188780Ssam [IEEE80211_MODE_STURBO_A] = { 3, { 12, 24, 48 } }, 706188782Ssam [IEEE80211_MODE_HALF] = { 3, { 6, 12, 24 } }, 707188782Ssam [IEEE80211_MODE_QUARTER] = { 3, { 3, 6, 12 } }, 708188780Ssam [IEEE80211_MODE_11NA] = { 3, { 12, 24, 48 } }, 709188780Ssam /* NB: mixed b/g */ 710188780Ssam [IEEE80211_MODE_11NG] = { 4, { 2, 4, 11, 22 } }, 711138568Ssam }; 712138568Ssam int i, j; 713138568Ssam 714138568Ssam for (i = 0; i < rs->rs_nrates; i++) { 715178354Ssam if (!add) 716178354Ssam rs->rs_rates[i] &= IEEE80211_RATE_VAL; 717138568Ssam for (j = 0; j < basic[mode].rs_nrates; j++) 718138568Ssam if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 719138568Ssam rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 720138568Ssam break; 721138568Ssam } 722138568Ssam } 723138568Ssam} 724138568Ssam 725138568Ssam/* 726178354Ssam * Set the basic rates in a rate set. 727138568Ssam */ 728178354Ssamvoid 729178354Ssamieee80211_setbasicrates(struct ieee80211_rateset *rs, 730178354Ssam enum ieee80211_phymode mode) 731178354Ssam{ 732178354Ssam setbasicrates(rs, mode, 0); 733178354Ssam} 734178354Ssam 735178354Ssam/* 736178354Ssam * Add basic rates to a rate set. 737178354Ssam */ 738178354Ssamvoid 739178354Ssamieee80211_addbasicrates(struct ieee80211_rateset *rs, 740178354Ssam enum ieee80211_phymode mode) 741178354Ssam{ 742178354Ssam setbasicrates(rs, mode, 1); 743178354Ssam} 744178354Ssam 745178354Ssam/* 746178354Ssam * WME protocol support. 747178354Ssam * 748178354Ssam * The default 11a/b/g/n parameters come from the WiFi Alliance WMM 749178354Ssam * System Interopability Test Plan (v1.4, Appendix F) and the 802.11n 750178354Ssam * Draft 2.0 Test Plan (Appendix D). 751178354Ssam * 752178354Ssam * Static/Dynamic Turbo mode settings come from Atheros. 753178354Ssam */ 754138568Ssamtypedef struct phyParamType { 755178354Ssam uint8_t aifsn; 756178354Ssam uint8_t logcwmin; 757178354Ssam uint8_t logcwmax; 758178354Ssam uint16_t txopLimit; 759178354Ssam uint8_t acm; 760138568Ssam} paramType; 761138568Ssam 762138568Ssamstatic const struct phyParamType phyParamForAC_BE[IEEE80211_MODE_MAX] = { 763188780Ssam [IEEE80211_MODE_AUTO] = { 3, 4, 6, 0, 0 }, 764188780Ssam [IEEE80211_MODE_11A] = { 3, 4, 6, 0, 0 }, 765188780Ssam [IEEE80211_MODE_11B] = { 3, 4, 6, 0, 0 }, 766188780Ssam [IEEE80211_MODE_11G] = { 3, 4, 6, 0, 0 }, 767188780Ssam [IEEE80211_MODE_FH] = { 3, 4, 6, 0, 0 }, 768188780Ssam [IEEE80211_MODE_TURBO_A]= { 2, 3, 5, 0, 0 }, 769188780Ssam [IEEE80211_MODE_TURBO_G]= { 2, 3, 5, 0, 0 }, 770188780Ssam [IEEE80211_MODE_STURBO_A]={ 2, 3, 5, 0, 0 }, 771188782Ssam [IEEE80211_MODE_HALF] = { 3, 4, 6, 0, 0 }, 772188782Ssam [IEEE80211_MODE_QUARTER]= { 3, 4, 6, 0, 0 }, 773188780Ssam [IEEE80211_MODE_11NA] = { 3, 4, 6, 0, 0 }, 774188780Ssam [IEEE80211_MODE_11NG] = { 3, 4, 6, 0, 0 }, 775138568Ssam}; 776138568Ssamstatic const struct phyParamType phyParamForAC_BK[IEEE80211_MODE_MAX] = { 777188780Ssam [IEEE80211_MODE_AUTO] = { 7, 4, 10, 0, 0 }, 778188780Ssam [IEEE80211_MODE_11A] = { 7, 4, 10, 0, 0 }, 779188780Ssam [IEEE80211_MODE_11B] = { 7, 4, 10, 0, 0 }, 780188780Ssam [IEEE80211_MODE_11G] = { 7, 4, 10, 0, 0 }, 781188780Ssam [IEEE80211_MODE_FH] = { 7, 4, 10, 0, 0 }, 782188780Ssam [IEEE80211_MODE_TURBO_A]= { 7, 3, 10, 0, 0 }, 783188780Ssam [IEEE80211_MODE_TURBO_G]= { 7, 3, 10, 0, 0 }, 784188780Ssam [IEEE80211_MODE_STURBO_A]={ 7, 3, 10, 0, 0 }, 785188782Ssam [IEEE80211_MODE_HALF] = { 7, 4, 10, 0, 0 }, 786188782Ssam [IEEE80211_MODE_QUARTER]= { 7, 4, 10, 0, 0 }, 787188780Ssam [IEEE80211_MODE_11NA] = { 7, 4, 10, 0, 0 }, 788188780Ssam [IEEE80211_MODE_11NG] = { 7, 4, 10, 0, 0 }, 789138568Ssam}; 790138568Ssamstatic const struct phyParamType phyParamForAC_VI[IEEE80211_MODE_MAX] = { 791188780Ssam [IEEE80211_MODE_AUTO] = { 1, 3, 4, 94, 0 }, 792188780Ssam [IEEE80211_MODE_11A] = { 1, 3, 4, 94, 0 }, 793188780Ssam [IEEE80211_MODE_11B] = { 1, 3, 4, 188, 0 }, 794188780Ssam [IEEE80211_MODE_11G] = { 1, 3, 4, 94, 0 }, 795188780Ssam [IEEE80211_MODE_FH] = { 1, 3, 4, 188, 0 }, 796188780Ssam [IEEE80211_MODE_TURBO_A]= { 1, 2, 3, 94, 0 }, 797188780Ssam [IEEE80211_MODE_TURBO_G]= { 1, 2, 3, 94, 0 }, 798188780Ssam [IEEE80211_MODE_STURBO_A]={ 1, 2, 3, 94, 0 }, 799188782Ssam [IEEE80211_MODE_HALF] = { 1, 3, 4, 94, 0 }, 800188782Ssam [IEEE80211_MODE_QUARTER]= { 1, 3, 4, 94, 0 }, 801188780Ssam [IEEE80211_MODE_11NA] = { 1, 3, 4, 94, 0 }, 802188780Ssam [IEEE80211_MODE_11NG] = { 1, 3, 4, 94, 0 }, 803138568Ssam}; 804138568Ssamstatic const struct phyParamType phyParamForAC_VO[IEEE80211_MODE_MAX] = { 805188780Ssam [IEEE80211_MODE_AUTO] = { 1, 2, 3, 47, 0 }, 806188780Ssam [IEEE80211_MODE_11A] = { 1, 2, 3, 47, 0 }, 807188780Ssam [IEEE80211_MODE_11B] = { 1, 2, 3, 102, 0 }, 808188780Ssam [IEEE80211_MODE_11G] = { 1, 2, 3, 47, 0 }, 809188780Ssam [IEEE80211_MODE_FH] = { 1, 2, 3, 102, 0 }, 810188780Ssam [IEEE80211_MODE_TURBO_A]= { 1, 2, 2, 47, 0 }, 811188780Ssam [IEEE80211_MODE_TURBO_G]= { 1, 2, 2, 47, 0 }, 812188780Ssam [IEEE80211_MODE_STURBO_A]={ 1, 2, 2, 47, 0 }, 813188782Ssam [IEEE80211_MODE_HALF] = { 1, 2, 3, 47, 0 }, 814188782Ssam [IEEE80211_MODE_QUARTER]= { 1, 2, 3, 47, 0 }, 815188780Ssam [IEEE80211_MODE_11NA] = { 1, 2, 3, 47, 0 }, 816188780Ssam [IEEE80211_MODE_11NG] = { 1, 2, 3, 47, 0 }, 817138568Ssam}; 818138568Ssam 819138568Ssamstatic const struct phyParamType bssPhyParamForAC_BE[IEEE80211_MODE_MAX] = { 820188780Ssam [IEEE80211_MODE_AUTO] = { 3, 4, 10, 0, 0 }, 821188780Ssam [IEEE80211_MODE_11A] = { 3, 4, 10, 0, 0 }, 822188780Ssam [IEEE80211_MODE_11B] = { 3, 4, 10, 0, 0 }, 823188780Ssam [IEEE80211_MODE_11G] = { 3, 4, 10, 0, 0 }, 824188780Ssam [IEEE80211_MODE_FH] = { 3, 4, 10, 0, 0 }, 825188780Ssam [IEEE80211_MODE_TURBO_A]= { 2, 3, 10, 0, 0 }, 826188780Ssam [IEEE80211_MODE_TURBO_G]= { 2, 3, 10, 0, 0 }, 827188780Ssam [IEEE80211_MODE_STURBO_A]={ 2, 3, 10, 0, 0 }, 828188782Ssam [IEEE80211_MODE_HALF] = { 3, 4, 10, 0, 0 }, 829188782Ssam [IEEE80211_MODE_QUARTER]= { 3, 4, 10, 0, 0 }, 830188780Ssam [IEEE80211_MODE_11NA] = { 3, 4, 10, 0, 0 }, 831188780Ssam [IEEE80211_MODE_11NG] = { 3, 4, 10, 0, 0 }, 832138568Ssam}; 833138568Ssamstatic const struct phyParamType bssPhyParamForAC_VI[IEEE80211_MODE_MAX] = { 834188780Ssam [IEEE80211_MODE_AUTO] = { 2, 3, 4, 94, 0 }, 835188780Ssam [IEEE80211_MODE_11A] = { 2, 3, 4, 94, 0 }, 836188780Ssam [IEEE80211_MODE_11B] = { 2, 3, 4, 188, 0 }, 837188780Ssam [IEEE80211_MODE_11G] = { 2, 3, 4, 94, 0 }, 838188780Ssam [IEEE80211_MODE_FH] = { 2, 3, 4, 188, 0 }, 839188780Ssam [IEEE80211_MODE_TURBO_A]= { 2, 2, 3, 94, 0 }, 840188780Ssam [IEEE80211_MODE_TURBO_G]= { 2, 2, 3, 94, 0 }, 841188780Ssam [IEEE80211_MODE_STURBO_A]={ 2, 2, 3, 94, 0 }, 842188782Ssam [IEEE80211_MODE_HALF] = { 2, 3, 4, 94, 0 }, 843188782Ssam [IEEE80211_MODE_QUARTER]= { 2, 3, 4, 94, 0 }, 844188780Ssam [IEEE80211_MODE_11NA] = { 2, 3, 4, 94, 0 }, 845188780Ssam [IEEE80211_MODE_11NG] = { 2, 3, 4, 94, 0 }, 846138568Ssam}; 847138568Ssamstatic const struct phyParamType bssPhyParamForAC_VO[IEEE80211_MODE_MAX] = { 848188780Ssam [IEEE80211_MODE_AUTO] = { 2, 2, 3, 47, 0 }, 849188780Ssam [IEEE80211_MODE_11A] = { 2, 2, 3, 47, 0 }, 850188780Ssam [IEEE80211_MODE_11B] = { 2, 2, 3, 102, 0 }, 851188780Ssam [IEEE80211_MODE_11G] = { 2, 2, 3, 47, 0 }, 852188780Ssam [IEEE80211_MODE_FH] = { 2, 2, 3, 102, 0 }, 853188780Ssam [IEEE80211_MODE_TURBO_A]= { 1, 2, 2, 47, 0 }, 854188780Ssam [IEEE80211_MODE_TURBO_G]= { 1, 2, 2, 47, 0 }, 855188780Ssam [IEEE80211_MODE_STURBO_A]={ 1, 2, 2, 47, 0 }, 856188782Ssam [IEEE80211_MODE_HALF] = { 2, 2, 3, 47, 0 }, 857188782Ssam [IEEE80211_MODE_QUARTER]= { 2, 2, 3, 47, 0 }, 858188780Ssam [IEEE80211_MODE_11NA] = { 2, 2, 3, 47, 0 }, 859188780Ssam [IEEE80211_MODE_11NG] = { 2, 2, 3, 47, 0 }, 860138568Ssam}; 861138568Ssam 862178354Ssamstatic void 863188863Ssam_setifsparams(struct wmeParams *wmep, const paramType *phy) 864188863Ssam{ 865188863Ssam wmep->wmep_aifsn = phy->aifsn; 866188863Ssam wmep->wmep_logcwmin = phy->logcwmin; 867188863Ssam wmep->wmep_logcwmax = phy->logcwmax; 868188863Ssam wmep->wmep_txopLimit = phy->txopLimit; 869188863Ssam} 870188863Ssam 871188863Ssamstatic void 872188863Ssamsetwmeparams(struct ieee80211vap *vap, const char *type, int ac, 873188863Ssam struct wmeParams *wmep, const paramType *phy) 874188863Ssam{ 875188863Ssam wmep->wmep_acm = phy->acm; 876188863Ssam _setifsparams(wmep, phy); 877188863Ssam 878188863Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 879188863Ssam "set %s (%s) [acm %u aifsn %u logcwmin %u logcwmax %u txop %u]\n", 880188863Ssam ieee80211_wme_acnames[ac], type, 881188863Ssam wmep->wmep_acm, wmep->wmep_aifsn, wmep->wmep_logcwmin, 882188863Ssam wmep->wmep_logcwmax, wmep->wmep_txopLimit); 883188863Ssam} 884188863Ssam 885188863Ssamstatic void 886178354Ssamieee80211_wme_initparams_locked(struct ieee80211vap *vap) 887138568Ssam{ 888178354Ssam struct ieee80211com *ic = vap->iv_ic; 889138568Ssam struct ieee80211_wme_state *wme = &ic->ic_wme; 890138568Ssam const paramType *pPhyParam, *pBssPhyParam; 891138568Ssam struct wmeParams *wmep; 892170530Ssam enum ieee80211_phymode mode; 893138568Ssam int i; 894138568Ssam 895178354Ssam IEEE80211_LOCK_ASSERT(ic); 896178354Ssam 897188864Ssam if ((ic->ic_caps & IEEE80211_C_WME) == 0 || ic->ic_nrunning > 1) 898138568Ssam return; 899138568Ssam 900170530Ssam /* 901219961Sadrian * Clear the wme cap_info field so a qoscount from a previous 902219961Sadrian * vap doesn't confuse later code which only parses the beacon 903219961Sadrian * field and updates hardware when said field changes. 904219961Sadrian * Otherwise the hardware is programmed with defaults, not what 905219961Sadrian * the beacon actually announces. 906219961Sadrian */ 907219961Sadrian wme->wme_wmeChanParams.cap_info = 0; 908219961Sadrian 909219961Sadrian /* 910170530Ssam * Select mode; we can be called early in which case we 911170530Ssam * always use auto mode. We know we'll be called when 912170530Ssam * entering the RUN state with bsschan setup properly 913170530Ssam * so state will eventually get set correctly 914170530Ssam */ 915170530Ssam if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) 916170530Ssam mode = ieee80211_chan2mode(ic->ic_bsschan); 917170530Ssam else 918170530Ssam mode = IEEE80211_MODE_AUTO; 919138568Ssam for (i = 0; i < WME_NUM_AC; i++) { 920138568Ssam switch (i) { 921138568Ssam case WME_AC_BK: 922170530Ssam pPhyParam = &phyParamForAC_BK[mode]; 923170530Ssam pBssPhyParam = &phyParamForAC_BK[mode]; 924138568Ssam break; 925138568Ssam case WME_AC_VI: 926170530Ssam pPhyParam = &phyParamForAC_VI[mode]; 927170530Ssam pBssPhyParam = &bssPhyParamForAC_VI[mode]; 928138568Ssam break; 929138568Ssam case WME_AC_VO: 930170530Ssam pPhyParam = &phyParamForAC_VO[mode]; 931170530Ssam pBssPhyParam = &bssPhyParamForAC_VO[mode]; 932138568Ssam break; 933138568Ssam case WME_AC_BE: 934138568Ssam default: 935170530Ssam pPhyParam = &phyParamForAC_BE[mode]; 936170530Ssam pBssPhyParam = &bssPhyParamForAC_BE[mode]; 937138568Ssam break; 938138568Ssam } 939138568Ssam wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 940138568Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP) { 941188863Ssam setwmeparams(vap, "chan", i, wmep, pPhyParam); 942138568Ssam } else { 943188863Ssam setwmeparams(vap, "chan", i, wmep, pBssPhyParam); 944138568Ssam } 945138568Ssam wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 946188863Ssam setwmeparams(vap, "bss ", i, wmep, pBssPhyParam); 947138568Ssam } 948138568Ssam /* NB: check ic_bss to avoid NULL deref on initial attach */ 949178354Ssam if (vap->iv_bss != NULL) { 950138568Ssam /* 951138568Ssam * Calculate agressive mode switching threshold based 952138568Ssam * on beacon interval. This doesn't need locking since 953138568Ssam * we're only called before entering the RUN state at 954138568Ssam * which point we start sending beacon frames. 955138568Ssam */ 956138568Ssam wme->wme_hipri_switch_thresh = 957178354Ssam (HIGH_PRI_SWITCH_THRESH * vap->iv_bss->ni_intval) / 100; 958188864Ssam wme->wme_flags &= ~WME_F_AGGRMODE; 959178354Ssam ieee80211_wme_updateparams(vap); 960138568Ssam } 961138568Ssam} 962138568Ssam 963178354Ssamvoid 964178354Ssamieee80211_wme_initparams(struct ieee80211vap *vap) 965178354Ssam{ 966178354Ssam struct ieee80211com *ic = vap->iv_ic; 967178354Ssam 968178354Ssam IEEE80211_LOCK(ic); 969178354Ssam ieee80211_wme_initparams_locked(vap); 970178354Ssam IEEE80211_UNLOCK(ic); 971178354Ssam} 972178354Ssam 973138568Ssam/* 974138568Ssam * Update WME parameters for ourself and the BSS. 975138568Ssam */ 976138568Ssamvoid 977178354Ssamieee80211_wme_updateparams_locked(struct ieee80211vap *vap) 978138568Ssam{ 979188863Ssam static const paramType aggrParam[IEEE80211_MODE_MAX] = { 980188780Ssam [IEEE80211_MODE_AUTO] = { 2, 4, 10, 64, 0 }, 981188780Ssam [IEEE80211_MODE_11A] = { 2, 4, 10, 64, 0 }, 982188780Ssam [IEEE80211_MODE_11B] = { 2, 5, 10, 64, 0 }, 983188780Ssam [IEEE80211_MODE_11G] = { 2, 4, 10, 64, 0 }, 984188780Ssam [IEEE80211_MODE_FH] = { 2, 5, 10, 64, 0 }, 985188780Ssam [IEEE80211_MODE_TURBO_A] = { 1, 3, 10, 64, 0 }, 986188780Ssam [IEEE80211_MODE_TURBO_G] = { 1, 3, 10, 64, 0 }, 987188780Ssam [IEEE80211_MODE_STURBO_A] = { 1, 3, 10, 64, 0 }, 988188782Ssam [IEEE80211_MODE_HALF] = { 2, 4, 10, 64, 0 }, 989188782Ssam [IEEE80211_MODE_QUARTER] = { 2, 4, 10, 64, 0 }, 990188780Ssam [IEEE80211_MODE_11NA] = { 2, 4, 10, 64, 0 }, /* XXXcheck*/ 991188780Ssam [IEEE80211_MODE_11NG] = { 2, 4, 10, 64, 0 }, /* XXXcheck*/ 992138568Ssam }; 993178354Ssam struct ieee80211com *ic = vap->iv_ic; 994138568Ssam struct ieee80211_wme_state *wme = &ic->ic_wme; 995138568Ssam const struct wmeParams *wmep; 996138568Ssam struct wmeParams *chanp, *bssp; 997170530Ssam enum ieee80211_phymode mode; 998138568Ssam int i; 999244062Sadrian int do_aggrmode = 0; 1000138568Ssam 1001188863Ssam /* 1002188863Ssam * Set up the channel access parameters for the physical 1003188863Ssam * device. First populate the configured settings. 1004188863Ssam */ 1005138568Ssam for (i = 0; i < WME_NUM_AC; i++) { 1006138568Ssam chanp = &wme->wme_chanParams.cap_wmeParams[i]; 1007138568Ssam wmep = &wme->wme_wmeChanParams.cap_wmeParams[i]; 1008138568Ssam chanp->wmep_aifsn = wmep->wmep_aifsn; 1009138568Ssam chanp->wmep_logcwmin = wmep->wmep_logcwmin; 1010138568Ssam chanp->wmep_logcwmax = wmep->wmep_logcwmax; 1011138568Ssam chanp->wmep_txopLimit = wmep->wmep_txopLimit; 1012138568Ssam 1013138568Ssam chanp = &wme->wme_bssChanParams.cap_wmeParams[i]; 1014138568Ssam wmep = &wme->wme_wmeBssChanParams.cap_wmeParams[i]; 1015138568Ssam chanp->wmep_aifsn = wmep->wmep_aifsn; 1016138568Ssam chanp->wmep_logcwmin = wmep->wmep_logcwmin; 1017138568Ssam chanp->wmep_logcwmax = wmep->wmep_logcwmax; 1018138568Ssam chanp->wmep_txopLimit = wmep->wmep_txopLimit; 1019138568Ssam } 1020138568Ssam 1021138568Ssam /* 1022170530Ssam * Select mode; we can be called early in which case we 1023170530Ssam * always use auto mode. We know we'll be called when 1024170530Ssam * entering the RUN state with bsschan setup properly 1025170530Ssam * so state will eventually get set correctly 1026170530Ssam */ 1027170530Ssam if (ic->ic_bsschan != IEEE80211_CHAN_ANYC) 1028170530Ssam mode = ieee80211_chan2mode(ic->ic_bsschan); 1029170530Ssam else 1030170530Ssam mode = IEEE80211_MODE_AUTO; 1031170530Ssam 1032170530Ssam /* 1033138568Ssam * This implements agressive mode as found in certain 1034138568Ssam * vendors' AP's. When there is significant high 1035138568Ssam * priority (VI/VO) traffic in the BSS throttle back BE 1036138568Ssam * traffic by using conservative parameters. Otherwise 1037138568Ssam * BE uses agressive params to optimize performance of 1038138568Ssam * legacy/non-QoS traffic. 1039138568Ssam */ 1040244062Sadrian 1041244062Sadrian /* Hostap? Only if aggressive mode is enabled */ 1042244062Sadrian if (vap->iv_opmode == IEEE80211_M_HOSTAP && 1043244062Sadrian (wme->wme_flags & WME_F_AGGRMODE) != 0) 1044244062Sadrian do_aggrmode = 1; 1045244062Sadrian 1046244062Sadrian /* 1047244062Sadrian * Station? Only if we're in a non-QoS BSS. 1048244062Sadrian */ 1049244062Sadrian else if ((vap->iv_opmode == IEEE80211_M_STA && 1050244062Sadrian (vap->iv_bss->ni_flags & IEEE80211_NODE_QOS) == 0)) 1051244062Sadrian do_aggrmode = 1; 1052244062Sadrian 1053244062Sadrian /* 1054244062Sadrian * IBSS? Only if we we have WME enabled. 1055244062Sadrian */ 1056244062Sadrian else if ((vap->iv_opmode == IEEE80211_M_IBSS) && 1057244062Sadrian (vap->iv_flags & IEEE80211_F_WME)) 1058244062Sadrian do_aggrmode = 1; 1059244062Sadrian 1060244062Sadrian /* 1061244062Sadrian * If WME is disabled on this VAP, default to aggressive mode 1062244062Sadrian * regardless of the configuration. 1063244062Sadrian */ 1064244062Sadrian if ((vap->iv_flags & IEEE80211_F_WME) == 0) 1065244062Sadrian do_aggrmode = 1; 1066244062Sadrian 1067244062Sadrian /* XXX WDS? */ 1068244062Sadrian 1069244062Sadrian /* XXX MBSS? */ 1070244062Sadrian 1071244062Sadrian if (do_aggrmode) { 1072138568Ssam chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 1073138568Ssam bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 1074138568Ssam 1075188863Ssam chanp->wmep_aifsn = bssp->wmep_aifsn = aggrParam[mode].aifsn; 1076138568Ssam chanp->wmep_logcwmin = bssp->wmep_logcwmin = 1077188863Ssam aggrParam[mode].logcwmin; 1078138568Ssam chanp->wmep_logcwmax = bssp->wmep_logcwmax = 1079188863Ssam aggrParam[mode].logcwmax; 1080138568Ssam chanp->wmep_txopLimit = bssp->wmep_txopLimit = 1081188863Ssam (vap->iv_flags & IEEE80211_F_BURST) ? 1082188863Ssam aggrParam[mode].txopLimit : 0; 1083178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 1084188863Ssam "update %s (chan+bss) [acm %u aifsn %u logcwmin %u " 1085188863Ssam "logcwmax %u txop %u]\n", ieee80211_wme_acnames[WME_AC_BE], 1086188863Ssam chanp->wmep_acm, chanp->wmep_aifsn, chanp->wmep_logcwmin, 1087188863Ssam chanp->wmep_logcwmax, chanp->wmep_txopLimit); 1088138568Ssam } 1089244062Sadrian 1090244062Sadrian 1091244062Sadrian /* 1092244062Sadrian * Change the contention window based on the number of associated 1093244062Sadrian * stations. If the number of associated stations is 1 and 1094244062Sadrian * aggressive mode is enabled, lower the contention window even 1095244062Sadrian * further. 1096244062Sadrian */ 1097178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP && 1098156524Ssam ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) { 1099188780Ssam static const uint8_t logCwMin[IEEE80211_MODE_MAX] = { 1100188780Ssam [IEEE80211_MODE_AUTO] = 3, 1101188780Ssam [IEEE80211_MODE_11A] = 3, 1102188780Ssam [IEEE80211_MODE_11B] = 4, 1103188780Ssam [IEEE80211_MODE_11G] = 3, 1104188780Ssam [IEEE80211_MODE_FH] = 4, 1105188780Ssam [IEEE80211_MODE_TURBO_A] = 3, 1106188780Ssam [IEEE80211_MODE_TURBO_G] = 3, 1107188780Ssam [IEEE80211_MODE_STURBO_A] = 3, 1108188782Ssam [IEEE80211_MODE_HALF] = 3, 1109188782Ssam [IEEE80211_MODE_QUARTER] = 3, 1110188780Ssam [IEEE80211_MODE_11NA] = 3, 1111188780Ssam [IEEE80211_MODE_11NG] = 3, 1112138568Ssam }; 1113138568Ssam chanp = &wme->wme_chanParams.cap_wmeParams[WME_AC_BE]; 1114138568Ssam bssp = &wme->wme_bssChanParams.cap_wmeParams[WME_AC_BE]; 1115138568Ssam 1116170530Ssam chanp->wmep_logcwmin = bssp->wmep_logcwmin = logCwMin[mode]; 1117178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 1118188863Ssam "update %s (chan+bss) logcwmin %u\n", 1119188863Ssam ieee80211_wme_acnames[WME_AC_BE], chanp->wmep_logcwmin); 1120244062Sadrian } 1121244062Sadrian 1122244062Sadrian /* 1123244062Sadrian * Arrange for the beacon update. 1124244062Sadrian * 1125244062Sadrian * XXX what about MBSS, WDS? 1126244062Sadrian */ 1127244062Sadrian if (vap->iv_opmode == IEEE80211_M_HOSTAP 1128244062Sadrian || vap->iv_opmode == IEEE80211_M_IBSS) { 1129138568Ssam /* 1130138568Ssam * Arrange for a beacon update and bump the parameter 1131138568Ssam * set number so associated stations load the new values. 1132138568Ssam */ 1133138568Ssam wme->wme_bssChanParams.cap_info = 1134138568Ssam (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT; 1135178354Ssam ieee80211_beacon_notify(vap, IEEE80211_BEACON_WME); 1136138568Ssam } 1137138568Ssam 1138138568Ssam wme->wme_update(ic); 1139138568Ssam 1140178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 1141188863Ssam "%s: WME params updated, cap_info 0x%x\n", __func__, 1142188863Ssam vap->iv_opmode == IEEE80211_M_STA ? 1143188863Ssam wme->wme_wmeChanParams.cap_info : 1144188863Ssam wme->wme_bssChanParams.cap_info); 1145138568Ssam} 1146138568Ssam 1147138568Ssamvoid 1148178354Ssamieee80211_wme_updateparams(struct ieee80211vap *vap) 1149138568Ssam{ 1150178354Ssam struct ieee80211com *ic = vap->iv_ic; 1151138568Ssam 1152138568Ssam if (ic->ic_caps & IEEE80211_C_WME) { 1153178354Ssam IEEE80211_LOCK(ic); 1154178354Ssam ieee80211_wme_updateparams_locked(vap); 1155178354Ssam IEEE80211_UNLOCK(ic); 1156138568Ssam } 1157138568Ssam} 1158138568Ssam 1159178354Ssamstatic void 1160178354Ssamparent_updown(void *arg, int npending) 1161178354Ssam{ 1162178354Ssam struct ifnet *parent = arg; 1163178354Ssam 1164178354Ssam parent->if_ioctl(parent, SIOCSIFFLAGS, NULL); 1165178354Ssam} 1166178354Ssam 1167191746Sthompsastatic void 1168191746Sthompsaupdate_mcast(void *arg, int npending) 1169191746Sthompsa{ 1170191746Sthompsa struct ieee80211com *ic = arg; 1171191746Sthompsa struct ifnet *parent = ic->ic_ifp; 1172191746Sthompsa 1173191746Sthompsa ic->ic_update_mcast(parent); 1174191746Sthompsa} 1175191746Sthompsa 1176191746Sthompsastatic void 1177191746Sthompsaupdate_promisc(void *arg, int npending) 1178191746Sthompsa{ 1179191746Sthompsa struct ieee80211com *ic = arg; 1180191746Sthompsa struct ifnet *parent = ic->ic_ifp; 1181191746Sthompsa 1182191746Sthompsa ic->ic_update_promisc(parent); 1183191746Sthompsa} 1184191746Sthompsa 1185191746Sthompsastatic void 1186191746Sthompsaupdate_channel(void *arg, int npending) 1187191746Sthompsa{ 1188191746Sthompsa struct ieee80211com *ic = arg; 1189191746Sthompsa 1190191746Sthompsa ic->ic_set_channel(ic); 1191192468Ssam ieee80211_radiotap_chan_change(ic); 1192191746Sthompsa} 1193191746Sthompsa 1194233452Sadrianstatic void 1195233452Sadrianupdate_chw(void *arg, int npending) 1196233452Sadrian{ 1197233452Sadrian struct ieee80211com *ic = arg; 1198233452Sadrian 1199233452Sadrian /* 1200233452Sadrian * XXX should we defer the channel width _config_ update until now? 1201233452Sadrian */ 1202233452Sadrian ic->ic_update_chw(ic); 1203233452Sadrian} 1204233452Sadrian 1205170530Ssam/* 1206188533Sthompsa * Block until the parent is in a known state. This is 1207188533Sthompsa * used after any operations that dispatch a task (e.g. 1208188533Sthompsa * to auto-configure the parent device up/down). 1209188533Sthompsa */ 1210188533Sthompsavoid 1211188533Sthompsaieee80211_waitfor_parent(struct ieee80211com *ic) 1212188533Sthompsa{ 1213191746Sthompsa taskqueue_block(ic->ic_tq); 1214191746Sthompsa ieee80211_draintask(ic, &ic->ic_parent_task); 1215191746Sthompsa ieee80211_draintask(ic, &ic->ic_mcast_task); 1216191746Sthompsa ieee80211_draintask(ic, &ic->ic_promisc_task); 1217191746Sthompsa ieee80211_draintask(ic, &ic->ic_chan_task); 1218191746Sthompsa ieee80211_draintask(ic, &ic->ic_bmiss_task); 1219233452Sadrian ieee80211_draintask(ic, &ic->ic_chw_task); 1220191746Sthompsa taskqueue_unblock(ic->ic_tq); 1221188533Sthompsa} 1222188533Sthompsa 1223188533Sthompsa/* 1224178354Ssam * Start a vap running. If this is the first vap to be 1225178354Ssam * set running on the underlying device then we 1226178354Ssam * automatically bring the device up. 1227170530Ssam */ 1228178354Ssamvoid 1229178354Ssamieee80211_start_locked(struct ieee80211vap *vap) 1230170530Ssam{ 1231178354Ssam struct ifnet *ifp = vap->iv_ifp; 1232178354Ssam struct ieee80211com *ic = vap->iv_ic; 1233178354Ssam struct ifnet *parent = ic->ic_ifp; 1234170530Ssam 1235178354Ssam IEEE80211_LOCK_ASSERT(ic); 1236178354Ssam 1237178354Ssam IEEE80211_DPRINTF(vap, 1238170530Ssam IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 1239178354Ssam "start running, %d vaps running\n", ic->ic_nrunning); 1240170530Ssam 1241178354Ssam if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1242178354Ssam /* 1243178354Ssam * Mark us running. Note that it's ok to do this first; 1244178354Ssam * if we need to bring the parent device up we defer that 1245178354Ssam * to avoid dropping the com lock. We expect the device 1246178354Ssam * to respond to being marked up by calling back into us 1247178354Ssam * through ieee80211_start_all at which point we'll come 1248178354Ssam * back in here and complete the work. 1249178354Ssam */ 1250178354Ssam ifp->if_drv_flags |= IFF_DRV_RUNNING; 1251178354Ssam /* 1252178354Ssam * We are not running; if this we are the first vap 1253178354Ssam * to be brought up auto-up the parent if necessary. 1254178354Ssam */ 1255178354Ssam if (ic->ic_nrunning++ == 0 && 1256178354Ssam (parent->if_drv_flags & IFF_DRV_RUNNING) == 0) { 1257178354Ssam IEEE80211_DPRINTF(vap, 1258178354Ssam IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 1259178354Ssam "%s: up parent %s\n", __func__, parent->if_xname); 1260178354Ssam parent->if_flags |= IFF_UP; 1261191746Sthompsa ieee80211_runtask(ic, &ic->ic_parent_task); 1262178354Ssam return; 1263178354Ssam } 1264178354Ssam } 1265170530Ssam /* 1266178354Ssam * If the parent is up and running, then kick the 1267178354Ssam * 802.11 state machine as appropriate. 1268170530Ssam */ 1269178354Ssam if ((parent->if_drv_flags & IFF_DRV_RUNNING) && 1270178354Ssam vap->iv_roaming != IEEE80211_ROAMING_MANUAL) { 1271178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) { 1272178354Ssam#if 0 1273178354Ssam /* XXX bypasses scan too easily; disable for now */ 1274178354Ssam /* 1275178354Ssam * Try to be intelligent about clocking the state 1276178354Ssam * machine. If we're currently in RUN state then 1277178354Ssam * we should be able to apply any new state/parameters 1278178354Ssam * simply by re-associating. Otherwise we need to 1279178354Ssam * re-scan to select an appropriate ap. 1280178354Ssam */ 1281178354Ssam if (vap->iv_state >= IEEE80211_S_RUN) 1282178354Ssam ieee80211_new_state_locked(vap, 1283178354Ssam IEEE80211_S_ASSOC, 1); 1284178354Ssam else 1285178354Ssam#endif 1286178354Ssam ieee80211_new_state_locked(vap, 1287178354Ssam IEEE80211_S_SCAN, 0); 1288170530Ssam } else { 1289170530Ssam /* 1290178354Ssam * For monitor+wds mode there's nothing to do but 1291178354Ssam * start running. Otherwise if this is the first 1292170530Ssam * vap to be brought up, start a scan which may be 1293170530Ssam * preempted if the station is locked to a particular 1294170530Ssam * channel. 1295170530Ssam */ 1296191746Sthompsa vap->iv_flags_ext |= IEEE80211_FEXT_REINIT; 1297178354Ssam if (vap->iv_opmode == IEEE80211_M_MONITOR || 1298178354Ssam vap->iv_opmode == IEEE80211_M_WDS) 1299178354Ssam ieee80211_new_state_locked(vap, 1300178354Ssam IEEE80211_S_RUN, -1); 1301178354Ssam else 1302178354Ssam ieee80211_new_state_locked(vap, 1303178354Ssam IEEE80211_S_SCAN, 0); 1304170530Ssam } 1305170530Ssam } 1306170530Ssam} 1307170530Ssam 1308170530Ssam/* 1309178354Ssam * Start a single vap. 1310178354Ssam */ 1311178354Ssamvoid 1312178354Ssamieee80211_init(void *arg) 1313178354Ssam{ 1314178354Ssam struct ieee80211vap *vap = arg; 1315178354Ssam 1316193348Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 1317193348Ssam "%s\n", __func__); 1318178354Ssam 1319193348Ssam IEEE80211_LOCK(vap->iv_ic); 1320193348Ssam ieee80211_start_locked(vap); 1321193348Ssam IEEE80211_UNLOCK(vap->iv_ic); 1322178354Ssam} 1323178354Ssam 1324178354Ssam/* 1325178354Ssam * Start all runnable vap's on a device. 1326178354Ssam */ 1327178354Ssamvoid 1328178354Ssamieee80211_start_all(struct ieee80211com *ic) 1329178354Ssam{ 1330178354Ssam struct ieee80211vap *vap; 1331178354Ssam 1332178354Ssam IEEE80211_LOCK(ic); 1333178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1334178354Ssam struct ifnet *ifp = vap->iv_ifp; 1335178354Ssam if (IFNET_IS_UP_RUNNING(ifp)) /* NB: avoid recursion */ 1336178354Ssam ieee80211_start_locked(vap); 1337178354Ssam } 1338178354Ssam IEEE80211_UNLOCK(ic); 1339178354Ssam} 1340178354Ssam 1341178354Ssam/* 1342178354Ssam * Stop a vap. We force it down using the state machine 1343178354Ssam * then mark it's ifnet not running. If this is the last 1344178354Ssam * vap running on the underlying device then we close it 1345178354Ssam * too to insure it will be properly initialized when the 1346178354Ssam * next vap is brought up. 1347178354Ssam */ 1348178354Ssamvoid 1349178354Ssamieee80211_stop_locked(struct ieee80211vap *vap) 1350178354Ssam{ 1351178354Ssam struct ieee80211com *ic = vap->iv_ic; 1352178354Ssam struct ifnet *ifp = vap->iv_ifp; 1353178354Ssam struct ifnet *parent = ic->ic_ifp; 1354178354Ssam 1355178354Ssam IEEE80211_LOCK_ASSERT(ic); 1356178354Ssam 1357178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 1358178354Ssam "stop running, %d vaps running\n", ic->ic_nrunning); 1359178354Ssam 1360178354Ssam ieee80211_new_state_locked(vap, IEEE80211_S_INIT, -1); 1361178354Ssam if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 1362178354Ssam ifp->if_drv_flags &= ~IFF_DRV_RUNNING; /* mark us stopped */ 1363178354Ssam if (--ic->ic_nrunning == 0 && 1364178354Ssam (parent->if_drv_flags & IFF_DRV_RUNNING)) { 1365178354Ssam IEEE80211_DPRINTF(vap, 1366178354Ssam IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 1367178354Ssam "down parent %s\n", parent->if_xname); 1368178354Ssam parent->if_flags &= ~IFF_UP; 1369191746Sthompsa ieee80211_runtask(ic, &ic->ic_parent_task); 1370178354Ssam } 1371178354Ssam } 1372178354Ssam} 1373178354Ssam 1374178354Ssamvoid 1375178354Ssamieee80211_stop(struct ieee80211vap *vap) 1376178354Ssam{ 1377178354Ssam struct ieee80211com *ic = vap->iv_ic; 1378178354Ssam 1379178354Ssam IEEE80211_LOCK(ic); 1380178354Ssam ieee80211_stop_locked(vap); 1381178354Ssam IEEE80211_UNLOCK(ic); 1382178354Ssam} 1383178354Ssam 1384178354Ssam/* 1385178354Ssam * Stop all vap's running on a device. 1386178354Ssam */ 1387178354Ssamvoid 1388178354Ssamieee80211_stop_all(struct ieee80211com *ic) 1389178354Ssam{ 1390178354Ssam struct ieee80211vap *vap; 1391178354Ssam 1392178354Ssam IEEE80211_LOCK(ic); 1393178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1394178354Ssam struct ifnet *ifp = vap->iv_ifp; 1395178354Ssam if (IFNET_IS_UP_RUNNING(ifp)) /* NB: avoid recursion */ 1396178354Ssam ieee80211_stop_locked(vap); 1397178354Ssam } 1398178354Ssam IEEE80211_UNLOCK(ic); 1399188533Sthompsa 1400188533Sthompsa ieee80211_waitfor_parent(ic); 1401178354Ssam} 1402178354Ssam 1403178354Ssam/* 1404179391Ssam * Stop all vap's running on a device and arrange 1405179391Ssam * for those that were running to be resumed. 1406179391Ssam */ 1407179391Ssamvoid 1408179391Ssamieee80211_suspend_all(struct ieee80211com *ic) 1409179391Ssam{ 1410179391Ssam struct ieee80211vap *vap; 1411179391Ssam 1412179391Ssam IEEE80211_LOCK(ic); 1413179391Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1414179391Ssam struct ifnet *ifp = vap->iv_ifp; 1415179391Ssam if (IFNET_IS_UP_RUNNING(ifp)) { /* NB: avoid recursion */ 1416179391Ssam vap->iv_flags_ext |= IEEE80211_FEXT_RESUME; 1417179391Ssam ieee80211_stop_locked(vap); 1418179391Ssam } 1419179391Ssam } 1420179391Ssam IEEE80211_UNLOCK(ic); 1421188533Sthompsa 1422188533Sthompsa ieee80211_waitfor_parent(ic); 1423179391Ssam} 1424179391Ssam 1425179391Ssam/* 1426179391Ssam * Start all vap's marked for resume. 1427179391Ssam */ 1428179391Ssamvoid 1429179391Ssamieee80211_resume_all(struct ieee80211com *ic) 1430179391Ssam{ 1431179391Ssam struct ieee80211vap *vap; 1432179391Ssam 1433179391Ssam IEEE80211_LOCK(ic); 1434179391Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1435179391Ssam struct ifnet *ifp = vap->iv_ifp; 1436179391Ssam if (!IFNET_IS_UP_RUNNING(ifp) && 1437179391Ssam (vap->iv_flags_ext & IEEE80211_FEXT_RESUME)) { 1438179391Ssam vap->iv_flags_ext &= ~IEEE80211_FEXT_RESUME; 1439179391Ssam ieee80211_start_locked(vap); 1440179391Ssam } 1441179391Ssam } 1442179391Ssam IEEE80211_UNLOCK(ic); 1443179391Ssam} 1444179391Ssam 1445153349Ssamvoid 1446153349Ssamieee80211_beacon_miss(struct ieee80211com *ic) 1447153349Ssam{ 1448191746Sthompsa IEEE80211_LOCK(ic); 1449191746Sthompsa if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 1450191746Sthompsa /* Process in a taskq, the handler may reenter the driver */ 1451191746Sthompsa ieee80211_runtask(ic, &ic->ic_bmiss_task); 1452191746Sthompsa } 1453191746Sthompsa IEEE80211_UNLOCK(ic); 1454191746Sthompsa} 1455191746Sthompsa 1456191746Sthompsastatic void 1457191746Sthompsabeacon_miss(void *arg, int npending) 1458191746Sthompsa{ 1459191746Sthompsa struct ieee80211com *ic = arg; 1460178354Ssam struct ieee80211vap *vap; 1461153349Ssam 1462225913Sadrian IEEE80211_LOCK(ic); 1463178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1464153349Ssam /* 1465178354Ssam * We only pass events through for sta vap's in RUN state; 1466178354Ssam * may be too restrictive but for now this saves all the 1467178354Ssam * handlers duplicating these checks. 1468153349Ssam */ 1469178354Ssam if (vap->iv_opmode == IEEE80211_M_STA && 1470193439Ssam vap->iv_state >= IEEE80211_S_RUN && 1471178354Ssam vap->iv_bmiss != NULL) 1472178354Ssam vap->iv_bmiss(vap); 1473153349Ssam } 1474225913Sadrian IEEE80211_UNLOCK(ic); 1475153349Ssam} 1476153349Ssam 1477191746Sthompsastatic void 1478191746Sthompsabeacon_swmiss(void *arg, int npending) 1479191746Sthompsa{ 1480191746Sthompsa struct ieee80211vap *vap = arg; 1481225913Sadrian struct ieee80211com *ic = vap->iv_ic; 1482191746Sthompsa 1483225913Sadrian IEEE80211_LOCK(ic); 1484225913Sadrian if (vap->iv_state == IEEE80211_S_RUN) { 1485225913Sadrian /* XXX Call multiple times if npending > zero? */ 1486225913Sadrian vap->iv_bmiss(vap); 1487225913Sadrian } 1488225913Sadrian IEEE80211_UNLOCK(ic); 1489191746Sthompsa} 1490191746Sthompsa 1491154736Ssam/* 1492154736Ssam * Software beacon miss handling. Check if any beacons 1493154736Ssam * were received in the last period. If not post a 1494154736Ssam * beacon miss; otherwise reset the counter. 1495154736Ssam */ 1496178354Ssamvoid 1497154736Ssamieee80211_swbmiss(void *arg) 1498154736Ssam{ 1499178354Ssam struct ieee80211vap *vap = arg; 1500179217Ssam struct ieee80211com *ic = vap->iv_ic; 1501154736Ssam 1502225913Sadrian IEEE80211_LOCK_ASSERT(ic); 1503225913Sadrian 1504179217Ssam /* XXX sleep state? */ 1505179217Ssam KASSERT(vap->iv_state == IEEE80211_S_RUN, 1506179217Ssam ("wrong state %d", vap->iv_state)); 1507179217Ssam 1508179217Ssam if (ic->ic_flags & IEEE80211_F_SCAN) { 1509179217Ssam /* 1510179217Ssam * If scanning just ignore and reset state. If we get a 1511179217Ssam * bmiss after coming out of scan because we haven't had 1512179217Ssam * time to receive a beacon then we should probe the AP 1513179217Ssam * before posting a real bmiss (unless iv_bmiss_max has 1514179217Ssam * been artifiically lowered). A cleaner solution might 1515179217Ssam * be to disable the timer on scan start/end but to handle 1516179217Ssam * case of multiple sta vap's we'd need to disable the 1517179217Ssam * timers of all affected vap's. 1518179217Ssam */ 1519179217Ssam vap->iv_swbmiss_count = 0; 1520179217Ssam } else if (vap->iv_swbmiss_count == 0) { 1521178354Ssam if (vap->iv_bmiss != NULL) 1522191746Sthompsa ieee80211_runtask(ic, &vap->iv_swbmiss_task); 1523154736Ssam } else 1524178354Ssam vap->iv_swbmiss_count = 0; 1525178354Ssam callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period, 1526178354Ssam ieee80211_swbmiss, vap); 1527154736Ssam} 1528154736Ssam 1529178354Ssam/* 1530178354Ssam * Start an 802.11h channel switch. We record the parameters, 1531178354Ssam * mark the operation pending, notify each vap through the 1532178354Ssam * beacon update mechanism so it can update the beacon frame 1533178354Ssam * contents, and then switch vap's to CSA state to block outbound 1534178354Ssam * traffic. Devices that handle CSA directly can use the state 1535178354Ssam * switch to do the right thing so long as they call 1536178354Ssam * ieee80211_csa_completeswitch when it's time to complete the 1537178354Ssam * channel change. Devices that depend on the net80211 layer can 1538178354Ssam * use ieee80211_beacon_update to handle the countdown and the 1539178354Ssam * channel switch. 1540178354Ssam */ 1541178354Ssamvoid 1542178354Ssamieee80211_csa_startswitch(struct ieee80211com *ic, 1543178354Ssam struct ieee80211_channel *c, int mode, int count) 1544178354Ssam{ 1545178354Ssam struct ieee80211vap *vap; 1546178354Ssam 1547178354Ssam IEEE80211_LOCK_ASSERT(ic); 1548178354Ssam 1549178354Ssam ic->ic_csa_newchan = c; 1550193439Ssam ic->ic_csa_mode = mode; 1551178354Ssam ic->ic_csa_count = count; 1552178354Ssam ic->ic_flags |= IEEE80211_F_CSAPENDING; 1553178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1554178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP || 1555195618Srpaulo vap->iv_opmode == IEEE80211_M_IBSS || 1556195618Srpaulo vap->iv_opmode == IEEE80211_M_MBSS) 1557178354Ssam ieee80211_beacon_notify(vap, IEEE80211_BEACON_CSA); 1558178354Ssam /* switch to CSA state to block outbound traffic */ 1559178354Ssam if (vap->iv_state == IEEE80211_S_RUN) 1560178354Ssam ieee80211_new_state_locked(vap, IEEE80211_S_CSA, 0); 1561178354Ssam } 1562178354Ssam ieee80211_notify_csa(ic, c, mode, count); 1563178354Ssam} 1564178354Ssam 1565224220Sadrian/* 1566224220Sadrian * Complete the channel switch by transitioning all CSA VAPs to RUN. 1567224220Sadrian * This is called by both the completion and cancellation functions 1568224220Sadrian * so each VAP is placed back in the RUN state and can thus transmit. 1569224220Sadrian */ 1570193439Ssamstatic void 1571193439Ssamcsa_completeswitch(struct ieee80211com *ic) 1572193439Ssam{ 1573193439Ssam struct ieee80211vap *vap; 1574193439Ssam 1575193439Ssam ic->ic_csa_newchan = NULL; 1576193439Ssam ic->ic_flags &= ~IEEE80211_F_CSAPENDING; 1577193439Ssam 1578193439Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 1579193439Ssam if (vap->iv_state == IEEE80211_S_CSA) 1580193439Ssam ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0); 1581193439Ssam} 1582193439Ssam 1583178354Ssam/* 1584178354Ssam * Complete an 802.11h channel switch started by ieee80211_csa_startswitch. 1585178354Ssam * We clear state and move all vap's in CSA state to RUN state 1586178354Ssam * so they can again transmit. 1587224220Sadrian * 1588224220Sadrian * Although this may not be completely correct, update the BSS channel 1589224220Sadrian * for each VAP to the newly configured channel. The setcurchan sets 1590224220Sadrian * the current operating channel for the interface (so the radio does 1591224220Sadrian * switch over) but the VAP BSS isn't updated, leading to incorrectly 1592224220Sadrian * reported information via ioctl. 1593178354Ssam */ 1594178354Ssamvoid 1595178354Ssamieee80211_csa_completeswitch(struct ieee80211com *ic) 1596178354Ssam{ 1597224222Sadrian struct ieee80211vap *vap; 1598224222Sadrian 1599178354Ssam IEEE80211_LOCK_ASSERT(ic); 1600178354Ssam 1601178354Ssam KASSERT(ic->ic_flags & IEEE80211_F_CSAPENDING, ("csa not pending")); 1602178354Ssam 1603178354Ssam ieee80211_setcurchan(ic, ic->ic_csa_newchan); 1604224220Sadrian TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 1605224220Sadrian if (vap->iv_state == IEEE80211_S_CSA) 1606224220Sadrian vap->iv_bss->ni_chan = ic->ic_curchan; 1607224220Sadrian 1608193439Ssam csa_completeswitch(ic); 1609193439Ssam} 1610178354Ssam 1611193439Ssam/* 1612193439Ssam * Cancel an 802.11h channel switch started by ieee80211_csa_startswitch. 1613193439Ssam * We clear state and move all vap's in CSA state to RUN state 1614193439Ssam * so they can again transmit. 1615193439Ssam */ 1616193439Ssamvoid 1617193439Ssamieee80211_csa_cancelswitch(struct ieee80211com *ic) 1618193439Ssam{ 1619193439Ssam IEEE80211_LOCK_ASSERT(ic); 1620193439Ssam 1621193439Ssam csa_completeswitch(ic); 1622178354Ssam} 1623178354Ssam 1624178354Ssam/* 1625178354Ssam * Complete a DFS CAC started by ieee80211_dfs_cac_start. 1626178354Ssam * We clear state and move all vap's in CAC state to RUN state. 1627178354Ssam */ 1628178354Ssamvoid 1629178354Ssamieee80211_cac_completeswitch(struct ieee80211vap *vap0) 1630178354Ssam{ 1631178354Ssam struct ieee80211com *ic = vap0->iv_ic; 1632178354Ssam struct ieee80211vap *vap; 1633178354Ssam 1634178354Ssam IEEE80211_LOCK(ic); 1635178354Ssam /* 1636178354Ssam * Complete CAC state change for lead vap first; then 1637178354Ssam * clock all the other vap's waiting. 1638178354Ssam */ 1639178354Ssam KASSERT(vap0->iv_state == IEEE80211_S_CAC, 1640178354Ssam ("wrong state %d", vap0->iv_state)); 1641178354Ssam ieee80211_new_state_locked(vap0, IEEE80211_S_RUN, 0); 1642178354Ssam 1643178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) 1644178354Ssam if (vap->iv_state == IEEE80211_S_CAC) 1645178354Ssam ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0); 1646178354Ssam IEEE80211_UNLOCK(ic); 1647178354Ssam} 1648178354Ssam 1649178354Ssam/* 1650178354Ssam * Force all vap's other than the specified vap to the INIT state 1651178354Ssam * and mark them as waiting for a scan to complete. These vaps 1652178354Ssam * will be brought up when the scan completes and the scanning vap 1653178354Ssam * reaches RUN state by wakeupwaiting. 1654178354Ssam */ 1655154736Ssamstatic void 1656178354Ssammarkwaiting(struct ieee80211vap *vap0) 1657147765Ssam{ 1658178354Ssam struct ieee80211com *ic = vap0->iv_ic; 1659178354Ssam struct ieee80211vap *vap; 1660147765Ssam 1661178354Ssam IEEE80211_LOCK_ASSERT(ic); 1662178354Ssam 1663191746Sthompsa /* 1664191746Sthompsa * A vap list entry can not disappear since we are running on the 1665191746Sthompsa * taskqueue and a vap destroy will queue and drain another state 1666191746Sthompsa * change task. 1667191746Sthompsa */ 1668178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1669178354Ssam if (vap == vap0) 1670178354Ssam continue; 1671178354Ssam if (vap->iv_state != IEEE80211_S_INIT) { 1672191746Sthompsa /* NB: iv_newstate may drop the lock */ 1673178354Ssam vap->iv_newstate(vap, IEEE80211_S_INIT, 0); 1674232096Sadrian IEEE80211_LOCK_ASSERT(ic); 1675178354Ssam vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; 1676178354Ssam } 1677147765Ssam } 1678147765Ssam} 1679147765Ssam 1680178354Ssam/* 1681178354Ssam * Wakeup all vap's waiting for a scan to complete. This is the 1682178354Ssam * companion to markwaiting (above) and is used to coordinate 1683178354Ssam * multiple vaps scanning. 1684191746Sthompsa * This is called from the state taskqueue. 1685178354Ssam */ 1686147765Ssamstatic void 1687178354Ssamwakeupwaiting(struct ieee80211vap *vap0) 1688147765Ssam{ 1689178354Ssam struct ieee80211com *ic = vap0->iv_ic; 1690178354Ssam struct ieee80211vap *vap; 1691147765Ssam 1692178354Ssam IEEE80211_LOCK_ASSERT(ic); 1693178354Ssam 1694191746Sthompsa /* 1695191746Sthompsa * A vap list entry can not disappear since we are running on the 1696191746Sthompsa * taskqueue and a vap destroy will queue and drain another state 1697191746Sthompsa * change task. 1698191746Sthompsa */ 1699178354Ssam TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 1700178354Ssam if (vap == vap0) 1701178354Ssam continue; 1702178354Ssam if (vap->iv_flags_ext & IEEE80211_FEXT_SCANWAIT) { 1703178354Ssam vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANWAIT; 1704178354Ssam /* NB: sta's cannot go INIT->RUN */ 1705191746Sthompsa /* NB: iv_newstate may drop the lock */ 1706178354Ssam vap->iv_newstate(vap, 1707178354Ssam vap->iv_opmode == IEEE80211_M_STA ? 1708178354Ssam IEEE80211_S_SCAN : IEEE80211_S_RUN, 0); 1709232096Sadrian IEEE80211_LOCK_ASSERT(ic); 1710178354Ssam } 1711178354Ssam } 1712147765Ssam} 1713147765Ssam 1714170530Ssam/* 1715178354Ssam * Handle post state change work common to all operating modes. 1716170530Ssam */ 1717170530Ssamstatic void 1718191746Sthompsaieee80211_newstate_cb(void *xvap, int npending) 1719170530Ssam{ 1720191746Sthompsa struct ieee80211vap *vap = xvap; 1721178354Ssam struct ieee80211com *ic = vap->iv_ic; 1722191746Sthompsa enum ieee80211_state nstate, ostate; 1723191746Sthompsa int arg, rc; 1724178354Ssam 1725191746Sthompsa IEEE80211_LOCK(ic); 1726191746Sthompsa nstate = vap->iv_nstate; 1727191746Sthompsa arg = vap->iv_nstate_arg; 1728178354Ssam 1729191746Sthompsa if (vap->iv_flags_ext & IEEE80211_FEXT_REINIT) { 1730191746Sthompsa /* 1731191746Sthompsa * We have been requested to drop back to the INIT before 1732191746Sthompsa * proceeding to the new state. 1733191746Sthompsa */ 1734191746Sthompsa IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1735191746Sthompsa "%s: %s -> %s arg %d\n", __func__, 1736191746Sthompsa ieee80211_state_name[vap->iv_state], 1737191746Sthompsa ieee80211_state_name[IEEE80211_S_INIT], arg); 1738191746Sthompsa vap->iv_newstate(vap, IEEE80211_S_INIT, arg); 1739232096Sadrian IEEE80211_LOCK_ASSERT(ic); 1740191746Sthompsa vap->iv_flags_ext &= ~IEEE80211_FEXT_REINIT; 1741191746Sthompsa } 1742191746Sthompsa 1743191746Sthompsa ostate = vap->iv_state; 1744191746Sthompsa if (nstate == IEEE80211_S_SCAN && ostate != IEEE80211_S_INIT) { 1745191746Sthompsa /* 1746191746Sthompsa * SCAN was forced; e.g. on beacon miss. Force other running 1747191746Sthompsa * vap's to INIT state and mark them as waiting for the scan to 1748191746Sthompsa * complete. This insures they don't interfere with our 1749191746Sthompsa * scanning. Since we are single threaded the vaps can not 1750191746Sthompsa * transition again while we are executing. 1751191746Sthompsa * 1752191746Sthompsa * XXX not always right, assumes ap follows sta 1753191746Sthompsa */ 1754191746Sthompsa markwaiting(vap); 1755191746Sthompsa } 1756178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1757191746Sthompsa "%s: %s -> %s arg %d\n", __func__, 1758191746Sthompsa ieee80211_state_name[ostate], ieee80211_state_name[nstate], arg); 1759178354Ssam 1760191746Sthompsa rc = vap->iv_newstate(vap, nstate, arg); 1761232096Sadrian IEEE80211_LOCK_ASSERT(ic); 1762191746Sthompsa vap->iv_flags_ext &= ~IEEE80211_FEXT_STATEWAIT; 1763191746Sthompsa if (rc != 0) { 1764191746Sthompsa /* State transition failed */ 1765191746Sthompsa KASSERT(rc != EINPROGRESS, ("iv_newstate was deferred")); 1766191746Sthompsa KASSERT(nstate != IEEE80211_S_INIT, 1767191746Sthompsa ("INIT state change failed")); 1768191746Sthompsa IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1769191746Sthompsa "%s: %s returned error %d\n", __func__, 1770191746Sthompsa ieee80211_state_name[nstate], rc); 1771191746Sthompsa goto done; 1772191746Sthompsa } 1773191746Sthompsa 1774191746Sthompsa /* No actual transition, skip post processing */ 1775191746Sthompsa if (ostate == nstate) 1776191746Sthompsa goto done; 1777191746Sthompsa 1778178354Ssam if (nstate == IEEE80211_S_RUN) { 1779178354Ssam /* 1780178354Ssam * OACTIVE may be set on the vap if the upper layer 1781178354Ssam * tried to transmit (e.g. IPv6 NDP) before we reach 1782178354Ssam * RUN state. Clear it and restart xmit. 1783178354Ssam * 1784178354Ssam * Note this can also happen as a result of SLEEP->RUN 1785178354Ssam * (i.e. coming out of power save mode). 1786178354Ssam */ 1787232096Sadrian IF_LOCK(&vap->iv_ifp->if_snd); 1788178354Ssam vap->iv_ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1789232096Sadrian IF_UNLOCK(&vap->iv_ifp->if_snd); 1790178354Ssam if_start(vap->iv_ifp); 1791178354Ssam 1792178354Ssam /* bring up any vaps waiting on us */ 1793178354Ssam wakeupwaiting(vap); 1794178354Ssam } else if (nstate == IEEE80211_S_INIT) { 1795178354Ssam /* 1796178354Ssam * Flush the scan cache if we did the last scan (XXX?) 1797178354Ssam * and flush any frames on send queues from this vap. 1798178354Ssam * Note the mgt q is used only for legacy drivers and 1799178354Ssam * will go away shortly. 1800178354Ssam */ 1801178354Ssam ieee80211_scan_flush(vap); 1802178354Ssam 1803178354Ssam /* XXX NB: cast for altq */ 1804178354Ssam ieee80211_flush_ifq((struct ifqueue *)&ic->ic_ifp->if_snd, vap); 1805170530Ssam } 1806191746Sthompsadone: 1807191746Sthompsa IEEE80211_UNLOCK(ic); 1808170530Ssam} 1809170530Ssam 1810178354Ssam/* 1811178354Ssam * Public interface for initiating a state machine change. 1812178354Ssam * This routine single-threads the request and coordinates 1813178354Ssam * the scheduling of multiple vaps for the purpose of selecting 1814178354Ssam * an operating channel. Specifically the following scenarios 1815178354Ssam * are handled: 1816178354Ssam * o only one vap can be selecting a channel so on transition to 1817178354Ssam * SCAN state if another vap is already scanning then 1818178354Ssam * mark the caller for later processing and return without 1819178354Ssam * doing anything (XXX? expectations by caller of synchronous operation) 1820178354Ssam * o only one vap can be doing CAC of a channel so on transition to 1821178354Ssam * CAC state if another vap is already scanning for radar then 1822178354Ssam * mark the caller for later processing and return without 1823178354Ssam * doing anything (XXX? expectations by caller of synchronous operation) 1824178354Ssam * o if another vap is already running when a request is made 1825178354Ssam * to SCAN then an operating channel has been chosen; bypass 1826178354Ssam * the scan and just join the channel 1827178354Ssam * 1828178354Ssam * Note that the state change call is done through the iv_newstate 1829178354Ssam * method pointer so any driver routine gets invoked. The driver 1830178354Ssam * will normally call back into operating mode-specific 1831178354Ssam * ieee80211_newstate routines (below) unless it needs to completely 1832178354Ssam * bypass the state machine (e.g. because the firmware has it's 1833178354Ssam * own idea how things should work). Bypassing the net80211 layer 1834178354Ssam * is usually a mistake and indicates lack of proper integration 1835178354Ssam * with the net80211 layer. 1836178354Ssam */ 1837117811Ssamstatic int 1838178354Ssamieee80211_new_state_locked(struct ieee80211vap *vap, 1839178354Ssam enum ieee80211_state nstate, int arg) 1840116742Ssam{ 1841178354Ssam struct ieee80211com *ic = vap->iv_ic; 1842178354Ssam struct ieee80211vap *vp; 1843117811Ssam enum ieee80211_state ostate; 1844191746Sthompsa int nrunning, nscanning; 1845116742Ssam 1846178354Ssam IEEE80211_LOCK_ASSERT(ic); 1847178354Ssam 1848191746Sthompsa if (vap->iv_flags_ext & IEEE80211_FEXT_STATEWAIT) { 1849191746Sthompsa if (vap->iv_nstate == IEEE80211_S_INIT) { 1850191746Sthompsa /* 1851191746Sthompsa * XXX The vap is being stopped, do no allow any other 1852191746Sthompsa * state changes until this is completed. 1853191746Sthompsa */ 1854191746Sthompsa return -1; 1855191768Sthompsa } else if (vap->iv_state != vap->iv_nstate) { 1856191746Sthompsa#if 0 1857191768Sthompsa /* Warn if the previous state hasn't completed. */ 1858191768Sthompsa IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1859191768Sthompsa "%s: pending %s -> %s transition lost\n", __func__, 1860191768Sthompsa ieee80211_state_name[vap->iv_state], 1861191768Sthompsa ieee80211_state_name[vap->iv_nstate]); 1862191746Sthompsa#else 1863191768Sthompsa /* XXX temporarily enable to identify issues */ 1864191768Sthompsa if_printf(vap->iv_ifp, 1865191768Sthompsa "%s: pending %s -> %s transition lost\n", 1866191768Sthompsa __func__, ieee80211_state_name[vap->iv_state], 1867191768Sthompsa ieee80211_state_name[vap->iv_nstate]); 1868191746Sthompsa#endif 1869191768Sthompsa } 1870191746Sthompsa } 1871191746Sthompsa 1872178354Ssam nrunning = nscanning = 0; 1873178354Ssam /* XXX can track this state instead of calculating */ 1874178354Ssam TAILQ_FOREACH(vp, &ic->ic_vaps, iv_next) { 1875178354Ssam if (vp != vap) { 1876178354Ssam if (vp->iv_state >= IEEE80211_S_RUN) 1877178354Ssam nrunning++; 1878178354Ssam /* XXX doesn't handle bg scan */ 1879178354Ssam /* NB: CAC+AUTH+ASSOC treated like SCAN */ 1880178354Ssam else if (vp->iv_state > IEEE80211_S_INIT) 1881178354Ssam nscanning++; 1882178354Ssam } 1883178354Ssam } 1884178354Ssam ostate = vap->iv_state; 1885178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1886178354Ssam "%s: %s -> %s (nrunning %d nscanning %d)\n", __func__, 1887178354Ssam ieee80211_state_name[ostate], ieee80211_state_name[nstate], 1888178354Ssam nrunning, nscanning); 1889116742Ssam switch (nstate) { 1890116742Ssam case IEEE80211_S_SCAN: 1891178354Ssam if (ostate == IEEE80211_S_INIT) { 1892178354Ssam /* 1893178354Ssam * INIT -> SCAN happens on initial bringup. 1894178354Ssam */ 1895178354Ssam KASSERT(!(nscanning && nrunning), 1896178354Ssam ("%d scanning and %d running", nscanning, nrunning)); 1897178354Ssam if (nscanning) { 1898116742Ssam /* 1899178354Ssam * Someone is scanning, defer our state 1900178354Ssam * change until the work has completed. 1901116742Ssam */ 1902178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1903178354Ssam "%s: defer %s -> %s\n", 1904178354Ssam __func__, ieee80211_state_name[ostate], 1905178354Ssam ieee80211_state_name[nstate]); 1906178354Ssam vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; 1907191746Sthompsa return 0; 1908116742Ssam } 1909178354Ssam if (nrunning) { 1910170530Ssam /* 1911178354Ssam * Someone is operating; just join the channel 1912178354Ssam * they have chosen. 1913170530Ssam */ 1914178354Ssam /* XXX kill arg? */ 1915178354Ssam /* XXX check each opmode, adhoc? */ 1916178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) 1917178354Ssam nstate = IEEE80211_S_SCAN; 1918178354Ssam else 1919178354Ssam nstate = IEEE80211_S_RUN; 1920138568Ssam#ifdef IEEE80211_DEBUG 1921178354Ssam if (nstate != IEEE80211_S_SCAN) { 1922178354Ssam IEEE80211_DPRINTF(vap, 1923178354Ssam IEEE80211_MSG_STATE, 1924178354Ssam "%s: override, now %s -> %s\n", 1925178354Ssam __func__, 1926178354Ssam ieee80211_state_name[ostate], 1927178354Ssam ieee80211_state_name[nstate]); 1928178354Ssam } 1929138568Ssam#endif 1930170530Ssam } 1931116742Ssam } 1932178354Ssam break; 1933178354Ssam case IEEE80211_S_RUN: 1934178354Ssam if (vap->iv_opmode == IEEE80211_M_WDS && 1935178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) && 1936178354Ssam nscanning) { 1937154736Ssam /* 1938178354Ssam * Legacy WDS with someone else scanning; don't 1939178354Ssam * go online until that completes as we should 1940178354Ssam * follow the other vap to the channel they choose. 1941154736Ssam */ 1942178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1943178354Ssam "%s: defer %s -> %s (legacy WDS)\n", __func__, 1944178354Ssam ieee80211_state_name[ostate], 1945178354Ssam ieee80211_state_name[nstate]); 1946178354Ssam vap->iv_flags_ext |= IEEE80211_FEXT_SCANWAIT; 1947191746Sthompsa return 0; 1948154736Ssam } 1949178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP && 1950178354Ssam IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 1951178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_DFS) && 1952178354Ssam !IEEE80211_IS_CHAN_CACDONE(ic->ic_bsschan)) { 1953178354Ssam /* 1954178354Ssam * This is a DFS channel, transition to CAC state 1955178354Ssam * instead of RUN. This allows us to initiate 1956178354Ssam * Channel Availability Check (CAC) as specified 1957178354Ssam * by 11h/DFS. 1958178354Ssam */ 1959178354Ssam nstate = IEEE80211_S_CAC; 1960178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, 1961178354Ssam "%s: override %s -> %s (DFS)\n", __func__, 1962178354Ssam ieee80211_state_name[ostate], 1963178354Ssam ieee80211_state_name[nstate]); 1964138568Ssam } 1965116742Ssam break; 1966178354Ssam case IEEE80211_S_INIT: 1967191955Sthompsa /* cancel any scan in progress */ 1968191955Sthompsa ieee80211_cancel_scan(vap); 1969178354Ssam if (ostate == IEEE80211_S_INIT ) { 1970178354Ssam /* XXX don't believe this */ 1971178354Ssam /* INIT -> INIT. nothing to do */ 1972178354Ssam vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANWAIT; 1973178354Ssam } 1974178354Ssam /* fall thru... */ 1975172058Ssam default: 1976172058Ssam break; 1977116742Ssam } 1978191746Sthompsa /* defer the state change to a thread */ 1979191746Sthompsa vap->iv_nstate = nstate; 1980191746Sthompsa vap->iv_nstate_arg = arg; 1981191746Sthompsa vap->iv_flags_ext |= IEEE80211_FEXT_STATEWAIT; 1982191746Sthompsa ieee80211_runtask(ic, &vap->iv_nstate_task); 1983191746Sthompsa return EINPROGRESS; 1984116742Ssam} 1985178354Ssam 1986178354Ssamint 1987178354Ssamieee80211_new_state(struct ieee80211vap *vap, 1988178354Ssam enum ieee80211_state nstate, int arg) 1989178354Ssam{ 1990178354Ssam struct ieee80211com *ic = vap->iv_ic; 1991178354Ssam int rc; 1992178354Ssam 1993178354Ssam IEEE80211_LOCK(ic); 1994178354Ssam rc = ieee80211_new_state_locked(vap, nstate, arg); 1995178354Ssam IEEE80211_UNLOCK(ic); 1996178354Ssam return rc; 1997178354Ssam} 1998