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

Cache object: 6c80ee58ae129398b96af82a3d364c5b


[ 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.