1*f186073cSJoerg Sonnenberger /* 2*f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 3*f186073cSJoerg Sonnenberger * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 4*f186073cSJoerg Sonnenberger * All rights reserved. 5*f186073cSJoerg Sonnenberger * 6*f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7*f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8*f186073cSJoerg Sonnenberger * are met: 9*f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10*f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11*f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12*f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13*f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14*f186073cSJoerg Sonnenberger * 3. The name of the author may not be used to endorse or promote products 15*f186073cSJoerg Sonnenberger * derived from this software without specific prior written permission. 16*f186073cSJoerg Sonnenberger * 17*f186073cSJoerg Sonnenberger * Alternatively, this software may be distributed under the terms of the 18*f186073cSJoerg Sonnenberger * GNU General Public License ("GPL") version 2 as published by the Free 19*f186073cSJoerg Sonnenberger * Software Foundation. 20*f186073cSJoerg Sonnenberger * 21*f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22*f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23*f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24*f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25*f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26*f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30*f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*f186073cSJoerg Sonnenberger * 32*f186073cSJoerg Sonnenberger * $FreeBSD: src/sys/net80211/ieee80211_proto.c,v 1.8 2004/04/02 20:22:25 sam Exp $ 33*f186073cSJoerg Sonnenberger * $DragonFly: src/sys/netproto/802_11/wlan/ieee80211_proto.c,v 1.1 2004/07/26 16:30:17 joerg Exp $ 34*f186073cSJoerg Sonnenberger */ 35*f186073cSJoerg Sonnenberger 36*f186073cSJoerg Sonnenberger /* 37*f186073cSJoerg Sonnenberger * IEEE 802.11 protocol support. 38*f186073cSJoerg Sonnenberger */ 39*f186073cSJoerg Sonnenberger 40*f186073cSJoerg Sonnenberger #include "opt_inet.h" 41*f186073cSJoerg Sonnenberger 42*f186073cSJoerg Sonnenberger #include <sys/param.h> 43*f186073cSJoerg Sonnenberger #include <sys/systm.h> 44*f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 45*f186073cSJoerg Sonnenberger #include <sys/malloc.h> 46*f186073cSJoerg Sonnenberger #include <sys/kernel.h> 47*f186073cSJoerg Sonnenberger #include <sys/socket.h> 48*f186073cSJoerg Sonnenberger #include <sys/sockio.h> 49*f186073cSJoerg Sonnenberger #include <sys/endian.h> 50*f186073cSJoerg Sonnenberger #include <sys/errno.h> 51*f186073cSJoerg Sonnenberger #include <sys/bus.h> 52*f186073cSJoerg Sonnenberger #include <sys/proc.h> 53*f186073cSJoerg Sonnenberger #include <sys/sysctl.h> 54*f186073cSJoerg Sonnenberger 55*f186073cSJoerg Sonnenberger #include <machine/atomic.h> 56*f186073cSJoerg Sonnenberger 57*f186073cSJoerg Sonnenberger #include <net/if.h> 58*f186073cSJoerg Sonnenberger #include <net/if_dl.h> 59*f186073cSJoerg Sonnenberger #include <net/if_media.h> 60*f186073cSJoerg Sonnenberger #include <net/if_arp.h> 61*f186073cSJoerg Sonnenberger #include <net/ethernet.h> 62*f186073cSJoerg Sonnenberger #include <net/if_llc.h> 63*f186073cSJoerg Sonnenberger 64*f186073cSJoerg Sonnenberger #include <netproto/802_11/ieee80211_var.h> 65*f186073cSJoerg Sonnenberger 66*f186073cSJoerg Sonnenberger #include <net/bpf.h> 67*f186073cSJoerg Sonnenberger 68*f186073cSJoerg Sonnenberger #ifdef INET 69*f186073cSJoerg Sonnenberger #include <netinet/in.h> 70*f186073cSJoerg Sonnenberger #include <netinet/if_ether.h> 71*f186073cSJoerg Sonnenberger #endif 72*f186073cSJoerg Sonnenberger 73*f186073cSJoerg Sonnenberger #define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 74*f186073cSJoerg Sonnenberger 75*f186073cSJoerg Sonnenberger const char *ieee80211_mgt_subtype_name[] = { 76*f186073cSJoerg Sonnenberger "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 77*f186073cSJoerg Sonnenberger "probe_req", "probe_resp", "reserved#6", "reserved#7", 78*f186073cSJoerg Sonnenberger "beacon", "atim", "disassoc", "auth", 79*f186073cSJoerg Sonnenberger "deauth", "reserved#13", "reserved#14", "reserved#15" 80*f186073cSJoerg Sonnenberger }; 81*f186073cSJoerg Sonnenberger const char *ieee80211_state_name[IEEE80211_S_MAX] = { 82*f186073cSJoerg Sonnenberger "INIT", /* IEEE80211_S_INIT */ 83*f186073cSJoerg Sonnenberger "SCAN", /* IEEE80211_S_SCAN */ 84*f186073cSJoerg Sonnenberger "AUTH", /* IEEE80211_S_AUTH */ 85*f186073cSJoerg Sonnenberger "ASSOC", /* IEEE80211_S_ASSOC */ 86*f186073cSJoerg Sonnenberger "RUN" /* IEEE80211_S_RUN */ 87*f186073cSJoerg Sonnenberger }; 88*f186073cSJoerg Sonnenberger 89*f186073cSJoerg Sonnenberger static int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 90*f186073cSJoerg Sonnenberger 91*f186073cSJoerg Sonnenberger void 92*f186073cSJoerg Sonnenberger ieee80211_proto_attach(struct ifnet *ifp) 93*f186073cSJoerg Sonnenberger { 94*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 95*f186073cSJoerg Sonnenberger 96*f186073cSJoerg Sonnenberger ifp->if_hdrlen = sizeof(struct ieee80211_frame); 97*f186073cSJoerg Sonnenberger 98*f186073cSJoerg Sonnenberger #ifdef notdef 99*f186073cSJoerg Sonnenberger ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 100*f186073cSJoerg Sonnenberger #else 101*f186073cSJoerg Sonnenberger ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 102*f186073cSJoerg Sonnenberger #endif 103*f186073cSJoerg Sonnenberger ic->ic_fragthreshold = 2346; /* XXX not used yet */ 104*f186073cSJoerg Sonnenberger ic->ic_fixed_rate = -1; /* no fixed rate */ 105*f186073cSJoerg Sonnenberger ic->ic_protmode = IEEE80211_PROT_CTSONLY; 106*f186073cSJoerg Sonnenberger 107*f186073cSJoerg Sonnenberger /* protocol state change handler */ 108*f186073cSJoerg Sonnenberger ic->ic_newstate = ieee80211_newstate; 109*f186073cSJoerg Sonnenberger 110*f186073cSJoerg Sonnenberger /* initialize management frame handlers */ 111*f186073cSJoerg Sonnenberger ic->ic_recv_mgmt = ieee80211_recv_mgmt; 112*f186073cSJoerg Sonnenberger ic->ic_send_mgmt = ieee80211_send_mgmt; 113*f186073cSJoerg Sonnenberger } 114*f186073cSJoerg Sonnenberger 115*f186073cSJoerg Sonnenberger void 116*f186073cSJoerg Sonnenberger ieee80211_proto_detach(struct ifnet *ifp) 117*f186073cSJoerg Sonnenberger { 118*f186073cSJoerg Sonnenberger struct ieee80211com *ic = (void *)ifp; 119*f186073cSJoerg Sonnenberger 120*f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 121*f186073cSJoerg Sonnenberger } 122*f186073cSJoerg Sonnenberger 123*f186073cSJoerg Sonnenberger void 124*f186073cSJoerg Sonnenberger ieee80211_print_essid(uint8_t *essid, int len) 125*f186073cSJoerg Sonnenberger { 126*f186073cSJoerg Sonnenberger int i; 127*f186073cSJoerg Sonnenberger uint8_t *p; 128*f186073cSJoerg Sonnenberger 129*f186073cSJoerg Sonnenberger if (len > IEEE80211_NWID_LEN) 130*f186073cSJoerg Sonnenberger len = IEEE80211_NWID_LEN; 131*f186073cSJoerg Sonnenberger /* determine printable or not */ 132*f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) { 133*f186073cSJoerg Sonnenberger if (*p < ' ' || *p > 0x7e) 134*f186073cSJoerg Sonnenberger break; 135*f186073cSJoerg Sonnenberger } 136*f186073cSJoerg Sonnenberger if (i == len) { 137*f186073cSJoerg Sonnenberger printf("\""); 138*f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 139*f186073cSJoerg Sonnenberger printf("%c", *p); 140*f186073cSJoerg Sonnenberger printf("\""); 141*f186073cSJoerg Sonnenberger } else { 142*f186073cSJoerg Sonnenberger printf("0x"); 143*f186073cSJoerg Sonnenberger for (i = 0, p = essid; i < len; i++, p++) 144*f186073cSJoerg Sonnenberger printf("%02x", *p); 145*f186073cSJoerg Sonnenberger } 146*f186073cSJoerg Sonnenberger } 147*f186073cSJoerg Sonnenberger 148*f186073cSJoerg Sonnenberger void 149*f186073cSJoerg Sonnenberger ieee80211_dump_pkt(uint8_t *buf, int len, int rate, int rssi) 150*f186073cSJoerg Sonnenberger { 151*f186073cSJoerg Sonnenberger struct ieee80211_frame *wh; 152*f186073cSJoerg Sonnenberger int i; 153*f186073cSJoerg Sonnenberger 154*f186073cSJoerg Sonnenberger wh = (struct ieee80211_frame *)buf; 155*f186073cSJoerg Sonnenberger switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 156*f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_NODS: 157*f186073cSJoerg Sonnenberger printf("NODS %6D->%6D(%6D)", wh->i_addr2, ":", 158*f186073cSJoerg Sonnenberger wh->i_addr1, ":", wh->i_addr3, ":"); 159*f186073cSJoerg Sonnenberger break; 160*f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_TODS: 161*f186073cSJoerg Sonnenberger printf("TODS %6D->%6D(%6D)", wh->i_addr2, ":", 162*f186073cSJoerg Sonnenberger wh->i_addr3, ":", wh->i_addr1, ":"); 163*f186073cSJoerg Sonnenberger break; 164*f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_FROMDS: 165*f186073cSJoerg Sonnenberger printf("FRDS %6D->%6D(%6D)", wh->i_addr3, ":", 166*f186073cSJoerg Sonnenberger wh->i_addr1, ":", wh->i_addr2, ":"); 167*f186073cSJoerg Sonnenberger break; 168*f186073cSJoerg Sonnenberger case IEEE80211_FC1_DIR_DSTODS: 169*f186073cSJoerg Sonnenberger printf("DSDS %6D->%6D(%6D->%6D)", (uint8_t *)&wh[1], ":", 170*f186073cSJoerg Sonnenberger wh->i_addr3, ":", wh->i_addr2, ":", wh->i_addr1, ":"); 171*f186073cSJoerg Sonnenberger break; 172*f186073cSJoerg Sonnenberger } 173*f186073cSJoerg Sonnenberger switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 174*f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_DATA: 175*f186073cSJoerg Sonnenberger printf(" data"); 176*f186073cSJoerg Sonnenberger break; 177*f186073cSJoerg Sonnenberger case IEEE80211_FC0_TYPE_MGT: 178*f186073cSJoerg Sonnenberger printf(" %s", ieee80211_mgt_subtype_name[ 179*f186073cSJoerg Sonnenberger (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 180*f186073cSJoerg Sonnenberger >> IEEE80211_FC0_SUBTYPE_SHIFT]); 181*f186073cSJoerg Sonnenberger break; 182*f186073cSJoerg Sonnenberger default: 183*f186073cSJoerg Sonnenberger printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 184*f186073cSJoerg Sonnenberger break; 185*f186073cSJoerg Sonnenberger } 186*f186073cSJoerg Sonnenberger if (wh->i_fc[1] & IEEE80211_FC1_WEP) 187*f186073cSJoerg Sonnenberger printf(" WEP"); 188*f186073cSJoerg Sonnenberger if (rate >= 0) 189*f186073cSJoerg Sonnenberger printf(" %dM", rate / 2); 190*f186073cSJoerg Sonnenberger if (rssi >= 0) 191*f186073cSJoerg Sonnenberger printf(" +%d", rssi); 192*f186073cSJoerg Sonnenberger printf("\n"); 193*f186073cSJoerg Sonnenberger if (len > 0) { 194*f186073cSJoerg Sonnenberger for (i = 0; i < len; i++) { 195*f186073cSJoerg Sonnenberger if ((i & 1) == 0) 196*f186073cSJoerg Sonnenberger printf(" "); 197*f186073cSJoerg Sonnenberger printf("%02x", buf[i]); 198*f186073cSJoerg Sonnenberger } 199*f186073cSJoerg Sonnenberger printf("\n"); 200*f186073cSJoerg Sonnenberger } 201*f186073cSJoerg Sonnenberger } 202*f186073cSJoerg Sonnenberger 203*f186073cSJoerg Sonnenberger int 204*f186073cSJoerg Sonnenberger ieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 205*f186073cSJoerg Sonnenberger { 206*f186073cSJoerg Sonnenberger #define RV(v) ((v) & IEEE80211_RATE_VAL) 207*f186073cSJoerg Sonnenberger int i, j, ignore, error; 208*f186073cSJoerg Sonnenberger int okrate, badrate; 209*f186073cSJoerg Sonnenberger struct ieee80211_rateset *srs, *nrs; 210*f186073cSJoerg Sonnenberger uint8_t r; 211*f186073cSJoerg Sonnenberger 212*f186073cSJoerg Sonnenberger error = 0; 213*f186073cSJoerg Sonnenberger okrate = badrate = 0; 214*f186073cSJoerg Sonnenberger srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 215*f186073cSJoerg Sonnenberger nrs = &ni->ni_rates; 216*f186073cSJoerg Sonnenberger for (i = 0; i < nrs->rs_nrates; ) { 217*f186073cSJoerg Sonnenberger ignore = 0; 218*f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOSORT) { 219*f186073cSJoerg Sonnenberger /* 220*f186073cSJoerg Sonnenberger * Sort rates. 221*f186073cSJoerg Sonnenberger */ 222*f186073cSJoerg Sonnenberger for (j = i + 1; j < nrs->rs_nrates; j++) { 223*f186073cSJoerg Sonnenberger if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 224*f186073cSJoerg Sonnenberger r = nrs->rs_rates[i]; 225*f186073cSJoerg Sonnenberger nrs->rs_rates[i] = nrs->rs_rates[j]; 226*f186073cSJoerg Sonnenberger nrs->rs_rates[j] = r; 227*f186073cSJoerg Sonnenberger } 228*f186073cSJoerg Sonnenberger } 229*f186073cSJoerg Sonnenberger } 230*f186073cSJoerg Sonnenberger r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 231*f186073cSJoerg Sonnenberger badrate = r; 232*f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DOFRATE) { 233*f186073cSJoerg Sonnenberger /* 234*f186073cSJoerg Sonnenberger * Apply fixed rate constraint. Note that we do 235*f186073cSJoerg Sonnenberger * not apply the constraint to basic rates as 236*f186073cSJoerg Sonnenberger * otherwise we may not be able to associate if 237*f186073cSJoerg Sonnenberger * the rate set we submit to the AP is invalid 238*f186073cSJoerg Sonnenberger * (e.g. fix rate at 36Mb/s which is not a basic 239*f186073cSJoerg Sonnenberger * rate for 11a operation). 240*f186073cSJoerg Sonnenberger */ 241*f186073cSJoerg Sonnenberger if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 242*f186073cSJoerg Sonnenberger ic->ic_fixed_rate >= 0 && 243*f186073cSJoerg Sonnenberger r != RV(srs->rs_rates[ic->ic_fixed_rate])) 244*f186073cSJoerg Sonnenberger ignore++; 245*f186073cSJoerg Sonnenberger } 246*f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DONEGO) { 247*f186073cSJoerg Sonnenberger /* 248*f186073cSJoerg Sonnenberger * Check against supported rates. 249*f186073cSJoerg Sonnenberger */ 250*f186073cSJoerg Sonnenberger for (j = 0; j < srs->rs_nrates; j++) { 251*f186073cSJoerg Sonnenberger if (r == RV(srs->rs_rates[j])) { 252*f186073cSJoerg Sonnenberger /* 253*f186073cSJoerg Sonnenberger * Overwrite with the supported rate 254*f186073cSJoerg Sonnenberger * value so any basic rate bit is set. 255*f186073cSJoerg Sonnenberger * This insures that response we send 256*f186073cSJoerg Sonnenberger * to stations have the necessary basic 257*f186073cSJoerg Sonnenberger * rate bit set. 258*f186073cSJoerg Sonnenberger */ 259*f186073cSJoerg Sonnenberger nrs->rs_rates[i] = srs->rs_rates[j]; 260*f186073cSJoerg Sonnenberger break; 261*f186073cSJoerg Sonnenberger } 262*f186073cSJoerg Sonnenberger } 263*f186073cSJoerg Sonnenberger if (j == srs->rs_nrates) { 264*f186073cSJoerg Sonnenberger /* 265*f186073cSJoerg Sonnenberger * A rate in the node's rate set is not 266*f186073cSJoerg Sonnenberger * supported. If this is a basic rate and we 267*f186073cSJoerg Sonnenberger * are operating as an AP then this is an error. 268*f186073cSJoerg Sonnenberger * Otherwise we just discard/ignore the rate. 269*f186073cSJoerg Sonnenberger * Note that this is important for 11b stations 270*f186073cSJoerg Sonnenberger * when they want to associate with an 11g AP. 271*f186073cSJoerg Sonnenberger */ 272*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP && 273*f186073cSJoerg Sonnenberger (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 274*f186073cSJoerg Sonnenberger error++; 275*f186073cSJoerg Sonnenberger ignore++; 276*f186073cSJoerg Sonnenberger } 277*f186073cSJoerg Sonnenberger } 278*f186073cSJoerg Sonnenberger if (flags & IEEE80211_F_DODEL) { 279*f186073cSJoerg Sonnenberger /* 280*f186073cSJoerg Sonnenberger * Delete unacceptable rates. 281*f186073cSJoerg Sonnenberger */ 282*f186073cSJoerg Sonnenberger if (ignore) { 283*f186073cSJoerg Sonnenberger nrs->rs_nrates--; 284*f186073cSJoerg Sonnenberger for (j = i; j < nrs->rs_nrates; j++) 285*f186073cSJoerg Sonnenberger nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 286*f186073cSJoerg Sonnenberger nrs->rs_rates[j] = 0; 287*f186073cSJoerg Sonnenberger continue; 288*f186073cSJoerg Sonnenberger } 289*f186073cSJoerg Sonnenberger } 290*f186073cSJoerg Sonnenberger if (!ignore) 291*f186073cSJoerg Sonnenberger okrate = nrs->rs_rates[i]; 292*f186073cSJoerg Sonnenberger i++; 293*f186073cSJoerg Sonnenberger } 294*f186073cSJoerg Sonnenberger if (okrate == 0 || error != 0) 295*f186073cSJoerg Sonnenberger return badrate | IEEE80211_RATE_BASIC; 296*f186073cSJoerg Sonnenberger else 297*f186073cSJoerg Sonnenberger return RV(okrate); 298*f186073cSJoerg Sonnenberger #undef RV 299*f186073cSJoerg Sonnenberger } 300*f186073cSJoerg Sonnenberger 301*f186073cSJoerg Sonnenberger static int 302*f186073cSJoerg Sonnenberger ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) 303*f186073cSJoerg Sonnenberger { 304*f186073cSJoerg Sonnenberger struct ifnet *ifp = &ic->ic_if; 305*f186073cSJoerg Sonnenberger struct ieee80211_node *ni; 306*f186073cSJoerg Sonnenberger enum ieee80211_state ostate; 307*f186073cSJoerg Sonnenberger struct lwkt_tokref ilock; 308*f186073cSJoerg Sonnenberger 309*f186073cSJoerg Sonnenberger ostate = ic->ic_state; 310*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 311*f186073cSJoerg Sonnenberger ieee80211_state_name[ostate], ieee80211_state_name[nstate])); 312*f186073cSJoerg Sonnenberger ic->ic_state = nstate; /* state transition */ 313*f186073cSJoerg Sonnenberger ni = ic->ic_bss; /* NB: no reference held */ 314*f186073cSJoerg Sonnenberger switch (nstate) { 315*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 316*f186073cSJoerg Sonnenberger switch (ostate) { 317*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 318*f186073cSJoerg Sonnenberger break; 319*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 320*f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 321*f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 322*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 323*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DISASSOC, 324*f186073cSJoerg Sonnenberger IEEE80211_REASON_ASSOC_LEAVE); 325*f186073cSJoerg Sonnenberger break; 326*f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 327*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 328*f186073cSJoerg Sonnenberger TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 329*f186073cSJoerg Sonnenberger if (ni->ni_associd == 0) 330*f186073cSJoerg Sonnenberger continue; 331*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 332*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DISASSOC, 333*f186073cSJoerg Sonnenberger IEEE80211_REASON_ASSOC_LEAVE); 334*f186073cSJoerg Sonnenberger } 335*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 336*f186073cSJoerg Sonnenberger break; 337*f186073cSJoerg Sonnenberger default: 338*f186073cSJoerg Sonnenberger break; 339*f186073cSJoerg Sonnenberger } 340*f186073cSJoerg Sonnenberger /* FALLTHRU */ 341*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 342*f186073cSJoerg Sonnenberger switch (ic->ic_opmode) { 343*f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 344*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 345*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 346*f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_LEAVE); 347*f186073cSJoerg Sonnenberger break; 348*f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 349*f186073cSJoerg Sonnenberger lwkt_gettoken(&ilock, &ic->ic_nodetoken); 350*f186073cSJoerg Sonnenberger TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 351*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 352*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_DEAUTH, 353*f186073cSJoerg Sonnenberger IEEE80211_REASON_AUTH_LEAVE); 354*f186073cSJoerg Sonnenberger } 355*f186073cSJoerg Sonnenberger lwkt_reltoken(&ilock); 356*f186073cSJoerg Sonnenberger break; 357*f186073cSJoerg Sonnenberger default: 358*f186073cSJoerg Sonnenberger break; 359*f186073cSJoerg Sonnenberger } 360*f186073cSJoerg Sonnenberger /* FALLTHRU */ 361*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 362*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 363*f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 364*f186073cSJoerg Sonnenberger IF_DRAIN(&ic->ic_mgtq); 365*f186073cSJoerg Sonnenberger if (ic->ic_wep_ctx != NULL) { 366*f186073cSJoerg Sonnenberger free(ic->ic_wep_ctx, M_DEVBUF); 367*f186073cSJoerg Sonnenberger ic->ic_wep_ctx = NULL; 368*f186073cSJoerg Sonnenberger } 369*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(ic); 370*f186073cSJoerg Sonnenberger break; 371*f186073cSJoerg Sonnenberger } 372*f186073cSJoerg Sonnenberger break; 373*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 374*f186073cSJoerg Sonnenberger ic->ic_flags &= ~IEEE80211_F_SIBSS; 375*f186073cSJoerg Sonnenberger /* initialize bss for probe request */ 376*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 377*f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 378*f186073cSJoerg Sonnenberger ni->ni_rates = ic->ic_sup_rates[ 379*f186073cSJoerg Sonnenberger ieee80211_chan2mode(ic, ni->ni_chan)]; 380*f186073cSJoerg Sonnenberger ni->ni_associd = 0; 381*f186073cSJoerg Sonnenberger ni->ni_rstamp = 0; 382*f186073cSJoerg Sonnenberger switch (ostate) { 383*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 384*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_HOSTAP && 385*f186073cSJoerg Sonnenberger ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 386*f186073cSJoerg Sonnenberger /* 387*f186073cSJoerg Sonnenberger * AP operation and we already have a channel; 388*f186073cSJoerg Sonnenberger * bypass the scan and startup immediately. 389*f186073cSJoerg Sonnenberger */ 390*f186073cSJoerg Sonnenberger ieee80211_create_ibss(ic, ic->ic_des_chan); 391*f186073cSJoerg Sonnenberger } else { 392*f186073cSJoerg Sonnenberger ieee80211_begin_scan(ifp); 393*f186073cSJoerg Sonnenberger } 394*f186073cSJoerg Sonnenberger break; 395*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 396*f186073cSJoerg Sonnenberger /* scan next */ 397*f186073cSJoerg Sonnenberger if (ic->ic_flags & IEEE80211_F_ASCAN) { 398*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 399*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 400*f186073cSJoerg Sonnenberger } 401*f186073cSJoerg Sonnenberger break; 402*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 403*f186073cSJoerg Sonnenberger /* beacon miss */ 404*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) { 405*f186073cSJoerg Sonnenberger /* XXX bssid clobbered above */ 406*f186073cSJoerg Sonnenberger if_printf(ifp, "no recent beacons from %6D;" 407*f186073cSJoerg Sonnenberger " rescanning\n", 408*f186073cSJoerg Sonnenberger ic->ic_bss->ni_bssid, ":"); 409*f186073cSJoerg Sonnenberger } 410*f186073cSJoerg Sonnenberger ieee80211_free_allnodes(ic); 411*f186073cSJoerg Sonnenberger /* FALLTHRU */ 412*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 413*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 414*f186073cSJoerg Sonnenberger /* timeout restart scan */ 415*f186073cSJoerg Sonnenberger ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 416*f186073cSJoerg Sonnenberger if (ni != NULL) { 417*f186073cSJoerg Sonnenberger ni->ni_fails++; 418*f186073cSJoerg Sonnenberger ieee80211_unref_node(&ni); 419*f186073cSJoerg Sonnenberger } 420*f186073cSJoerg Sonnenberger ieee80211_begin_scan(ifp); 421*f186073cSJoerg Sonnenberger break; 422*f186073cSJoerg Sonnenberger } 423*f186073cSJoerg Sonnenberger break; 424*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 425*f186073cSJoerg Sonnenberger switch (ostate) { 426*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 427*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("%s: invalid transition\n", 428*f186073cSJoerg Sonnenberger __func__)); 429*f186073cSJoerg Sonnenberger break; 430*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 431*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 432*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 433*f186073cSJoerg Sonnenberger break; 434*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 435*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 436*f186073cSJoerg Sonnenberger switch (mgt) { 437*f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 438*f186073cSJoerg Sonnenberger /* ??? */ 439*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 440*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 441*f186073cSJoerg Sonnenberger break; 442*f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 443*f186073cSJoerg Sonnenberger /* ignore and retry scan on timeout */ 444*f186073cSJoerg Sonnenberger break; 445*f186073cSJoerg Sonnenberger } 446*f186073cSJoerg Sonnenberger break; 447*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 448*f186073cSJoerg Sonnenberger switch (mgt) { 449*f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 450*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 451*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 2); 452*f186073cSJoerg Sonnenberger ic->ic_state = ostate; /* stay RUN */ 453*f186073cSJoerg Sonnenberger break; 454*f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 455*f186073cSJoerg Sonnenberger /* try to reauth */ 456*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 457*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_AUTH, 1); 458*f186073cSJoerg Sonnenberger break; 459*f186073cSJoerg Sonnenberger } 460*f186073cSJoerg Sonnenberger break; 461*f186073cSJoerg Sonnenberger } 462*f186073cSJoerg Sonnenberger break; 463*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 464*f186073cSJoerg Sonnenberger switch (ostate) { 465*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 466*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: 467*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: 468*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("%s: invalid transition\n", 469*f186073cSJoerg Sonnenberger __func__)); 470*f186073cSJoerg Sonnenberger break; 471*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 472*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 473*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 474*f186073cSJoerg Sonnenberger break; 475*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 476*f186073cSJoerg Sonnenberger IEEE80211_SEND_MGMT(ic, ni, 477*f186073cSJoerg Sonnenberger IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 478*f186073cSJoerg Sonnenberger break; 479*f186073cSJoerg Sonnenberger } 480*f186073cSJoerg Sonnenberger break; 481*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 482*f186073cSJoerg Sonnenberger switch (ostate) { 483*f186073cSJoerg Sonnenberger case IEEE80211_S_INIT: 484*f186073cSJoerg Sonnenberger case IEEE80211_S_AUTH: 485*f186073cSJoerg Sonnenberger case IEEE80211_S_RUN: 486*f186073cSJoerg Sonnenberger IEEE80211_DPRINTF(("%s: invalid transition\n", 487*f186073cSJoerg Sonnenberger __func__)); 488*f186073cSJoerg Sonnenberger break; 489*f186073cSJoerg Sonnenberger case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 490*f186073cSJoerg Sonnenberger case IEEE80211_S_ASSOC: /* infra mode */ 491*f186073cSJoerg Sonnenberger KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 492*f186073cSJoerg Sonnenberger ("%s: bogus xmit rate %u setup\n", __func__, 493*f186073cSJoerg Sonnenberger ni->ni_txrate)); 494*f186073cSJoerg Sonnenberger if (ifp->if_flags & IFF_DEBUG) { 495*f186073cSJoerg Sonnenberger if_printf(ifp, " "); 496*f186073cSJoerg Sonnenberger if (ic->ic_opmode == IEEE80211_M_STA) 497*f186073cSJoerg Sonnenberger printf("associated "); 498*f186073cSJoerg Sonnenberger else 499*f186073cSJoerg Sonnenberger printf("synchronized "); 500*f186073cSJoerg Sonnenberger printf("with %6D ssid ", ni->ni_bssid, ":"); 501*f186073cSJoerg Sonnenberger ieee80211_print_essid(ic->ic_bss->ni_essid, 502*f186073cSJoerg Sonnenberger ni->ni_esslen); 503*f186073cSJoerg Sonnenberger printf(" channel %d start %uMb\n", 504*f186073cSJoerg Sonnenberger ieee80211_chan2ieee(ic, ni->ni_chan), 505*f186073cSJoerg Sonnenberger IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 506*f186073cSJoerg Sonnenberger } 507*f186073cSJoerg Sonnenberger ic->ic_mgt_timer = 0; 508*f186073cSJoerg Sonnenberger (*ifp->if_start)(ifp); 509*f186073cSJoerg Sonnenberger break; 510*f186073cSJoerg Sonnenberger } 511*f186073cSJoerg Sonnenberger break; 512*f186073cSJoerg Sonnenberger } 513*f186073cSJoerg Sonnenberger return 0; 514*f186073cSJoerg Sonnenberger } 515