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.47 2006/11/16 01:33:40 christos 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.47 2006/11/16 01:33:40 christos 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                 if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
  467                 rs = &ic->ic_sup_rates[mode];
  468                 for (i = 0; i < rs->rs_nrates; i++) {
  469                         rate = rs->rs_rates[i];
  470                         mword = ieee80211_rate2media(ic, rate, mode);
  471                         if (mword == 0)
  472                                 continue;
  473                         printf("%s%d%sMbps", (i != 0 ? " " : ""),
  474                             (rate & IEEE80211_RATE_VAL) / 2,
  475                             ((rate & 0x1) != 0 ? ".5" : ""));
  476                 }
  477                 printf("\n");
  478         }
  479 }
  480 
  481 static int
  482 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  483 {
  484 #define IEEERATE(_ic,_m,_i) \
  485         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
  486         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
  487         for (i = 0; i < nrates; i++)
  488                 if (IEEERATE(ic, mode, i) == rate)
  489                         return i;
  490         return -1;
  491 #undef IEEERATE
  492 }
  493 
  494 /*
  495  * Find an instance by it's mac address.
  496  */
  497 struct ieee80211com *
  498 ieee80211_find_vap(const u_int8_t mac[IEEE80211_ADDR_LEN])
  499 {
  500         int s;
  501         struct ieee80211com *ic;
  502 
  503         s = splnet();
  504         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  505                 if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
  506                         break;
  507         splx(s);
  508         return ic;
  509 }
  510 
  511 static struct ieee80211com *
  512 ieee80211_find_instance(struct ifnet *ifp)
  513 {
  514         int s;
  515         struct ieee80211com *ic;
  516 
  517         s = splnet();
  518         /* XXX not right for multiple instances but works for now */
  519         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  520                 if (ic->ic_ifp == ifp)
  521                         break;
  522         splx(s);
  523         return ic;
  524 }
  525 
  526 /*
  527  * Handle a media change request.
  528  */
  529 int
  530 ieee80211_media_change(struct ifnet *ifp)
  531 {
  532         struct ieee80211com *ic;
  533         struct ifmedia_entry *ime;
  534         enum ieee80211_opmode newopmode;
  535         enum ieee80211_phymode newphymode;
  536         int i, j, newrate, error = 0;
  537 
  538         ic = ieee80211_find_instance(ifp);
  539         if (!ic) {
  540                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  541                 return EINVAL;
  542         }
  543         ime = ic->ic_media.ifm_cur;
  544         /*
  545          * First, identify the phy mode.
  546          */
  547         switch (IFM_MODE(ime->ifm_media)) {
  548         case IFM_IEEE80211_11A:
  549                 newphymode = IEEE80211_MODE_11A;
  550                 break;
  551         case IFM_IEEE80211_11B:
  552                 newphymode = IEEE80211_MODE_11B;
  553                 break;
  554         case IFM_IEEE80211_11G:
  555                 newphymode = IEEE80211_MODE_11G;
  556                 break;
  557         case IFM_IEEE80211_FH:
  558                 newphymode = IEEE80211_MODE_FH;
  559                 break;
  560         case IFM_AUTO:
  561                 newphymode = IEEE80211_MODE_AUTO;
  562                 break;
  563         default:
  564                 return EINVAL;
  565         }
  566         /*
  567          * Turbo mode is an ``option''.
  568          * XXX does not apply to AUTO
  569          */
  570         if (ime->ifm_media & IFM_IEEE80211_TURBO) {
  571                 if (newphymode == IEEE80211_MODE_11A)
  572                         newphymode = IEEE80211_MODE_TURBO_A;
  573                 else if (newphymode == IEEE80211_MODE_11G)
  574                         newphymode = IEEE80211_MODE_TURBO_G;
  575                 else
  576                         return EINVAL;
  577         }
  578         /*
  579          * Validate requested mode is available.
  580          */
  581         if ((ic->ic_modecaps & (1<<newphymode)) == 0)
  582                 return EINVAL;
  583 
  584         /*
  585          * Next, the fixed/variable rate.
  586          */
  587         i = -1;
  588         if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
  589                 /*
  590                  * Convert media subtype to rate.
  591                  */
  592                 newrate = ieee80211_media2rate(ime->ifm_media);
  593                 if (newrate == 0)
  594                         return EINVAL;
  595                 /*
  596                  * Check the rate table for the specified/current phy.
  597                  */
  598                 if (newphymode == IEEE80211_MODE_AUTO) {
  599                         /*
  600                          * In autoselect mode search for the rate.
  601                          */
  602                         for (j = IEEE80211_MODE_11A;
  603                              j < IEEE80211_MODE_MAX; j++) {
  604                                 if ((ic->ic_modecaps & (1<<j)) == 0)
  605                                         continue;
  606                                 i = findrate(ic, j, newrate);
  607                                 if (i != -1) {
  608                                         /* lock mode too */
  609                                         newphymode = j;
  610                                         break;
  611                                 }
  612                         }
  613                 } else {
  614                         i = findrate(ic, newphymode, newrate);
  615                 }
  616                 if (i == -1)                    /* mode/rate mismatch */
  617                         return EINVAL;
  618         }
  619         /* NB: defer rate setting to later */
  620 
  621         /*
  622          * Deduce new operating mode but don't install it just yet.
  623          */
  624         if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
  625             (IFM_IEEE80211_ADHOC|IFM_FLAG0))
  626                 newopmode = IEEE80211_M_AHDEMO;
  627         else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
  628                 newopmode = IEEE80211_M_HOSTAP;
  629         else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
  630                 newopmode = IEEE80211_M_IBSS;
  631         else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
  632                 newopmode = IEEE80211_M_MONITOR;
  633         else
  634                 newopmode = IEEE80211_M_STA;
  635 
  636 #ifndef IEEE80211_NO_HOSTAP
  637         /*
  638          * Autoselect doesn't make sense when operating as an AP.
  639          * If no phy mode has been selected, pick one and lock it
  640          * down so rate tables can be used in forming beacon frames
  641          * and the like.
  642          */
  643         if (newopmode == IEEE80211_M_HOSTAP &&
  644             newphymode == IEEE80211_MODE_AUTO) {
  645                 for (j = IEEE80211_MODE_11A; j < IEEE80211_MODE_MAX; j++)
  646                         if (ic->ic_modecaps & (1<<j)) {
  647                                 newphymode = j;
  648                                 break;
  649                         }
  650         }
  651 #endif /* !IEEE80211_NO_HOSTAP */
  652 
  653         /*
  654          * Handle phy mode change.
  655          */
  656         if (ic->ic_curmode != newphymode) {             /* change phy mode */
  657                 error = ieee80211_setmode(ic, newphymode);
  658                 if (error != 0)
  659                         return error;
  660                 error = ENETRESET;
  661         }
  662 
  663         /*
  664          * Committed to changes, install the rate setting.
  665          */
  666         if (ic->ic_fixed_rate != i) {
  667                 ic->ic_fixed_rate = i;                  /* set fixed tx rate */
  668                 error = ENETRESET;
  669         }
  670 
  671         /*
  672          * Handle operating mode change.
  673          */
  674         if (ic->ic_opmode != newopmode) {
  675                 ic->ic_opmode = newopmode;
  676                 switch (newopmode) {
  677                 case IEEE80211_M_AHDEMO:
  678                 case IEEE80211_M_HOSTAP:
  679                 case IEEE80211_M_STA:
  680                 case IEEE80211_M_MONITOR:
  681                         ic->ic_flags &= ~IEEE80211_F_IBSSON;
  682                         break;
  683                 case IEEE80211_M_IBSS:
  684                         ic->ic_flags |= IEEE80211_F_IBSSON;
  685                         break;
  686                 }
  687                 /*
  688                  * Yech, slot time may change depending on the
  689                  * operating mode so reset it to be sure everything
  690                  * is setup appropriately.
  691                  */
  692                 ieee80211_reset_erp(ic);
  693                 ieee80211_wme_initparams(ic);   /* after opmode change */
  694                 error = ENETRESET;
  695         }
  696 #ifdef notdef
  697         if (error == 0)
  698                 ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
  699 #endif
  700         return error;
  701 }
  702 
  703 void
  704 ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
  705 {
  706         struct ieee80211com *ic;
  707         struct ieee80211_rateset *rs;
  708 
  709         ic = ieee80211_find_instance(ifp);
  710         if (!ic) {
  711                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  712                 return;
  713         }
  714         imr->ifm_status = IFM_AVALID;
  715         imr->ifm_active = IFM_IEEE80211;
  716         if (ic->ic_state == IEEE80211_S_RUN)
  717                 imr->ifm_status |= IFM_ACTIVE;
  718         /*
  719          * Calculate a current rate if possible.
  720          */
  721         if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
  722                 /*
  723                  * A fixed rate is set, report that.
  724                  */
  725                 rs = &ic->ic_sup_rates[ic->ic_curmode];
  726                 imr->ifm_active |= ieee80211_rate2media(ic,
  727                         rs->rs_rates[ic->ic_fixed_rate], ic->ic_curmode);
  728         } else if (ic->ic_opmode == IEEE80211_M_STA) {
  729                 /*
  730                  * In station mode report the current transmit rate.
  731                  */
  732                 rs = &ic->ic_bss->ni_rates;
  733                 imr->ifm_active |= ieee80211_rate2media(ic,
  734                         rs->rs_rates[ic->ic_bss->ni_txrate], ic->ic_curmode);
  735         } else
  736                 imr->ifm_active |= IFM_AUTO;
  737         switch (ic->ic_opmode) {
  738         case IEEE80211_M_STA:
  739                 break;
  740         case IEEE80211_M_IBSS:
  741                 imr->ifm_active |= IFM_IEEE80211_ADHOC;
  742                 break;
  743         case IEEE80211_M_AHDEMO:
  744                 /* should not come here */
  745                 break;
  746         case IEEE80211_M_HOSTAP:
  747                 imr->ifm_active |= IFM_IEEE80211_HOSTAP;
  748                 break;
  749         case IEEE80211_M_MONITOR:
  750                 imr->ifm_active |= IFM_IEEE80211_MONITOR;
  751                 break;
  752         }
  753         switch (ic->ic_curmode) {
  754         case IEEE80211_MODE_11A:
  755                 imr->ifm_active |= IFM_IEEE80211_11A;
  756                 break;
  757         case IEEE80211_MODE_11B:
  758                 imr->ifm_active |= IFM_IEEE80211_11B;
  759                 break;
  760         case IEEE80211_MODE_11G:
  761                 imr->ifm_active |= IFM_IEEE80211_11G;
  762                 break;
  763         case IEEE80211_MODE_FH:
  764                 imr->ifm_active |= IFM_IEEE80211_FH;
  765                 break;
  766         case IEEE80211_MODE_TURBO_A:
  767                 imr->ifm_active |= IFM_IEEE80211_11A
  768                                 |  IFM_IEEE80211_TURBO;
  769                 break;
  770         case IEEE80211_MODE_TURBO_G:
  771                 imr->ifm_active |= IFM_IEEE80211_11G
  772                                 |  IFM_IEEE80211_TURBO;
  773                 break;
  774         }
  775 }
  776 
  777 void
  778 ieee80211_watchdog(struct ieee80211com *ic)
  779 {
  780         struct ieee80211_node_table *nt;
  781         int need_inact_timer = 0;
  782 
  783         if (ic->ic_state != IEEE80211_S_INIT) {
  784                 if (ic->ic_mgt_timer && --ic->ic_mgt_timer == 0)
  785                         ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
  786                 nt = &ic->ic_scan;
  787                 if (nt->nt_inact_timer) {
  788                         if (--nt->nt_inact_timer == 0)
  789                                 nt->nt_timeout(nt);
  790                         need_inact_timer += nt->nt_inact_timer;
  791                 }
  792                 nt = &ic->ic_sta;
  793                 if (nt->nt_inact_timer) {
  794                         if (--nt->nt_inact_timer == 0)
  795                                 nt->nt_timeout(nt);
  796                         need_inact_timer += nt->nt_inact_timer;
  797                 }
  798         }
  799         if (ic->ic_mgt_timer != 0 || need_inact_timer)
  800                 ic->ic_ifp->if_timer = 1;
  801 }
  802 
  803 /*
  804  * Set the current phy mode and recalculate the active channel
  805  * set based on the available channels for this mode.  Also
  806  * select a new default/current channel if the current one is
  807  * inappropriate for this mode.
  808  */
  809 int
  810 ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
  811 {
  812 #define N(a)    (sizeof(a) / sizeof(a[0]))
  813         static const u_int chanflags[] = {
  814                 0,                      /* IEEE80211_MODE_AUTO */
  815                 IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
  816                 IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
  817                 IEEE80211_CHAN_PUREG,   /* IEEE80211_MODE_11G */
  818                 IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
  819                 IEEE80211_CHAN_T,       /* IEEE80211_MODE_TURBO_A */
  820                 IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
  821         };
  822         struct ieee80211_channel *c;
  823         u_int modeflags;
  824         int i;
  825 
  826         /* validate new mode */
  827         if ((ic->ic_modecaps & (1<<mode)) == 0) {
  828                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
  829                         "%s: mode %u not supported (caps 0x%x)\n",
  830                         __func__, mode, ic->ic_modecaps);
  831                 return EINVAL;
  832         }
  833 
  834         /*
  835          * Verify at least one channel is present in the available
  836          * channel list before committing to the new mode.
  837          */
  838         IASSERT(mode < N(chanflags), ("Unexpected mode %u", mode));
  839         modeflags = chanflags[mode];
  840         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
  841                 c = &ic->ic_channels[i];
  842                 if (c->ic_flags == 0)
  843                         continue;
  844                 if (mode == IEEE80211_MODE_AUTO) {
  845                         /* ignore turbo channels for autoselect */
  846                         if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0)
  847                                 break;
  848                 } else {
  849                         if ((c->ic_flags & modeflags) == modeflags)
  850                                 break;
  851                 }
  852         }
  853         if (i > IEEE80211_CHAN_MAX) {
  854                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
  855                         "%s: no channels found for mode %u\n", __func__, mode);
  856                 return EINVAL;
  857         }
  858 
  859         /*
  860          * Calculate the active channel set.
  861          */
  862         memset(ic->ic_chan_active, 0, sizeof(ic->ic_chan_active));
  863         for (i = 0; i <= IEEE80211_CHAN_MAX; i++) {
  864                 c = &ic->ic_channels[i];
  865                 if (c->ic_flags == 0)
  866                         continue;
  867                 if (mode == IEEE80211_MODE_AUTO) {
  868                         /* take anything but pure turbo channels */
  869                         if ((c->ic_flags & IEEE80211_CHAN_TURBO) == 0)
  870                                 setbit(ic->ic_chan_active, i);
  871                 } else {
  872                         if ((c->ic_flags & modeflags) == modeflags)
  873                                 setbit(ic->ic_chan_active, i);
  874                 }
  875         }
  876         /*
  877          * If no current/default channel is setup or the current
  878          * channel is wrong for the mode then pick the first
  879          * available channel from the active list.  This is likely
  880          * not the right one.
  881          */
  882         if (ic->ic_ibss_chan == NULL ||
  883             isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_ibss_chan))) {
  884                 for (i = 0; i <= IEEE80211_CHAN_MAX; i++)
  885                         if (isset(ic->ic_chan_active, i)) {
  886                                 ic->ic_ibss_chan = &ic->ic_channels[i];
  887                                 break;
  888                         }
  889                 IASSERT(ic->ic_ibss_chan != NULL &&
  890                     isset(ic->ic_chan_active,
  891                         ieee80211_chan2ieee(ic, ic->ic_ibss_chan)),
  892                     ("Bad IBSS channel %u",
  893                      ieee80211_chan2ieee(ic, ic->ic_ibss_chan)));
  894         }
  895         /*
  896          * If the desired channel is set but no longer valid then reset it.
  897          */
  898         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
  899             isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ic->ic_des_chan)))
  900                 ic->ic_des_chan = IEEE80211_CHAN_ANYC;
  901 
  902         /*
  903          * Do mode-specific rate setup.
  904          */
  905         if (mode == IEEE80211_MODE_11G) {
  906                 /*
  907                  * Use a mixed 11b/11g rate set.
  908                  */
  909                 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
  910                         IEEE80211_MODE_11G);
  911         } else if (mode == IEEE80211_MODE_11B) {
  912                 /*
  913                  * Force pure 11b rate set.
  914                  */
  915                 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode],
  916                         IEEE80211_MODE_11B);
  917         }
  918         /*
  919          * Setup an initial rate set according to the
  920          * current/default channel selected above.  This
  921          * will be changed when scanning but must exist
  922          * now so driver have a consistent state of ic_ibss_chan.
  923          */
  924         if (ic->ic_bss)         /* NB: can be called before lateattach */
  925                 ic->ic_bss->ni_rates = ic->ic_sup_rates[mode];
  926 
  927         ic->ic_curmode = mode;
  928         ieee80211_reset_erp(ic);        /* reset ERP state */
  929         ieee80211_wme_initparams(ic);   /* reset WME stat */
  930 
  931         return 0;
  932 #undef N
  933 }
  934 
  935 /*
  936  * Return the phy mode for with the specified channel so the
  937  * caller can select a rate set.  This is problematic for channels
  938  * where multiple operating modes are possible (e.g. 11g+11b).
  939  * In those cases we defer to the current operating mode when set.
  940  */
  941 enum ieee80211_phymode
  942 ieee80211_chan2mode(struct ieee80211com *ic, struct ieee80211_channel *chan)
  943 {
  944         if (IEEE80211_IS_CHAN_T(chan)) {
  945                 return IEEE80211_MODE_TURBO_A;
  946         } else if (IEEE80211_IS_CHAN_5GHZ(chan)) {
  947                 return IEEE80211_MODE_11A;
  948         } else if (IEEE80211_IS_CHAN_FHSS(chan))
  949                 return IEEE80211_MODE_FH;
  950         else if (chan->ic_flags & (IEEE80211_CHAN_OFDM|IEEE80211_CHAN_DYN)) {
  951                 /*
  952                  * This assumes all 11g channels are also usable
  953                  * for 11b, which is currently true.
  954                  */
  955                 if (ic->ic_curmode == IEEE80211_MODE_TURBO_G)
  956                         return IEEE80211_MODE_TURBO_G;
  957                 if (ic->ic_curmode == IEEE80211_MODE_11B)
  958                         return IEEE80211_MODE_11B;
  959                 return IEEE80211_MODE_11G;
  960         } else
  961                 return IEEE80211_MODE_11B;
  962 }
  963 
  964 /*
  965  * convert IEEE80211 rate value to ifmedia subtype.
  966  * ieee80211 rate is in unit of 0.5Mbps.
  967  */
  968 int
  969 ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
  970 {
  971 #define N(a)    (sizeof(a) / sizeof(a[0]))
  972         static const struct {
  973                 u_int   m;      /* rate + mode */
  974                 u_int   r;      /* if_media rate */
  975         } rates[] = {
  976                 {   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
  977                 {   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
  978                 {   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
  979                 {   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
  980                 {  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
  981                 {  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
  982                 {  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
  983                 {  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
  984                 {  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
  985                 {  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
  986                 {  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
  987                 {  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
  988                 {  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
  989                 {  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
  990                 { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
  991                 {   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
  992                 {   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
  993                 {  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
  994                 {  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
  995                 {  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
  996                 {  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
  997                 {  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
  998                 {  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
  999                 {  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
 1000                 {  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
 1001                 {  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
 1002                 { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
 1003                 /* NB: OFDM72 doesn't realy exist so we don't handle it */
 1004         };
 1005         u_int mask, i;
 1006 
 1007         mask = rate & IEEE80211_RATE_VAL;
 1008         switch (mode) {
 1009         case IEEE80211_MODE_11A:
 1010         case IEEE80211_MODE_TURBO_A:
 1011                 mask |= IFM_IEEE80211_11A;
 1012                 break;
 1013         case IEEE80211_MODE_11B:
 1014                 mask |= IFM_IEEE80211_11B;
 1015                 break;
 1016         case IEEE80211_MODE_FH:
 1017                 mask |= IFM_IEEE80211_FH;
 1018                 break;
 1019         case IEEE80211_MODE_AUTO:
 1020                 /* NB: ic may be NULL for some drivers */
 1021                 if (ic && ic->ic_phytype == IEEE80211_T_FH) {
 1022                         mask |= IFM_IEEE80211_FH;
 1023                         break;
 1024                 }
 1025                 /* NB: hack, 11g matches both 11b+11a rates */
 1026                 /* fall thru... */
 1027         case IEEE80211_MODE_11G:
 1028         case IEEE80211_MODE_TURBO_G:
 1029                 mask |= IFM_IEEE80211_11G;
 1030                 break;
 1031         }
 1032         for (i = 0; i < N(rates); i++)
 1033                 if (rates[i].m == mask)
 1034                         return rates[i].r;
 1035         return IFM_AUTO;
 1036 #undef N
 1037 }
 1038 
 1039 int
 1040 ieee80211_media2rate(int mword)
 1041 {
 1042 #define N(a)    (sizeof(a) / sizeof(a[0]))
 1043         static const int ieeerates[] = {
 1044                 -1,             /* IFM_AUTO */
 1045                 0,              /* IFM_MANUAL */
 1046                 0,              /* IFM_NONE */
 1047                 2,              /* IFM_IEEE80211_FH1 */
 1048                 4,              /* IFM_IEEE80211_FH2 */
 1049                 4,              /* IFM_IEEE80211_DS2 */
 1050                 11,             /* IFM_IEEE80211_DS5 */
 1051                 22,             /* IFM_IEEE80211_DS11 */
 1052                 2,              /* IFM_IEEE80211_DS1 */
 1053                 44,             /* IFM_IEEE80211_DS22 */
 1054                 12,             /* IFM_IEEE80211_OFDM6 */
 1055                 18,             /* IFM_IEEE80211_OFDM9 */
 1056                 24,             /* IFM_IEEE80211_OFDM12 */
 1057                 36,             /* IFM_IEEE80211_OFDM18 */
 1058                 48,             /* IFM_IEEE80211_OFDM24 */
 1059                 72,             /* IFM_IEEE80211_OFDM36 */
 1060                 96,             /* IFM_IEEE80211_OFDM48 */
 1061                 108,            /* IFM_IEEE80211_OFDM54 */
 1062                 144,            /* IFM_IEEE80211_OFDM72 */
 1063         };
 1064         return IFM_SUBTYPE(mword) < N(ieeerates) ?
 1065                 ieeerates[IFM_SUBTYPE(mword)] : 0;
 1066 #undef N
 1067 }

Cache object: a3a18f71c40f0e22de2eef8a81f698ed


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