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 }; 811a1e1d21SSam Leffler 821a1e1d21SSam Leffler void 831a1e1d21SSam Leffler ieee80211_proto_attach(struct ifnet *ifp) 841a1e1d21SSam Leffler { 851a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 861a1e1d21SSam Leffler 871a1e1d21SSam Leffler ifp->if_hdrlen = sizeof(struct ieee80211_frame); 881a1e1d21SSam Leffler 891a1e1d21SSam Leffler #ifdef notdef 901a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 911a1e1d21SSam Leffler #else 921a1e1d21SSam Leffler ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 931a1e1d21SSam Leffler #endif 941a1e1d21SSam Leffler ic->ic_fragthreshold = 2346; /* XXX not used yet */ 951a1e1d21SSam Leffler ic->ic_fixed_rate = -1; /* no fixed rate */ 961a1e1d21SSam Leffler 971a1e1d21SSam Leffler mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF); 981a1e1d21SSam Leffler 991a1e1d21SSam Leffler /* initialize management frame handlers */ 1001a1e1d21SSam Leffler ic->ic_recv_mgmt = ieee80211_recv_mgmt; 1011a1e1d21SSam Leffler ic->ic_send_mgmt = ieee80211_send_mgmt; 1021a1e1d21SSam Leffler } 1031a1e1d21SSam Leffler 1041a1e1d21SSam Leffler void 1051a1e1d21SSam Leffler ieee80211_proto_detach(struct ifnet *ifp) 1061a1e1d21SSam Leffler { 1071a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 1081a1e1d21SSam Leffler 1091a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 1101a1e1d21SSam Leffler mtx_destroy(&ic->ic_mgtq.ifq_mtx); 1111a1e1d21SSam Leffler } 1121a1e1d21SSam Leffler 1131a1e1d21SSam Leffler void 1141a1e1d21SSam Leffler ieee80211_print_essid(u_int8_t *essid, int len) 1151a1e1d21SSam Leffler { 1161a1e1d21SSam Leffler int i; 1171a1e1d21SSam Leffler u_int8_t *p; 1181a1e1d21SSam Leffler 1191a1e1d21SSam Leffler if (len > IEEE80211_NWID_LEN) 1201a1e1d21SSam Leffler len = IEEE80211_NWID_LEN; 1211a1e1d21SSam Leffler /* determine printable or not */ 1221a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) { 1231a1e1d21SSam Leffler if (*p < ' ' || *p > 0x7e) 1241a1e1d21SSam Leffler break; 1251a1e1d21SSam Leffler } 1261a1e1d21SSam Leffler if (i == len) { 1271a1e1d21SSam Leffler printf("\""); 1281a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 1291a1e1d21SSam Leffler printf("%c", *p); 1301a1e1d21SSam Leffler printf("\""); 1311a1e1d21SSam Leffler } else { 1321a1e1d21SSam Leffler printf("0x"); 1331a1e1d21SSam Leffler for (i = 0, p = essid; i < len; i++, p++) 1341a1e1d21SSam Leffler printf("%02x", *p); 1351a1e1d21SSam Leffler } 1361a1e1d21SSam Leffler } 1371a1e1d21SSam Leffler 1381a1e1d21SSam Leffler void 1391a1e1d21SSam Leffler ieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 1401a1e1d21SSam Leffler { 1411a1e1d21SSam Leffler struct ieee80211_frame *wh; 1421a1e1d21SSam Leffler int i; 1431a1e1d21SSam Leffler 1441a1e1d21SSam Leffler wh = (struct ieee80211_frame *)buf; 1451a1e1d21SSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 1461a1e1d21SSam Leffler case IEEE80211_FC1_DIR_NODS: 1471a1e1d21SSam Leffler printf("NODS %s", ether_sprintf(wh->i_addr2)); 1481a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 1491a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr3)); 1501a1e1d21SSam Leffler break; 1511a1e1d21SSam Leffler case IEEE80211_FC1_DIR_TODS: 1521a1e1d21SSam Leffler printf("TODS %s", ether_sprintf(wh->i_addr2)); 1531a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 1541a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr1)); 1551a1e1d21SSam Leffler break; 1561a1e1d21SSam Leffler case IEEE80211_FC1_DIR_FROMDS: 1571a1e1d21SSam Leffler printf("FRDS %s", ether_sprintf(wh->i_addr3)); 1581a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr1)); 1591a1e1d21SSam Leffler printf("(%s)", ether_sprintf(wh->i_addr2)); 1601a1e1d21SSam Leffler break; 1611a1e1d21SSam Leffler case IEEE80211_FC1_DIR_DSTODS: 1621a1e1d21SSam Leffler printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 1631a1e1d21SSam Leffler printf("->%s", ether_sprintf(wh->i_addr3)); 1641a1e1d21SSam Leffler printf("(%s", ether_sprintf(wh->i_addr2)); 1651a1e1d21SSam Leffler printf("->%s)", ether_sprintf(wh->i_addr1)); 1661a1e1d21SSam Leffler break; 1671a1e1d21SSam Leffler } 1681a1e1d21SSam Leffler switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 1691a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_DATA: 1701a1e1d21SSam Leffler printf(" data"); 1711a1e1d21SSam Leffler break; 1721a1e1d21SSam Leffler case IEEE80211_FC0_TYPE_MGT: 1731a1e1d21SSam Leffler printf(" %s", ieee80211_mgt_subtype_name[ 1741a1e1d21SSam Leffler (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 1751a1e1d21SSam Leffler >> IEEE80211_FC0_SUBTYPE_SHIFT]); 1761a1e1d21SSam Leffler break; 1771a1e1d21SSam Leffler default: 1781a1e1d21SSam Leffler printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 1791a1e1d21SSam Leffler break; 1801a1e1d21SSam Leffler } 1811a1e1d21SSam Leffler if (wh->i_fc[1] & IEEE80211_FC1_WEP) 1821a1e1d21SSam Leffler printf(" WEP"); 1831a1e1d21SSam Leffler if (rate >= 0) 1841a1e1d21SSam Leffler printf(" %dM", rate / 2); 1851a1e1d21SSam Leffler if (rssi >= 0) 1861a1e1d21SSam Leffler printf(" +%d", rssi); 1871a1e1d21SSam Leffler printf("\n"); 1881a1e1d21SSam Leffler if (len > 0) { 1891a1e1d21SSam Leffler for (i = 0; i < len; i++) { 1901a1e1d21SSam Leffler if ((i & 1) == 0) 1911a1e1d21SSam Leffler printf(" "); 1921a1e1d21SSam Leffler printf("%02x", buf[i]); 1931a1e1d21SSam Leffler } 1941a1e1d21SSam Leffler printf("\n"); 1951a1e1d21SSam Leffler } 1961a1e1d21SSam Leffler } 1971a1e1d21SSam Leffler 1981a1e1d21SSam Leffler int 1991a1e1d21SSam Leffler ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 2001a1e1d21SSam Leffler { 2011a1e1d21SSam Leffler #define RV(v) ((v) & IEEE80211_RATE_VAL) 2021a1e1d21SSam Leffler int i, j, ignore, error; 2031a1e1d21SSam Leffler int okrate, badrate; 2041a1e1d21SSam Leffler struct ieee80211_rateset *srs, *nrs; 2051a1e1d21SSam Leffler u_int8_t r; 2061a1e1d21SSam Leffler 2071a1e1d21SSam Leffler error = 0; 2081a1e1d21SSam Leffler okrate = badrate = 0; 2091a1e1d21SSam Leffler srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 2101a1e1d21SSam Leffler nrs = &ni->ni_rates; 2111a1e1d21SSam Leffler for (i = 0; i < ni->ni_rates.rs_nrates; ) { 2121a1e1d21SSam Leffler ignore = 0; 2131a1e1d21SSam Leffler if (flags & IEEE80211_F_DOSORT) { 2141a1e1d21SSam Leffler /* 2151a1e1d21SSam Leffler * Sort rates. 2161a1e1d21SSam Leffler */ 2171a1e1d21SSam Leffler for (j = i + 1; j < nrs->rs_nrates; j++) { 2181a1e1d21SSam Leffler if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 2191a1e1d21SSam Leffler r = nrs->rs_rates[i]; 2201a1e1d21SSam Leffler nrs->rs_rates[i] = nrs->rs_rates[j]; 2211a1e1d21SSam Leffler nrs->rs_rates[j] = r; 2221a1e1d21SSam Leffler } 2231a1e1d21SSam Leffler } 2241a1e1d21SSam Leffler } 2251a1e1d21SSam Leffler r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 2261a1e1d21SSam Leffler badrate = r; 2271a1e1d21SSam Leffler if (flags & IEEE80211_F_DOFRATE) { 2281a1e1d21SSam Leffler /* 2291a1e1d21SSam Leffler * Apply fixed rate constraint. Note that we do 2301a1e1d21SSam Leffler * not apply the constraint to basic rates as 2311a1e1d21SSam Leffler * otherwise we may not be able to associate if 2321a1e1d21SSam Leffler * the rate set we submit to the AP is invalid 2331a1e1d21SSam Leffler * (e.g. fix rate at 36Mb/s which is not a basic 2341a1e1d21SSam Leffler * rate for 11a operation). 2351a1e1d21SSam Leffler */ 2361a1e1d21SSam Leffler if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 2371a1e1d21SSam Leffler ic->ic_fixed_rate >= 0 && 2381a1e1d21SSam Leffler r != RV(srs->rs_rates[ic->ic_fixed_rate])) 2391a1e1d21SSam Leffler ignore++; 2401a1e1d21SSam Leffler } 2411a1e1d21SSam Leffler if (flags & IEEE80211_F_DONEGO) { 2421a1e1d21SSam Leffler /* 2431a1e1d21SSam Leffler * Check against supported rates. 2441a1e1d21SSam Leffler */ 2451a1e1d21SSam Leffler for (j = 0; j < srs->rs_nrates; j++) { 2461a1e1d21SSam Leffler if (r == RV(srs->rs_rates[j])) 2471a1e1d21SSam Leffler break; 2481a1e1d21SSam Leffler } 2491a1e1d21SSam Leffler if (j == srs->rs_nrates) { 2501a1e1d21SSam Leffler if (nrs->rs_rates[i] & IEEE80211_RATE_BASIC) 2511a1e1d21SSam Leffler error++; 2521a1e1d21SSam Leffler ignore++; 2531a1e1d21SSam Leffler } 2541a1e1d21SSam Leffler } 2551a1e1d21SSam Leffler if (flags & IEEE80211_F_DODEL) { 2561a1e1d21SSam Leffler /* 2571a1e1d21SSam Leffler * Delete unacceptable rates. 2581a1e1d21SSam Leffler */ 2591a1e1d21SSam Leffler if (ignore) { 2601a1e1d21SSam Leffler nrs->rs_nrates--; 2611a1e1d21SSam Leffler for (j = i; j < nrs->rs_nrates; j++) 2621a1e1d21SSam Leffler nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 2631a1e1d21SSam Leffler nrs->rs_rates[j] = 0; 2641a1e1d21SSam Leffler continue; 2651a1e1d21SSam Leffler } 2661a1e1d21SSam Leffler } 2671a1e1d21SSam Leffler if (!ignore) 2681a1e1d21SSam Leffler okrate = nrs->rs_rates[i]; 2691a1e1d21SSam Leffler i++; 2701a1e1d21SSam Leffler } 2711a1e1d21SSam Leffler if (okrate == 0 || error != 0) 2721a1e1d21SSam Leffler return badrate | IEEE80211_RATE_BASIC; 2731a1e1d21SSam Leffler else 2741a1e1d21SSam Leffler return RV(okrate); 2751a1e1d21SSam Leffler #undef RV 2761a1e1d21SSam Leffler } 2771a1e1d21SSam Leffler 2781a1e1d21SSam Leffler int 2791a1e1d21SSam Leffler ieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt) 2801a1e1d21SSam Leffler { 2811a1e1d21SSam Leffler struct ieee80211com *ic = (void *)ifp; 2821a1e1d21SSam Leffler struct ieee80211_node *ni; 2831a1e1d21SSam Leffler int error, ostate; 2841a1e1d21SSam Leffler #ifdef IEEE80211_DEBUG 2851a1e1d21SSam Leffler static const char *stname[] = 2861a1e1d21SSam Leffler { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; 2871a1e1d21SSam Leffler #endif 2881a1e1d21SSam Leffler 2891a1e1d21SSam Leffler ostate = ic->ic_state; 2901a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 2911a1e1d21SSam Leffler stname[ostate], stname[nstate])); 2921a1e1d21SSam Leffler if (ic->ic_newstate) { 2931a1e1d21SSam Leffler error = (*ic->ic_newstate)(ic->ic_softc, nstate); 2941a1e1d21SSam Leffler if (error == EINPROGRESS) 2951a1e1d21SSam Leffler return 0; 2961a1e1d21SSam Leffler if (error != 0) 2971a1e1d21SSam Leffler return error; 2981a1e1d21SSam Leffler } 2991a1e1d21SSam Leffler 3001a1e1d21SSam Leffler /* state transition */ 3011a1e1d21SSam Leffler ic->ic_state = nstate; 3021a1e1d21SSam Leffler ni = ic->ic_bss; /* NB: no reference held */ 3031a1e1d21SSam Leffler switch (nstate) { 3041a1e1d21SSam Leffler case IEEE80211_S_INIT: 3051a1e1d21SSam Leffler switch (ostate) { 3061a1e1d21SSam Leffler case IEEE80211_S_INIT: 3071a1e1d21SSam Leffler break; 3081a1e1d21SSam Leffler case IEEE80211_S_RUN: 3091a1e1d21SSam Leffler switch (ic->ic_opmode) { 3101a1e1d21SSam Leffler case IEEE80211_M_STA: 3111a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3121a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 3131a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 3141a1e1d21SSam Leffler break; 3151a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 3161a1e1d21SSam Leffler mtx_lock(&ic->ic_nodelock); 3171a1e1d21SSam Leffler TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 3181a1e1d21SSam Leffler if (ni->ni_associd == 0) 3191a1e1d21SSam Leffler continue; 3201a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3211a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DISASSOC, 3221a1e1d21SSam Leffler IEEE80211_REASON_ASSOC_LEAVE); 3231a1e1d21SSam Leffler } 3241a1e1d21SSam Leffler mtx_unlock(&ic->ic_nodelock); 3251a1e1d21SSam Leffler break; 3261a1e1d21SSam Leffler default: 3271a1e1d21SSam Leffler break; 3281a1e1d21SSam Leffler } 3291a1e1d21SSam Leffler /* FALLTHRU */ 3301a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 3311a1e1d21SSam Leffler switch (ic->ic_opmode) { 3321a1e1d21SSam Leffler case IEEE80211_M_STA: 3331a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3341a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 3351a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 3361a1e1d21SSam Leffler break; 3371a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 3381a1e1d21SSam Leffler mtx_lock(&ic->ic_nodelock); 3391a1e1d21SSam Leffler TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 3401a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3411a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_DEAUTH, 3421a1e1d21SSam Leffler IEEE80211_REASON_AUTH_LEAVE); 3431a1e1d21SSam Leffler } 3441a1e1d21SSam Leffler mtx_unlock(&ic->ic_nodelock); 3451a1e1d21SSam Leffler break; 3461a1e1d21SSam Leffler default: 3471a1e1d21SSam Leffler break; 3481a1e1d21SSam Leffler } 3491a1e1d21SSam Leffler /* FALLTHRU */ 3501a1e1d21SSam Leffler case IEEE80211_S_AUTH: 3511a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3521a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 3531a1e1d21SSam Leffler IF_DRAIN(&ic->ic_mgtq); 3541a1e1d21SSam Leffler if (ic->ic_wep_ctx != NULL) { 3551a1e1d21SSam Leffler free(ic->ic_wep_ctx, M_DEVBUF); 3561a1e1d21SSam Leffler ic->ic_wep_ctx = NULL; 3571a1e1d21SSam Leffler } 3581a1e1d21SSam Leffler ieee80211_free_allnodes(ic); 3591a1e1d21SSam Leffler break; 3601a1e1d21SSam Leffler } 3611a1e1d21SSam Leffler break; 3621a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3631a1e1d21SSam Leffler ic->ic_flags &= ~IEEE80211_F_SIBSS; 3641a1e1d21SSam Leffler /* initialize bss for probe request */ 3651a1e1d21SSam Leffler IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 3661a1e1d21SSam Leffler IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 3671a1e1d21SSam Leffler ni->ni_rates = ic->ic_sup_rates[ 3681a1e1d21SSam Leffler ieee80211_chan2mode(ic, ni->ni_chan)]; 3691a1e1d21SSam Leffler ni->ni_associd = 0; 3701a1e1d21SSam Leffler ni->ni_rstamp = 0; 3711a1e1d21SSam Leffler switch (ostate) { 3721a1e1d21SSam Leffler case IEEE80211_S_INIT: 3731a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_HOSTAP && 3741a1e1d21SSam Leffler ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 3751a1e1d21SSam Leffler /* 3761a1e1d21SSam Leffler * AP operation and we already have a channel; 3771a1e1d21SSam Leffler * bypass the scan and startup immediately. 3781a1e1d21SSam Leffler */ 3791a1e1d21SSam Leffler ieee80211_create_ibss(ic, ic->ic_des_chan); 3801a1e1d21SSam Leffler } else { 3811a1e1d21SSam Leffler ieee80211_begin_scan(ifp, ni); 3821a1e1d21SSam Leffler } 3831a1e1d21SSam Leffler break; 3841a1e1d21SSam Leffler case IEEE80211_S_SCAN: 3851a1e1d21SSam Leffler /* scan next */ 3861a1e1d21SSam Leffler if (ic->ic_flags & IEEE80211_F_ASCAN) { 3871a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 3881a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 3891a1e1d21SSam Leffler } 3901a1e1d21SSam Leffler break; 3911a1e1d21SSam Leffler case IEEE80211_S_RUN: 3921a1e1d21SSam Leffler /* beacon miss */ 3931a1e1d21SSam Leffler if (ifp->if_flags & IFF_DEBUG) { 3941a1e1d21SSam Leffler /* XXX bssid clobbered above */ 3951a1e1d21SSam Leffler if_printf(ifp, "no recent beacons from %s;" 3961a1e1d21SSam Leffler " rescanning\n", 3971a1e1d21SSam Leffler ether_sprintf(ic->ic_bss->ni_bssid)); 3981a1e1d21SSam Leffler } 3991a1e1d21SSam Leffler ieee80211_free_allnodes(ic); 4001a1e1d21SSam Leffler /* FALLTHRU */ 4011a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4021a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4031a1e1d21SSam Leffler /* timeout restart scan */ 4041a1e1d21SSam Leffler ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 4051a1e1d21SSam Leffler if (ni != NULL) { 4061a1e1d21SSam Leffler ni->ni_fails++; 4071a1e1d21SSam Leffler ieee80211_unref_node(&ni); 4081a1e1d21SSam Leffler } 4091a1e1d21SSam Leffler ieee80211_begin_scan(ifp, ic->ic_bss); 4101a1e1d21SSam Leffler break; 4111a1e1d21SSam Leffler } 4121a1e1d21SSam Leffler break; 4131a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4141a1e1d21SSam Leffler switch (ostate) { 4151a1e1d21SSam Leffler case IEEE80211_S_INIT: 4161a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4171a1e1d21SSam Leffler __func__)); 4181a1e1d21SSam Leffler break; 4191a1e1d21SSam Leffler case IEEE80211_S_SCAN: 4201a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4211a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 4221a1e1d21SSam Leffler break; 4231a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4241a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4251a1e1d21SSam Leffler switch (mgt) { 4261a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 4271a1e1d21SSam Leffler /* ??? */ 4281a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4291a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 4301a1e1d21SSam Leffler break; 4311a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 4321a1e1d21SSam Leffler /* ignore and retry scan on timeout */ 4331a1e1d21SSam Leffler break; 4341a1e1d21SSam Leffler } 4351a1e1d21SSam Leffler break; 4361a1e1d21SSam Leffler case IEEE80211_S_RUN: 4371a1e1d21SSam Leffler switch (mgt) { 4381a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 4391a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4401a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 2); 4411a1e1d21SSam Leffler ic->ic_state = ostate; /* stay RUN */ 4421a1e1d21SSam Leffler break; 4431a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 4441a1e1d21SSam Leffler /* try to reauth */ 4451a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4461a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_AUTH, 1); 4471a1e1d21SSam Leffler break; 4481a1e1d21SSam Leffler } 4491a1e1d21SSam Leffler break; 4501a1e1d21SSam Leffler } 4511a1e1d21SSam Leffler break; 4521a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4531a1e1d21SSam Leffler switch (ostate) { 4541a1e1d21SSam Leffler case IEEE80211_S_INIT: 4551a1e1d21SSam Leffler case IEEE80211_S_SCAN: 4561a1e1d21SSam Leffler case IEEE80211_S_ASSOC: 4571a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4581a1e1d21SSam Leffler __func__)); 4591a1e1d21SSam Leffler break; 4601a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4611a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4621a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 4631a1e1d21SSam Leffler break; 4641a1e1d21SSam Leffler case IEEE80211_S_RUN: 4651a1e1d21SSam Leffler IEEE80211_SEND_MGMT(ic, ni, 4661a1e1d21SSam Leffler IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 4671a1e1d21SSam Leffler break; 4681a1e1d21SSam Leffler } 4691a1e1d21SSam Leffler break; 4701a1e1d21SSam Leffler case IEEE80211_S_RUN: 4711a1e1d21SSam Leffler switch (ostate) { 4721a1e1d21SSam Leffler case IEEE80211_S_INIT: 4731a1e1d21SSam Leffler case IEEE80211_S_AUTH: 4741a1e1d21SSam Leffler case IEEE80211_S_RUN: 4751a1e1d21SSam Leffler IEEE80211_DPRINTF(("%s: invalid transition\n", 4761a1e1d21SSam Leffler __func__)); 4771a1e1d21SSam Leffler break; 4781a1e1d21SSam Leffler case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 4791a1e1d21SSam Leffler case IEEE80211_S_ASSOC: /* infra mode */ 4801a1e1d21SSam Leffler KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 4811a1e1d21SSam Leffler ("%s: bogus xmit rate %u setup\n", __func__, 4821a1e1d21SSam Leffler ni->ni_txrate)); 4831a1e1d21SSam Leffler if (ifp->if_flags & IFF_DEBUG) { 4841a1e1d21SSam Leffler if_printf(ifp, " "); 4851a1e1d21SSam Leffler if (ic->ic_opmode == IEEE80211_M_STA) 4861a1e1d21SSam Leffler printf("associated "); 4871a1e1d21SSam Leffler else 4881a1e1d21SSam Leffler printf("synchronized "); 4891a1e1d21SSam Leffler printf("with %s ssid ", 4901a1e1d21SSam Leffler ether_sprintf(ni->ni_bssid)); 4911a1e1d21SSam Leffler ieee80211_print_essid(ic->ic_bss->ni_essid, 4921a1e1d21SSam Leffler ni->ni_esslen); 4931a1e1d21SSam Leffler printf(" channel %d start %uMb\n", 4941a1e1d21SSam Leffler ieee80211_chan2ieee(ic, ni->ni_chan), 4951a1e1d21SSam Leffler IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 4961a1e1d21SSam Leffler } 4971a1e1d21SSam Leffler ic->ic_mgt_timer = 0; 4981a1e1d21SSam Leffler (*ifp->if_start)(ifp); 4991a1e1d21SSam Leffler break; 5001a1e1d21SSam Leffler } 5011a1e1d21SSam Leffler break; 5021a1e1d21SSam Leffler } 5031a1e1d21SSam Leffler return 0; 5041a1e1d21SSam Leffler } 505