ieee80211_proto.c revision 120482
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 120482 2003-09-26 16:54:55Z 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 */ 105116742Ssam 106116742Ssam mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF); 107116742Ssam 108117811Ssam /* protocol state change handler */ 109117811Ssam ic->ic_newstate = ieee80211_newstate; 110117811Ssam 111116742Ssam /* initialize management frame handlers */ 112116742Ssam ic->ic_recv_mgmt = ieee80211_recv_mgmt; 113116742Ssam ic->ic_send_mgmt = ieee80211_send_mgmt; 114116742Ssam} 115116742Ssam 116116742Ssamvoid 117116742Ssamieee80211_proto_detach(struct ifnet *ifp) 118116742Ssam{ 119116742Ssam struct ieee80211com *ic = (void *)ifp; 120116742Ssam 121116742Ssam IF_DRAIN(&ic->ic_mgtq); 122116742Ssam mtx_destroy(&ic->ic_mgtq.ifq_mtx); 123116742Ssam} 124116742Ssam 125116742Ssamvoid 126116742Ssamieee80211_print_essid(u_int8_t *essid, int len) 127116742Ssam{ 128116742Ssam int i; 129116742Ssam u_int8_t *p; 130116742Ssam 131116742Ssam if (len > IEEE80211_NWID_LEN) 132116742Ssam len = IEEE80211_NWID_LEN; 133116742Ssam /* determine printable or not */ 134116742Ssam for (i = 0, p = essid; i < len; i++, p++) { 135116742Ssam if (*p < ' ' || *p > 0x7e) 136116742Ssam break; 137116742Ssam } 138116742Ssam if (i == len) { 139116742Ssam printf("\""); 140116742Ssam for (i = 0, p = essid; i < len; i++, p++) 141116742Ssam printf("%c", *p); 142116742Ssam printf("\""); 143116742Ssam } else { 144116742Ssam printf("0x"); 145116742Ssam for (i = 0, p = essid; i < len; i++, p++) 146116742Ssam printf("%02x", *p); 147116742Ssam } 148116742Ssam} 149116742Ssam 150116742Ssamvoid 151116742Ssamieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 152116742Ssam{ 153116742Ssam struct ieee80211_frame *wh; 154116742Ssam int i; 155116742Ssam 156116742Ssam wh = (struct ieee80211_frame *)buf; 157116742Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 158116742Ssam case IEEE80211_FC1_DIR_NODS: 159116742Ssam printf("NODS %s", ether_sprintf(wh->i_addr2)); 160116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 161116742Ssam printf("(%s)", ether_sprintf(wh->i_addr3)); 162116742Ssam break; 163116742Ssam case IEEE80211_FC1_DIR_TODS: 164116742Ssam printf("TODS %s", ether_sprintf(wh->i_addr2)); 165116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 166116742Ssam printf("(%s)", ether_sprintf(wh->i_addr1)); 167116742Ssam break; 168116742Ssam case IEEE80211_FC1_DIR_FROMDS: 169116742Ssam printf("FRDS %s", ether_sprintf(wh->i_addr3)); 170116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 171116742Ssam printf("(%s)", ether_sprintf(wh->i_addr2)); 172116742Ssam break; 173116742Ssam case IEEE80211_FC1_DIR_DSTODS: 174116742Ssam printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 175116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 176116742Ssam printf("(%s", ether_sprintf(wh->i_addr2)); 177116742Ssam printf("->%s)", ether_sprintf(wh->i_addr1)); 178116742Ssam break; 179116742Ssam } 180116742Ssam switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 181116742Ssam case IEEE80211_FC0_TYPE_DATA: 182116742Ssam printf(" data"); 183116742Ssam break; 184116742Ssam case IEEE80211_FC0_TYPE_MGT: 185116742Ssam printf(" %s", ieee80211_mgt_subtype_name[ 186116742Ssam (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 187116742Ssam >> IEEE80211_FC0_SUBTYPE_SHIFT]); 188116742Ssam break; 189116742Ssam default: 190116742Ssam printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 191116742Ssam break; 192116742Ssam } 193116742Ssam if (wh->i_fc[1] & IEEE80211_FC1_WEP) 194116742Ssam printf(" WEP"); 195116742Ssam if (rate >= 0) 196116742Ssam printf(" %dM", rate / 2); 197116742Ssam if (rssi >= 0) 198116742Ssam printf(" +%d", rssi); 199116742Ssam printf("\n"); 200116742Ssam if (len > 0) { 201116742Ssam for (i = 0; i < len; i++) { 202116742Ssam if ((i & 1) == 0) 203116742Ssam printf(" "); 204116742Ssam printf("%02x", buf[i]); 205116742Ssam } 206116742Ssam printf("\n"); 207116742Ssam } 208116742Ssam} 209116742Ssam 210116742Ssamint 211116742Ssamieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 212116742Ssam{ 213116742Ssam#define RV(v) ((v) & IEEE80211_RATE_VAL) 214116742Ssam int i, j, ignore, error; 215116742Ssam int okrate, badrate; 216116742Ssam struct ieee80211_rateset *srs, *nrs; 217116742Ssam u_int8_t r; 218116742Ssam 219116742Ssam error = 0; 220116742Ssam okrate = badrate = 0; 221116742Ssam srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 222116742Ssam nrs = &ni->ni_rates; 223120482Ssam for (i = 0; i < nrs->rs_nrates; ) { 224116742Ssam ignore = 0; 225116742Ssam if (flags & IEEE80211_F_DOSORT) { 226116742Ssam /* 227116742Ssam * Sort rates. 228116742Ssam */ 229116742Ssam for (j = i + 1; j < nrs->rs_nrates; j++) { 230116742Ssam if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 231116742Ssam r = nrs->rs_rates[i]; 232116742Ssam nrs->rs_rates[i] = nrs->rs_rates[j]; 233116742Ssam nrs->rs_rates[j] = r; 234116742Ssam } 235116742Ssam } 236116742Ssam } 237116742Ssam r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 238116742Ssam badrate = r; 239116742Ssam if (flags & IEEE80211_F_DOFRATE) { 240116742Ssam /* 241116742Ssam * Apply fixed rate constraint. Note that we do 242116742Ssam * not apply the constraint to basic rates as 243116742Ssam * otherwise we may not be able to associate if 244116742Ssam * the rate set we submit to the AP is invalid 245116742Ssam * (e.g. fix rate at 36Mb/s which is not a basic 246116742Ssam * rate for 11a operation). 247116742Ssam */ 248116742Ssam if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 249116742Ssam ic->ic_fixed_rate >= 0 && 250116742Ssam r != RV(srs->rs_rates[ic->ic_fixed_rate])) 251116742Ssam ignore++; 252116742Ssam } 253116742Ssam if (flags & IEEE80211_F_DONEGO) { 254116742Ssam /* 255116742Ssam * Check against supported rates. 256116742Ssam */ 257116742Ssam for (j = 0; j < srs->rs_nrates; j++) { 258116742Ssam if (r == RV(srs->rs_rates[j])) 259116742Ssam break; 260116742Ssam } 261116742Ssam if (j == srs->rs_nrates) { 262120482Ssam /* 263120482Ssam * A rate in the node's rate set is not 264120482Ssam * supported. If this is a basic rate and we 265120482Ssam * are operating as an AP then this is an error. 266120482Ssam * Otherwise we just discard/ignore the rate. 267120482Ssam * Note that this is important for 11b stations 268120482Ssam * when they want to associate with an 11g AP. 269120482Ssam */ 270120482Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP && 271120482Ssam (nrs->rs_rates[i] & IEEE80211_RATE_BASIC)) 272116742Ssam error++; 273116742Ssam ignore++; 274116742Ssam } 275116742Ssam } 276116742Ssam if (flags & IEEE80211_F_DODEL) { 277116742Ssam /* 278116742Ssam * Delete unacceptable rates. 279116742Ssam */ 280116742Ssam if (ignore) { 281116742Ssam nrs->rs_nrates--; 282116742Ssam for (j = i; j < nrs->rs_nrates; j++) 283116742Ssam nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 284116742Ssam nrs->rs_rates[j] = 0; 285116742Ssam continue; 286116742Ssam } 287116742Ssam } 288116742Ssam if (!ignore) 289116742Ssam okrate = nrs->rs_rates[i]; 290116742Ssam i++; 291116742Ssam } 292116742Ssam if (okrate == 0 || error != 0) 293116742Ssam return badrate | IEEE80211_RATE_BASIC; 294116742Ssam else 295116742Ssam return RV(okrate); 296116742Ssam#undef RV 297116742Ssam} 298116742Ssam 299117811Ssamstatic int 300117811Ssamieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int mgt) 301116742Ssam{ 302117811Ssam struct ifnet *ifp = &ic->ic_if; 303116742Ssam struct ieee80211_node *ni; 304117811Ssam enum ieee80211_state ostate; 305116742Ssam 306116742Ssam ostate = ic->ic_state; 307116742Ssam IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 308117811Ssam ieee80211_state_name[ostate], ieee80211_state_name[nstate])); 309117811Ssam ic->ic_state = nstate; /* state transition */ 310116742Ssam ni = ic->ic_bss; /* NB: no reference held */ 311116742Ssam switch (nstate) { 312116742Ssam case IEEE80211_S_INIT: 313116742Ssam switch (ostate) { 314116742Ssam case IEEE80211_S_INIT: 315116742Ssam break; 316116742Ssam case IEEE80211_S_RUN: 317116742Ssam switch (ic->ic_opmode) { 318116742Ssam case IEEE80211_M_STA: 319116742Ssam IEEE80211_SEND_MGMT(ic, ni, 320116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 321116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 322116742Ssam break; 323116742Ssam case IEEE80211_M_HOSTAP: 324116742Ssam mtx_lock(&ic->ic_nodelock); 325116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 326116742Ssam if (ni->ni_associd == 0) 327116742Ssam continue; 328116742Ssam IEEE80211_SEND_MGMT(ic, ni, 329116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 330116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 331116742Ssam } 332116742Ssam mtx_unlock(&ic->ic_nodelock); 333116742Ssam break; 334116742Ssam default: 335116742Ssam break; 336116742Ssam } 337116742Ssam /* FALLTHRU */ 338116742Ssam case IEEE80211_S_ASSOC: 339116742Ssam switch (ic->ic_opmode) { 340116742Ssam case IEEE80211_M_STA: 341116742Ssam IEEE80211_SEND_MGMT(ic, ni, 342116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 343116742Ssam IEEE80211_REASON_AUTH_LEAVE); 344116742Ssam break; 345116742Ssam case IEEE80211_M_HOSTAP: 346116742Ssam mtx_lock(&ic->ic_nodelock); 347116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 348116742Ssam IEEE80211_SEND_MGMT(ic, ni, 349116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 350116742Ssam IEEE80211_REASON_AUTH_LEAVE); 351116742Ssam } 352116742Ssam mtx_unlock(&ic->ic_nodelock); 353116742Ssam break; 354116742Ssam default: 355116742Ssam break; 356116742Ssam } 357116742Ssam /* FALLTHRU */ 358116742Ssam case IEEE80211_S_AUTH: 359116742Ssam case IEEE80211_S_SCAN: 360116742Ssam ic->ic_mgt_timer = 0; 361116742Ssam IF_DRAIN(&ic->ic_mgtq); 362116742Ssam if (ic->ic_wep_ctx != NULL) { 363116742Ssam free(ic->ic_wep_ctx, M_DEVBUF); 364116742Ssam ic->ic_wep_ctx = NULL; 365116742Ssam } 366116742Ssam ieee80211_free_allnodes(ic); 367116742Ssam break; 368116742Ssam } 369116742Ssam break; 370116742Ssam case IEEE80211_S_SCAN: 371116742Ssam ic->ic_flags &= ~IEEE80211_F_SIBSS; 372116742Ssam /* initialize bss for probe request */ 373116742Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 374116742Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 375116742Ssam ni->ni_rates = ic->ic_sup_rates[ 376116742Ssam ieee80211_chan2mode(ic, ni->ni_chan)]; 377116742Ssam ni->ni_associd = 0; 378116742Ssam ni->ni_rstamp = 0; 379116742Ssam switch (ostate) { 380116742Ssam case IEEE80211_S_INIT: 381116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP && 382116742Ssam ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 383116742Ssam /* 384116742Ssam * AP operation and we already have a channel; 385116742Ssam * bypass the scan and startup immediately. 386116742Ssam */ 387116742Ssam ieee80211_create_ibss(ic, ic->ic_des_chan); 388116742Ssam } else { 389117811Ssam ieee80211_begin_scan(ifp); 390116742Ssam } 391116742Ssam break; 392116742Ssam case IEEE80211_S_SCAN: 393116742Ssam /* scan next */ 394116742Ssam if (ic->ic_flags & IEEE80211_F_ASCAN) { 395116742Ssam IEEE80211_SEND_MGMT(ic, ni, 396116742Ssam IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 397116742Ssam } 398116742Ssam break; 399116742Ssam case IEEE80211_S_RUN: 400116742Ssam /* beacon miss */ 401116742Ssam if (ifp->if_flags & IFF_DEBUG) { 402116742Ssam /* XXX bssid clobbered above */ 403116742Ssam if_printf(ifp, "no recent beacons from %s;" 404116742Ssam " rescanning\n", 405116742Ssam ether_sprintf(ic->ic_bss->ni_bssid)); 406116742Ssam } 407116742Ssam ieee80211_free_allnodes(ic); 408116742Ssam /* FALLTHRU */ 409116742Ssam case IEEE80211_S_AUTH: 410116742Ssam case IEEE80211_S_ASSOC: 411116742Ssam /* timeout restart scan */ 412116742Ssam ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 413116742Ssam if (ni != NULL) { 414116742Ssam ni->ni_fails++; 415116742Ssam ieee80211_unref_node(&ni); 416116742Ssam } 417117811Ssam ieee80211_begin_scan(ifp); 418116742Ssam break; 419116742Ssam } 420116742Ssam break; 421116742Ssam case IEEE80211_S_AUTH: 422116742Ssam switch (ostate) { 423116742Ssam case IEEE80211_S_INIT: 424116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 425116742Ssam __func__)); 426116742Ssam break; 427116742Ssam case IEEE80211_S_SCAN: 428116742Ssam IEEE80211_SEND_MGMT(ic, ni, 429116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 430116742Ssam break; 431116742Ssam case IEEE80211_S_AUTH: 432116742Ssam case IEEE80211_S_ASSOC: 433116742Ssam switch (mgt) { 434116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 435116742Ssam /* ??? */ 436116742Ssam IEEE80211_SEND_MGMT(ic, ni, 437116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 438116742Ssam break; 439116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 440116742Ssam /* ignore and retry scan on timeout */ 441116742Ssam break; 442116742Ssam } 443116742Ssam break; 444116742Ssam case IEEE80211_S_RUN: 445116742Ssam switch (mgt) { 446116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 447116742Ssam IEEE80211_SEND_MGMT(ic, ni, 448116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 449116742Ssam ic->ic_state = ostate; /* stay RUN */ 450116742Ssam break; 451116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 452116742Ssam /* try to reauth */ 453116742Ssam IEEE80211_SEND_MGMT(ic, ni, 454116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 455116742Ssam break; 456116742Ssam } 457116742Ssam break; 458116742Ssam } 459116742Ssam break; 460116742Ssam case IEEE80211_S_ASSOC: 461116742Ssam switch (ostate) { 462116742Ssam case IEEE80211_S_INIT: 463116742Ssam case IEEE80211_S_SCAN: 464116742Ssam case IEEE80211_S_ASSOC: 465116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 466116742Ssam __func__)); 467116742Ssam break; 468116742Ssam case IEEE80211_S_AUTH: 469116742Ssam IEEE80211_SEND_MGMT(ic, ni, 470116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 471116742Ssam break; 472116742Ssam case IEEE80211_S_RUN: 473116742Ssam IEEE80211_SEND_MGMT(ic, ni, 474116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 475116742Ssam break; 476116742Ssam } 477116742Ssam break; 478116742Ssam case IEEE80211_S_RUN: 479116742Ssam switch (ostate) { 480116742Ssam case IEEE80211_S_INIT: 481116742Ssam case IEEE80211_S_AUTH: 482116742Ssam case IEEE80211_S_RUN: 483116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 484116742Ssam __func__)); 485116742Ssam break; 486116742Ssam case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 487116742Ssam case IEEE80211_S_ASSOC: /* infra mode */ 488116742Ssam KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 489116742Ssam ("%s: bogus xmit rate %u setup\n", __func__, 490116742Ssam ni->ni_txrate)); 491116742Ssam if (ifp->if_flags & IFF_DEBUG) { 492116742Ssam if_printf(ifp, " "); 493116742Ssam if (ic->ic_opmode == IEEE80211_M_STA) 494116742Ssam printf("associated "); 495116742Ssam else 496116742Ssam printf("synchronized "); 497116742Ssam printf("with %s ssid ", 498116742Ssam ether_sprintf(ni->ni_bssid)); 499116742Ssam ieee80211_print_essid(ic->ic_bss->ni_essid, 500116742Ssam ni->ni_esslen); 501116742Ssam printf(" channel %d start %uMb\n", 502116742Ssam ieee80211_chan2ieee(ic, ni->ni_chan), 503116742Ssam IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 504116742Ssam } 505116742Ssam ic->ic_mgt_timer = 0; 506116742Ssam (*ifp->if_start)(ifp); 507116742Ssam break; 508116742Ssam } 509116742Ssam break; 510116742Ssam } 511116742Ssam return 0; 512116742Ssam} 513