The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: ieee80211.c,v 1.61 2021/08/21 11:55:25 andvar Exp $    */
    2 /*-
    3  * Copyright (c) 2001 Atsushi Onoe
    4  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * Alternatively, this software may be distributed under the terms of the
   19  * GNU General Public License ("GPL") version 2 as published by the Free
   20  * Software Foundation.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 #ifdef __FreeBSD__
   36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211.c,v 1.22 2005/08/10 16:22:29 sam Exp $");
   37 #endif
   38 #ifdef __NetBSD__
   39 __KERNEL_RCSID(0, "$NetBSD: ieee80211.c,v 1.61 2021/08/21 11:55:25 andvar Exp $");
   40 #endif
   41 
   42 /*
   43  * IEEE 802.11 generic handler
   44  */
   45 
   46 #ifdef _KERNEL_OPT
   47 #include "opt_inet.h"
   48 #endif
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h> 
   52 #include <sys/kernel.h>
   53  
   54 #include <sys/socket.h>
   55 #include <sys/sockio.h>
   56 #include <sys/endian.h>
   57 #include <sys/errno.h>
   58 #include <sys/proc.h>
   59 #include <sys/sysctl.h>
   60 
   61 #include <net/if.h>
   62 #include <net/if_media.h>
   63 #include <net/if_arp.h>
   64 #include <net/if_ether.h>
   65 #include <net/if_llc.h>
   66 
   67 #include <net80211/ieee80211_netbsd.h>
   68 #include <net80211/ieee80211_var.h>
   69 #include <net80211/ieee80211_sysctl.h>
   70 
   71 #include <net/bpf.h>
   72 
   73 #ifdef INET
   74 #include <netinet/in.h> 
   75 #include <net/if_ether.h>
   76 #endif
   77 
   78 const struct ieee80211_channel ieee80211_channel_anyc = {
   79         0, 0
   80 };
   81 
   82 struct ieee80211com_head ieee80211com_head =
   83     LIST_HEAD_INITIALIZER(ieee80211com_head);
   84 
   85 const char *ieee80211_phymode_name[] = {
   86         "auto",         /* IEEE80211_MODE_AUTO */
   87         "11a",          /* IEEE80211_MODE_11A */
   88         "11b",          /* IEEE80211_MODE_11B */
   89         "11g",          /* IEEE80211_MODE_11G */
   90         "FH",           /* IEEE80211_MODE_FH */
   91         "turboA",       /* IEEE80211_MODE_TURBO_A */
   92         "turboG",       /* IEEE80211_MODE_TURBO_G */
   93 };
   94 
   95 /* list of all instances */
   96 SLIST_HEAD(ieee80211_list, ieee80211com);
   97 static struct ieee80211_list ieee80211_list =
   98         SLIST_HEAD_INITIALIZER(ieee80211_list);
   99 static u_int8_t ieee80211_vapmap[32];           /* enough for 256 */
  100 
  101 static void
  102 ieee80211_add_vap(struct ieee80211com *ic)
  103 {
  104 #define N(a)    (sizeof(a)/sizeof(a[0]))
  105         int i;
  106         int s;
  107         u_int8_t b;
  108 
  109         s = splnet();
  110         ic->ic_vap = 0;
  111         for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++)
  112                 ic->ic_vap += NBBY;
  113         if (i == N(ieee80211_vapmap))
  114                 panic("vap table full");
  115         for (b = ieee80211_vapmap[i]; b & 1; b >>= 1)
  116                 ic->ic_vap++;
  117         setbit(ieee80211_vapmap, ic->ic_vap);
  118         SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next);
  119         splx(s);
  120 #undef N
  121 }
  122 
  123 static void
  124 ieee80211_remove_vap(struct ieee80211com *ic)
  125 {
  126         int s;
  127 
  128         s = splnet();
  129         SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next);
  130         IASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY,
  131                 ("invalid vap id %d", ic->ic_vap));
  132         IASSERT(isset(ieee80211_vapmap, ic->ic_vap),
  133                 ("vap id %d not allocated", ic->ic_vap));
  134         clrbit(ieee80211_vapmap, ic->ic_vap);
  135         splx(s);
  136 }
  137 
  138 /*
  139  * Default reset method for use with the ioctl support.  This
  140  * method is invoked after any state change in the 802.11
  141  * layer that should be propagated to the hardware but not
  142  * require re-initialization of the 802.11 state machine (e.g
  143  * rescanning for an ap).  We always return ENETRESET which
  144  * should cause the driver to re-initialize the device. Drivers
  145  * can override this method to implement more optimized support.
  146  */
  147 static int
  148 ieee80211_default_reset(struct ifnet *ifp)
  149 {
  150         return ENETRESET;
  151 }
  152 
  153 static void
  154 ieee80211_init_link_state(struct ieee80211com *ic)
  155 {
  156         struct ifnet *ifp = ic->ic_ifp;
  157 
  158         /*
  159          * Link state does not make sense in IBSS or HOSTAP modes.
  160          * We know that the link in MONITOR mode is DOWN as we cannot
  161          * transmit, only monitor.
  162          * That leaves BSS mode, which starts off DOWN and will
  163          * transition to UP when it joins a node.
  164          */
  165         switch (ic->ic_opmode) {
  166         case IEEE80211_M_AHDEMO:
  167         case IEEE80211_M_HOSTAP:
  168         case IEEE80211_M_IBSS:
  169                 if_link_state_change(ifp, LINK_STATE_UNKNOWN);
  170                 break;
  171         default:
  172                 if_link_state_change(ifp, LINK_STATE_DOWN);
  173                 break;
  174         }
  175 }
  176 
  177 void
  178 ieee80211_ifattach(struct ieee80211com *ic)
  179 {
  180         struct ifnet *ifp = ic->ic_ifp;
  181         struct ieee80211_channel *c;
  182         int i;
  183 
  184 #ifdef __NetBSD__
  185         ieee80211_init();
  186 #endif /* __NetBSD__ */
  187 
  188         ether_ifattach(ifp, ic->ic_myaddr);
  189         bpf_attach2(ifp, DLT_IEEE802_11,
  190             sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
  191 
  192         ieee80211_crypto_attach(ic);
  193 
  194         /*
  195          * Fill in 802.11 available channel set, mark
  196          * all available channels as active, and pick
  197          * a default channel if not already specified.
  198          */
  199         memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
  200         ic->ic_modecaps |= 1<<IEEE80211_MODE_AUTO;
  201         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
  202                 c = &ic->ic_channels[i];
  203                 if (c->ic_flags) {
  204                         /*
  205                          * Verify driver passed us valid data.
  206                          */
  207                         if (i != ieee80211_chan2ieee(ic, c)) {
  208                                 if_printf(ifp, "bad channel ignored; "
  209                                         "freq %u flags %x number %u\n",
  210                                         c->ic_freq, c->ic_flags, i);
  211                                 c->ic_flags = 0;        /* NB: remove */
  212                                 continue;
  213                         }
  214                         setbit(ic->ic_chan_avail, i);
  215                         /*
  216                          * Identify mode capabilities.
  217                          */
  218                         if (IEEE80211_IS_CHAN_A(c))
  219                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_11A;
  220                         if (IEEE80211_IS_CHAN_B(c))
  221                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_11B;
  222                         if (IEEE80211_IS_CHAN_PUREG(c))
  223                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_11G;
  224                         if (IEEE80211_IS_CHAN_FHSS(c))
  225                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_FH;
  226                         if (IEEE80211_IS_CHAN_T(c))
  227                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_A;
  228                         if (IEEE80211_IS_CHAN_108G(c))
  229                                 ic->ic_modecaps |= 1<<IEEE80211_MODE_TURBO_G;
  230                         if (ic->ic_curchan == NULL) {
  231                                 /* arbitrarily pick the first channel */
  232                                 ic->ic_curchan = &ic->ic_channels[i];
  233                         }
  234                 }
  235         }
  236         /* validate ic->ic_curmode */
  237         if ((ic->ic_modecaps & (1<<ic->ic_curmode)) == 0)
  238                 ic->ic_curmode = IEEE80211_MODE_AUTO;
  239         ic->ic_des_chan = IEEE80211_CHAN_ANYC;  /* any channel is ok */
  240 #if 0
  241         /*
  242          * Enable WME by default if we're capable.
  243          */
  244         if (ic->ic_caps & IEEE80211_C_WME)
  245                 ic->ic_flags |= IEEE80211_F_WME;
  246 #endif
  247         (void) ieee80211_setmode(ic, ic->ic_curmode);
  248 
  249         if (ic->ic_bintval == 0)
  250                 ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
  251         ic->ic_bmisstimeout = 7*ic->ic_bintval; /* default 7 beacons */
  252         ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT;
  253         IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
  254 
  255         if (ic->ic_lintval == 0)
  256                 ic->ic_lintval = ic->ic_bintval;
  257         ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
  258 
  259         LIST_INSERT_HEAD(&ieee80211com_head, ic, ic_list);
  260         ieee80211_node_attach(ic);
  261         ieee80211_proto_attach(ic);
  262 
  263         ieee80211_add_vap(ic);
  264 
  265         ieee80211_sysctl_attach(ic);            /* NB: requires ic_vap */
  266 
  267         /*
  268          * Install a default reset method for the ioctl support.
  269          * The driver is expected to fill this in before calling us.
  270          */
  271         if (ic->ic_reset == NULL)
  272                 ic->ic_reset = ieee80211_default_reset;
  273 
  274         ieee80211_init_link_state(ic);
  275 }
  276 
  277 void
  278 ieee80211_ifdetach(struct ieee80211com *ic)
  279 {
  280         struct ifnet *ifp = ic->ic_ifp;
  281 
  282         ieee80211_remove_vap(ic);
  283 
  284         ieee80211_sysctl_detach(ic);
  285         ieee80211_proto_detach(ic);
  286         ieee80211_crypto_detach(ic);
  287         ieee80211_node_detach(ic);
  288         LIST_REMOVE(ic, ic_list);
  289         ifmedia_fini(&ic->ic_media);
  290 
  291         IEEE80211_BEACON_LOCK_DESTROY(ic);
  292 
  293         bpf_detach(ifp);
  294         ether_ifdetach(ifp);
  295 }
  296 
  297 /*
  298  * Convert MHz frequency to IEEE channel number.
  299  */
  300 u_int
  301 ieee80211_mhz2ieee(u_int freq, u_int flags)
  302 {
  303         if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
  304                 if (freq == 2484)
  305                         return 14;
  306                 if (freq < 2484)
  307                         return (freq - 2407) / 5;
  308                 else
  309                         return 15 + ((freq - 2512) / 20);
  310         } else if (flags & IEEE80211_CHAN_5GHZ) {       /* 5 GHz band */
  311                 return (freq - 5000) / 5;
  312         } else {                                /* either, guess */
  313                 if (freq == 2484)
  314                         return 14;
  315                 if (freq < 2484)
  316                         return (freq - 2407) / 5;
  317                 if (freq < 5000)
  318                         return 15 + ((freq - 2512) / 20);
  319                 return (freq - 5000) / 5;
  320         }
  321 }
  322 
  323 /*
  324  * Convert channel to IEEE channel number.
  325  */
  326 u_int
  327 ieee80211_chan2ieee(struct ieee80211com *ic, struct ieee80211_channel *c)
  328 {
  329         if (ic->ic_channels <= c && c <= &ic->ic_channels[IEEE80211_CHAN_MAX])
  330                 return c - ic->ic_channels;
  331         else if (c == IEEE80211_CHAN_ANYC)
  332                 return IEEE80211_CHAN_ANY;
  333         else if (c != NULL) {
  334                 if_printf(ic->ic_ifp, "invalid channel freq %u flags %x\n",
  335                         c->ic_freq, c->ic_flags);
  336                 return 0;               /* XXX */
  337         } else {
  338                 if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
  339                 return 0;               /* XXX */
  340         }
  341 }
  342 
  343 /*
  344  * Convert IEEE channel number to MHz frequency.
  345  */
  346 u_int
  347 ieee80211_ieee2mhz(u_int chan, u_int flags)
  348 {
  349         if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
  350                 if (chan == 14)
  351                         return 2484;
  352                 if (chan < 14)
  353                         return 2407 + chan*5;
  354                 else
  355                         return 2512 + ((chan-15)*20);
  356         } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5 GHz band */
  357                 return 5000 + (chan*5);
  358         } else {                                /* either, guess */
  359                 if (chan == 14)
  360                         return 2484;
  361                 if (chan < 14)                  /* 0-13 */
  362                         return 2407 + chan*5;
  363                 if (chan < 27)                  /* 15-26 */
  364                         return 2512 + ((chan-15)*20);
  365                 return 5000 + (chan*5);
  366         }
  367 }
  368 
  369 /*
  370  * Setup the media data structures according to the channel and
  371  * rate tables.  This must be called by the driver after
  372  * ieee80211_attach and before most anything else.
  373  */
  374 void
  375 ieee80211_media_init_with_lock(struct ieee80211com *ic,
  376         ifm_change_cb_t media_change, ifm_stat_cb_t media_stat,
  377         ieee80211_media_lock_t *lock)
  378 {
  379 #define ADD(_ic, _s, _o) \
  380         ifmedia_add(&(_ic)->ic_media, \
  381                 IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
  382         struct ifnet *ifp = ic->ic_ifp;
  383         struct ifmediareq imr;
  384         int i, j, mode, rate, maxrate, mword, mopt, r;
  385         const struct ieee80211_rateset *rs;
  386         struct ieee80211_rateset allrates;
  387 
  388         /*
  389          * Do late attach work that must wait for any subclass
  390          * (i.e. driver) work such as overriding methods.
  391          */
  392         ieee80211_node_lateattach(ic);
  393 
  394 #ifdef IEEE80211_NO_HOSTAP
  395         ic->ic_caps &= ~IEEE80211_C_HOSTAP;
  396 #endif /* IEEE80211_NO_HOSTAP */
  397 
  398         /*
  399          * Fill in media characteristics.
  400          */
  401         ifmedia_init_with_lock(&ic->ic_media, 0,
  402             media_change, media_stat, lock);
  403         maxrate = 0;
  404         memset(&allrates, 0, sizeof(allrates));
  405         for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_MAX; mode++) {
  406                 static const u_int mopts[] = { 
  407                         IFM_AUTO,
  408                         IFM_IEEE80211_11A,
  409                         IFM_IEEE80211_11B,
  410                         IFM_IEEE80211_11G,
  411                         IFM_IEEE80211_FH,
  412                         IFM_IEEE80211_11A | IFM_IEEE80211_TURBO,
  413                         IFM_IEEE80211_11G | IFM_IEEE80211_TURBO,
  414                 };
  415                 if ((ic->ic_modecaps & (1<<mode)) == 0)
  416                         continue;
  417                 mopt = mopts[mode];
  418                 ADD(ic, IFM_AUTO, mopt);        /* e.g. 11a auto */
  419                 if (ic->ic_caps & IEEE80211_C_IBSS)
  420                         ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC);
  421                 if (ic->ic_caps & IEEE80211_C_HOSTAP)
  422                         ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_HOSTAP);
  423                 if (ic->ic_caps & IEEE80211_C_AHDEMO)
  424                         ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
  425                 if (ic->ic_caps & IEEE80211_C_MONITOR)
  426                         ADD(ic, IFM_AUTO, mopt | IFM_IEEE80211_MONITOR);
  427                 if (mode == IEEE80211_MODE_AUTO)
  428                         continue;
  429                 rs = &ic->ic_sup_rates[mode];
  430                 for (i = 0; i < rs->rs_nrates; i++) {
  431                         rate = rs->rs_rates[i];
  432                         mword = ieee80211_rate2media(ic, rate, mode);
  433                         if (mword == 0)
  434                                 continue;
  435                         ADD(ic, mword, mopt);
  436                         if (ic->ic_caps & IEEE80211_C_IBSS)
  437                                 ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
  438                         if (ic->ic_caps & IEEE80211_C_HOSTAP)
  439                                 ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
  440                         if (ic->ic_caps & IEEE80211_C_AHDEMO)
  441                                 ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
  442                         if (ic->ic_caps & IEEE80211_C_MONITOR)
  443                                 ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
  444                         /*
  445                          * Add rate to the collection of all rates.
  446                          */
  447                         r = rate & IEEE80211_RATE_VAL;
  448                         for (j = 0; j < allrates.rs_nrates; j++)
  449                                 if (allrates.rs_rates[j] == r)
  450                                         break;
  451                         if (j == allrates.rs_nrates) {
  452                                 /* unique, add to the set */
  453                                 allrates.rs_rates[j] = r;
  454                                 allrates.rs_nrates++;
  455                         }
  456                         rate = (rate & IEEE80211_RATE_VAL) / 2;
  457                         if (rate > maxrate)
  458                                 maxrate = rate;
  459                 }
  460         }
  461         for (i = 0; i < allrates.rs_nrates; i++) {
  462                 mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
  463                                 IEEE80211_MODE_AUTO);
  464                 if (mword == 0)
  465                         continue;
  466                 mword = IFM_SUBTYPE(mword);     /* remove media options */
  467                 ADD(ic, mword, 0);
  468                 if (ic->ic_caps & IEEE80211_C_IBSS)
  469                         ADD(ic, mword, IFM_IEEE80211_ADHOC);
  470                 if (ic->ic_caps & IEEE80211_C_HOSTAP)
  471                         ADD(ic, mword, IFM_IEEE80211_HOSTAP);
  472                 if (ic->ic_caps & IEEE80211_C_AHDEMO)
  473                         ADD(ic, mword, IFM_IEEE80211_ADHOC | IFM_FLAG0);
  474                 if (ic->ic_caps & IEEE80211_C_MONITOR)
  475                         ADD(ic, mword, IFM_IEEE80211_MONITOR);
  476         }
  477         ieee80211_media_status(ifp, &imr);
  478         ifmedia_set(&ic->ic_media, imr.ifm_active);
  479 
  480         if (maxrate)
  481                 ifp->if_baudrate = IF_Mbps(maxrate);
  482 #undef ADD
  483 }
  484 
  485 void
  486 ieee80211_media_init(struct ieee80211com *ic,
  487         ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
  488 {
  489 
  490         ieee80211_media_init_with_lock(ic, media_change, media_stat, NULL);
  491 }
  492 
  493 void
  494 ieee80211_announce(struct ieee80211com *ic)
  495 {
  496         struct ifnet *ifp = ic->ic_ifp;
  497         int i, mode, rate, mword;
  498         struct ieee80211_rateset *rs;
  499 
  500         for (mode = IEEE80211_MODE_11A; mode < IEEE80211_MODE_MAX; mode++) {
  501                 if ((ic->ic_modecaps & (1<<mode)) == 0)
  502                         continue;
  503                 aprint_debug("%s: %s rates: ", ifp->if_xname,
  504                     ieee80211_phymode_name[mode]);
  505                 rs = &ic->ic_sup_rates[mode];
  506                 for (i = 0; i < rs->rs_nrates; i++) {
  507                         rate = rs->rs_rates[i];
  508                         mword = ieee80211_rate2media(ic, rate, mode);
  509                         if (mword == 0)
  510                                 continue;
  511                         aprint_debug("%s%d%sMbps", (i != 0 ? " " : ""),
  512                             (rate & IEEE80211_RATE_VAL) / 2,
  513                             ((rate & 0x1) != 0 ? ".5" : ""));
  514                 }
  515                 aprint_debug("\n");
  516         }
  517 }
  518 
  519 static int
  520 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  521 {
  522 #define IEEERATE(_ic,_m,_i) \
  523         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
  524         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
  525         for (i = 0; i < nrates; i++)
  526                 if (IEEERATE(ic, mode, i) == rate)
  527                         return i;
  528         return -1;
  529 #undef IEEERATE
  530 }
  531 
  532 /*
  533  * Find an instance by its mac address.
  534  */
  535 struct ieee80211com *
  536 ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN])
  537 {
  538         int s;
  539         struct ieee80211com *ic;
  540 
  541         s = splnet();
  542         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  543                 if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
  544                         break;
  545         splx(s);
  546         return ic;
  547 }
  548 
  549 static struct ieee80211com *
  550 ieee80211_find_instance(struct ifnet *ifp)
  551 {
  552         int s;
  553         struct ieee80211com *ic;
  554 
  555         s = splnet();
  556         /* XXX not right for multiple instances but works for now */
  557         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  558                 if (ic->ic_ifp == ifp)
  559                         break;
  560         splx(s);
  561         return ic;
  562 }
  563 
  564 /*
  565  * Handle a media change request.
  566  */
  567 int
  568 ieee80211_media_change(struct ifnet *ifp)
  569 {
  570         struct ieee80211com *ic;
  571         struct ifmedia_entry *ime;
  572         enum ieee80211_opmode newopmode;
  573         enum ieee80211_phymode newphymode;
  574         int i, j, newrate, error = 0;
  575 
  576         ic = ieee80211_find_instance(ifp);
  577         if (!ic) {
  578                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  579                 return EINVAL;
  580         }
  581         ime = ic->ic_media.ifm_cur;
  582         /*
  583          * First, identify the phy mode.
  584          */
  585         switch (IFM_MODE(ime->ifm_media)) {
  586         case IFM_IEEE80211_11A:
  587                 newphymode = IEEE80211_MODE_11A;
  588                 break;
  589         case IFM_IEEE80211_11B:
  590                 newphymode = IEEE80211_MODE_11B;
  591                 break;
  592         case IFM_IEEE80211_11G:
  593                 newphymode = IEEE80211_MODE_11G;
  594                 break;
  595         case IFM_IEEE80211_FH:
  596                 newphymode = IEEE80211_MODE_FH;
  597                 break;
  598         case IFM_AUTO:
  599                 newphymode = IEEE80211_MODE_AUTO;
  600                 break;
  601         default:
  602                 return EINVAL;
  603         }
  604         /*
  605          * Turbo mode is an ``option''.
  606          * XXX does not apply to AUTO
  607          */
  608         if (ime->ifm_media & IFM_IEEE80211_TURBO) {
  609                 if (newphymode == IEEE80211_MODE_11A)
  610                         newphymode = IEEE80211_MODE_TURBO_A;
  611                 else if (newphymode == IEEE80211_MODE_11G)
  612                         newphymode = IEEE80211_MODE_TURBO_G;
  613                 else
  614                         return EINVAL;
  615         }
  616         /*
  617          * Validate requested mode is available.
  618          */
  619         if ((ic->ic_modecaps & (1<<newphymode)) == 0)
  620                 return EINVAL;
  621 
  622         /*
  623          * Next, the fixed/variable rate.
  624          */
  625         i = -1;
  626         if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
  627                 /*
  628                  * Convert media subtype to rate.
  629                  */
  630                 newrate = ieee80211_media2rate(ime->ifm_media);
  631                 if (newrate == 0)
  632                         return EINVAL;
  633                 /*
  634                  * Check the rate table for the specified/current phy.
  635                  */
  636                 if (newphymode == IEEE80211_MODE_AUTO) {
  637                         /*
  638                          * In autoselect mode search for the rate.
  639                          */
  640                         for (j = IEEE80211_MODE_11A;
  641                              j < IEEE80211_MODE_MAX; j++) {
  642                                 if ((ic->ic_modecaps & (1<<j)) == 0)
  643                                         continue;
  644                                 i = findrate(ic, j, newrate);
  645                                 if (i != -1) {
  646                                         /* lock mode too */
  647                                         newphymode = j;
  648                                         break;
  649                                 }
  650                         }
  651                 } else {
  652                         i = findrate(ic, newphymode, newrate);
  653                 }
  654                 if (i == -1)                    /* mode/rate mismatch */
  655                         return EINVAL;
  656         }
  657         /* NB: defer rate setting to later */
  658 
  659         /*
  660          * Deduce new operating mode but don't install it just yet.
  661          */
  662         if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
  663             (IFM_IEEE80211_ADHOC|IFM_FLAG0))
  664                 newopmode = IEEE80211_M_AHDEMO;
  665         else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
  666                 newopmode = IEEE80211_M_HOSTAP;
  667         else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
  668                 newopmode = IEEE80211_M_IBSS;
  669         else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
  670                 newopmode = IEEE80211_M_MONITOR;
  671         else
  672                 newopmode = IEEE80211_M_STA;
  673 
  674 #ifndef IEEE80211_NO_HOSTAP
  675         /*
  676          * Autoselect doesn't make sense when operating as an AP.
  677          * If no phy mode has been selected, pick one and lock it
  678          * down so rate tables can be used in forming beacon frames
  679          * and the like.
  680          */
  681         if (newopmode == IEEE80211_M_HOSTAP &&
  682             newphymode == IEEE80211_MODE_AUTO) {
  683                 for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
  684                         if (ic->ic_modecaps & (1<<j)) {
  685                                 newphymode = j;
  686                                 break;
  687                         }
  688         }
  689 #endif /* !IEEE80211_NO_HOSTAP */
  690 
  691         /*
  692          * Handle phy mode change.
  693          */
  694         if (ic->ic_curmode != newphymode) {             /* change phy mode */
  695                 error = ieee80211_setmode(ic, newphymode);
  696                 if (error != 0)
  697                         return error;
  698                 error = ENETRESET;
  699         }
  700 
  701         /*
  702          * Committed to changes, install the rate setting.
  703          */
  704         if (ic->ic_fixed_rate != i) {
  705                 ic->ic_fixed_rate = i;                  /* set fixed tx rate */
  706                 error = ENETRESET;
  707         }
  708 
  709         /*
  710          * Handle operating mode change.
  711          */
  712         if (ic->ic_opmode != newopmode) {
  713                 ic->ic_opmode = newopmode;
  714                 switch (newopmode) {
  715                 case IEEE80211_M_AHDEMO:
  716                 case IEEE80211_M_HOSTAP:
  717                 case IEEE80211_M_STA:
  718                 case IEEE80211_M_MONITOR:
  719                         ic->ic_flags &= ~IEEE80211_F_IBSSON;
  720                         break;
  721                 case IEEE80211_M_IBSS:
  722                         ic->ic_flags |= IEEE80211_F_IBSSON;
  723                         break;
  724                 }
  725                 /*
  726                  * Yech, slot time may change depending on the
  727                  * operating mode so reset it to be sure everything
  728                  * is setup appropriately.
  729                  */
  730                 ieee80211_reset_erp(ic);
  731                 ieee80211_wme_initparams(ic);   /* after opmode change */
  732                 ieee80211_init_link_state(ic);  /* after opmode change */
  733                 error = ENETRESET;
  734         }
  735 #ifdef notdef
  736         if (error == 0)
  737                 ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
  738 #endif
  739         return error;
  740 }
  741 
  742 void
  743 ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
  744 {
  745         struct ieee80211com *ic;
  746         struct ieee80211_rateset *rs;
  747 
  748         ic = ieee80211_find_instance(ifp);
  749         if (!ic) {
  750                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  751                 return;
  752         }
  753         imr->ifm_status = IFM_AVALID;
  754         imr->ifm_active = IFM_IEEE80211;
  755         if (ic->ic_state == IEEE80211_S_RUN)
  756                 imr->ifm_status |= IFM_ACTIVE;
  757         /*
  758          * Calculate a current rate if possible.
  759          */
  760         if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
  761                 /*
  762                  * A fixed rate is set, report that.
  763                  */
  764                 rs = &ic->ic_sup_rates[ic->ic_curmode];
  765                 imr->ifm_active |= ieee80211_rate2media(ic,
  766                         rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode);
  767         } else if (ic->ic_opmode == IEEE80211_M_STA) {
  768                 /*
  769                  * In station mode report the current transmit rate.
  770                  */
  771                 rs = &ic->ic_bss->ni_rates;
  772                 imr->ifm_active |= ieee80211_rate2media(ic,
  773                         rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode);
  774         } else
  775                 imr->ifm_active |= IFM_AUTO;
  776         switch (ic->ic_opmode) {
  777         case IEEE80211_M_STA:
  778                 break;
  779         case IEEE80211_M_IBSS:
  780                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
  781                 break;
  782         case IEEE80211_M_AHDEMO:
  783                 /* should not come here */
  784                 break;
  785         case IEEE80211_M_HOSTAP:
  786                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
  787                 break;
  788         case IEEE80211_M_MONITOR:
  789                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
  790                 break;
  791         }
  792         switch (ic->ic_curmode) {
  793         case IEEE80211_MODE_11A:
  794                 imr->ifm_active |= IFM_IEEE80211_11A;
  795                 break;
  796         case IEEE80211_MODE_11B:
  797                 imr->ifm_active |= IFM_IEEE80211_11B;
  798                 break;
  799         case IEEE80211_MODE_11G:
  800                 imr->ifm_active |= IFM_IEEE80211_11G;
  801                 break;
  802         case IEEE80211_MODE_FH:
  803                 imr->ifm_active |= IFM_IEEE80211_FH;
  804                 break;
  805         case IEEE80211_MODE_TURBO_A:
  806                 imr->ifm_active |= IFM_IEEE80211_11A
  807                                 |  IFM_IEEE80211_TURBO;
  808                 break;
  809         case IEEE80211_MODE_TURBO_G:
  810                 imr->ifm_active |= IFM_IEEE80211_11G
  811                                 |  IFM_IEEE80211_TURBO;
  812                 break;
  813         }
  814 }
  815 
  816 void
  817 ieee80211_watchdog(struct ieee80211com *ic)
  818 {
  819         struct ieee80211_node_table *nt;
  820         int need_inact_timer = 0;
  821 
  822         if (ic->ic_state != IEEE80211_S_INIT) {
  823                 if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
  824                         ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
  825                 nt = &ic->ic_scan;
  826                 if (nt->nt_inact_timer) {
  827                         if (--nt->nt_inact_timer == 0)
  828                                 nt->nt_timeout(nt);
  829                         need_inact_timer += nt->nt_inact_timer;
  830                 }
  831                 nt = &ic->ic_sta;
  832                 if (nt->nt_inact_timer) {
  833                         if (--nt->nt_inact_timer == 0)
  834                                 nt->nt_timeout(nt);
  835                         need_inact_timer += nt->nt_inact_timer;
  836                 }
  837         }
  838         if (ic->ic_mgt_timer != 0 || need_inact_timer)
  839                 ic->ic_ifp->if_timer = 1;
  840 }
  841 
  842 const struct ieee80211_rateset ieee80211_std_rateset_11a =
  843         { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } };
  844 
  845 const struct ieee80211_rateset ieee80211_std_rateset_11b =
  846         { 4, { 2, 4, 11, 22 } };
  847 
  848 const struct ieee80211_rateset ieee80211_std_rateset_11g =
  849         { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } };
  850 
  851 /*
  852  * Set the current phy mode and recalculate the active channel
  853  * set based on the available channels for this mode.  Also
  854  * select a new default/current channel if the current one is
  855  * inappropriate for this mode.
  856  */
  857 int
  858 ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
  859 {
  860 #define N(a)    (sizeof(a) / sizeof(a[0]))
  861         static const u_int chanflags[] = {
  862                 0,                      /* IEEE80211_MODE_AUTO */
  863                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
  864                 IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
  865                 IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
  866                 IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
  867                 IEEE80211_CHAN_T,       /* IEEE80211_MODE_TURBO_A */
  868                 IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
  869         };
  870         struct ieee80211_channel *c;
  871         u_int modeflags;
  872         int i;
  873 
  874         /* validate new mode */
  875         if ((ic->ic_modecaps & (1<<mode)) == 0) {
  876                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
  877                         "%s: mode %u not supported (caps 0x%x)\n",
  878                         __func__, mode, ic->ic_modecaps);
  879                 return EINVAL;
  880         }
  881 
  882         /*
  883          * Verify at least one channel is present in the available
  884          * channel list before committing to the new mode.
  885          */
  886         IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode));
  887         modeflags = chanflags[mode];
  888         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
  889                 c = &ic->ic_channels[i];
  890                 if (c->ic_flags == 0)
  891                         continue;
  892                 if (mode == IEEE80211_MODE_AUTO) {
  893                         /* ignore turbo channels for autoselect */
  894                         if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0)
  895                                 break;
  896                 } else {
  897                         if ((c->ic_flags & modeflags) == modeflags)
  898                                 break;
  899                 }
  900         }
  901         if (i > IEEE80211_CHAN_MAX) {
  902                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
  903                         "%s: no channels found for mode %u\n", __func__, mode);
  904                 return EINVAL;
  905         }
  906 
  907         /*
  908          * Calculate the active channel set.
  909          */
  910         memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
  911         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
  912                 c = &ic->ic_channels[i];
  913                 if (c->ic_flags == 0)
  914                         continue;
  915                 if (mode == IEEE80211_MODE_AUTO) {
  916                         /* take anything but pure turbo channels */
  917                         if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0)
  918                                 setbit(ic->ic_chan_active, i);
  919                 } else {
  920                         if ((c->ic_flags & modeflags) == modeflags)
  921                                 setbit(ic->ic_chan_active, i);
  922                 }
  923         }
  924         /*
  925          * If no current/default channel is setup or the current
  926          * channel is wrong for the mode then pick the first
  927          * available channel from the active list.  This is likely
  928          * not the right one.
  929          */
  930         if (ic->ic_ibss_chan == NULL ||
  931             isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
  932                 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
  933                         if (isset(ic->ic_chan_active, i)) {
  934                                 ic->ic_ibss_chan = &ic->ic_channels[i];
  935                                 break;
  936                         }
  937                 IASSERT(ic->ic_ibss_chan != NULL &&
  938                     isset(ic->ic_chan_active,
  939                         ieee80211_chan2ieee(ic, ic->ic_ibss_chan)),
  940                     ("Bad IBSS channel %u",
  941                      ieee80211_chan2ieee(ic, ic->ic_ibss_chan)));
  942         }
  943         /*
  944          * If the desired channel is set but no longer valid then reset it.
  945          */
  946         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
  947             isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan)))
  948                 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
  949 
  950         /*
  951          * Do mode-specific rate setup.
  952          */
  953         if (mode == IEEE80211_MODE_11G) {
  954                 /*
  955                  * Use a mixed 11b/11g rate set.
  956                  */
  957                 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
  958                         IEEE80211_MODE_11G);
  959         } else if (mode == IEEE80211_MODE_11B) {
  960                 /*
  961                  * Force pure 11b rate set.
  962                  */
  963                 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
  964                         IEEE80211_MODE_11B);
  965         }
  966         /*
  967          * Setup an initial rate set according to the
  968          * current/default channel selected above.  This
  969          * will be changed when scanning but must exist
  970          * now so driver have a consistent state of ic_ibss_chan.
  971          */
  972         if (ic->ic_bss)         /* NB: can be called before lateattach */
  973                 ic->ic_bss->ni_rates = ic->ic_sup_rates[mode];
  974 
  975         ic->ic_curmode = mode;
  976         ieee80211_reset_erp(ic);        /* reset ERP state */
  977         ieee80211_wme_initparams(ic);   /* reset WME stat */
  978 
  979         return 0;
  980 #undef N
  981 }
  982 
  983 /*
  984  * Return the phy mode for with the specified channel so the
  985  * caller can select a rate set.  This is problematic for channels
  986  * where multiple operating modes are possible (e.g. 11g+11b).
  987  * In those cases we defer to the current operating mode when set.
  988  */
  989 enum ieee80211_phymode
  990 ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
  991 {
  992         if (IEEE80211_IS_CHAN_T(chan)) {
  993                 return IEEE80211_MODE_TURBO_A;
  994         } else if (IEEE80211_IS_CHAN_5GHZ(chan)) {
  995                 return IEEE80211_MODE_11A;
  996         } else if (IEEE80211_IS_CHAN_FHSS(chan))
  997                 return IEEE80211_MODE_FH;
  998         else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) {
  999                 /*
 1000                  * This assumes all 11g channels are also usable
 1001                  * for 11b, which is currently true.
 1002                  */
 1003                 if (ic->ic_curmode == IEEE80211_MODE_TURBO_G)
 1004                         return IEEE80211_MODE_TURBO_G;
 1005                 if (ic->ic_curmode == IEEE80211_MODE_11B)
 1006                         return IEEE80211_MODE_11B;
 1007                 return IEEE80211_MODE_11G;
 1008         } else
 1009                 return IEEE80211_MODE_11B;
 1010 }
 1011 
 1012 /*
 1013  * convert IEEE80211 rate value to ifmedia subtype.
 1014  * ieee80211 rate is in unit of 0.5Mbps.
 1015  */
 1016 int
 1017 ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
 1018 {
 1019 #define N(a)    (sizeof(a) / sizeof(a[0]))
 1020         static const struct {
 1021                 u_int   m;      /* rate + mode */
 1022                 u_int   r;      /* if_media rate */
 1023         } rates[] = {
 1024                 {   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
 1025                 {   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
 1026                 {   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
 1027                 {   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
 1028                 {  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
 1029                 {  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
 1030                 {  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
 1031                 {  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
 1032                 {  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
 1033                 {  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
 1034                 {  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
 1035                 {  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
 1036                 {  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
 1037                 {  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
 1038                 { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
 1039                 {   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
 1040                 {   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
 1041                 {  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
 1042                 {  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
 1043                 {  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
 1044                 {  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
 1045                 {  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
 1046                 {  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
 1047                 {  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
 1048                 {  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
 1049                 {  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
 1050                 { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
 1051                 /* NB: OFDM72 doesn't really exist so we don't handle it */
 1052         };
 1053         u_int mask, i;
 1054 
 1055         mask = rate & IEEE80211_RATE_VAL;
 1056         switch (mode) {
 1057         case IEEE80211_MODE_11A:
 1058         case IEEE80211_MODE_TURBO_A:
 1059                 mask |= IFM_IEEE80211_11A;
 1060                 break;
 1061         case IEEE80211_MODE_11B:
 1062                 mask |= IFM_IEEE80211_11B;
 1063                 break;
 1064         case IEEE80211_MODE_FH:
 1065                 mask |= IFM_IEEE80211_FH;
 1066                 break;
 1067         case IEEE80211_MODE_AUTO:
 1068                 /* NB: ic may be NULL for some drivers */
 1069                 if (ic && ic->ic_phytype == IEEE80211_T_FH) {
 1070                         mask |= IFM_IEEE80211_FH;
 1071                         break;
 1072                 }
 1073                 /* NB: hack, 11g matches both 11b+11a rates */
 1074                 /* fall thru... */
 1075         case IEEE80211_MODE_11G:
 1076         case IEEE80211_MODE_TURBO_G:
 1077                 mask |= IFM_IEEE80211_11G;
 1078                 break;
 1079         }
 1080         for (i = 0; i < N(rates); i++)
 1081                 if (rates[i].m == mask)
 1082                         return rates[i].r;
 1083         return IFM_AUTO;
 1084 #undef N
 1085 }
 1086 
 1087 int
 1088 ieee80211_media2rate(int mword)
 1089 {
 1090 #define N(a)    (sizeof(a) / sizeof(a[0]))
 1091         static const int ieeerates[] = {
 1092                 -1,             /* IFM_AUTO */
 1093                 0,              /* IFM_MANUAL */
 1094                 0,              /* IFM_NONE */
 1095                 2,              /* IFM_IEEE80211_FH1 */
 1096                 4,              /* IFM_IEEE80211_FH2 */
 1097                 4,              /* IFM_IEEE80211_DS2 */
 1098                 11,             /* IFM_IEEE80211_DS5 */
 1099                 22,             /* IFM_IEEE80211_DS11 */
 1100                 2,              /* IFM_IEEE80211_DS1 */
 1101                 44,             /* IFM_IEEE80211_DS22 */
 1102                 12,             /* IFM_IEEE80211_OFDM6 */
 1103                 18,             /* IFM_IEEE80211_OFDM9 */
 1104                 24,             /* IFM_IEEE80211_OFDM12 */
 1105                 36,             /* IFM_IEEE80211_OFDM18 */
 1106                 48,             /* IFM_IEEE80211_OFDM24 */
 1107                 72,             /* IFM_IEEE80211_OFDM36 */
 1108                 96,             /* IFM_IEEE80211_OFDM48 */
 1109                 108,            /* IFM_IEEE80211_OFDM54 */
 1110                 144,            /* IFM_IEEE80211_OFDM72 */
 1111         };
 1112         return IFM_SUBTYPE(mword) < N(ieeerates) ?
 1113                 ieeerates[IFM_SUBTYPE(mword)] : 0;
 1114 #undef N
 1115 }

Cache object: e8f74e3380d50c4ea2e26812e4349812


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.