11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 31a1e1d21SSam Leffler * Copyright (c) 2002, 2003 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/systm.h> 441a1e1d21SSam Leffler #include <sys/mbuf.h> 451a1e1d21SSam Leffler #include <sys/malloc.h> 461a1e1d21SSam Leffler #include <sys/kernel.h> 471a1e1d21SSam Leffler #include <sys/socket.h> 481a1e1d21SSam Leffler #include <sys/sockio.h> 491a1e1d21SSam Leffler #include <sys/endian.h> 501a1e1d21SSam Leffler #include <sys/errno.h> 511a1e1d21SSam Leffler #include <sys/bus.h> 521a1e1d21SSam Leffler #include <sys/proc.h> 531a1e1d21SSam Leffler #include <sys/sysctl.h> 541a1e1d21SSam Leffler 551a1e1d21SSam Leffler #include <machine/atomic.h> 561a1e1d21SSam Leffler 571a1e1d21SSam Leffler #include <net/if.h> 581a1e1d21SSam Leffler #include <net/if_dl.h> 591a1e1d21SSam Leffler #include <net/if_media.h> 601a1e1d21SSam Leffler #include <net/if_arp.h> 611a1e1d21SSam Leffler #include <net/ethernet.h> 621a1e1d21SSam Leffler #include <net/if_llc.h> 631a1e1d21SSam Leffler 641a1e1d21SSam Leffler #include <net80211/ieee80211_var.h> 651a1e1d21SSam Leffler 661a1e1d21SSam Leffler #include <net/bpf.h> 671a1e1d21SSam Leffler 681a1e1d21SSam Leffler #ifdef INET 691a1e1d21SSam Leffler #include <netinet/in.h> 701a1e1d21SSam Leffler #include <netinet/if_ether.h> 711a1e1d21SSam Leffler #endif 721a1e1d21SSam Leffler 731a1e1d21SSam Leffler #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 741a1e1d21SSam Leffler 751a1e1d21SSam Leffler const char *ieee80211_mgt_subtype_name[] = { 761a1e1d21SSam Leffler "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 771a1e1d21SSam Leffler "probe_req", "probe_resp", "reserved#6", "reserved#7", 781a1e1d21SSam Leffler "beacon", "atim", "disassoc", "auth", 791a1e1d21SSam Leffler "deauth", "reserved#13", "reserved#14", "reserved#15" 801a1e1d21SSam Leffler }; 81a11c9a5cSSam Leffler const char *ieee80211_state_name[IEEE80211_S_MAX] = { 82a11c9a5cSSam Leffler "INIT", /* IEEE80211_S_INIT */ 83a11c9a5cSSam Leffler "SCAN", /* IEEE80211_S_SCAN */ 84a11c9a5cSSam Leffler "AUTH", /* IEEE80211_S_AUTH */ 85a11c9a5cSSam Leffler "ASSOC", /* IEEE80211_S_ASSOC */ 86a11c9a5cSSam Leffler "RUN" /* IEEE80211_S_RUN */ 87a11c9a5cSSam Leffler }; 88a11c9a5cSSam Leffler 89a11c9a5cSSam Leffler static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 901a1e1d21SSam Leffler 911a1e1d21SSam Leffler void 921a1e1d21SSam Leffler ieee80211_proto_attach(struct ifnet *ifp) 931a1e1d21SSam Leffler { 941a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 951a1e1d21SSam Leffler 961a1e1d21SSam Leffler ifp->if_hdrlen = sizeof(struct ieee80211_frame); 971a1e1d21SSam Leffler 981a1e1d21SSam Leffler #ifdef notdef 991a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 1001a1e1d21SSam Leffler #else 1011a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 1021a1e1d21SSam Leffler #endif 1031a1e1d21SSam Leffler ic->ic_fragthreshold = 2346; /* XXX not used yet */ 1041a1e1d21SSam Leffler ic->ic_fixed_rate = -1; /* no fixed rate */ 1051a1e1d21SSam Leffler 1061a1e1d21SSam Leffler mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "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 1171a1e1d21SSam Leffler ieee80211_proto_detach(struct ifnet *ifp) 1181a1e1d21SSam Leffler { 1191a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 1201a1e1d21SSam Leffler 1211a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 1221a1e1d21SSam Leffler mtx_destroy(&ic->ic_mgtq.ifq_mtx); 1231a1e1d21SSam Leffler } 1241a1e1d21SSam Leffler 1251a1e1d21SSam Leffler void 1261a1e1d21SSam Leffler ieee80211_print_essid(u_int8_t *essid, int len) 1271a1e1d21SSam Leffler { 1281a1e1d21SSam Leffler int i; 1291a1e1d21SSam Leffler u_int8_t *p; 1301a1e1d21SSam Leffler 1311a1e1d21SSam Leffler if (len > IEEE80211_NWID_LEN) 1321a1e1d21SSam Leffler len = IEEE80211_NWID_LEN; 1331a1e1d21SSam Leffler /* determine printable or not */ 1341a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) { 1351a1e1d21SSam Leffler if (*p < ' ' || *p > 0x7e) 1361a1e1d21SSam Leffler break; 1371a1e1d21SSam Leffler } 1381a1e1d21SSam Leffler if (i == len) { 1391a1e1d21SSam Leffler printf("\""); 1401a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 1411a1e1d21SSam Leffler printf("%c", *p); 1421a1e1d21SSam Leffler printf("\""); 1431a1e1d21SSam Leffler } else { 1441a1e1d21SSam Leffler printf("0x"); 1451a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 1461a1e1d21SSam Leffler printf("%02x", *p); 1471a1e1d21SSam Leffler } 1481a1e1d21SSam Leffler } 1491a1e1d21SSam Leffler 1501a1e1d21SSam Leffler void 1511a1e1d21SSam Leffler ieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 1521a1e1d21SSam Leffler { 1531a1e1d21SSam Leffler struct ieee80211_frame *wh; 1541a1e1d21SSam Leffler int i; 1551a1e1d21SSam Leffler 1561a1e1d21SSam Leffler wh = (struct ieee80211_frame *)buf; 1571a1e1d21SSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 1581a1e1d21SSam Leffler case IEEE80211_FC1_DIR_NODS: 1591a1e1d21SSam Leffler printf("NODS %s", ether_sprintf(wh->i_addr2)); 1601a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 1611a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr3)); 1621a1e1d21SSam Leffler break; 1631a1e1d21SSam Leffler case IEEE80211_FC1_DIR_TODS: 1641a1e1d21SSam Leffler printf("TODS %s", ether_sprintf(wh->i_addr2)); 1651a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 1661a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr1)); 1671a1e1d21SSam Leffler break; 1681a1e1d21SSam Leffler case IEEE80211_FC1_DIR_FROMDS: 1691a1e1d21SSam Leffler printf("FRDS %s", ether_sprintf(wh->i_addr3)); 1701a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 1711a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr2)); 1721a1e1d21SSam Leffler break; 1731a1e1d21SSam Leffler case IEEE80211_FC1_DIR_DSTODS: 1741a1e1d21SSam Leffler printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 1751a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 1761a1e1d21SSam Leffler printf("(%s", ether_sprintf(wh->i_addr2)); 1771a1e1d21SSam Leffler printf("->%s)", ether_sprintf(wh->i_addr1)); 1781a1e1d21SSam Leffler break; 1791a1e1d21SSam Leffler } 1801a1e1d21SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 1811a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_DATA: 1821a1e1d21SSam Leffler printf(" data"); 1831a1e1d21SSam Leffler break; 1841a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_MGT: 1851a1e1d21SSam Leffler printf(" %s", ieee80211_mgt_subtype_name[ 1861a1e1d21SSam Leffler (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 1871a1e1d21SSam Leffler >> IEEE80211_FC0_SUBTYPE_SHIFT]); 1881a1e1d21SSam Leffler break; 1891a1e1d21SSam Leffler default: 1901a1e1d21SSam Leffler printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 1911a1e1d21SSam Leffler break; 1921a1e1d21SSam Leffler } 1931a1e1d21SSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) 1941a1e1d21SSam Leffler printf(" WEP"); 1951a1e1d21SSam Leffler if (rate >= 0) 1961a1e1d21SSam Leffler printf(" %dM", rate / 2); 1971a1e1d21SSam Leffler if (rssi >= 0) 1981a1e1d21SSam Leffler printf(" +%d", rssi); 1991a1e1d21SSam Leffler printf("\n"); 2001a1e1d21SSam Leffler if (len > 0) { 2011a1e1d21SSam Leffler for (i = 0; i < len; i++) { 2021a1e1d21SSam Leffler if ((i & 1) == 0) 2031a1e1d21SSam Leffler printf(" "); 2041a1e1d21SSam Leffler printf("%02x", buf[i]); 2051a1e1d21SSam Leffler } 2061a1e1d21SSam Leffler printf("\n"); 2071a1e1d21SSam Leffler } 2081a1e1d21SSam Leffler } 2091a1e1d21SSam Leffler 2101a1e1d21SSam Leffler int 2111a1e1d21SSam Leffler ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 2121a1e1d21SSam Leffler { 2131a1e1d21SSam Leffler #define RV(v) ((v) & IEEE80211_RATE_VAL) 2141a1e1d21SSam Leffler int i, j, ignore, error; 2151a1e1d21SSam Leffler int okrate, badrate; 2161a1e1d21SSam Leffler struct ieee80211_rateset *srs, *nrs; 2171a1e1d21SSam Leffler u_int8_t r; 2181a1e1d21SSam Leffler 2191a1e1d21SSam Leffler error = 0; 2201a1e1d21SSam Leffler okrate = badrate = 0; 2211a1e1d21SSam Leffler srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 2221a1e1d21SSam Leffler nrs = &ni->ni_rates; 223ef39d4beSSam Leffler for (i = 0; i < nrs->rs_nrates; ) { 2241a1e1d21SSam Leffler ignore = 0; 2251a1e1d21SSam Leffler if (flags & IEEE80211_F_DOSORT) { 2261a1e1d21SSam Leffler /* 2271a1e1d21SSam Leffler * Sort rates. 2281a1e1d21SSam Leffler */ 2291a1e1d21SSam Leffler for (j = i + 1; j < nrs->rs_nrates; j++) { 2301a1e1d21SSam Leffler if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 2311a1e1d21SSam Leffler r = nrs->rs_rates[i]; 2321a1e1d21SSam Leffler nrs->rs_rates[i] = nrs->rs_rates[j]; 2331a1e1d21SSam Leffler nrs->rs_rates[j] = r; 2341a1e1d21SSam Leffler } 2351a1e1d21SSam Leffler } 2361a1e1d21SSam Leffler } 2371a1e1d21SSam Leffler r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 2381a1e1d21SSam Leffler badrate = r; 2391a1e1d21SSam Leffler if (flags & IEEE80211_F_DOFRATE) { 2401a1e1d21SSam Leffler /* 2411a1e1d21SSam Leffler * Apply fixed rate constraint. Note that we do 2421a1e1d21SSam Leffler * not apply the constraint to basic rates as 2431a1e1d21SSam Leffler * otherwise we may not be able to associate if 2441a1e1d21SSam Leffler * the rate set we submit to the AP is invalid 2451a1e1d21SSam Leffler * (e.g. fix rate at 36Mb/s which is not a basic 2461a1e1d21SSam Leffler * rate for 11a operation). 2471a1e1d21SSam Leffler */ 2481a1e1d21SSam Leffler if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 2491a1e1d21SSam Leffler ic->ic_fixed_rate >= 0 && 2501a1e1d21SSam Leffler r != RV(srs->rs_rates[ic->ic_fixed_rate])) 2511a1e1d21SSam Leffler ignore++; 2521a1e1d21SSam Leffler } 2531a1e1d21SSam Leffler if (flags & IEEE80211_F_DONEGO) { 2541a1e1d21SSam Leffler /* 2551a1e1d21SSam Leffler * Check against supported rates. 2561a1e1d21SSam Leffler */ 2571a1e1d21SSam Leffler for (j = 0; j < srs->rs_nrates; j++) { 2581a1e1d21SSam Leffler if (r == RV(srs->rs_rates[j])) 2591a1e1d21SSam Leffler break; 2601a1e1d21SSam Leffler } 2611a1e1d21SSam Leffler if (j == srs->rs_nrates) { 262ef39d4beSSam Leffler /* 263ef39d4beSSam Leffler * A rate in the node's rate set is not 264ef39d4beSSam Leffler * supported. If this is a basic rate and we 265ef39d4beSSam Leffler * are operating as an AP then this is an error. 266ef39d4beSSam Leffler * Otherwise we just discard/ignore the rate. 267ef39d4beSSam Leffler * Note that this is important for 11b stations 268ef39d4beSSam Leffler * when they want to associate with an 11g AP. 269ef39d4beSSam Leffler */ 270ef39d4beSSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 271ef39d4beSSam Leffler (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 2721a1e1d21SSam Leffler error++; 2731a1e1d21SSam Leffler ignore++; 2741a1e1d21SSam Leffler } 2751a1e1d21SSam Leffler } 2761a1e1d21SSam Leffler if (flags & IEEE80211_F_DODEL) { 2771a1e1d21SSam Leffler /* 2781a1e1d21SSam Leffler * Delete unacceptable rates. 2791a1e1d21SSam Leffler */ 2801a1e1d21SSam Leffler if (ignore) { 2811a1e1d21SSam Leffler nrs->rs_nrates--; 2821a1e1d21SSam Leffler for (j = i; j < nrs->rs_nrates; j++) 2831a1e1d21SSam Leffler nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 2841a1e1d21SSam Leffler nrs->rs_rates[j] = 0; 2851a1e1d21SSam Leffler continue; 2861a1e1d21SSam Leffler } 2871a1e1d21SSam Leffler } 2881a1e1d21SSam Leffler if (!ignore) 2891a1e1d21SSam Leffler okrate = nrs->rs_rates[i]; 2901a1e1d21SSam Leffler i++; 2911a1e1d21SSam Leffler } 2921a1e1d21SSam Leffler if (okrate == 0 || error != 0) 2931a1e1d21SSam Leffler return badrate | IEEE80211_RATE_BASIC; 2941a1e1d21SSam Leffler else 2951a1e1d21SSam Leffler return RV(okrate); 2961a1e1d21SSam Leffler #undef RV 2971a1e1d21SSam Leffler } 2981a1e1d21SSam Leffler 299a11c9a5cSSam Leffler static int 300a11c9a5cSSam Leffler ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) 3011a1e1d21SSam Leffler { 302a11c9a5cSSam Leffler struct ifnet *ifp = &ic->ic_if; 3031a1e1d21SSam Leffler struct ieee80211_node *ni; 304a11c9a5cSSam Leffler enum ieee80211_state ostate; 3051a1e1d21SSam Leffler 3061a1e1d21SSam Leffler ostate = ic->ic_state; 3071a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 308a11c9a5cSSam Leffler ieee80211_state_name[ostate], ieee80211_state_name[nstate])); 309a11c9a5cSSam Leffler ic->ic_state = nstate; /* state transition */ 3101a1e1d21SSam Leffler ni = ic->ic_bss; /* NB: no reference held */ 3111a1e1d21SSam Leffler switch (nstate) { 3121a1e1d21SSam Leffler case IEEE80211_S_INIT: 3131a1e1d21SSam Leffler switch (ostate) { 3141a1e1d21SSam Leffler case IEEE80211_S_INIT: 3151a1e1d21SSam Leffler break; 3161a1e1d21SSam Leffler case IEEE80211_S_RUN: 3171a1e1d21SSam Leffler switch (ic->ic_opmode) { 3181a1e1d21SSam Leffler case IEEE80211_M_STA: 3191a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3201a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 3211a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 3221a1e1d21SSam Leffler break; 3231a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 3241a1e1d21SSam Leffler mtx_lock(&ic->ic_nodelock); 3251a1e1d21SSam Leffler TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 3261a1e1d21SSam Leffler if (ni->ni_associd == 0) 3271a1e1d21SSam Leffler continue; 3281a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3291a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 3301a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 3311a1e1d21SSam Leffler } 3321a1e1d21SSam Leffler mtx_unlock(&ic->ic_nodelock); 3331a1e1d21SSam Leffler break; 3341a1e1d21SSam Leffler default: 3351a1e1d21SSam Leffler break; 3361a1e1d21SSam Leffler } 3371a1e1d21SSam Leffler /* FALLTHRU */ 3381a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 3391a1e1d21SSam Leffler switch (ic->ic_opmode) { 3401a1e1d21SSam Leffler case IEEE80211_M_STA: 3411a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3421a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 3431a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 3441a1e1d21SSam Leffler break; 3451a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 3461a1e1d21SSam Leffler mtx_lock(&ic->ic_nodelock); 3471a1e1d21SSam Leffler TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 3481a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3491a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 3501a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 3511a1e1d21SSam Leffler } 3521a1e1d21SSam Leffler mtx_unlock(&ic->ic_nodelock); 3531a1e1d21SSam Leffler break; 3541a1e1d21SSam Leffler default: 3551a1e1d21SSam Leffler break; 3561a1e1d21SSam Leffler } 3571a1e1d21SSam Leffler /* FALLTHRU */ 3581a1e1d21SSam Leffler case IEEE80211_S_AUTH: 3591a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3601a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 3611a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 3621a1e1d21SSam Leffler if (ic->ic_wep_ctx != NULL) { 3631a1e1d21SSam Leffler free(ic->ic_wep_ctx, M_DEVBUF); 3641a1e1d21SSam Leffler ic->ic_wep_ctx = NULL; 3651a1e1d21SSam Leffler } 3661a1e1d21SSam Leffler ieee80211_free_allnodes(ic); 3671a1e1d21SSam Leffler break; 3681a1e1d21SSam Leffler } 3691a1e1d21SSam Leffler break; 3701a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3711a1e1d21SSam Leffler ic->ic_flags &= ~IEEE80211_F_SIBSS; 3721a1e1d21SSam Leffler /* initialize bss for probe request */ 3731a1e1d21SSam Leffler IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 3741a1e1d21SSam Leffler IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 3751a1e1d21SSam Leffler ni->ni_rates = ic->ic_sup_rates[ 3761a1e1d21SSam Leffler ieee80211_chan2mode(ic, ni->ni_chan)]; 3771a1e1d21SSam Leffler ni->ni_associd = 0; 3781a1e1d21SSam Leffler ni->ni_rstamp = 0; 3791a1e1d21SSam Leffler switch (ostate) { 3801a1e1d21SSam Leffler case IEEE80211_S_INIT: 3811a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 3821a1e1d21SSam Leffler ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 3831a1e1d21SSam Leffler /* 3841a1e1d21SSam Leffler * AP operation and we already have a channel; 3851a1e1d21SSam Leffler * bypass the scan and startup immediately. 3861a1e1d21SSam Leffler */ 3871a1e1d21SSam Leffler ieee80211_create_ibss(ic, ic->ic_des_chan); 3881a1e1d21SSam Leffler } else { 389a11c9a5cSSam Leffler ieee80211_begin_scan(ifp); 3901a1e1d21SSam Leffler } 3911a1e1d21SSam Leffler break; 3921a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3931a1e1d21SSam Leffler /* scan next */ 3941a1e1d21SSam Leffler if (ic->ic_flags & IEEE80211_F_ASCAN) { 3951a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3961a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 3971a1e1d21SSam Leffler } 3981a1e1d21SSam Leffler break; 3991a1e1d21SSam Leffler case IEEE80211_S_RUN: 4001a1e1d21SSam Leffler /* beacon miss */ 4011a1e1d21SSam Leffler if (ifp->if_flags & IFF_DEBUG) { 4021a1e1d21SSam Leffler /* XXX bssid clobbered above */ 4031a1e1d21SSam Leffler if_printf(ifp, "no recent beacons from %s;" 4041a1e1d21SSam Leffler " rescanning\n", 4051a1e1d21SSam Leffler ether_sprintf(ic->ic_bss->ni_bssid)); 4061a1e1d21SSam Leffler } 4071a1e1d21SSam Leffler ieee80211_free_allnodes(ic); 4081a1e1d21SSam Leffler /* FALLTHRU */ 4091a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4101a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4111a1e1d21SSam Leffler /* timeout restart scan */ 4121a1e1d21SSam Leffler ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 4131a1e1d21SSam Leffler if (ni != NULL) { 4141a1e1d21SSam Leffler ni->ni_fails++; 4151a1e1d21SSam Leffler ieee80211_unref_node(&ni); 4161a1e1d21SSam Leffler } 417a11c9a5cSSam Leffler ieee80211_begin_scan(ifp); 4181a1e1d21SSam Leffler break; 4191a1e1d21SSam Leffler } 4201a1e1d21SSam Leffler break; 4211a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4221a1e1d21SSam Leffler switch (ostate) { 4231a1e1d21SSam Leffler case IEEE80211_S_INIT: 4241a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4251a1e1d21SSam Leffler __func__)); 4261a1e1d21SSam Leffler break; 4271a1e1d21SSam Leffler case IEEE80211_S_SCAN: 4281a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4291a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 4301a1e1d21SSam Leffler break; 4311a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4321a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4331a1e1d21SSam Leffler switch (mgt) { 4341a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 4351a1e1d21SSam Leffler /* ??? */ 4361a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4371a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 4381a1e1d21SSam Leffler break; 4391a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 4401a1e1d21SSam Leffler /* ignore and retry scan on timeout */ 4411a1e1d21SSam Leffler break; 4421a1e1d21SSam Leffler } 4431a1e1d21SSam Leffler break; 4441a1e1d21SSam Leffler case IEEE80211_S_RUN: 4451a1e1d21SSam Leffler switch (mgt) { 4461a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 4471a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4481a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 4491a1e1d21SSam Leffler ic->ic_state = ostate; /* stay RUN */ 4501a1e1d21SSam Leffler break; 4511a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 4521a1e1d21SSam Leffler /* try to reauth */ 4531a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4541a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 4551a1e1d21SSam Leffler break; 4561a1e1d21SSam Leffler } 4571a1e1d21SSam Leffler break; 4581a1e1d21SSam Leffler } 4591a1e1d21SSam Leffler break; 4601a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4611a1e1d21SSam Leffler switch (ostate) { 4621a1e1d21SSam Leffler case IEEE80211_S_INIT: 4631a1e1d21SSam Leffler case IEEE80211_S_SCAN: 4641a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4651a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4661a1e1d21SSam Leffler __func__)); 4671a1e1d21SSam Leffler break; 4681a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4691a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4701a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 4711a1e1d21SSam Leffler break; 4721a1e1d21SSam Leffler case IEEE80211_S_RUN: 4731a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4741a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 4751a1e1d21SSam Leffler break; 4761a1e1d21SSam Leffler } 4771a1e1d21SSam Leffler break; 4781a1e1d21SSam Leffler case IEEE80211_S_RUN: 4791a1e1d21SSam Leffler switch (ostate) { 4801a1e1d21SSam Leffler case IEEE80211_S_INIT: 4811a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4821a1e1d21SSam Leffler case IEEE80211_S_RUN: 4831a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4841a1e1d21SSam Leffler __func__)); 4851a1e1d21SSam Leffler break; 4861a1e1d21SSam Leffler case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 4871a1e1d21SSam Leffler case IEEE80211_S_ASSOC: /* infra mode */ 4881a1e1d21SSam Leffler KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 4891a1e1d21SSam Leffler ("%s: bogus xmit rate %u setup\n", __func__, 4901a1e1d21SSam Leffler ni->ni_txrate)); 4911a1e1d21SSam Leffler if (ifp->if_flags & IFF_DEBUG) { 4921a1e1d21SSam Leffler if_printf(ifp, " "); 4931a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 4941a1e1d21SSam Leffler printf("associated "); 4951a1e1d21SSam Leffler else 4961a1e1d21SSam Leffler printf("synchronized "); 4971a1e1d21SSam Leffler printf("with %s ssid ", 4981a1e1d21SSam Leffler ether_sprintf(ni->ni_bssid)); 4991a1e1d21SSam Leffler ieee80211_print_essid(ic->ic_bss->ni_essid, 5001a1e1d21SSam Leffler ni->ni_esslen); 5011a1e1d21SSam Leffler printf(" channel %d start %uMb\n", 5021a1e1d21SSam Leffler ieee80211_chan2ieee(ic, ni->ni_chan), 5031a1e1d21SSam Leffler IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 5041a1e1d21SSam Leffler } 5051a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 5061a1e1d21SSam Leffler (*ifp->if_start)(ifp); 5071a1e1d21SSam Leffler break; 5081a1e1d21SSam Leffler } 5091a1e1d21SSam Leffler break; 5101a1e1d21SSam Leffler } 5111a1e1d21SSam Leffler return 0; 5121a1e1d21SSam Leffler } 513