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