ieee80211.c revision 116742
1139804Simp/*- 21541Srgrimes * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer, 101541Srgrimes * without modification. 111541Srgrimes * 2. Redistributions in binary form must reproduce at minimum a disclaimer 121541Srgrimes * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 131541Srgrimes * redistribution must be conditioned upon including a substantially 141541Srgrimes * similar Disclaimer requirement for further binary redistribution. 151541Srgrimes * 3. Neither the names of the above-listed copyright holders nor the names 161541Srgrimes * of any contributors may be used to endorse or promote products derived 171541Srgrimes * from this software without specific prior written permission. 181541Srgrimes * 191541Srgrimes * Alternatively, this software may be distributed under the terms of the 201541Srgrimes * GNU General Public License ("GPL") version 2 as published by the Free 211541Srgrimes * Software Foundation. 221541Srgrimes * 231541Srgrimes * NO WARRANTY 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 251541Srgrimes * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 261541Srgrimes * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 271541Srgrimes * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 281541Srgrimes * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 291541Srgrimes * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 301541Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 311541Srgrimes * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 32116182Sobrien * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33116182Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 34116182Sobrien * THE POSSIBILITY OF SUCH DAMAGES. 3531778Seivind */ 3631778Seivind 371541Srgrimes#include <sys/cdefs.h> 381541Srgrimes__FBSDID("$FreeBSD: head/sys/net80211/ieee80211.c 116742 2003-06-23 16:55:01Z sam $"); 3912221Sbde 401541Srgrimes/* 41164033Srwatson * IEEE 802.11 generic handler 421541Srgrimes */ 4382717Sdillon 4482717Sdillon#include "opt_inet.h" 45186570Sed 461541Srgrimes#include <sys/param.h> 471549Srgrimes#include <sys/systm.h> 481541Srgrimes#include <sys/mbuf.h> 49186570Sed#include <sys/malloc.h> 508876Srgrimes#include <sys/kernel.h> 51130344Sphk#include <sys/socket.h> 521541Srgrimes#include <sys/sockio.h> 5312221Sbde#include <sys/endian.h> 541541Srgrimes#include <sys/errno.h> 551541Srgrimes#include <sys/bus.h> 561541Srgrimes#include <sys/proc.h> 571541Srgrimes#include <sys/sysctl.h> 5812221Sbde 591541Srgrimes#include <machine/atomic.h> 601549Srgrimes 6183366Sjulian#include <net/if.h> 6283366Sjulian#include <net/if_dl.h> 631541Srgrimes#include <net/if_media.h> 641541Srgrimes#include <net/if_arp.h> 6512171Sphk#include <net/ethernet.h> 6638517Sdfr#include <net/if_llc.h> 671541Srgrimes 6812171Sphk#include <net80211/ieee80211_var.h> 6912171Sphk 70186564Sed#include <net/bpf.h> 71186564Sed 721541Srgrimes#ifdef INET 731541Srgrimes#include <netinet/in.h> 7412221Sbde#include <netinet/if_ether.h> 751541Srgrimes#endif 761541Srgrimes 771541Srgrimes#ifdef IEEE80211_DEBUG 781541Srgrimesint ieee80211_debug = 0; 7912221SbdeSYSCTL_INT(_debug, OID_AUTO, ieee80211, CTLFLAG_RW, &ieee80211_debug, 801541Srgrimes 0, "IEEE 802.11 media debugging printfs"); 811549Srgrimes#endif 8283366Sjulian 8383366Sjulianstatic void ieee80211_set11gbasicrates(struct ieee80211_rateset *, 841541Srgrimes enum ieee80211_phymode); 851541Srgrimes 8612171Sphkstatic const char *ieee80211_phymode_name[] = { 871541Srgrimes "auto", /* IEEE80211_MODE_AUTO */ 8812171Sphk "11a", /* IEEE80211_MODE_11A */ 8912171Sphk "11b", /* IEEE80211_MODE_11B */ 90186564Sed "11g", /* IEEE80211_MODE_11G */ 91186564Sed "turbo", /* IEEE80211_MODE_TURBO */ 921541Srgrimes}; 931541Srgrimes 9412221Sbdevoid 9512200Sbdeieee80211_ifattach(struct ifnet *ifp) 961541Srgrimes{ 971541Srgrimes struct ieee80211com *ic = (void *)ifp; 9812221Sbde struct ieee80211_channel *c; 991541Srgrimes int i; 1001549Srgrimes 10183366Sjulian ether_ifattach(ifp, ic->ic_myaddr); 10283366Sjulian bpfattach2(ifp, DLT_IEEE802_11, 10312200Sbde sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf); 1041541Srgrimes ieee80211_crypto_attach(ifp); 105193066Sjamie 106193066Sjamie /* 1071541Srgrimes * Fill in 802.11 available channel set, mark 108193066Sjamie * all available channels as active, and pick 109193066Sjamie * a default channel if not already specified. 110193066Sjamie */ 111193066Sjamie memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail)); 1121541Srgrimes ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO; 113130344Sphk for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 1141541Srgrimes c = &ic->ic_channels[i]; 1151541Srgrimes if (c->ic_flags) { 11612221Sbde /* 11712200Sbde * Verify driver passed us valid data. 1181541Srgrimes */ 1191541Srgrimes if (i != ieee80211_chan2ieee(ic, c)) { 12012221Sbde if_printf(ifp, "bad channel ignored; " 1211541Srgrimes "freq %u flags %x number %u\n", 1221549Srgrimes c->ic_freq, c->ic_flags, i); 12383366Sjulian c->ic_flags = 0; /* NB: remove */ 12483366Sjulian continue; 12512200Sbde } 1261541Srgrimes setbit(ic->ic_chan_avail, i); 127193066Sjamie /* 1281541Srgrimes * Identify mode capabilities. 129193066Sjamie */ 130193066Sjamie if (IEEE80211_IS_CHAN_A(c)) 131193066Sjamie ic->ic_modecaps |= 1<<IEEE80211_MODE_11A; 132193066Sjamie if (IEEE80211_IS_CHAN_B(c)) 1331541Srgrimes ic->ic_modecaps |= 1<<IEEE80211_MODE_11B; 1341541Srgrimes if (IEEE80211_IS_CHAN_PUREG(c)) 1351549Srgrimes ic->ic_modecaps |= 1<<IEEE80211_MODE_11G; 13683366Sjulian if (IEEE80211_IS_CHAN_T(c)) 13783366Sjulian ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO; 13812200Sbde } 1391541Srgrimes } 140167232Srwatson /* validate ic->ic_curmode */ 1411541Srgrimes if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0) 1421541Srgrimes ic->ic_curmode = IEEE80211_MODE_AUTO; 143186570Sed 144186570Sed (void) ieee80211_setmode(ic, ic->ic_curmode); 145186570Sed 146186570Sed ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */ 147186570Sed if (ic->ic_lintval == 0) 148186570Sed ic->ic_lintval = 100; /* default sleep */ 149186570Sed ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ 150186570Sed 151186570Sed ieee80211_node_attach(ifp); 152186570Sed ieee80211_proto_attach(ifp); 153186570Sed} 154186570Sed 155186570Sedvoid 156186570Sedieee80211_ifdetach(struct ifnet *ifp) 157186570Sed{ 158186570Sed struct ieee80211com *ic = (void *)ifp; 159186570Sed 160186570Sed ieee80211_proto_detach(ifp); 161186570Sed ieee80211_crypto_detach(ifp); 162186570Sed ieee80211_node_detach(ifp); 163186570Sed ifmedia_removeall(&ic->ic_media); 164186570Sed bpfdetach(ifp); 165186570Sed ether_ifdetach(ifp); 166186570Sed} 167186570Sed 168186570Sed/* 169186570Sed * Convert MHz frequency to IEEE channel number. 170186570Sed */ 171186570Sedu_int 172186570Sedieee80211_mhz2ieee(u_int freq, u_int flags) 173186570Sed{ 174186570Sed if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ 175186570Sed if (freq == 2484) 176186570Sed return 14; 177186570Sed if (freq < 2484) 178186570Sed return (freq - 2407) / 5; 179186570Sed else 180186570Sed return 15 + ((freq - 2512) / 20); 181186570Sed } else if (IEEE80211_CHAN_5GHZ) { /* 5Ghz band */ 182186570Sed return (freq - 5000) / 5; 183186570Sed } else { /* either, guess */ 184186570Sed if (freq == 2484) 185186570Sed return 14; 186186570Sed if (freq < 2484) 187186570Sed return (freq - 2407) / 5; 188186570Sed if (freq < 5000) 189186570Sed return 15 + ((freq - 2512) / 20); 190186570Sed return (freq - 5000) / 5; 191186570Sed } 192186570Sed} 193186570Sed 194186570Sed/* 195186570Sed * Convert channel to IEEE channel number. 196186570Sed */ 197186570Sedu_int 198186570Sedieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c) 199186570Sed{ 200186570Sed if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX]) 201186570Sed return c - ic->ic_channels; 202186570Sed else if (c == IEEE80211_CHAN_ANYC) 203186570Sed return IEEE80211_CHAN_ANY; 204186570Sed else { 205186570Sed if_printf(&ic->ic_if, "invalid channel freq %u flags %x\n", 206186570Sed c->ic_freq, c->ic_flags); 207186570Sed return 0; /* XXX */ 208186570Sed } 209186570Sed} 210186570Sed 211186570Sed/* 212186570Sed * Convert IEEE channel number to MHz frequency. 213186570Sed */ 214186570Sedu_int 215186570Sedieee80211_ieee2mhz(u_int chan, u_int flags) 216186570Sed{ 217186570Sed if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */ 218186570Sed if (chan == 14) 219186570Sed return 2484; 220186570Sed if (chan < 14) 221186570Sed return 2407 + chan*5; 222186570Sed else 223186570Sed return 2512 + ((chan-15)*20); 224186570Sed } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */ 225186570Sed return 5000 + (chan*5); 226186570Sed } else { /* either, guess */ 227186570Sed if (chan == 14) 228186570Sed return 2484; 229186570Sed if (chan < 14) /* 0-13 */ 230186570Sed return 2407 + chan*5; 231186570Sed if (chan < 27) /* 15-26 */ 232186570Sed return 2512 + ((chan-15)*20); 233186570Sed return 5000 + (chan*5); 234186570Sed } 235186570Sed} 236186570Sed 237186570Sed/* 238186570Sed * Setup the media data structures according to the channel and 239186570Sed * rate tables. This must be called by the driver after 240186570Sed * ieee80211_attach and before most anything else. 241186570Sed */ 242186570Sedvoid 243186570Sedieee80211_media_init(struct ifnet *ifp, 244186570Sed ifm_change_cb_t media_change, ifm_stat_cb_t media_stat) 245186570Sed{ 246186570Sed#define ADD(_ic, _s, _o) \ 247186570Sed ifmedia_add(&(_ic)->ic_media, \ 248186570Sed IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL) 249186570Sed struct ieee80211com *ic = (void *)ifp; 250186570Sed struct ifmediareq imr; 251186570Sed int i, j, mode, rate, maxrate, mword, mopt, r; 252186570Sed struct ieee80211_rateset *rs; 253186570Sed struct ieee80211_rateset allrates; 254186570Sed 255186570Sed /* 256186570Sed * Fill in media characteristics. 257186570Sed */ 258186570Sed ifmedia_init(&ic->ic_media, 0, media_change, media_stat); 259186570Sed maxrate = 0; 260186570Sed memset(&allrates, 0, sizeof(allrates)); 261186570Sed for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) { 262186570Sed static const u_int mopts[] = { 263186570Sed IFM_AUTO, 264186570Sed IFM_MAKEMODE(IFM_IEEE80211_11A), 265186570Sed IFM_MAKEMODE(IFM_IEEE80211_11B), 266186570Sed IFM_MAKEMODE(IFM_IEEE80211_11G), 267186570Sed IFM_MAKEMODE(IFM_IEEE80211_11A) | IFM_IEEE80211_TURBO, 268186570Sed }; 269186570Sed if ((ic->ic_modecaps & (1<<mode)) == 0) 270186570Sed continue; 271186570Sed mopt = mopts[mode]; 272186570Sed ADD(ic, IFM_AUTO, mopt); /* e.g. 11a auto */ 273186570Sed if (ic->ic_caps & IEEE80211_C_IBSS) 274186570Sed ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC); 275186570Sed if (ic->ic_caps & IEEE80211_C_HOSTAP) 276186570Sed ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP); 277186570Sed if (ic->ic_caps & IEEE80211_C_AHDEMO) 278186570Sed ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); 279186570Sed if (mode == IEEE80211_MODE_AUTO) 280186570Sed continue; 281186570Sed if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]); 282186570Sed rs = &ic->ic_sup_rates[mode]; 283186570Sed for (i = 0; i < rs->rs_nrates; i++) { 284186570Sed rate = rs->rs_rates[i]; 285186570Sed mword = ieee80211_rate2media(ic, rate, mode); 286186570Sed if (mword == 0) 287186570Sed continue; 288186570Sed printf("%s%d%sMbps", (i != 0 ? " " : ""), 289186570Sed (rate & IEEE80211_RATE_VAL) / 2, 290186570Sed ((rate & 0x1) != 0 ? ".5" : "")); 291186570Sed ADD(ic, mword, mopt); 292186570Sed if (ic->ic_caps & IEEE80211_C_IBSS) 293186570Sed ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC); 294186570Sed if (ic->ic_caps & IEEE80211_C_HOSTAP) 295186570Sed ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP); 296186570Sed if (ic->ic_caps & IEEE80211_C_AHDEMO) 297186570Sed ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0); 298186570Sed /* 299186570Sed * Add rate to the collection of all rates. 300186570Sed */ 301186570Sed r = rate & IEEE80211_RATE_VAL; 302186570Sed for (j = 0; j < allrates.rs_nrates; j++) 303186570Sed if (allrates.rs_rates[j] == r) 304186570Sed break; 305186570Sed if (j == allrates.rs_nrates) { 306186570Sed /* unique, add to the set */ 307186570Sed allrates.rs_rates[j] = r; 308186570Sed allrates.rs_nrates++; 309186570Sed } 310186570Sed rate = (rate & IEEE80211_RATE_VAL) / 2; 311186570Sed if (rate > maxrate) 312186570Sed maxrate = rate; 313186570Sed } 314186570Sed printf("\n"); 315186570Sed } 316186570Sed for (i = 0; i < allrates.rs_nrates; i++) { 317186570Sed mword = ieee80211_rate2media(ic, allrates.rs_rates[i], 318186570Sed IEEE80211_MODE_AUTO); 319186570Sed if (mword == 0) 320186570Sed continue; 321186570Sed mword = IFM_SUBTYPE(mword); /* remove media options */ 322186570Sed ADD(ic, mword, 0); 323186570Sed if (ic->ic_caps & IEEE80211_C_IBSS) 324186570Sed ADD(ic, mword, IFM_IEEE80211_ADHOC); 325186570Sed if (ic->ic_caps & IEEE80211_C_HOSTAP) 326186570Sed ADD(ic, mword, IFM_IEEE80211_HOSTAP); 327186570Sed if (ic->ic_caps & IEEE80211_C_AHDEMO) 328186570Sed ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0); 329186570Sed } 330186570Sed ieee80211_media_status(ifp, &imr); 331186570Sed ifmedia_set(&ic->ic_media, imr.ifm_active); 332186570Sed 333186570Sed if (maxrate) 334186570Sed ifp->if_baudrate = IF_Mbps(maxrate); 335186570Sed#undef ADD 336186570Sed} 337186570Sed 338186570Sedstatic int 339186570Sedfindrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate) 340186570Sed{ 341186570Sed#define IEEERATE(_ic,_m,_i) \ 342186570Sed ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL) 343186570Sed int i, nrates = ic->ic_sup_rates[mode].rs_nrates; 344186570Sed for (i = 0; i < nrates; i++) 345186570Sed if (IEEERATE(ic, mode, i) == rate) 346186570Sed return i; 347186570Sed return -1; 348186570Sed#undef IEEERATE 3491541Srgrimes} 3501549Srgrimes 351184789Sed/* 35274729Speter * Handle a media change request. 353184789Sed */ 354167232Srwatsonint 355167232Srwatsonieee80211_media_change(struct ifnet *ifp) 35674729Speter{ 35774729Speter struct ieee80211com *ic = (void *)ifp; 35874729Speter struct ifmedia_entry *ime; 35974729Speter enum ieee80211_opmode newopmode; 36012221Sbde enum ieee80211_phymode newphymode; 3611549Srgrimes int i, j, newrate, error = 0; 362180039Sjulian 3631549Srgrimes ime = ic->ic_media.ifm_cur; 36412221Sbde /* 3651549Srgrimes * First, identify the phy mode. 3661549Srgrimes */ 367184789Sed switch (IFM_MODE(ime->ifm_media)) { 3681549Srgrimes case IFM_IEEE80211_11A: 36982717Sdillon newphymode = IEEE80211_MODE_11A; 37038517Sdfr break; 3711549Srgrimes case IFM_IEEE80211_11B: 3721549Srgrimes newphymode = IEEE80211_MODE_11B; 37312171Sphk break; 37412171Sphk case IFM_IEEE80211_11G: 37582717Sdillon newphymode = IEEE80211_MODE_11G; 37683366Sjulian break; 377136404Speter case IFM_AUTO: 37882717Sdillon newphymode = IEEE80211_MODE_AUTO; 379186564Sed break; 3801549Srgrimes default: 3811549Srgrimes return EINVAL; 38212171Sphk } 3831549Srgrimes /* 38483366Sjulian * Turbo mode is an ``option''. Eventually it 385136404Speter * needs to be applied to 11g too. 38682717Sdillon */ 387186564Sed if (ime->ifm_media & IFM_IEEE80211_TURBO) { 3881549Srgrimes if (newphymode != IEEE80211_MODE_11A) 3891549Srgrimes return EINVAL; 39012171Sphk newphymode = IEEE80211_MODE_TURBO; 3911549Srgrimes } 39283366Sjulian /* 393136404Speter * Validate requested mode is available. 39482717Sdillon */ 395186564Sed if ((ic->ic_modecaps & (1<<newphymode)) == 0) 3961549Srgrimes return EINVAL; 3971549Srgrimes 3981549Srgrimes /* 3991549Srgrimes * Next, the fixed/variable rate. 4001549Srgrimes */ 40183366Sjulian i = -1; 402136404Speter if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) { 40382717Sdillon /* 404186564Sed * Convert media subtype to rate. 4051549Srgrimes */ 4061549Srgrimes newrate = ieee80211_media2rate(ime->ifm_media); 4071549Srgrimes if (newrate == 0) 4081549Srgrimes return EINVAL; 4091549Srgrimes /* 4101549Srgrimes * Check the rate table for the specified/current phy. 4111549Srgrimes */ 4121549Srgrimes if (newphymode == IEEE80211_MODE_AUTO) { 4131549Srgrimes /* 41482717Sdillon * In autoselect mode search for the rate. 41582717Sdillon */ 416186564Sed for (j = IEEE80211_MODE_11A; 4171549Srgrimes j < IEEE80211_MODE_MAX; j++) { 41882717Sdillon if ((ic->ic_modecaps & (1<<j)) == 0) 41982717Sdillon continue; 420186564Sed i = findrate(ic, j, newrate); 4211549Srgrimes if (i != -1) { 42238517Sdfr /* lock mode too */ 42312171Sphk newphymode = j; 4241549Srgrimes break; 42583366Sjulian } 426136404Speter } 42782717Sdillon } else { 428186564Sed i = findrate(ic, newphymode, newrate); 4291549Srgrimes } 430186564Sed if (i == -1) /* mode/rate mismatch */ 4311549Srgrimes return EINVAL; 4321549Srgrimes } 43312221Sbde /* NB: defer rate setting to later */ 4341549Srgrimes 435180039Sjulian /* 436180039Sjulian * Deduce new operating mode but don't install it just yet. 4371549Srgrimes */ 43812222Sbde if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) == 4391549Srgrimes (IFM_IEEE80211_ADHOC|IFM_FLAG0)) 4401549Srgrimes newopmode = IEEE80211_M_AHDEMO; 441184789Sed else if (ime->ifm_media & IFM_IEEE80211_HOSTAP) 442184789Sed newopmode = IEEE80211_M_HOSTAP; 4431549Srgrimes else if (ime->ifm_media & IFM_IEEE80211_ADHOC) 444184789Sed newopmode = IEEE80211_M_IBSS; 445184789Sed else 44682717Sdillon newopmode = IEEE80211_M_STA; 447184789Sed 448184789Sed /* 449186564Sed * Autoselect doesn't make sense when operating as an AP. 450186564Sed * If no phy mode has been selected, pick one and lock it 4511549Srgrimes * down so rate tables can be used in forming beacon frames 4521549Srgrimes * and the like. 45312221Sbde */ 4541549Srgrimes if (newopmode == IEEE80211_M_HOSTAP && 455180039Sjulian newphymode == IEEE80211_MODE_AUTO) { 456180039Sjulian for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++) 4571549Srgrimes if (ic->ic_modecaps & (1<<j)) { 45812221Sbde newphymode = j; 4591549Srgrimes break; 4601549Srgrimes } 461184789Sed } 462184789Sed 4631549Srgrimes /* 464184789Sed * Handle phy mode change. 4651549Srgrimes */ 466184789Sed if (ic->ic_curmode != newphymode) { /* change phy mode */ 467184789Sed error = ieee80211_setmode(ic, newphymode); 468186564Sed if (error != 0) 469186564Sed return error; 4701549Srgrimes error = ENETRESET; 471184789Sed } 472 473 /* 474 * Committed to changes, install the rate setting. 475 */ 476 if (ic->ic_fixed_rate != i) { 477 ic->ic_fixed_rate = i; /* set fixed tx rate */ 478 error = ENETRESET; 479 } 480 481 /* 482 * Handle operating mode change. 483 */ 484 if (ic->ic_opmode != newopmode) { 485 ic->ic_opmode = newopmode; 486 switch (newopmode) { 487 case IEEE80211_M_AHDEMO: 488 case IEEE80211_M_HOSTAP: 489 case IEEE80211_M_STA: 490 ic->ic_flags &= ~IEEE80211_F_IBSSON; 491 break; 492 case IEEE80211_M_IBSS: 493 ic->ic_flags |= IEEE80211_F_IBSSON; 494#ifdef notdef 495 if (ic->ic_curmode == IEEE80211_MODE_11G) 496 ieee80211_set11gbasicrates( 497 &ic->ic_suprates[newphymode], 498 IEEE80211_MODE_11B); 499#endif 500 break; 501 } 502 error = ENETRESET; 503 } 504#ifdef notdef 505 if (error == 0) 506 ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media); 507#endif 508 return error; 509} 510 511void 512ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr) 513{ 514 struct ieee80211com *ic = (void *)ifp; 515 struct ieee80211_node *ni = NULL; 516 517 imr->ifm_status = IFM_AVALID; 518 imr->ifm_active = IFM_IEEE80211; 519 if (ic->ic_state == IEEE80211_S_RUN) 520 imr->ifm_status |= IFM_ACTIVE; 521 imr->ifm_active |= IFM_AUTO; 522 switch (ic->ic_opmode) { 523 case IEEE80211_M_STA: 524 ni = ic->ic_bss; 525 /* calculate rate subtype */ 526 imr->ifm_active |= ieee80211_rate2media(ic, 527 ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode); 528 break; 529 case IEEE80211_M_IBSS: 530 imr->ifm_active |= IFM_IEEE80211_ADHOC; 531 break; 532 case IEEE80211_M_AHDEMO: 533 /* should not come here */ 534 break; 535 case IEEE80211_M_HOSTAP: 536 imr->ifm_active |= IFM_IEEE80211_HOSTAP; 537 break; 538 } 539 switch (ic->ic_curmode) { 540 case IEEE80211_MODE_11A: 541 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A); 542 break; 543 case IEEE80211_MODE_11B: 544 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11B); 545 break; 546 case IEEE80211_MODE_11G: 547 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11G); 548 break; 549 case IEEE80211_MODE_TURBO: 550 imr->ifm_active |= IFM_MAKEMODE(IFM_IEEE80211_11A) 551 | IFM_IEEE80211_TURBO; 552 break; 553 } 554} 555 556void 557ieee80211_watchdog(struct ifnet *ifp) 558{ 559 struct ieee80211com *ic = (void *)ifp; 560 561 if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0) 562 ieee80211_new_state(ifp, IEEE80211_S_SCAN, -1); 563 if (ic->ic_inact_timer && --ic->ic_inact_timer == 0) 564 ieee80211_timeout_nodes(ic); 565 566 if (ic->ic_mgt_timer != 0 || ic->ic_inact_timer != 0) 567 ifp->if_timer = 1; 568} 569 570/* 571 * Mark the basic rates for the 11g rate table based on the 572 * operating mode. For real 11g we mark all the 11b rates 573 * and 6, 12, and 24 OFDM. For 11b compatibility we mark only 574 * 11b rates. There's also a pseudo 11a-mode used to mark only 575 * the basic OFDM rates. 576 */ 577static void 578ieee80211_set11gbasicrates(struct ieee80211_rateset *rs, enum ieee80211_phymode mode) 579{ 580 static const struct ieee80211_rateset basic[] = { 581 { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */ 582 { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11B */ 583 { 7, { 2, 4, 11, 22, 12, 24, 48 } },/* IEEE80211_MODE_11G */ 584 { 0 }, /* IEEE80211_MODE_TURBO */ 585 }; 586 int i, j; 587 588 for (i = 0; i < rs->rs_nrates; i++) { 589 rs->rs_rates[i] &= IEEE80211_RATE_VAL; 590 for (j = 0; j < basic[mode].rs_nrates; j++) 591 if (basic[mode].rs_rates[j] == rs->rs_rates[i]) { 592 rs->rs_rates[i] |= IEEE80211_RATE_BASIC; 593 break; 594 } 595 } 596} 597 598/* 599 * Set the current phy mode and recalculate the active channel 600 * set based on the available channels for this mode. Also 601 * select a new default/current channel if the current one is 602 * inappropriate for this mode. 603 */ 604int 605ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode) 606{ 607#define N(a) (sizeof(a) / sizeof(a[0])) 608 static const u_int chanflags[] = { 609 0, /* IEEE80211_MODE_AUTO */ 610 IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */ 611 IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */ 612 IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */ 613 IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */ 614 }; 615 struct ieee80211_channel *c; 616 u_int modeflags; 617 int i; 618 619 /* validate new mode */ 620 if ((ic->ic_modecaps & (1<<mode)) == 0) { 621 IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n", 622 __func__, mode, ic->ic_modecaps)); 623 return EINVAL; 624 } 625 626 /* 627 * Verify at least one channel is present in the available 628 * channel list before committing to the new mode. 629 */ 630 KASSERT(mode < N(chanflags), ("Unexpected mode %u\n", mode)); 631 modeflags = chanflags[mode]; 632 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 633 c = &ic->ic_channels[i]; 634 if (mode == IEEE80211_MODE_AUTO) { 635 /* ignore turbo channels for autoselect */ 636 if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) 637 break; 638 } else { 639 if ((c->ic_flags & modeflags) == modeflags) 640 break; 641 } 642 } 643 if (i > IEEE80211_CHAN_MAX) { 644 IEEE80211_DPRINTF(("%s: no channels found for mode %u\n", 645 __func__, mode)); 646 return EINVAL; 647 } 648 649 /* 650 * Calculate the active channel set. 651 */ 652 memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active)); 653 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) { 654 c = &ic->ic_channels[i]; 655 if (mode == IEEE80211_MODE_AUTO) { 656 /* take anything but pure turbo channels */ 657 if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0) 658 setbit(ic->ic_chan_active, i); 659 } else { 660 if ((c->ic_flags & modeflags) == modeflags) 661 setbit(ic->ic_chan_active, i); 662 } 663 } 664 /* 665 * If no current/default channel is setup or the current 666 * channel is wrong for the mode then pick the first 667 * available channel from the active list. This is likely 668 * not the right one. 669 */ 670 if (ic->ic_ibss_chan == NULL || 671 isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) { 672 for (i = 0; i <= IEEE80211_CHAN_MAX; i++) 673 if (isset(ic->ic_chan_active, i)) { 674 ic->ic_ibss_chan = &ic->ic_channels[i]; 675 break; 676 } 677 } 678 679 /* 680 * Set/reset state flags that influence beacon contents, etc. 681 * 682 * XXX what if we have stations already associated??? 683 * XXX probably not right for autoselect? 684 */ 685 if (mode == IEEE80211_MODE_11G) { 686 if (ic->ic_caps & IEEE80211_C_SHSLOT) 687 ic->ic_flags |= IEEE80211_F_SHSLOT; 688 if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) 689 ic->ic_flags |= IEEE80211_F_SHPREAMBLE; 690 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], 691 IEEE80211_MODE_11G); 692 } else { 693 ic->ic_flags &= ~(IEEE80211_F_SHSLOT | IEEE80211_F_SHPREAMBLE); 694 } 695 696 ic->ic_curmode = mode; 697 return 0; 698#undef N 699} 700 701/* 702 * Return the phy mode for with the specified channel so the 703 * caller can select a rate set. This is problematic and the 704 * work here assumes how things work elsewhere in this code. 705 */ 706enum ieee80211_phymode 707ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan) 708{ 709 /* 710 * NB: this assumes the channel would not be supplied to us 711 * unless it was already compatible with the current mode. 712 */ 713 if (ic->ic_curmode != IEEE80211_MODE_AUTO) 714 return ic->ic_curmode; 715 /* 716 * In autoselect mode; deduce a mode based on the channel 717 * characteristics. We assume that turbo-only channels 718 * are not considered when the channel set is constructed. 719 */ 720 if (IEEE80211_IS_CHAN_5GHZ(chan)) 721 return IEEE80211_MODE_11A; 722 else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) 723 return IEEE80211_MODE_11G; 724 else 725 return IEEE80211_MODE_11B; 726} 727 728/* 729 * convert IEEE80211 rate value to ifmedia subtype. 730 * ieee80211 rate is in unit of 0.5Mbps. 731 */ 732int 733ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode) 734{ 735#define N(a) (sizeof(a) / sizeof(a[0])) 736 static const struct { 737 u_int m; /* rate + mode */ 738 u_int r; /* if_media rate */ 739 } rates[] = { 740 { 2 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS1 }, 741 { 4 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS2 }, 742 { 11 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS5 }, 743 { 22 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS11 }, 744 { 44 | IFM_MAKEMODE(IFM_IEEE80211_11B), IFM_IEEE80211_DS22 }, 745 { 12 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM6 }, 746 { 18 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM9 }, 747 { 24 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM12 }, 748 { 36 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM18 }, 749 { 48 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM24 }, 750 { 72 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM36 }, 751 { 96 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM48 }, 752 { 108 | IFM_MAKEMODE(IFM_IEEE80211_11A), IFM_IEEE80211_OFDM54 }, 753 { 2 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS1 }, 754 { 4 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS2 }, 755 { 11 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS5 }, 756 { 22 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_DS11 }, 757 { 12 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM6 }, 758 { 18 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM9 }, 759 { 24 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM12 }, 760 { 36 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM18 }, 761 { 48 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM24 }, 762 { 72 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM36 }, 763 { 96 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM48 }, 764 { 108 | IFM_MAKEMODE(IFM_IEEE80211_11G), IFM_IEEE80211_OFDM54 }, 765 /* NB: OFDM72 doesn't realy exist so we don't handle it */ 766 }; 767 u_int mask, i; 768 769 mask = rate & IEEE80211_RATE_VAL; 770 switch (mode) { 771 case IEEE80211_MODE_11A: 772 case IEEE80211_MODE_TURBO: 773 mask |= IFM_MAKEMODE(IFM_IEEE80211_11A); 774 break; 775 case IEEE80211_MODE_11B: 776 mask |= IFM_MAKEMODE(IFM_IEEE80211_11B); 777 break; 778 case IEEE80211_MODE_AUTO: 779 /* NB: ic may be NULL for some drivers */ 780 if (ic && ic->ic_phytype == IEEE80211_T_FH) { 781 /* must handle these specially */ 782 switch (mask) { 783 case 2: return IFM_IEEE80211_FH1; 784 case 4: return IFM_IEEE80211_FH2; 785 } 786 return IFM_AUTO; 787 } 788 /* NB: hack, 11g matches both 11b+11a rates */ 789 /* fall thru... */ 790 case IEEE80211_MODE_11G: 791 mask |= IFM_MAKEMODE(IFM_IEEE80211_11G); 792 break; 793 } 794 for (i = 0; i < N(rates); i++) 795 if (rates[i].m == mask) 796 return rates[i].r; 797 return IFM_AUTO; 798#undef N 799} 800 801int 802ieee80211_media2rate(int mword) 803{ 804#define N(a) (sizeof(a) / sizeof(a[0])) 805 static const int ieeerates[] = { 806 -1, /* IFM_AUTO */ 807 0, /* IFM_MANUAL */ 808 0, /* IFM_NONE */ 809 2, /* IFM_IEEE80211_FH1 */ 810 4, /* IFM_IEEE80211_FH2 */ 811 2, /* IFM_IEEE80211_DS1 */ 812 4, /* IFM_IEEE80211_DS2 */ 813 11, /* IFM_IEEE80211_DS5 */ 814 22, /* IFM_IEEE80211_DS11 */ 815 44, /* IFM_IEEE80211_DS22 */ 816 12, /* IFM_IEEE80211_OFDM6 */ 817 18, /* IFM_IEEE80211_OFDM9 */ 818 24, /* IFM_IEEE80211_OFDM12 */ 819 36, /* IFM_IEEE80211_OFDM18 */ 820 48, /* IFM_IEEE80211_OFDM24 */ 821 72, /* IFM_IEEE80211_OFDM36 */ 822 96, /* IFM_IEEE80211_OFDM48 */ 823 108, /* IFM_IEEE80211_OFDM54 */ 824 144, /* IFM_IEEE80211_OFDM72 */ 825 }; 826 return IFM_SUBTYPE(mword) < N(ieeerates) ? 827 ieeerates[IFM_SUBTYPE(mword)] : 0; 828#undef N 829} 830 831/* 832 * Module glue. 833 * 834 * NB: the module name is "wlan" for compatibility with NetBSD. 835 */ 836 837static int 838ieee80211_modevent(module_t mod, int type, void *unused) 839{ 840 switch (type) { 841 case MOD_LOAD: 842 if (bootverbose) 843 printf("wlan: <802.11 Link Layer>\n"); 844 return 0; 845 case MOD_UNLOAD: 846 return 0; 847 } 848 return EINVAL; 849} 850 851static moduledata_t ieee80211_mod = { 852 "wlan", 853 ieee80211_modevent, 854 0 855}; 856DECLARE_MODULE(wlan, ieee80211_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 857MODULE_VERSION(wlan, 1); 858MODULE_DEPEND(wlan, rc4, 1, 1, 1); 859