Annotation of sys/net80211/ieee80211.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ieee80211.c,v 1.24 2007/07/03 20:25:32 damien Exp $ */
! 2: /* $NetBSD: ieee80211.c,v 1.19 2004/06/06 05:45:29 dyoung Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 Atsushi Onoe
! 6: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. The name of the author may not be used to endorse or promote products
! 18: * derived from this software without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 21: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 22: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 23: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 24: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 25: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 29: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 30: */
! 31:
! 32: /*
! 33: * IEEE 802.11 generic handler
! 34: */
! 35:
! 36: #include "bpfilter.h"
! 37:
! 38: #include <sys/param.h>
! 39: #include <sys/systm.h>
! 40: #include <sys/mbuf.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/socket.h>
! 43: #include <sys/sockio.h>
! 44: #include <sys/endian.h>
! 45: #include <sys/errno.h>
! 46: #include <sys/proc.h>
! 47: #include <sys/sysctl.h>
! 48:
! 49: #include <net/if.h>
! 50: #include <net/if_dl.h>
! 51: #include <net/if_media.h>
! 52: #include <net/if_arp.h>
! 53: #include <net/if_llc.h>
! 54:
! 55: #if NBPFILTER > 0
! 56: #include <net/bpf.h>
! 57: #endif
! 58:
! 59: #ifdef INET
! 60: #include <netinet/in.h>
! 61: #include <netinet/if_ether.h>
! 62: #endif
! 63:
! 64: #include <net80211/ieee80211_var.h>
! 65:
! 66: #ifdef IEEE80211_DEBUG
! 67: int ieee80211_debug = 0;
! 68: #endif
! 69:
! 70: int ieee80211_cache_size = IEEE80211_CACHE_SIZE;
! 71:
! 72: struct ieee80211com_head ieee80211com_head =
! 73: LIST_HEAD_INITIALIZER(ieee80211com_head);
! 74:
! 75: void ieee80211_setbasicrates(struct ieee80211com *);
! 76: int ieee80211_findrate(struct ieee80211com *, enum ieee80211_phymode, int);
! 77:
! 78: void
! 79: ieee80211_ifattach(struct ifnet *ifp)
! 80: {
! 81: struct ieee80211com *ic = (void *)ifp;
! 82: struct ieee80211_channel *c;
! 83: int i;
! 84:
! 85: memcpy(((struct arpcom *)ifp)->ac_enaddr, ic->ic_myaddr,
! 86: ETHER_ADDR_LEN);
! 87: ether_ifattach(ifp);
! 88:
! 89: ifp->if_output = ieee80211_output;
! 90:
! 91: #if NBPFILTER > 0
! 92: bpfattach(&ic->ic_rawbpf, ifp, DLT_IEEE802_11,
! 93: sizeof(struct ieee80211_frame_addr4));
! 94: #endif
! 95: ieee80211_crypto_attach(ifp);
! 96:
! 97: /*
! 98: * Fill in 802.11 available channel set, mark
! 99: * all available channels as active, and pick
! 100: * a default channel if not already specified.
! 101: */
! 102: memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
! 103: ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO;
! 104: for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
! 105: c = &ic->ic_channels[i];
! 106: if (c->ic_flags) {
! 107: /*
! 108: * Verify driver passed us valid data.
! 109: */
! 110: if (i != ieee80211_chan2ieee(ic, c)) {
! 111: printf("%s: bad channel ignored; "
! 112: "freq %u flags %x number %u\n",
! 113: ifp->if_xname, c->ic_freq, c->ic_flags,
! 114: i);
! 115: c->ic_flags = 0; /* NB: remove */
! 116: continue;
! 117: }
! 118: setbit(ic->ic_chan_avail, i);
! 119: /*
! 120: * Identify mode capabilities.
! 121: */
! 122: if (IEEE80211_IS_CHAN_A(c))
! 123: ic->ic_modecaps |= 1<<IEEE80211_MODE_11A;
! 124: if (IEEE80211_IS_CHAN_B(c))
! 125: ic->ic_modecaps |= 1<<IEEE80211_MODE_11B;
! 126: if (IEEE80211_IS_CHAN_PUREG(c))
! 127: ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
! 128: if (IEEE80211_IS_CHAN_FHSS(c))
! 129: ic->ic_modecaps |= 1<<IEEE80211_MODE_FH;
! 130: if (IEEE80211_IS_CHAN_T(c))
! 131: ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO;
! 132: }
! 133: }
! 134: /* validate ic->ic_curmode */
! 135: if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
! 136: ic->ic_curmode = IEEE80211_MODE_AUTO;
! 137: ic->ic_des_chan = IEEE80211_CHAN_ANYC; /* any channel is ok */
! 138: ic->ic_scan_lock = IEEE80211_SCAN_UNLOCKED;
! 139:
! 140: /* IEEE 802.11 defines a MTU >= 2290 */
! 141: ifp->if_capabilities |= IFCAP_VLAN_MTU;
! 142:
! 143: ieee80211_setbasicrates(ic);
! 144: (void) ieee80211_setmode(ic, ic->ic_curmode);
! 145:
! 146: if (ic->ic_lintval == 0)
! 147: ic->ic_lintval = 100; /* default sleep */
! 148: ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */
! 149: ic->ic_dtim_period = 1; /* all TIMs are DTIMs */
! 150:
! 151: LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
! 152: ieee80211_node_attach(ifp);
! 153: ieee80211_proto_attach(ifp);
! 154:
! 155: if_addgroup(ifp, "wlan");
! 156: }
! 157:
! 158: void
! 159: ieee80211_ifdetach(struct ifnet *ifp)
! 160: {
! 161: struct ieee80211com *ic = (void *)ifp;
! 162:
! 163: ieee80211_proto_detach(ifp);
! 164: ieee80211_crypto_detach(ifp);
! 165: ieee80211_node_detach(ifp);
! 166: LIST_REMOVE(ic, ic_list);
! 167: ifmedia_delete_instance(&ic->ic_media, IFM_INST_ANY);
! 168: ether_ifdetach(ifp);
! 169: }
! 170:
! 171: /*
! 172: * Convert MHz frequency to IEEE channel number.
! 173: */
! 174: u_int
! 175: ieee80211_mhz2ieee(u_int freq, u_int flags)
! 176: {
! 177: if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
! 178: if (freq == 2484)
! 179: return 14;
! 180: if (freq < 2484)
! 181: return (freq - 2407) / 5;
! 182: else
! 183: return 15 + ((freq - 2512) / 20);
! 184: } else if (flags & IEEE80211_CHAN_5GHZ) { /* 5Ghz band */
! 185: return (freq - 5000) / 5;
! 186: } else { /* either, guess */
! 187: if (freq == 2484)
! 188: return 14;
! 189: if (freq < 2484)
! 190: return (freq - 2407) / 5;
! 191: if (freq < 5000)
! 192: return 15 + ((freq - 2512) / 20);
! 193: return (freq - 5000) / 5;
! 194: }
! 195: }
! 196:
! 197: /*
! 198: * Convert channel to IEEE channel number.
! 199: */
! 200: u_int
! 201: ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
! 202: {
! 203: struct ifnet *ifp = &ic->ic_if;
! 204: if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX])
! 205: return c - ic->ic_channels;
! 206: else if (c == IEEE80211_CHAN_ANYC)
! 207: return IEEE80211_CHAN_ANY;
! 208: else if (c != NULL) {
! 209: printf("%s: invalid channel freq %u flags %x\n",
! 210: ifp->if_xname, c->ic_freq, c->ic_flags);
! 211: return 0; /* XXX */
! 212: } else {
! 213: printf("%s: invalid channel (NULL)\n", ifp->if_xname);
! 214: return 0; /* XXX */
! 215: }
! 216: }
! 217:
! 218: /*
! 219: * Convert IEEE channel number to MHz frequency.
! 220: */
! 221: u_int
! 222: ieee80211_ieee2mhz(u_int chan, u_int flags)
! 223: {
! 224: if (flags & IEEE80211_CHAN_2GHZ) { /* 2GHz band */
! 225: if (chan == 14)
! 226: return 2484;
! 227: if (chan < 14)
! 228: return 2407 + chan*5;
! 229: else
! 230: return 2512 + ((chan-15)*20);
! 231: } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
! 232: return 5000 + (chan*5);
! 233: } else { /* either, guess */
! 234: if (chan == 14)
! 235: return 2484;
! 236: if (chan < 14) /* 0-13 */
! 237: return 2407 + chan*5;
! 238: if (chan < 27) /* 15-26 */
! 239: return 2512 + ((chan-15)*20);
! 240: return 5000 + (chan*5);
! 241: }
! 242: }
! 243:
! 244: /*
! 245: * Setup the media data structures according to the channel and
! 246: * rate tables. This must be called by the driver after
! 247: * ieee80211_attach and before most anything else.
! 248: */
! 249: void
! 250: ieee80211_media_init(struct ifnet *ifp,
! 251: ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
! 252: {
! 253: #define ADD(_ic, _s, _o) \
! 254: ifmedia_add(&(_ic)->ic_media, \
! 255: IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
! 256: struct ieee80211com *ic = (void *)ifp;
! 257: struct ifmediareq imr;
! 258: int i, j, mode, rate, maxrate, mword, mopt, r;
! 259: const struct ieee80211_rateset *rs;
! 260: struct ieee80211_rateset allrates;
! 261:
! 262: /*
! 263: * Do late attach work that must wait for any subclass
! 264: * (i.e. driver) work such as overriding methods.
! 265: */
! 266: ieee80211_node_lateattach(ifp);
! 267:
! 268: /*
! 269: * Fill in media characteristics.
! 270: */
! 271: ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
! 272: maxrate = 0;
! 273: memset(&allrates, 0, sizeof(allrates));
! 274: for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) {
! 275: static const u_int mopts[] = {
! 276: IFM_AUTO,
! 277: IFM_IEEE80211_11A,
! 278: IFM_IEEE80211_11B,
! 279: IFM_IEEE80211_11G,
! 280: IFM_IEEE80211_FH,
! 281: IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
! 282: };
! 283: if ((ic->ic_modecaps & (1<<mode)) == 0)
! 284: continue;
! 285: mopt = mopts[mode];
! 286: ADD(ic, IFM_AUTO, mopt); /* e.g. 11a auto */
! 287: if (ic->ic_caps & IEEE80211_C_IBSS)
! 288: ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_IBSS);
! 289: if (ic->ic_caps & IEEE80211_C_HOSTAP)
! 290: ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
! 291: if (ic->ic_caps & IEEE80211_C_AHDEMO)
! 292: ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC);
! 293: if (ic->ic_caps & IEEE80211_C_MONITOR)
! 294: ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
! 295: if (mode == IEEE80211_MODE_AUTO)
! 296: continue;
! 297: rs = &ic->ic_sup_rates[mode];
! 298: for (i = 0; i < rs->rs_nrates; i++) {
! 299: rate = rs->rs_rates[i];
! 300: mword = ieee80211_rate2media(ic, rate, mode);
! 301: if (mword == 0)
! 302: continue;
! 303: ADD(ic, mword, mopt);
! 304: if (ic->ic_caps & IEEE80211_C_IBSS)
! 305: ADD(ic, mword, mopt | IFM_IEEE80211_IBSS);
! 306: if (ic->ic_caps & IEEE80211_C_HOSTAP)
! 307: ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
! 308: if (ic->ic_caps & IEEE80211_C_AHDEMO)
! 309: ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
! 310: if (ic->ic_caps & IEEE80211_C_MONITOR)
! 311: ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
! 312: /*
! 313: * Add rate to the collection of all rates.
! 314: */
! 315: r = rate & IEEE80211_RATE_VAL;
! 316: for (j = 0; j < allrates.rs_nrates; j++)
! 317: if (allrates.rs_rates[j] == r)
! 318: break;
! 319: if (j == allrates.rs_nrates) {
! 320: /* unique, add to the set */
! 321: allrates.rs_rates[j] = r;
! 322: allrates.rs_nrates++;
! 323: }
! 324: rate = (rate & IEEE80211_RATE_VAL) / 2;
! 325: if (rate > maxrate)
! 326: maxrate = rate;
! 327: }
! 328: }
! 329: for (i = 0; i < allrates.rs_nrates; i++) {
! 330: mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
! 331: IEEE80211_MODE_AUTO);
! 332: if (mword == 0)
! 333: continue;
! 334: mword = IFM_SUBTYPE(mword); /* remove media options */
! 335: ADD(ic, mword, 0);
! 336: if (ic->ic_caps & IEEE80211_C_IBSS)
! 337: ADD(ic, mword, IFM_IEEE80211_IBSS);
! 338: if (ic->ic_caps & IEEE80211_C_HOSTAP)
! 339: ADD(ic, mword, IFM_IEEE80211_HOSTAP);
! 340: if (ic->ic_caps & IEEE80211_C_AHDEMO)
! 341: ADD(ic, mword, IFM_IEEE80211_ADHOC);
! 342: if (ic->ic_caps & IEEE80211_C_MONITOR)
! 343: ADD(ic, mword, IFM_IEEE80211_MONITOR);
! 344: }
! 345: ieee80211_media_status(ifp, &imr);
! 346: ifmedia_set(&ic->ic_media, imr.ifm_active);
! 347:
! 348: if (maxrate)
! 349: ifp->if_baudrate = IF_Mbps(maxrate);
! 350:
! 351: #undef ADD
! 352: }
! 353:
! 354: int
! 355: ieee80211_findrate(struct ieee80211com *ic, enum ieee80211_phymode mode,
! 356: int rate)
! 357: {
! 358: #define IEEERATE(_ic,_m,_i) \
! 359: ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
! 360: int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
! 361: for (i = 0; i < nrates; i++)
! 362: if (IEEERATE(ic, mode, i) == rate)
! 363: return i;
! 364: return -1;
! 365: #undef IEEERATE
! 366: }
! 367:
! 368: /*
! 369: * Handle a media change request.
! 370: */
! 371: int
! 372: ieee80211_media_change(struct ifnet *ifp)
! 373: {
! 374: struct ieee80211com *ic = (void *)ifp;
! 375: struct ifmedia_entry *ime;
! 376: enum ieee80211_opmode newopmode;
! 377: enum ieee80211_phymode newphymode;
! 378: int i, j, newrate, error = 0;
! 379:
! 380: ime = ic->ic_media.ifm_cur;
! 381: /*
! 382: * First, identify the phy mode.
! 383: */
! 384: switch (IFM_MODE(ime->ifm_media)) {
! 385: case IFM_IEEE80211_11A:
! 386: newphymode = IEEE80211_MODE_11A;
! 387: break;
! 388: case IFM_IEEE80211_11B:
! 389: newphymode = IEEE80211_MODE_11B;
! 390: break;
! 391: case IFM_IEEE80211_11G:
! 392: newphymode = IEEE80211_MODE_11G;
! 393: break;
! 394: case IFM_IEEE80211_FH:
! 395: newphymode = IEEE80211_MODE_FH;
! 396: break;
! 397: case IFM_AUTO:
! 398: newphymode = IEEE80211_MODE_AUTO;
! 399: break;
! 400: default:
! 401: return EINVAL;
! 402: }
! 403: /*
! 404: * Turbo mode is an ``option''. Eventually it
! 405: * needs to be applied to 11g too.
! 406: */
! 407: if (ime->ifm_media & IFM_IEEE80211_TURBO) {
! 408: if (newphymode != IEEE80211_MODE_11A)
! 409: return EINVAL;
! 410: newphymode = IEEE80211_MODE_TURBO;
! 411: }
! 412: /*
! 413: * Validate requested mode is available.
! 414: */
! 415: if ((ic->ic_modecaps & (1<<newphymode)) == 0)
! 416: return EINVAL;
! 417:
! 418: /*
! 419: * Next, the fixed/variable rate.
! 420: */
! 421: i = -1;
! 422: if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
! 423: /*
! 424: * Convert media subtype to rate.
! 425: */
! 426: newrate = ieee80211_media2rate(ime->ifm_media);
! 427: if (newrate == 0)
! 428: return EINVAL;
! 429: /*
! 430: * Check the rate table for the specified/current phy.
! 431: */
! 432: if (newphymode == IEEE80211_MODE_AUTO) {
! 433: /*
! 434: * In autoselect mode search for the rate.
! 435: */
! 436: for (j = IEEE80211_MODE_11A;
! 437: j < IEEE80211_MODE_MAX; j++) {
! 438: if ((ic->ic_modecaps & (1<<j)) == 0)
! 439: continue;
! 440: i = ieee80211_findrate(ic, j, newrate);
! 441: if (i != -1) {
! 442: /* lock mode too */
! 443: newphymode = j;
! 444: break;
! 445: }
! 446: }
! 447: } else {
! 448: i = ieee80211_findrate(ic, newphymode, newrate);
! 449: }
! 450: if (i == -1) /* mode/rate mismatch */
! 451: return EINVAL;
! 452: }
! 453: /* NB: defer rate setting to later */
! 454:
! 455: /*
! 456: * Deduce new operating mode but don't install it just yet.
! 457: */
! 458: if (ime->ifm_media & IFM_IEEE80211_ADHOC)
! 459: newopmode = IEEE80211_M_AHDEMO;
! 460: else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
! 461: newopmode = IEEE80211_M_HOSTAP;
! 462: else if (ime->ifm_media & IFM_IEEE80211_IBSS)
! 463: newopmode = IEEE80211_M_IBSS;
! 464: else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
! 465: newopmode = IEEE80211_M_MONITOR;
! 466: else
! 467: newopmode = IEEE80211_M_STA;
! 468:
! 469: /*
! 470: * Autoselect doesn't make sense when operating as an AP.
! 471: * If no phy mode has been selected, pick one and lock it
! 472: * down so rate tables can be used in forming beacon frames
! 473: * and the like.
! 474: */
! 475: if (newopmode == IEEE80211_M_HOSTAP &&
! 476: newphymode == IEEE80211_MODE_AUTO) {
! 477: for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
! 478: if (ic->ic_modecaps & (1<<j)) {
! 479: newphymode = j;
! 480: break;
! 481: }
! 482: }
! 483:
! 484: /*
! 485: * Handle phy mode change.
! 486: */
! 487: if (ic->ic_curmode != newphymode) { /* change phy mode */
! 488: error = ieee80211_setmode(ic, newphymode);
! 489: if (error != 0)
! 490: return error;
! 491: error = ENETRESET;
! 492: }
! 493:
! 494: /*
! 495: * Committed to changes, install the rate setting.
! 496: */
! 497: if (ic->ic_fixed_rate != i) {
! 498: ic->ic_fixed_rate = i; /* set fixed tx rate */
! 499: error = ENETRESET;
! 500: }
! 501:
! 502: /*
! 503: * Handle operating mode change.
! 504: */
! 505: if (ic->ic_opmode != newopmode) {
! 506: ic->ic_opmode = newopmode;
! 507: switch (newopmode) {
! 508: case IEEE80211_M_AHDEMO:
! 509: case IEEE80211_M_HOSTAP:
! 510: case IEEE80211_M_STA:
! 511: case IEEE80211_M_MONITOR:
! 512: ic->ic_flags &= ~IEEE80211_F_IBSSON;
! 513: break;
! 514: case IEEE80211_M_IBSS:
! 515: ic->ic_flags |= IEEE80211_F_IBSSON;
! 516: break;
! 517: }
! 518: /*
! 519: * Yech, slot time may change depending on the
! 520: * operating mode so reset it to be sure everything
! 521: * is setup appropriately.
! 522: */
! 523: ieee80211_reset_erp(ic);
! 524: error = ENETRESET;
! 525: }
! 526: #ifdef notdef
! 527: if (error == 0)
! 528: ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
! 529: #endif
! 530: return error;
! 531: }
! 532:
! 533: void
! 534: ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
! 535: {
! 536: struct ieee80211com *ic = (void *)ifp;
! 537: const struct ieee80211_node *ni = NULL;
! 538:
! 539: imr->ifm_status = IFM_AVALID;
! 540: imr->ifm_active = IFM_IEEE80211;
! 541: if (ic->ic_state == IEEE80211_S_RUN)
! 542: imr->ifm_status |= IFM_ACTIVE;
! 543: imr->ifm_active |= IFM_AUTO;
! 544: switch (ic->ic_opmode) {
! 545: case IEEE80211_M_STA:
! 546: ni = ic->ic_bss;
! 547: /* calculate rate subtype */
! 548: imr->ifm_active |= ieee80211_rate2media(ic,
! 549: ni->ni_rates.rs_rates[ni->ni_txrate], ic->ic_curmode);
! 550: break;
! 551: case IEEE80211_M_IBSS:
! 552: imr->ifm_active |= IFM_IEEE80211_IBSS;
! 553: break;
! 554: case IEEE80211_M_AHDEMO:
! 555: imr->ifm_active |= IFM_IEEE80211_ADHOC;
! 556: break;
! 557: case IEEE80211_M_HOSTAP:
! 558: imr->ifm_active |= IFM_IEEE80211_HOSTAP;
! 559: break;
! 560: case IEEE80211_M_MONITOR:
! 561: imr->ifm_active |= IFM_IEEE80211_MONITOR;
! 562: break;
! 563: }
! 564: switch (ic->ic_curmode) {
! 565: case IEEE80211_MODE_11A:
! 566: imr->ifm_active |= IFM_IEEE80211_11A;
! 567: break;
! 568: case IEEE80211_MODE_11B:
! 569: imr->ifm_active |= IFM_IEEE80211_11B;
! 570: break;
! 571: case IEEE80211_MODE_11G:
! 572: imr->ifm_active |= IFM_IEEE80211_11G;
! 573: break;
! 574: case IEEE80211_MODE_FH:
! 575: imr->ifm_active |= IFM_IEEE80211_FH;
! 576: break;
! 577: case IEEE80211_MODE_TURBO:
! 578: imr->ifm_active |= IFM_IEEE80211_11A
! 579: | IFM_IEEE80211_TURBO;
! 580: break;
! 581: }
! 582: }
! 583:
! 584: void
! 585: ieee80211_watchdog(struct ifnet *ifp)
! 586: {
! 587: struct ieee80211com *ic = (void *)ifp;
! 588:
! 589: if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
! 590: ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
! 591:
! 592: if (ic->ic_mgt_timer != 0)
! 593: ifp->if_timer = 1;
! 594: }
! 595:
! 596: const struct ieee80211_rateset ieee80211_std_rateset_11a =
! 597: { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
! 598:
! 599: const struct ieee80211_rateset ieee80211_std_rateset_11b =
! 600: { 4, { 2, 4, 11, 22 } };
! 601:
! 602: const struct ieee80211_rateset ieee80211_std_rateset_11g =
! 603: { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
! 604:
! 605: /*
! 606: * Mark the basic rates for the 11g rate table based on the
! 607: * operating mode. For real 11g we mark all the 11b rates
! 608: * and 6, 12, and 24 OFDM. For 11b compatibility we mark only
! 609: * 11b rates. There's also a pseudo 11a-mode used to mark only
! 610: * the basic OFDM rates.
! 611: */
! 612: void
! 613: ieee80211_setbasicrates(struct ieee80211com *ic)
! 614: {
! 615: static const struct ieee80211_rateset basic[] = {
! 616: { 0 }, /* IEEE80211_MODE_AUTO */
! 617: { 3, { 12, 24, 48 } }, /* IEEE80211_MODE_11A */
! 618: { 2, { 2, 4 } }, /* IEEE80211_MODE_11B */
! 619: { 4, { 2, 4, 11, 22 } }, /* IEEE80211_MODE_11G */
! 620: { 2, { 2, 4 } }, /* IEEE80211_MODE_FH */
! 621: { 0 }, /* IEEE80211_MODE_TURBO */
! 622: };
! 623: enum ieee80211_phymode mode;
! 624: struct ieee80211_rateset *rs;
! 625: int i, j;
! 626:
! 627: for (mode = 0; mode < IEEE80211_MODE_MAX; mode++) {
! 628: rs = &ic->ic_sup_rates[mode];
! 629: for (i = 0; i < rs->rs_nrates; i++) {
! 630: rs->rs_rates[i] &= IEEE80211_RATE_VAL;
! 631: for (j = 0; j < basic[mode].rs_nrates; j++) {
! 632: if (basic[mode].rs_rates[j] ==
! 633: rs->rs_rates[i]) {
! 634: rs->rs_rates[i] |=
! 635: IEEE80211_RATE_BASIC;
! 636: break;
! 637: }
! 638: }
! 639: }
! 640: }
! 641: }
! 642:
! 643: /*
! 644: * Set the current phy mode and recalculate the active channel
! 645: * set based on the available channels for this mode. Also
! 646: * select a new default/current channel if the current one is
! 647: * inappropriate for this mode.
! 648: */
! 649: int
! 650: ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
! 651: {
! 652: #define N(a) (sizeof(a) / sizeof(a[0]))
! 653: struct ifnet *ifp = &ic->ic_if;
! 654: static const u_int chanflags[] = {
! 655: 0, /* IEEE80211_MODE_AUTO */
! 656: IEEE80211_CHAN_A, /* IEEE80211_MODE_11A */
! 657: IEEE80211_CHAN_B, /* IEEE80211_MODE_11B */
! 658: IEEE80211_CHAN_PUREG, /* IEEE80211_MODE_11G */
! 659: IEEE80211_CHAN_FHSS, /* IEEE80211_MODE_FH */
! 660: IEEE80211_CHAN_T, /* IEEE80211_MODE_TURBO */
! 661: };
! 662: const struct ieee80211_channel *c;
! 663: u_int modeflags;
! 664: int i;
! 665:
! 666: /* validate new mode */
! 667: if ((ic->ic_modecaps & (1<<mode)) == 0) {
! 668: IEEE80211_DPRINTF(("%s: mode %u not supported (caps 0x%x)\n",
! 669: __func__, mode, ic->ic_modecaps));
! 670: return EINVAL;
! 671: }
! 672:
! 673: /*
! 674: * Verify at least one channel is present in the available
! 675: * channel list before committing to the new mode.
! 676: */
! 677: if (mode >= N(chanflags))
! 678: panic("Unexpected mode %u", mode);
! 679: modeflags = chanflags[mode];
! 680: for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
! 681: c = &ic->ic_channels[i];
! 682: if (mode == IEEE80211_MODE_AUTO) {
! 683: /* ignore turbo channels for autoselect */
! 684: if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
! 685: break;
! 686: } else {
! 687: if ((c->ic_flags & modeflags) == modeflags)
! 688: break;
! 689: }
! 690: }
! 691: if (i > IEEE80211_CHAN_MAX) {
! 692: IEEE80211_DPRINTF(("%s: no channels found for mode %u\n",
! 693: __func__, mode));
! 694: return EINVAL;
! 695: }
! 696:
! 697: /*
! 698: * Calculate the active channel set.
! 699: */
! 700: memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
! 701: for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
! 702: c = &ic->ic_channels[i];
! 703: if (mode == IEEE80211_MODE_AUTO) {
! 704: /* take anything but pure turbo channels */
! 705: if ((c->ic_flags &~ IEEE80211_CHAN_TURBO) != 0)
! 706: setbit(ic->ic_chan_active, i);
! 707: } else {
! 708: if ((c->ic_flags & modeflags) == modeflags)
! 709: setbit(ic->ic_chan_active, i);
! 710: }
! 711: }
! 712: /*
! 713: * If no current/default channel is setup or the current
! 714: * channel is wrong for the mode then pick the first
! 715: * available channel from the active list. This is likely
! 716: * not the right one.
! 717: */
! 718: if (ic->ic_ibss_chan == NULL || isclr(ic->ic_chan_active,
! 719: ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
! 720: for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
! 721: if (isset(ic->ic_chan_active, i)) {
! 722: ic->ic_ibss_chan = &ic->ic_channels[i];
! 723: break;
! 724: }
! 725: if ((ic->ic_ibss_chan == NULL) || isclr(ic->ic_chan_active,
! 726: ieee80211_chan2ieee(ic, ic->ic_ibss_chan)))
! 727: panic("Bad IBSS channel %u\n",
! 728: ieee80211_chan2ieee(ic, ic->ic_ibss_chan));
! 729: }
! 730:
! 731: /*
! 732: * Reset the scan state for the new mode. This avoids scanning
! 733: * of invalid channels, ie. 5GHz channels in 11b mode.
! 734: */
! 735: ieee80211_reset_scan(ifp);
! 736:
! 737: ic->ic_curmode = mode;
! 738: ieee80211_reset_erp(ic); /* reset ERP state */
! 739:
! 740: return 0;
! 741: #undef N
! 742: }
! 743:
! 744: enum ieee80211_phymode
! 745: ieee80211_next_mode(struct ifnet *ifp)
! 746: {
! 747: struct ieee80211com *ic = (void *)ifp;
! 748:
! 749: if (IFM_MODE(ic->ic_media.ifm_cur->ifm_media) != IFM_AUTO) {
! 750: /*
! 751: * Reset the scan state and indicate a wrap around
! 752: * if we're running in a fixed, user-specified phy mode.
! 753: */
! 754: ieee80211_reset_scan(ifp);
! 755: return (IEEE80211_MODE_AUTO);
! 756: }
! 757:
! 758: /*
! 759: * Get the next supported mode
! 760: */
! 761: for (++ic->ic_curmode;
! 762: ic->ic_curmode <= IEEE80211_MODE_TURBO;
! 763: ic->ic_curmode++) {
! 764: /* Wrap around and ignore turbo mode */
! 765: if (ic->ic_curmode >= IEEE80211_MODE_TURBO) {
! 766: ic->ic_curmode = IEEE80211_MODE_AUTO;
! 767: break;
! 768: }
! 769:
! 770: if (ic->ic_modecaps & (1 << ic->ic_curmode))
! 771: break;
! 772: }
! 773:
! 774: ieee80211_setmode(ic, ic->ic_curmode);
! 775:
! 776: return (ic->ic_curmode);
! 777: }
! 778:
! 779: /*
! 780: * Return the phy mode for with the specified channel so the
! 781: * caller can select a rate set. This is problematic and the
! 782: * work here assumes how things work elsewhere in this code.
! 783: *
! 784: * XXX never returns turbo modes -dcy
! 785: */
! 786: enum ieee80211_phymode
! 787: ieee80211_chan2mode(struct ieee80211com *ic,
! 788: const struct ieee80211_channel *chan)
! 789: {
! 790: /*
! 791: * NB: this assumes the channel would not be supplied to us
! 792: * unless it was already compatible with the current mode.
! 793: */
! 794: if (ic->ic_curmode != IEEE80211_MODE_AUTO ||
! 795: chan == IEEE80211_CHAN_ANYC)
! 796: return ic->ic_curmode;
! 797: /*
! 798: * In autoselect mode; deduce a mode based on the channel
! 799: * characteristics. We assume that turbo-only channels
! 800: * are not considered when the channel set is constructed.
! 801: */
! 802: if (IEEE80211_IS_CHAN_T(chan))
! 803: return IEEE80211_MODE_TURBO;
! 804: else if (IEEE80211_IS_CHAN_5GHZ(chan))
! 805: return IEEE80211_MODE_11A;
! 806: else if (IEEE80211_IS_CHAN_FHSS(chan))
! 807: return IEEE80211_MODE_FH;
! 808: else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN))
! 809: return IEEE80211_MODE_11G;
! 810: else
! 811: return IEEE80211_MODE_11B;
! 812: }
! 813:
! 814: /*
! 815: * convert IEEE80211 rate value to ifmedia subtype.
! 816: * ieee80211 rate is in unit of 0.5Mbps.
! 817: */
! 818: int
! 819: ieee80211_rate2media(struct ieee80211com *ic, int rate,
! 820: enum ieee80211_phymode mode)
! 821: {
! 822: #define N(a) (sizeof(a) / sizeof(a[0]))
! 823: static const struct {
! 824: u_int m; /* rate + mode */
! 825: u_int r; /* if_media rate */
! 826: } rates[] = {
! 827: { 2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
! 828: { 4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
! 829: { 2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
! 830: { 4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
! 831: { 11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
! 832: { 22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
! 833: { 44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
! 834: { 12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
! 835: { 18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
! 836: { 24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
! 837: { 36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
! 838: { 48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
! 839: { 72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
! 840: { 96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
! 841: { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
! 842: { 2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
! 843: { 4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
! 844: { 11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
! 845: { 22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
! 846: { 12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
! 847: { 18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
! 848: { 24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
! 849: { 36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
! 850: { 48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
! 851: { 72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
! 852: { 96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
! 853: { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
! 854: /* NB: OFDM72 doesn't realy exist so we don't handle it */
! 855: };
! 856: u_int mask, i;
! 857:
! 858: mask = rate & IEEE80211_RATE_VAL;
! 859: switch (mode) {
! 860: case IEEE80211_MODE_11A:
! 861: case IEEE80211_MODE_TURBO:
! 862: mask |= IFM_IEEE80211_11A;
! 863: break;
! 864: case IEEE80211_MODE_11B:
! 865: mask |= IFM_IEEE80211_11B;
! 866: break;
! 867: case IEEE80211_MODE_FH:
! 868: mask |= IFM_IEEE80211_FH;
! 869: break;
! 870: case IEEE80211_MODE_AUTO:
! 871: /* NB: ic may be NULL for some drivers */
! 872: if (ic && ic->ic_phytype == IEEE80211_T_FH) {
! 873: mask |= IFM_IEEE80211_FH;
! 874: break;
! 875: }
! 876: /* NB: hack, 11g matches both 11b+11a rates */
! 877: /* FALLTHROUGH */
! 878: case IEEE80211_MODE_11G:
! 879: mask |= IFM_IEEE80211_11G;
! 880: break;
! 881: }
! 882: for (i = 0; i < N(rates); i++)
! 883: if (rates[i].m == mask)
! 884: return rates[i].r;
! 885: return IFM_AUTO;
! 886: #undef N
! 887: }
! 888:
! 889: int
! 890: ieee80211_media2rate(int mword)
! 891: {
! 892: #define N(a) (sizeof(a) / sizeof(a[0]))
! 893: int i;
! 894: static const struct {
! 895: int subtype;
! 896: int rate;
! 897: } ieeerates[] = {
! 898: { IFM_AUTO, -1 },
! 899: { IFM_MANUAL, 0 },
! 900: { IFM_NONE, 0 },
! 901: { IFM_IEEE80211_FH1, 2 },
! 902: { IFM_IEEE80211_FH2, 4 },
! 903: { IFM_IEEE80211_DS1, 2 },
! 904: { IFM_IEEE80211_DS2, 4 },
! 905: { IFM_IEEE80211_DS5, 11 },
! 906: { IFM_IEEE80211_DS11, 22 },
! 907: { IFM_IEEE80211_DS22, 44 },
! 908: { IFM_IEEE80211_OFDM6, 12 },
! 909: { IFM_IEEE80211_OFDM9, 18 },
! 910: { IFM_IEEE80211_OFDM12, 24 },
! 911: { IFM_IEEE80211_OFDM18, 36 },
! 912: { IFM_IEEE80211_OFDM24, 48 },
! 913: { IFM_IEEE80211_OFDM36, 72 },
! 914: { IFM_IEEE80211_OFDM48, 96 },
! 915: { IFM_IEEE80211_OFDM54, 108 },
! 916: { IFM_IEEE80211_OFDM72, 144 },
! 917: };
! 918: for (i = 0; i < N(ieeerates); i++) {
! 919: if (ieeerates[i].subtype == IFM_SUBTYPE(mword))
! 920: return ieeerates[i].rate;
! 921: }
! 922: return 0;
! 923: #undef N
! 924: }
CVSweb