ieee80211_proto.c revision 116742
1116742Ssam/*- 2116742Ssam * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 3116742Ssam * All rights reserved. 4116742Ssam * 5116742Ssam * Redistribution and use in source and binary forms, with or without 6116742Ssam * modification, are permitted provided that the following conditions 7116742Ssam * are met: 8116742Ssam * 1. Redistributions of source code must retain the above copyright 9116742Ssam * notice, this list of conditions and the following disclaimer, 10116742Ssam * without modification. 11116742Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12116742Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13116742Ssam * redistribution must be conditioned upon including a substantially 14116742Ssam * similar Disclaimer requirement for further binary redistribution. 15116742Ssam * 3. Neither the names of the above-listed copyright holders nor the names 16116742Ssam * of any contributors may be used to endorse or promote products derived 17116742Ssam * from this software without specific prior written permission. 18116742Ssam * 19116742Ssam * Alternatively, this software may be distributed under the terms of the 20116742Ssam * GNU General Public License ("GPL") version 2 as published by the Free 21116742Ssam * Software Foundation. 22116742Ssam * 23116742Ssam * NO WARRANTY 24116742Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25116742Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26116742Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 27116742Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 28116742Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 29116742Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30116742Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31116742Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32116742Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33116742Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34116742Ssam * THE POSSIBILITY OF SUCH DAMAGES. 35116742Ssam */ 36116742Ssam 37116742Ssam#include <sys/cdefs.h> 38116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_proto.c 116742 2003-06-23 16:55:01Z sam $"); 39116742Ssam 40116742Ssam/* 41116742Ssam * IEEE 802.11 protocol support. 42116742Ssam */ 43116742Ssam 44116742Ssam#include "opt_inet.h" 45116742Ssam 46116742Ssam#include <sys/param.h> 47116742Ssam#include <sys/systm.h> 48116742Ssam#include <sys/mbuf.h> 49116742Ssam#include <sys/malloc.h> 50116742Ssam#include <sys/kernel.h> 51116742Ssam#include <sys/socket.h> 52116742Ssam#include <sys/sockio.h> 53116742Ssam#include <sys/endian.h> 54116742Ssam#include <sys/errno.h> 55116742Ssam#include <sys/bus.h> 56116742Ssam#include <sys/proc.h> 57116742Ssam#include <sys/sysctl.h> 58116742Ssam 59116742Ssam#include <machine/atomic.h> 60116742Ssam 61116742Ssam#include <net/if.h> 62116742Ssam#include <net/if_dl.h> 63116742Ssam#include <net/if_media.h> 64116742Ssam#include <net/if_arp.h> 65116742Ssam#include <net/ethernet.h> 66116742Ssam#include <net/if_llc.h> 67116742Ssam 68116742Ssam#include <net80211/ieee80211_var.h> 69116742Ssam 70116742Ssam#include <net/bpf.h> 71116742Ssam 72116742Ssam#ifdef INET 73116742Ssam#include <netinet/in.h> 74116742Ssam#include <netinet/if_ether.h> 75116742Ssam#endif 76116742Ssam 77116742Ssam#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 78116742Ssam 79116742Ssamconst char *ieee80211_mgt_subtype_name[] = { 80116742Ssam "assoc_req", "assoc_resp", "reassoc_req", "reassoc_resp", 81116742Ssam "probe_req", "probe_resp", "reserved#6", "reserved#7", 82116742Ssam "beacon", "atim", "disassoc", "auth", 83116742Ssam "deauth", "reserved#13", "reserved#14", "reserved#15" 84116742Ssam}; 85116742Ssam 86116742Ssamvoid 87116742Ssamieee80211_proto_attach(struct ifnet *ifp) 88116742Ssam{ 89116742Ssam struct ieee80211com *ic = (void *)ifp; 90116742Ssam 91116742Ssam ifp->if_hdrlen = sizeof(struct ieee80211_frame); 92116742Ssam 93116742Ssam#ifdef notdef 94116742Ssam ic->ic_rtsthreshold = IEEE80211_RTS_DEFAULT; 95116742Ssam#else 96116742Ssam ic->ic_rtsthreshold = IEEE80211_RTS_MAX; 97116742Ssam#endif 98116742Ssam ic->ic_fragthreshold = 2346; /* XXX not used yet */ 99116742Ssam ic->ic_fixed_rate = -1; /* no fixed rate */ 100116742Ssam 101116742Ssam mtx_init(&ic->ic_mgtq.ifq_mtx, ifp->if_name, "mgmt send q", MTX_DEF); 102116742Ssam 103116742Ssam /* initialize management frame handlers */ 104116742Ssam ic->ic_recv_mgmt = ieee80211_recv_mgmt; 105116742Ssam ic->ic_send_mgmt = ieee80211_send_mgmt; 106116742Ssam} 107116742Ssam 108116742Ssamvoid 109116742Ssamieee80211_proto_detach(struct ifnet *ifp) 110116742Ssam{ 111116742Ssam struct ieee80211com *ic = (void *)ifp; 112116742Ssam 113116742Ssam IF_DRAIN(&ic->ic_mgtq); 114116742Ssam mtx_destroy(&ic->ic_mgtq.ifq_mtx); 115116742Ssam} 116116742Ssam 117116742Ssamvoid 118116742Ssamieee80211_print_essid(u_int8_t *essid, int len) 119116742Ssam{ 120116742Ssam int i; 121116742Ssam u_int8_t *p; 122116742Ssam 123116742Ssam if (len > IEEE80211_NWID_LEN) 124116742Ssam len = IEEE80211_NWID_LEN; 125116742Ssam /* determine printable or not */ 126116742Ssam for (i = 0, p = essid; i < len; i++, p++) { 127116742Ssam if (*p < ' ' || *p > 0x7e) 128116742Ssam break; 129116742Ssam } 130116742Ssam if (i == len) { 131116742Ssam printf("\""); 132116742Ssam for (i = 0, p = essid; i < len; i++, p++) 133116742Ssam printf("%c", *p); 134116742Ssam printf("\""); 135116742Ssam } else { 136116742Ssam printf("0x"); 137116742Ssam for (i = 0, p = essid; i < len; i++, p++) 138116742Ssam printf("%02x", *p); 139116742Ssam } 140116742Ssam} 141116742Ssam 142116742Ssamvoid 143116742Ssamieee80211_dump_pkt(u_int8_t *buf, int len, int rate, int rssi) 144116742Ssam{ 145116742Ssam struct ieee80211_frame *wh; 146116742Ssam int i; 147116742Ssam 148116742Ssam wh = (struct ieee80211_frame *)buf; 149116742Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 150116742Ssam case IEEE80211_FC1_DIR_NODS: 151116742Ssam printf("NODS %s", ether_sprintf(wh->i_addr2)); 152116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 153116742Ssam printf("(%s)", ether_sprintf(wh->i_addr3)); 154116742Ssam break; 155116742Ssam case IEEE80211_FC1_DIR_TODS: 156116742Ssam printf("TODS %s", ether_sprintf(wh->i_addr2)); 157116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 158116742Ssam printf("(%s)", ether_sprintf(wh->i_addr1)); 159116742Ssam break; 160116742Ssam case IEEE80211_FC1_DIR_FROMDS: 161116742Ssam printf("FRDS %s", ether_sprintf(wh->i_addr3)); 162116742Ssam printf("->%s", ether_sprintf(wh->i_addr1)); 163116742Ssam printf("(%s)", ether_sprintf(wh->i_addr2)); 164116742Ssam break; 165116742Ssam case IEEE80211_FC1_DIR_DSTODS: 166116742Ssam printf("DSDS %s", ether_sprintf((u_int8_t *)&wh[1])); 167116742Ssam printf("->%s", ether_sprintf(wh->i_addr3)); 168116742Ssam printf("(%s", ether_sprintf(wh->i_addr2)); 169116742Ssam printf("->%s)", ether_sprintf(wh->i_addr1)); 170116742Ssam break; 171116742Ssam } 172116742Ssam switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { 173116742Ssam case IEEE80211_FC0_TYPE_DATA: 174116742Ssam printf(" data"); 175116742Ssam break; 176116742Ssam case IEEE80211_FC0_TYPE_MGT: 177116742Ssam printf(" %s", ieee80211_mgt_subtype_name[ 178116742Ssam (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) 179116742Ssam >> IEEE80211_FC0_SUBTYPE_SHIFT]); 180116742Ssam break; 181116742Ssam default: 182116742Ssam printf(" type#%d", wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); 183116742Ssam break; 184116742Ssam } 185116742Ssam if (wh->i_fc[1] & IEEE80211_FC1_WEP) 186116742Ssam printf(" WEP"); 187116742Ssam if (rate >= 0) 188116742Ssam printf(" %dM", rate / 2); 189116742Ssam if (rssi >= 0) 190116742Ssam printf(" +%d", rssi); 191116742Ssam printf("\n"); 192116742Ssam if (len > 0) { 193116742Ssam for (i = 0; i < len; i++) { 194116742Ssam if ((i & 1) == 0) 195116742Ssam printf(" "); 196116742Ssam printf("%02x", buf[i]); 197116742Ssam } 198116742Ssam printf("\n"); 199116742Ssam } 200116742Ssam} 201116742Ssam 202116742Ssamint 203116742Ssamieee80211_fix_rate(struct ieee80211com *ic, struct ieee80211_node *ni, int flags) 204116742Ssam{ 205116742Ssam#define RV(v) ((v) & IEEE80211_RATE_VAL) 206116742Ssam int i, j, ignore, error; 207116742Ssam int okrate, badrate; 208116742Ssam struct ieee80211_rateset *srs, *nrs; 209116742Ssam u_int8_t r; 210116742Ssam 211116742Ssam error = 0; 212116742Ssam okrate = badrate = 0; 213116742Ssam srs = &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; 214116742Ssam nrs = &ni->ni_rates; 215116742Ssam for (i = 0; i < ni->ni_rates.rs_nrates; ) { 216116742Ssam ignore = 0; 217116742Ssam if (flags & IEEE80211_F_DOSORT) { 218116742Ssam /* 219116742Ssam * Sort rates. 220116742Ssam */ 221116742Ssam for (j = i + 1; j < nrs->rs_nrates; j++) { 222116742Ssam if (RV(nrs->rs_rates[i]) > RV(nrs->rs_rates[j])) { 223116742Ssam r = nrs->rs_rates[i]; 224116742Ssam nrs->rs_rates[i] = nrs->rs_rates[j]; 225116742Ssam nrs->rs_rates[j] = r; 226116742Ssam } 227116742Ssam } 228116742Ssam } 229116742Ssam r = nrs->rs_rates[i] & IEEE80211_RATE_VAL; 230116742Ssam badrate = r; 231116742Ssam if (flags & IEEE80211_F_DOFRATE) { 232116742Ssam /* 233116742Ssam * Apply fixed rate constraint. Note that we do 234116742Ssam * not apply the constraint to basic rates as 235116742Ssam * otherwise we may not be able to associate if 236116742Ssam * the rate set we submit to the AP is invalid 237116742Ssam * (e.g. fix rate at 36Mb/s which is not a basic 238116742Ssam * rate for 11a operation). 239116742Ssam */ 240116742Ssam if ((nrs->rs_rates[i] & IEEE80211_RATE_BASIC) == 0 && 241116742Ssam ic->ic_fixed_rate >= 0 && 242116742Ssam r != RV(srs->rs_rates[ic->ic_fixed_rate])) 243116742Ssam ignore++; 244116742Ssam } 245116742Ssam if (flags & IEEE80211_F_DONEGO) { 246116742Ssam /* 247116742Ssam * Check against supported rates. 248116742Ssam */ 249116742Ssam for (j = 0; j < srs->rs_nrates; j++) { 250116742Ssam if (r == RV(srs->rs_rates[j])) 251116742Ssam break; 252116742Ssam } 253116742Ssam if (j == srs->rs_nrates) { 254116742Ssam if (nrs->rs_rates[i] & IEEE80211_RATE_BASIC) 255116742Ssam error++; 256116742Ssam ignore++; 257116742Ssam } 258116742Ssam } 259116742Ssam if (flags & IEEE80211_F_DODEL) { 260116742Ssam /* 261116742Ssam * Delete unacceptable rates. 262116742Ssam */ 263116742Ssam if (ignore) { 264116742Ssam nrs->rs_nrates--; 265116742Ssam for (j = i; j < nrs->rs_nrates; j++) 266116742Ssam nrs->rs_rates[j] = nrs->rs_rates[j + 1]; 267116742Ssam nrs->rs_rates[j] = 0; 268116742Ssam continue; 269116742Ssam } 270116742Ssam } 271116742Ssam if (!ignore) 272116742Ssam okrate = nrs->rs_rates[i]; 273116742Ssam i++; 274116742Ssam } 275116742Ssam if (okrate == 0 || error != 0) 276116742Ssam return badrate | IEEE80211_RATE_BASIC; 277116742Ssam else 278116742Ssam return RV(okrate); 279116742Ssam#undef RV 280116742Ssam} 281116742Ssam 282116742Ssamint 283116742Ssamieee80211_new_state(struct ifnet *ifp, enum ieee80211_state nstate, int mgt) 284116742Ssam{ 285116742Ssam struct ieee80211com *ic = (void *)ifp; 286116742Ssam struct ieee80211_node *ni; 287116742Ssam int error, ostate; 288116742Ssam#ifdef IEEE80211_DEBUG 289116742Ssam static const char *stname[] = 290116742Ssam { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; 291116742Ssam#endif 292116742Ssam 293116742Ssam ostate = ic->ic_state; 294116742Ssam IEEE80211_DPRINTF(("%s: %s -> %s\n", __func__, 295116742Ssam stname[ostate], stname[nstate])); 296116742Ssam if (ic->ic_newstate) { 297116742Ssam error = (*ic->ic_newstate)(ic->ic_softc, nstate); 298116742Ssam if (error == EINPROGRESS) 299116742Ssam return 0; 300116742Ssam if (error != 0) 301116742Ssam return error; 302116742Ssam } 303116742Ssam 304116742Ssam /* state transition */ 305116742Ssam ic->ic_state = nstate; 306116742Ssam ni = ic->ic_bss; /* NB: no reference held */ 307116742Ssam switch (nstate) { 308116742Ssam case IEEE80211_S_INIT: 309116742Ssam switch (ostate) { 310116742Ssam case IEEE80211_S_INIT: 311116742Ssam break; 312116742Ssam case IEEE80211_S_RUN: 313116742Ssam switch (ic->ic_opmode) { 314116742Ssam case IEEE80211_M_STA: 315116742Ssam IEEE80211_SEND_MGMT(ic, ni, 316116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 317116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 318116742Ssam break; 319116742Ssam case IEEE80211_M_HOSTAP: 320116742Ssam mtx_lock(&ic->ic_nodelock); 321116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 322116742Ssam if (ni->ni_associd == 0) 323116742Ssam continue; 324116742Ssam IEEE80211_SEND_MGMT(ic, ni, 325116742Ssam IEEE80211_FC0_SUBTYPE_DISASSOC, 326116742Ssam IEEE80211_REASON_ASSOC_LEAVE); 327116742Ssam } 328116742Ssam mtx_unlock(&ic->ic_nodelock); 329116742Ssam break; 330116742Ssam default: 331116742Ssam break; 332116742Ssam } 333116742Ssam /* FALLTHRU */ 334116742Ssam case IEEE80211_S_ASSOC: 335116742Ssam switch (ic->ic_opmode) { 336116742Ssam case IEEE80211_M_STA: 337116742Ssam IEEE80211_SEND_MGMT(ic, ni, 338116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 339116742Ssam IEEE80211_REASON_AUTH_LEAVE); 340116742Ssam break; 341116742Ssam case IEEE80211_M_HOSTAP: 342116742Ssam mtx_lock(&ic->ic_nodelock); 343116742Ssam TAILQ_FOREACH(ni, &ic->ic_node, ni_list) { 344116742Ssam IEEE80211_SEND_MGMT(ic, ni, 345116742Ssam IEEE80211_FC0_SUBTYPE_DEAUTH, 346116742Ssam IEEE80211_REASON_AUTH_LEAVE); 347116742Ssam } 348116742Ssam mtx_unlock(&ic->ic_nodelock); 349116742Ssam break; 350116742Ssam default: 351116742Ssam break; 352116742Ssam } 353116742Ssam /* FALLTHRU */ 354116742Ssam case IEEE80211_S_AUTH: 355116742Ssam case IEEE80211_S_SCAN: 356116742Ssam ic->ic_mgt_timer = 0; 357116742Ssam IF_DRAIN(&ic->ic_mgtq); 358116742Ssam if (ic->ic_wep_ctx != NULL) { 359116742Ssam free(ic->ic_wep_ctx, M_DEVBUF); 360116742Ssam ic->ic_wep_ctx = NULL; 361116742Ssam } 362116742Ssam ieee80211_free_allnodes(ic); 363116742Ssam break; 364116742Ssam } 365116742Ssam break; 366116742Ssam case IEEE80211_S_SCAN: 367116742Ssam ic->ic_flags &= ~IEEE80211_F_SIBSS; 368116742Ssam /* initialize bss for probe request */ 369116742Ssam IEEE80211_ADDR_COPY(ni->ni_macaddr, ifp->if_broadcastaddr); 370116742Ssam IEEE80211_ADDR_COPY(ni->ni_bssid, ifp->if_broadcastaddr); 371116742Ssam ni->ni_rates = ic->ic_sup_rates[ 372116742Ssam ieee80211_chan2mode(ic, ni->ni_chan)]; 373116742Ssam ni->ni_associd = 0; 374116742Ssam ni->ni_rstamp = 0; 375116742Ssam switch (ostate) { 376116742Ssam case IEEE80211_S_INIT: 377116742Ssam if (ic->ic_opmode == IEEE80211_M_HOSTAP && 378116742Ssam ic->ic_des_chan != IEEE80211_CHAN_ANYC) { 379116742Ssam /* 380116742Ssam * AP operation and we already have a channel; 381116742Ssam * bypass the scan and startup immediately. 382116742Ssam */ 383116742Ssam ieee80211_create_ibss(ic, ic->ic_des_chan); 384116742Ssam } else { 385116742Ssam ieee80211_begin_scan(ifp, ni); 386116742Ssam } 387116742Ssam break; 388116742Ssam case IEEE80211_S_SCAN: 389116742Ssam /* scan next */ 390116742Ssam if (ic->ic_flags & IEEE80211_F_ASCAN) { 391116742Ssam IEEE80211_SEND_MGMT(ic, ni, 392116742Ssam IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0); 393116742Ssam } 394116742Ssam break; 395116742Ssam case IEEE80211_S_RUN: 396116742Ssam /* beacon miss */ 397116742Ssam if (ifp->if_flags & IFF_DEBUG) { 398116742Ssam /* XXX bssid clobbered above */ 399116742Ssam if_printf(ifp, "no recent beacons from %s;" 400116742Ssam " rescanning\n", 401116742Ssam ether_sprintf(ic->ic_bss->ni_bssid)); 402116742Ssam } 403116742Ssam ieee80211_free_allnodes(ic); 404116742Ssam /* FALLTHRU */ 405116742Ssam case IEEE80211_S_AUTH: 406116742Ssam case IEEE80211_S_ASSOC: 407116742Ssam /* timeout restart scan */ 408116742Ssam ni = ieee80211_find_node(ic, ic->ic_bss->ni_macaddr); 409116742Ssam if (ni != NULL) { 410116742Ssam ni->ni_fails++; 411116742Ssam ieee80211_unref_node(&ni); 412116742Ssam } 413116742Ssam ieee80211_begin_scan(ifp, ic->ic_bss); 414116742Ssam break; 415116742Ssam } 416116742Ssam break; 417116742Ssam case IEEE80211_S_AUTH: 418116742Ssam switch (ostate) { 419116742Ssam case IEEE80211_S_INIT: 420116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 421116742Ssam __func__)); 422116742Ssam break; 423116742Ssam case IEEE80211_S_SCAN: 424116742Ssam IEEE80211_SEND_MGMT(ic, ni, 425116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 426116742Ssam break; 427116742Ssam case IEEE80211_S_AUTH: 428116742Ssam case IEEE80211_S_ASSOC: 429116742Ssam switch (mgt) { 430116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 431116742Ssam /* ??? */ 432116742Ssam IEEE80211_SEND_MGMT(ic, ni, 433116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 434116742Ssam break; 435116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 436116742Ssam /* ignore and retry scan on timeout */ 437116742Ssam break; 438116742Ssam } 439116742Ssam break; 440116742Ssam case IEEE80211_S_RUN: 441116742Ssam switch (mgt) { 442116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 443116742Ssam IEEE80211_SEND_MGMT(ic, ni, 444116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 2); 445116742Ssam ic->ic_state = ostate; /* stay RUN */ 446116742Ssam break; 447116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 448116742Ssam /* try to reauth */ 449116742Ssam IEEE80211_SEND_MGMT(ic, ni, 450116742Ssam IEEE80211_FC0_SUBTYPE_AUTH, 1); 451116742Ssam break; 452116742Ssam } 453116742Ssam break; 454116742Ssam } 455116742Ssam break; 456116742Ssam case IEEE80211_S_ASSOC: 457116742Ssam switch (ostate) { 458116742Ssam case IEEE80211_S_INIT: 459116742Ssam case IEEE80211_S_SCAN: 460116742Ssam case IEEE80211_S_ASSOC: 461116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 462116742Ssam __func__)); 463116742Ssam break; 464116742Ssam case IEEE80211_S_AUTH: 465116742Ssam IEEE80211_SEND_MGMT(ic, ni, 466116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0); 467116742Ssam break; 468116742Ssam case IEEE80211_S_RUN: 469116742Ssam IEEE80211_SEND_MGMT(ic, ni, 470116742Ssam IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 1); 471116742Ssam break; 472116742Ssam } 473116742Ssam break; 474116742Ssam case IEEE80211_S_RUN: 475116742Ssam switch (ostate) { 476116742Ssam case IEEE80211_S_INIT: 477116742Ssam case IEEE80211_S_AUTH: 478116742Ssam case IEEE80211_S_RUN: 479116742Ssam IEEE80211_DPRINTF(("%s: invalid transition\n", 480116742Ssam __func__)); 481116742Ssam break; 482116742Ssam case IEEE80211_S_SCAN: /* adhoc/hostap mode */ 483116742Ssam case IEEE80211_S_ASSOC: /* infra mode */ 484116742Ssam KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates, 485116742Ssam ("%s: bogus xmit rate %u setup\n", __func__, 486116742Ssam ni->ni_txrate)); 487116742Ssam if (ifp->if_flags & IFF_DEBUG) { 488116742Ssam if_printf(ifp, " "); 489116742Ssam if (ic->ic_opmode == IEEE80211_M_STA) 490116742Ssam printf("associated "); 491116742Ssam else 492116742Ssam printf("synchronized "); 493116742Ssam printf("with %s ssid ", 494116742Ssam ether_sprintf(ni->ni_bssid)); 495116742Ssam ieee80211_print_essid(ic->ic_bss->ni_essid, 496116742Ssam ni->ni_esslen); 497116742Ssam printf(" channel %d start %uMb\n", 498116742Ssam ieee80211_chan2ieee(ic, ni->ni_chan), 499116742Ssam IEEE80211_RATE2MBS(ni->ni_rates.rs_rates[ni->ni_txrate])); 500116742Ssam } 501116742Ssam ic->ic_mgt_timer = 0; 502116742Ssam (*ifp->if_start)(ifp); 503116742Ssam break; 504116742Ssam } 505116742Ssam break; 506116742Ssam } 507116742Ssam return 0; 508116742Ssam} 509