ieee80211_proto.c revision 127648
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3116742Ssam * Copyright (c) 2002, 2003 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. 14116904Ssam * 3. The name of the author may not be used to endorse or promote products 15116904Ssam * derived from this software without specific prior written permission. 16116742Ssam * 17116742Ssam * Alternatively, this software may be distributed under the terms of the 18116742Ssam * GNU General Public License ("GPL") version 2 as published by the Free 19116742Ssam * Software Foundation. 20116742Ssam * 21116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31116742Ssam */ 32116742Ssam 33116742Ssam#include <sys/cdefs.h> 34116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_proto.c 127648 2004-03-30 22:57:57Z sam $"); 35116742Ssam 36116742Ssam/* 37116742Ssam * IEEE 802.11 protocol support. 38116742Ssam */ 39116742Ssam 40116742Ssam#include "opt_inet.h" 41116742Ssam 42116742Ssam#include <sys/param.h> 43116742Ssam#include <sys/systm.h> 44116742Ssam#include <sys/mbuf.h> 45116742Ssam#include <sys/malloc.h> 46116742Ssam#include <sys/kernel.h> 47116742Ssam#include <sys/socket.h> 48116742Ssam#include <sys/sockio.h> 49116742Ssam#include <sys/endian.h> 50116742Ssam#include <sys/errno.h> 51116742Ssam#include <sys/bus.h> 52116742Ssam#include <sys/proc.h> 53116742Ssam#include <sys/sysctl.h> 54116742Ssam 55116742Ssam#include <machine/atomic.h> 56116742Ssam 57116742Ssam#include <net/if.h> 58116742Ssam#include <net/if_dl.h> 59116742Ssam#include <net/if_media.h> 60116742Ssam#include <net/if_arp.h> 61116742Ssam#include <net/ethernet.h> 62116742Ssam#include <net/if_llc.h> 63116742Ssam 64116742Ssam#include <net80211/ieee80211_var.h> 65116742Ssam 66116742Ssam#include <net/bpf.h> 67116742Ssam 68116742Ssam#ifdef INET 69116742Ssam#include <netinet/in.h> 70116742Ssam#include <netinet/if_ether.h> 71116742Ssam#endif 72116742Ssam 73116742Ssam#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 74116742Ssam 75116742Ssamconst char *ieee80211_mgt_subtype_name[] = { 76116742Ssam "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 77116742Ssam "probe_req", "probe_resp", "reserved#6", "reserved#7", 78116742Ssam "beacon", "atim", "disassoc", "auth", 79116742Ssam "deauth", "reserved#13", "reserved#14", "reserved#15" 80116742Ssam}; 81117811Ssamconst char *ieee80211_state_name[IEEE80211_S_MAX] = { 82117811Ssam "INIT", /* IEEE80211_S_INIT */ 83117811Ssam "SCAN", /* IEEE80211_S_SCAN */ 84117811Ssam "AUTH", /* IEEE80211_S_AUTH */ 85117811Ssam "ASSOC", /* IEEE80211_S_ASSOC */ 86117811Ssam "RUN" /* IEEE80211_S_RUN */ 87117811Ssam}; 88116742Ssam 89117811Ssamstatic int ieee80211_newstate(struct ieee80211com *, enum ieee80211_state, int); 90117811Ssam 91116742Ssamvoid 92116742Ssamieee80211_proto_attach(struct ifnet *ifp) 93116742Ssam{ 94116742Ssam struct ieee80211com *ic = (void *)ifp; 95116742Ssam 96116742Ssam ifp->if_hdrlen = sizeof(struct ieee80211_frame); 97116742Ssam 98116742Ssam#ifdef notdef 99116742Ssam ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 100116742Ssam#else 101116742Ssam ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 102116742Ssam#endif 103116742Ssam ic->ic_fragthreshold = 2346; /* XXX not used yet */ 104116742Ssam ic->ic_fixed_rate = -1; /* no fixed rate */ 105127648Ssam ic->ic_protmode = IEEE80211_PROT_CTSONLY; 106116742Ssam 107121816Sbrooks mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_xname, "mgmt send q", MTX_DEF); 108116742Ssam 109117811Ssam /* protocol state change handler */ 110117811Ssam ic->ic_newstate = ieee80211_newstate; 111117811Ssam 112116742Ssam /* initialize management frame handlers */ 113116742Ssam ic->ic_recv_mgmt = ieee80211_recv_mgmt; 114116742Ssam ic->ic_send_mgmt = ieee80211_send_mgmt; 115116742Ssam} 116116742Ssam 117116742Ssamvoid 118116742Ssamieee80211_proto_detach(struct ifnet *ifp) 119116742Ssam{ 120116742Ssam struct ieee80211com *ic = (void *)ifp; 121116742Ssam 122116742Ssam IF_DRAIN(&ic->ic_mgtq); 123116742Ssam mtx_destroy(&ic->ic_mgtq.ifq_mtx); 124116742Ssam} 125116742Ssam 126116742Ssamvoid 127116742Ssamieee80211_print_essid(u_int8_t *essid, int len) 128116742Ssam{ 129116742Ssam int i; 130116742Ssam u_int8_t *p; 131116742Ssam 132116742Ssam if (len > IEEE80211_NWID_LEN) 133116742Ssam len = IEEE80211_NWID_LEN; 134116742Ssam /* determine printable or not */ 135116742Ssam for (i = 0, p = essid; i < len; i++, p++) { 136116742Ssam if (*p < ' ' || *p > 0x7e) 137116742Ssam break; 138116742Ssam } 139116742Ssam if (i == len) { 140116742Ssam printf("\""); 141116742Ssam for (i = 0, p = essid; i < len; i++, p++) 142116742Ssam printf("%c", *p); 143116742Ssam printf("\""); 144116742Ssam } else { 145116742Ssam printf("0x"); 146116742Ssam for (i = 0, p = essid; i < len; i++, p++) 147116742Ssam printf("%02x", *p); 148116742Ssam } 149116742Ssam} 150116742Ssam 151116742Ssamvoid 152116742Ssamieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 153116742Ssam{ 154116742Ssam struct ieee80211_frame *wh; 155116742Ssam int i; 156116742Ssam 157116742Ssam wh = (struct ieee80211_frame *)buf; 158116742Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 159116742Ssam case IEEE80211_FC1_DIR_NODS: 160116742Ssam printf("NODS %s", ether_sprintf(wh->i_addr2)); 161116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 162116742Ssam printf("(%s)", ether_sprintf(wh->i_addr3)); 163116742Ssam break; 164116742Ssam case IEEE80211_FC1_DIR_TODS: 165116742Ssam printf("TODS %s", ether_sprintf(wh->i_addr2)); 166116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 167116742Ssam printf("(%s)", ether_sprintf(wh->i_addr1)); 168116742Ssam break; 169116742Ssam case IEEE80211_FC1_DIR_FROMDS: 170116742Ssam printf("FRDS %s", ether_sprintf(wh->i_addr3)); 171116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 172116742Ssam printf("(%s)", ether_sprintf(wh->i_addr2)); 173116742Ssam break; 174116742Ssam case IEEE80211_FC1_DIR_DSTODS: 175116742Ssam printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 176116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 177116742Ssam printf("(%s", ether_sprintf(wh->i_addr2)); 178116742Ssam printf("->%s)", ether_sprintf(wh->i_addr1)); 179116742Ssam break; 180116742Ssam } 181116742Ssam switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 182116742Ssam case IEEE80211_FC0_TYPE_DATA: 183116742Ssam printf(" data"); 184116742Ssam break; 185116742Ssam case IEEE80211_FC0_TYPE_MGT: 186116742Ssam printf(" %s", ieee80211_mgt_subtype_name[ 187116742Ssam (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 188116742Ssam >> IEEE80211_FC0_SUBTYPE_SHIFT]); 189116742Ssam break; 190116742Ssam default: 191116742Ssam printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 192116742Ssam break; 193116742Ssam } 194116742Ssam if (wh->i_fc[1] & IEEE80211_FC1_WEP) 195116742Ssam printf(" WEP"); 196116742Ssam if (rate >= 0) 197116742Ssam printf(" %dM", rate / 2); 198116742Ssam if (rssi >= 0) 199116742Ssam printf(" +%d", rssi); 200116742Ssam printf("\n"); 201116742Ssam if (len > 0) { 202116742Ssam for (i = 0; i < len; i++) { 203116742Ssam if ((i & 1) == 0) 204116742Ssam printf(" "); 205116742Ssam printf("%02x", buf[i]); 206116742Ssam } 207116742Ssam printf("\n"); 208116742Ssam } 209116742Ssam} 210116742Ssam 211116742Ssamint 212116742Ssamieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 213116742Ssam{ 214116742Ssam#define RV(v) ((v) & IEEE80211_RATE_VAL) 215116742Ssam int i, j, ignore, error; 216116742Ssam int okrate, badrate; 217116742Ssam struct ieee80211_rateset *srs, *nrs; 218116742Ssam u_int8_t r; 219116742Ssam 220116742Ssam error = 0; 221116742Ssam okrate = badrate = 0; 222116742Ssam srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 223116742Ssam nrs = &ni->ni_rates; 224120482Ssam for (i = 0; i < nrs->rs_nrates; ) { 225116742Ssam ignore = 0; 226116742Ssam if (flags & IEEE80211_F_DOSORT) { 227116742Ssam /* 228116742Ssam * Sort rates. 229116742Ssam */ 230116742Ssam for (j = i + 1; j < nrs->rs_nrates; j++) { 231116742Ssam if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 232116742Ssam r = nrs->rs_rates[i]; 233116742Ssam nrs->rs_rates[i] = nrs->rs_rates[j]; 234116742Ssam nrs->rs_rates[j] = r; 235116742Ssam } 236116742Ssam } 237116742Ssam } 238116742Ssam r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 239116742Ssam badrate = r; 240116742Ssam if (flags & IEEE80211_F_DOFRATE) { 241116742Ssam /* 242116742Ssam * Apply fixed rate constraint. Note that we do 243116742Ssam * not apply the constraint to basic rates as 244116742Ssam * otherwise we may not be able to associate if 245116742Ssam * the rate set we submit to the AP is invalid 246116742Ssam * (e.g. fix rate at 36Mb/s which is not a basic 247116742Ssam * rate for 11a operation). 248116742Ssam */ 249116742Ssam if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 250116742Ssam ic->ic_fixed_rate >= 0 && 251116742Ssam r != RV(srs->rs_rates[ic->ic_fixed_rate])) 252116742Ssam ignore++; 253116742Ssam } 254116742Ssam if (flags & IEEE80211_F_DONEGO) { 255116742Ssam /* 256116742Ssam * Check against supported rates. 257116742Ssam */ 258116742Ssam for (j = 0; j < srs->rs_nrates; j++) { 259116742Ssam if (r == RV(srs->rs_rates[j])) 260116742Ssam break; 261116742Ssam } 262116742Ssam if (j == srs->rs_nrates) { 263120482Ssam /* 264120482Ssam * A rate in the node's rate set is not 265120482Ssam * supported. If this is a basic rate and we 266120482Ssam * are operating as an AP then this is an error. 267120482Ssam * Otherwise we just discard/ignore the rate. 268120482Ssam * Note that this is important for 11b stations 269120482Ssam * when they want to associate with an 11g AP. 270120482Ssam */ 271120482Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP && 272120482Ssam (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 273116742Ssam error++; 274116742Ssam ignore++; 275116742Ssam } 276116742Ssam } 277116742Ssam if (flags & IEEE80211_F_DODEL) { 278116742Ssam /* 279116742Ssam * Delete unacceptable rates. 280116742Ssam */ 281116742Ssam if (ignore) { 282116742Ssam nrs->rs_nrates--; 283116742Ssam for (j = i; j < nrs->rs_nrates; j++) 284116742Ssam nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 285116742Ssam nrs->rs_rates[j] = 0; 286116742Ssam continue; 287116742Ssam } 288116742Ssam } 289116742Ssam if (!ignore) 290116742Ssam okrate = nrs->rs_rates[i]; 291116742Ssam i++; 292116742Ssam } 293116742Ssam if (okrate == 0 || error != 0) 294116742Ssam return badrate | IEEE80211_RATE_BASIC; 295116742Ssam else 296116742Ssam return RV(okrate); 297116742Ssam#undef RV 298116742Ssam} 299116742Ssam 300117811Ssamstatic int 301117811Ssamieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) 302116742Ssam{ 303117811Ssam struct ifnet *ifp = &ic->ic_if; 304116742Ssam struct ieee80211_node *ni; 305117811Ssam enum ieee80211_state ostate; 306116742Ssam 307116742Ssam ostate = ic->ic_state; 308116742Ssam IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 309117811Ssam ieee80211_state_name[ostate], ieee80211_state_name[nstate])); 310117811Ssam ic->ic_state = nstate; /* state transition */ 311116742Ssam ni = ic->ic_bss; /* NB: no reference held */ 312116742Ssam switch (nstate) { 313116742Ssam case IEEE80211_S_INIT: 314116742Ssam switch (ostate) { 315116742Ssam case IEEE80211_S_INIT: 316116742Ssam break; 317116742Ssam case IEEE80211_S_RUN: 318116742Ssam switch (ic->ic_opmode) { 319116742Ssam case IEEE80211_M_STA: 320116742Ssam IEEE80211_SEND_MGMT(ic, ni, 321116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 322116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 323116742Ssam break; 324116742Ssam case IEEE80211_M_HOSTAP: 325121172Ssam IEEE80211_NODE_LOCK(ic); 326116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 327116742Ssam if (ni->ni_associd == 0) 328116742Ssam continue; 329116742Ssam IEEE80211_SEND_MGMT(ic, ni, 330116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 331116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 332116742Ssam } 333121172Ssam IEEE80211_NODE_UNLOCK(ic); 334116742Ssam break; 335116742Ssam default: 336116742Ssam break; 337116742Ssam } 338116742Ssam /* FALLTHRU */ 339116742Ssam case IEEE80211_S_ASSOC: 340116742Ssam switch (ic->ic_opmode) { 341116742Ssam case IEEE80211_M_STA: 342116742Ssam IEEE80211_SEND_MGMT(ic, ni, 343116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 344116742Ssam IEEE80211_REASON_AUTH_LEAVE); 345116742Ssam break; 346116742Ssam case IEEE80211_M_HOSTAP: 347121172Ssam IEEE80211_NODE_LOCK(ic); 348116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 349116742Ssam IEEE80211_SEND_MGMT(ic, ni, 350116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 351116742Ssam IEEE80211_REASON_AUTH_LEAVE); 352116742Ssam } 353121172Ssam IEEE80211_NODE_UNLOCK(ic); 354116742Ssam break; 355116742Ssam default: 356116742Ssam break; 357116742Ssam } 358116742Ssam /* FALLTHRU */ 359116742Ssam case IEEE80211_S_AUTH: 360116742Ssam case IEEE80211_S_SCAN: 361116742Ssam ic->ic_mgt_timer = 0; 362116742Ssam IF_DRAIN(&ic->ic_mgtq); 363116742Ssam if (ic->ic_wep_ctx != NULL) { 364116742Ssam free(ic->ic_wep_ctx, M_DEVBUF); 365116742Ssam ic->ic_wep_ctx = NULL; 366116742Ssam } 367116742Ssam ieee80211_free_allnodes(ic); 368116742Ssam break; 369116742Ssam } 370116742Ssam break; 371116742Ssam case IEEE80211_S_SCAN: 372116742Ssam ic->ic_flags &= ~IEEE80211_F_SIBSS; 373116742Ssam /* initialize bss for probe request */ 374116742Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 375116742Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 376116742Ssam ni->ni_rates = ic->ic_sup_rates[ 377116742Ssam ieee80211_chan2mode(ic, ni->ni_chan)]; 378116742Ssam ni->ni_associd = 0; 379116742Ssam ni->ni_rstamp = 0; 380116742Ssam switch (ostate) { 381116742Ssam case IEEE80211_S_INIT: 382116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP && 383116742Ssam ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 384116742Ssam /* 385116742Ssam * AP operation and we already have a channel; 386116742Ssam * bypass the scan and startup immediately. 387116742Ssam */ 388116742Ssam ieee80211_create_ibss(ic, ic->ic_des_chan); 389116742Ssam } else { 390117811Ssam ieee80211_begin_scan(ifp); 391116742Ssam } 392116742Ssam break; 393116742Ssam case IEEE80211_S_SCAN: 394116742Ssam /* scan next */ 395116742Ssam if (ic->ic_flags & IEEE80211_F_ASCAN) { 396116742Ssam IEEE80211_SEND_MGMT(ic, ni, 397116742Ssam IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 398116742Ssam } 399116742Ssam break; 400116742Ssam case IEEE80211_S_RUN: 401116742Ssam /* beacon miss */ 402116742Ssam if (ifp->if_flags & IFF_DEBUG) { 403116742Ssam /* XXX bssid clobbered above */ 404116742Ssam if_printf(ifp, "no recent beacons from %s;" 405116742Ssam " rescanning\n", 406116742Ssam ether_sprintf(ic->ic_bss->ni_bssid)); 407116742Ssam } 408116742Ssam ieee80211_free_allnodes(ic); 409116742Ssam /* FALLTHRU */ 410116742Ssam case IEEE80211_S_AUTH: 411116742Ssam case IEEE80211_S_ASSOC: 412116742Ssam /* timeout restart scan */ 413116742Ssam ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 414116742Ssam if (ni != NULL) { 415116742Ssam ni->ni_fails++; 416116742Ssam ieee80211_unref_node(&ni); 417116742Ssam } 418117811Ssam ieee80211_begin_scan(ifp); 419116742Ssam break; 420116742Ssam } 421116742Ssam break; 422116742Ssam case IEEE80211_S_AUTH: 423116742Ssam switch (ostate) { 424116742Ssam case IEEE80211_S_INIT: 425116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 426116742Ssam __func__)); 427116742Ssam break; 428116742Ssam case IEEE80211_S_SCAN: 429116742Ssam IEEE80211_SEND_MGMT(ic, ni, 430116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 431116742Ssam break; 432116742Ssam case IEEE80211_S_AUTH: 433116742Ssam case IEEE80211_S_ASSOC: 434116742Ssam switch (mgt) { 435116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 436116742Ssam /* ??? */ 437116742Ssam IEEE80211_SEND_MGMT(ic, ni, 438116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 439116742Ssam break; 440116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 441116742Ssam /* ignore and retry scan on timeout */ 442116742Ssam break; 443116742Ssam } 444116742Ssam break; 445116742Ssam case IEEE80211_S_RUN: 446116742Ssam switch (mgt) { 447116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 448116742Ssam IEEE80211_SEND_MGMT(ic, ni, 449116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 450116742Ssam ic->ic_state = ostate; /* stay RUN */ 451116742Ssam break; 452116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 453116742Ssam /* try to reauth */ 454116742Ssam IEEE80211_SEND_MGMT(ic, ni, 455116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 456116742Ssam break; 457116742Ssam } 458116742Ssam break; 459116742Ssam } 460116742Ssam break; 461116742Ssam case IEEE80211_S_ASSOC: 462116742Ssam switch (ostate) { 463116742Ssam case IEEE80211_S_INIT: 464116742Ssam case IEEE80211_S_SCAN: 465116742Ssam case IEEE80211_S_ASSOC: 466116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 467116742Ssam __func__)); 468116742Ssam break; 469116742Ssam case IEEE80211_S_AUTH: 470116742Ssam IEEE80211_SEND_MGMT(ic, ni, 471116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 472116742Ssam break; 473116742Ssam case IEEE80211_S_RUN: 474116742Ssam IEEE80211_SEND_MGMT(ic, ni, 475116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 476116742Ssam break; 477116742Ssam } 478116742Ssam break; 479116742Ssam case IEEE80211_S_RUN: 480116742Ssam switch (ostate) { 481116742Ssam case IEEE80211_S_INIT: 482116742Ssam case IEEE80211_S_AUTH: 483116742Ssam case IEEE80211_S_RUN: 484116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 485116742Ssam __func__)); 486116742Ssam break; 487116742Ssam case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 488116742Ssam case IEEE80211_S_ASSOC: /* infra mode */ 489116742Ssam KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 490116742Ssam ("%s: bogus xmit rate %u setup\n", __func__, 491116742Ssam ni->ni_txrate)); 492116742Ssam if (ifp->if_flags & IFF_DEBUG) { 493116742Ssam if_printf(ifp, " "); 494116742Ssam if (ic->ic_opmode == IEEE80211_M_STA) 495116742Ssam printf("associated "); 496116742Ssam else 497116742Ssam printf("synchronized "); 498116742Ssam printf("with %s ssid ", 499116742Ssam ether_sprintf(ni->ni_bssid)); 500116742Ssam ieee80211_print_essid(ic->ic_bss->ni_essid, 501116742Ssam ni->ni_esslen); 502116742Ssam printf(" channel %d start %uMb\n", 503116742Ssam ieee80211_chan2ieee(ic, ni->ni_chan), 504116742Ssam IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 505116742Ssam } 506116742Ssam ic->ic_mgt_timer = 0; 507116742Ssam (*ifp->if_start)(ifp); 508116742Ssam break; 509116742Ssam } 510116742Ssam break; 511116742Ssam } 512116742Ssam return 0; 513116742Ssam} 514