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 /*-
    2  * Copyright (c) 2001 Atsushi Onoe
    3  * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * IEEE 802.11 generic handler
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h> 
   36 #include <sys/kernel.h>
   37  
   38 #include <sys/socket.h>
   39 
   40 #include <net/if.h>
   41 #include <net/if_media.h>
   42 #include <net/ethernet.h>
   43 
   44 #include <net80211/ieee80211_var.h>
   45 
   46 #include <net/bpf.h>
   47 
   48 const char *ieee80211_phymode_name[] = {
   49         "auto",         /* IEEE80211_MODE_AUTO */
   50         "11a",          /* IEEE80211_MODE_11A */
   51         "11b",          /* IEEE80211_MODE_11B */
   52         "11g",          /* IEEE80211_MODE_11G */
   53         "FH",           /* IEEE80211_MODE_FH */
   54         "turboA",       /* IEEE80211_MODE_TURBO_A */
   55         "turboG",       /* IEEE80211_MODE_TURBO_G */
   56         "sturboA",      /* IEEE80211_MODE_STURBO_A */
   57         "11na",         /* IEEE80211_MODE_11NA */
   58         "11ng",         /* IEEE80211_MODE_11NG */
   59 };
   60 
   61 /*
   62  * Default supported rates for 802.11 operation (in IEEE .5Mb units).
   63  */
   64 #define B(r)    ((r) | IEEE80211_RATE_BASIC)
   65 static const struct ieee80211_rateset ieee80211_rateset_11a =
   66         { 8, { B(12), 18, B(24), 36, B(48), 72, 96, 108 } };
   67 static const struct ieee80211_rateset ieee80211_rateset_half =
   68         { 8, { B(6), 9, B(12), 18, B(24), 36, 48, 54 } };
   69 static const struct ieee80211_rateset ieee80211_rateset_quarter =
   70         { 8, { B(3), 4, B(6), 9, B(12), 18, 24, 27 } };
   71 static const struct ieee80211_rateset ieee80211_rateset_11b =
   72         { 4, { B(2), B(4), B(11), B(22) } };
   73 /* NB: OFDM rates are handled specially based on mode */
   74 static const struct ieee80211_rateset ieee80211_rateset_11g =
   75         { 12, { B(2), B(4), B(11), B(22), 12, 18, 24, 36, 48, 72, 96, 108 } };
   76 #undef B
   77 
   78 static  int media_status(enum ieee80211_opmode ,
   79                 const struct ieee80211_channel *);
   80 
   81 /* list of all instances */
   82 SLIST_HEAD(ieee80211_list, ieee80211com);
   83 static struct ieee80211_list ieee80211_list =
   84         SLIST_HEAD_INITIALIZER(ieee80211_list);
   85 static uint8_t ieee80211_vapmap[32];            /* enough for 256 */
   86 static struct mtx ieee80211_vap_mtx;
   87 MTX_SYSINIT(ieee80211, &ieee80211_vap_mtx, "net80211 instances", MTX_DEF);
   88 
   89 static void
   90 ieee80211_add_vap(struct ieee80211com *ic)
   91 {
   92 #define N(a)    (sizeof(a)/sizeof(a[0]))
   93         int i;
   94         uint8_t b;
   95 
   96         mtx_lock(&ieee80211_vap_mtx);
   97         ic->ic_vap = 0;
   98         for (i = 0; i < N(ieee80211_vapmap) && ieee80211_vapmap[i] == 0xff; i++)
   99                 ic->ic_vap += NBBY;
  100         if (i == N(ieee80211_vapmap))
  101                 panic("vap table full");
  102         for (b = ieee80211_vapmap[i]; b & 1; b >>= 1)
  103                 ic->ic_vap++;
  104         setbit(ieee80211_vapmap, ic->ic_vap);
  105         SLIST_INSERT_HEAD(&ieee80211_list, ic, ic_next);
  106         mtx_unlock(&ieee80211_vap_mtx);
  107 #undef N
  108 }
  109 
  110 static void
  111 ieee80211_remove_vap(struct ieee80211com *ic)
  112 {
  113         mtx_lock(&ieee80211_vap_mtx);
  114         SLIST_REMOVE(&ieee80211_list, ic, ieee80211com, ic_next);
  115         KASSERT(ic->ic_vap < sizeof(ieee80211_vapmap)*NBBY,
  116                 ("invalid vap id %d", ic->ic_vap));
  117         KASSERT(isset(ieee80211_vapmap, ic->ic_vap),
  118                 ("vap id %d not allocated", ic->ic_vap));
  119         clrbit(ieee80211_vapmap, ic->ic_vap);
  120         mtx_unlock(&ieee80211_vap_mtx);
  121 }
  122 
  123 /*
  124  * Default reset method for use with the ioctl support.  This
  125  * method is invoked after any state change in the 802.11
  126  * layer that should be propagated to the hardware but not
  127  * require re-initialization of the 802.11 state machine (e.g
  128  * rescanning for an ap).  We always return ENETRESET which
  129  * should cause the driver to re-initialize the device. Drivers
  130  * can override this method to implement more optimized support.
  131  */
  132 static int
  133 ieee80211_default_reset(struct ifnet *ifp)
  134 {
  135         return ENETRESET;
  136 }
  137 
  138 /*
  139  * Fill in 802.11 available channel set, mark
  140  * all available channels as active, and pick
  141  * a default channel if not already specified.
  142  */
  143 static void
  144 ieee80211_chan_init(struct ieee80211com *ic)
  145 {
  146 #define DEFAULTRATES(m, def) do { \
  147         if (isset(ic->ic_modecaps, m) && ic->ic_sup_rates[m].rs_nrates == 0) \
  148                 ic->ic_sup_rates[m] = def; \
  149 } while (0)
  150         struct ieee80211_channel *c;
  151         int i;
  152 
  153         KASSERT(0 < ic->ic_nchans && ic->ic_nchans < IEEE80211_CHAN_MAX,
  154                 ("invalid number of channels specified: %u", ic->ic_nchans));
  155         memset(ic->ic_chan_avail, 0, sizeof(ic->ic_chan_avail));
  156         setbit(ic->ic_modecaps, IEEE80211_MODE_AUTO);
  157         for (i = 0; i < ic->ic_nchans; i++) {
  158                 c = &ic->ic_channels[i];
  159                 KASSERT(c->ic_flags != 0, ("channel with no flags"));
  160                 KASSERT(c->ic_ieee < IEEE80211_CHAN_MAX,
  161                         ("channel with bogus ieee number %u", c->ic_ieee));
  162                 setbit(ic->ic_chan_avail, c->ic_ieee);
  163                 /*
  164                  * Identify mode capabilities.
  165                  */
  166                 if (IEEE80211_IS_CHAN_A(c))
  167                         setbit(ic->ic_modecaps, IEEE80211_MODE_11A);
  168                 if (IEEE80211_IS_CHAN_B(c))
  169                         setbit(ic->ic_modecaps, IEEE80211_MODE_11B);
  170                 if (IEEE80211_IS_CHAN_ANYG(c))
  171                         setbit(ic->ic_modecaps, IEEE80211_MODE_11G);
  172                 if (IEEE80211_IS_CHAN_FHSS(c))
  173                         setbit(ic->ic_modecaps, IEEE80211_MODE_FH);
  174                 if (IEEE80211_IS_CHAN_108A(c))
  175                         setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_A);
  176                 if (IEEE80211_IS_CHAN_108G(c))
  177                         setbit(ic->ic_modecaps, IEEE80211_MODE_TURBO_G);
  178                 if (IEEE80211_IS_CHAN_ST(c))
  179                         setbit(ic->ic_modecaps, IEEE80211_MODE_STURBO_A);
  180                 if (IEEE80211_IS_CHAN_HTA(c))
  181                         setbit(ic->ic_modecaps, IEEE80211_MODE_11NA);
  182                 if (IEEE80211_IS_CHAN_HTG(c))
  183                         setbit(ic->ic_modecaps, IEEE80211_MODE_11NG);
  184         }
  185         /* initialize candidate channels to all available */
  186         memcpy(ic->ic_chan_active, ic->ic_chan_avail,
  187                 sizeof(ic->ic_chan_avail));
  188 
  189         ic->ic_des_chan = IEEE80211_CHAN_ANYC;  /* any channel is ok */
  190         ic->ic_bsschan = IEEE80211_CHAN_ANYC;
  191         ic->ic_prevchan = NULL;
  192         /* arbitrarily pick the first channel */
  193         ic->ic_curchan = &ic->ic_channels[0];
  194 
  195         /* fillin well-known rate sets if driver has not specified */
  196         DEFAULTRATES(IEEE80211_MODE_11B,         ieee80211_rateset_11b);
  197         DEFAULTRATES(IEEE80211_MODE_11G,         ieee80211_rateset_11g);
  198         DEFAULTRATES(IEEE80211_MODE_11A,         ieee80211_rateset_11a);
  199         DEFAULTRATES(IEEE80211_MODE_TURBO_A,     ieee80211_rateset_11a);
  200         DEFAULTRATES(IEEE80211_MODE_TURBO_G,     ieee80211_rateset_11g);
  201 
  202         /*
  203          * Set auto mode to reset active channel state and any desired channel.
  204          */
  205         (void) ieee80211_setmode(ic, IEEE80211_MODE_AUTO);
  206 #undef DEFAULTRATES
  207 }
  208 
  209 void
  210 ieee80211_ifattach(struct ieee80211com *ic)
  211 {
  212         struct ifnet *ifp = ic->ic_ifp;
  213 
  214         ether_ifattach(ifp, ic->ic_myaddr);
  215         ifp->if_output = ieee80211_output;
  216 
  217         bpfattach2(ifp, DLT_IEEE802_11,
  218             sizeof(struct ieee80211_frame_addr4), &ic->ic_rawbpf);
  219 
  220         /* override the 802.3 setting */
  221         ifp->if_hdrlen = ic->ic_headroom
  222                 + sizeof(struct ieee80211_qosframe_addr4)
  223                 + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN
  224                 + IEEE80211_WEP_EXTIVLEN;
  225         /* XXX no way to recalculate on ifdetach */
  226         if (ALIGN(ifp->if_hdrlen) > max_linkhdr) {
  227                 /* XXX sanity check... */
  228                 max_linkhdr = ALIGN(ifp->if_hdrlen);
  229                 max_hdr = max_linkhdr + max_protohdr;
  230                 max_datalen = MHLEN - max_hdr;
  231         }
  232 
  233         /*
  234          * Fill in 802.11 available channel set, mark all
  235          * available channels as active, and pick a default
  236          * channel if not already specified.
  237          */
  238         ieee80211_chan_init(ic);
  239 
  240         if (ic->ic_caps & IEEE80211_C_BGSCAN)   /* enable if capable */
  241                 ic->ic_flags |= IEEE80211_F_BGSCAN;
  242 #if 0
  243         /* XXX not until WME+WPA issues resolved */
  244         if (ic->ic_caps & IEEE80211_C_WME)      /* enable if capable */
  245                 ic->ic_flags |= IEEE80211_F_WME;
  246 #endif
  247         if (ic->ic_caps & IEEE80211_C_BURST)
  248                 ic->ic_flags |= IEEE80211_F_BURST;
  249         ic->ic_flags |= IEEE80211_F_DOTH;       /* XXX out of caps, just ena */
  250 
  251         ic->ic_bintval = IEEE80211_BINTVAL_DEFAULT;
  252         ic->ic_bmissthreshold = IEEE80211_HWBMISS_DEFAULT;
  253         ic->ic_dtim_period = IEEE80211_DTIM_DEFAULT;
  254         IEEE80211_LOCK_INIT(ic, "ieee80211com");
  255         IEEE80211_BEACON_LOCK_INIT(ic, "beacon");
  256 
  257         ic->ic_lintval = ic->ic_bintval;
  258         ic->ic_txpowlimit = IEEE80211_TXPOWER_MAX;
  259 
  260         ieee80211_crypto_attach(ic);
  261         ieee80211_node_attach(ic);
  262         ieee80211_power_attach(ic);
  263         ieee80211_proto_attach(ic);
  264         ieee80211_ht_attach(ic);
  265         ieee80211_scan_attach(ic);
  266 
  267         ieee80211_add_vap(ic);
  268 
  269         ieee80211_sysctl_attach(ic);            /* NB: requires ic_vap */
  270 
  271         /*
  272          * Install a default reset method for the ioctl support.
  273          * The driver is expected to fill this in before calling us.
  274          */
  275         if (ic->ic_reset == NULL)
  276                 ic->ic_reset = ieee80211_default_reset;
  277 
  278         KASSERT(ifp->if_llsoftc == NULL, ("oops, hosed"));
  279         ifp->if_llsoftc = ic;
  280 }
  281 
  282 void
  283 ieee80211_ifdetach(struct ieee80211com *ic)
  284 {
  285         struct ifnet *ifp = ic->ic_ifp;
  286 
  287         ieee80211_remove_vap(ic);
  288 
  289         ieee80211_sysctl_detach(ic);
  290         ieee80211_scan_detach(ic);
  291         ieee80211_ht_detach(ic);
  292         /* NB: must be called before ieee80211_node_detach */
  293         ieee80211_proto_detach(ic);
  294         ieee80211_crypto_detach(ic);
  295         ieee80211_power_detach(ic);
  296         ieee80211_node_detach(ic);
  297         ifmedia_removeall(&ic->ic_media);
  298 
  299         IEEE80211_LOCK_DESTROY(ic);
  300         IEEE80211_BEACON_LOCK_DESTROY(ic);
  301 
  302         bpfdetach(ifp);
  303         ether_ifdetach(ifp);
  304 }
  305 
  306 static __inline int
  307 mapgsm(u_int freq, u_int flags)
  308 {
  309         freq *= 10;
  310         if (flags & IEEE80211_CHAN_QUARTER)
  311                 freq += 5;
  312         else if (flags & IEEE80211_CHAN_HALF)
  313                 freq += 10;
  314         else
  315                 freq += 20;
  316         /* NB: there is no 907/20 wide but leave room */
  317         return (freq - 906*10) / 5;
  318 }
  319 
  320 static __inline int
  321 mappsb(u_int freq, u_int flags)
  322 {
  323         return 37 + ((freq * 10) + ((freq % 5) == 2 ? 5 : 0) - 49400) / 5;
  324 }
  325 
  326 /*
  327  * Convert MHz frequency to IEEE channel number.
  328  */
  329 int
  330 ieee80211_mhz2ieee(u_int freq, u_int flags)
  331 {
  332 #define IS_FREQ_IN_PSB(_freq) ((_freq) > 4940 && (_freq) < 4990)
  333         if (flags & IEEE80211_CHAN_GSM)
  334                 return mapgsm(freq, flags);
  335         if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
  336                 if (freq == 2484)
  337                         return 14;
  338                 if (freq < 2484)
  339                         return ((int) freq - 2407) / 5;
  340                 else
  341                         return 15 + ((freq - 2512) / 20);
  342         } else if (flags & IEEE80211_CHAN_5GHZ) {       /* 5Ghz band */
  343                 if (freq <= 5000) {
  344                         /* XXX check regdomain? */
  345                         if (IS_FREQ_IN_PSB(freq))
  346                                 return mappsb(freq, flags);
  347                         return (freq - 4000) / 5;
  348                 } else
  349                         return (freq - 5000) / 5;
  350         } else {                                /* either, guess */
  351                 if (freq == 2484)
  352                         return 14;
  353                 if (freq < 2484) {
  354                         if (907 <= freq && freq <= 922)
  355                                 return mapgsm(freq, flags);
  356                         return ((int) freq - 2407) / 5;
  357                 }
  358                 if (freq < 5000) {
  359                         if (IS_FREQ_IN_PSB(freq))
  360                                 return mappsb(freq, flags);
  361                         else if (freq > 4900)
  362                                 return (freq - 4000) / 5;
  363                         else
  364                                 return 15 + ((freq - 2512) / 20);
  365                 }
  366                 return (freq - 5000) / 5;
  367         }
  368 #undef IS_FREQ_IN_PSB
  369 }
  370 
  371 /*
  372  * Convert channel to IEEE channel number.
  373  */
  374 int
  375 ieee80211_chan2ieee(struct ieee80211com *ic, const struct ieee80211_channel *c)
  376 {
  377         if (c == NULL) {
  378                 if_printf(ic->ic_ifp, "invalid channel (NULL)\n");
  379                 return 0;               /* XXX */
  380         }
  381         return (c == IEEE80211_CHAN_ANYC ?  IEEE80211_CHAN_ANY : c->ic_ieee);
  382 }
  383 
  384 /*
  385  * Convert IEEE channel number to MHz frequency.
  386  */
  387 u_int
  388 ieee80211_ieee2mhz(u_int chan, u_int flags)
  389 {
  390         if (flags & IEEE80211_CHAN_GSM)
  391                 return 907 + 5 * (chan / 10);
  392         if (flags & IEEE80211_CHAN_2GHZ) {      /* 2GHz band */
  393                 if (chan == 14)
  394                         return 2484;
  395                 if (chan < 14)
  396                         return 2407 + chan*5;
  397                 else
  398                         return 2512 + ((chan-15)*20);
  399         } else if (flags & IEEE80211_CHAN_5GHZ) {/* 5Ghz band */
  400                 if (flags & (IEEE80211_CHAN_HALF|IEEE80211_CHAN_QUARTER)) {
  401                         chan -= 37;
  402                         return 4940 + chan*5 + (chan % 5 ? 2 : 0);
  403                 }
  404                 return 5000 + (chan*5);
  405         } else {                                /* either, guess */
  406                 /* XXX can't distinguish PSB+GSM channels */
  407                 if (chan == 14)
  408                         return 2484;
  409                 if (chan < 14)                  /* 0-13 */
  410                         return 2407 + chan*5;
  411                 if (chan < 27)                  /* 15-26 */
  412                         return 2512 + ((chan-15)*20);
  413                 return 5000 + (chan*5);
  414         }
  415 }
  416 
  417 /*
  418  * Locate a channel given a frequency+flags.  We cache
  419  * the previous lookup to optimize swithing between two
  420  * channels--as happens with dynamic turbo.
  421  */
  422 struct ieee80211_channel *
  423 ieee80211_find_channel(struct ieee80211com *ic, int freq, int flags)
  424 {
  425         struct ieee80211_channel *c;
  426         int i;
  427 
  428         flags &= IEEE80211_CHAN_ALLTURBO;
  429         c = ic->ic_prevchan;
  430         if (c != NULL && c->ic_freq == freq &&
  431             (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
  432                 return c;
  433         /* brute force search */
  434         for (i = 0; i < ic->ic_nchans; i++) {
  435                 c = &ic->ic_channels[i];
  436                 if (c->ic_freq == freq &&
  437                     (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
  438                         return c;
  439         }
  440         return NULL;
  441 }
  442 
  443 /*
  444  * Locate a channel given a channel number+flags.  We cache
  445  * the previous lookup to optimize switching between two
  446  * channels--as happens with dynamic turbo.
  447  */
  448 struct ieee80211_channel *
  449 ieee80211_find_channel_byieee(struct ieee80211com *ic, int ieee, int flags)
  450 {
  451         struct ieee80211_channel *c;
  452         int i;
  453 
  454         flags &= IEEE80211_CHAN_ALLTURBO;
  455         c = ic->ic_prevchan;
  456         if (c != NULL && c->ic_ieee == ieee &&
  457             (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
  458                 return c;
  459         /* brute force search */
  460         for (i = 0; i < ic->ic_nchans; i++) {
  461                 c = &ic->ic_channels[i];
  462                 if (c->ic_ieee == ieee &&
  463                     (c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)
  464                         return c;
  465         }
  466         return NULL;
  467 }
  468 
  469 static void
  470 addmedia(struct ieee80211com *ic, int mode, int mword)
  471 {
  472 #define TURBO(m)        ((m) | IFM_IEEE80211_TURBO)
  473 #define ADD(_ic, _s, _o) \
  474         ifmedia_add(&(_ic)->ic_media, \
  475                 IFM_MAKEWORD(IFM_IEEE80211, (_s), (_o), 0), 0, NULL)
  476         static const u_int mopts[IEEE80211_MODE_MAX] = { 
  477                 IFM_AUTO,                       /* IEEE80211_MODE_AUTO */
  478                 IFM_IEEE80211_11A,              /* IEEE80211_MODE_11A */
  479                 IFM_IEEE80211_11B,              /* IEEE80211_MODE_11B */
  480                 IFM_IEEE80211_11G,              /* IEEE80211_MODE_11G */
  481                 IFM_IEEE80211_FH,               /* IEEE80211_MODE_FH */
  482                 TURBO(IFM_IEEE80211_11A),       /* IEEE80211_MODE_TURBO_A */
  483                 TURBO(IFM_IEEE80211_11G),       /* IEEE80211_MODE_TURBO_G */
  484                 TURBO(IFM_IEEE80211_11A),       /* IEEE80211_MODE_STURBO_A */
  485                 IFM_IEEE80211_11NA,             /* IEEE80211_MODE_11NA */
  486                 IFM_IEEE80211_11NG,             /* IEEE80211_MODE_11NG */
  487         };
  488         u_int mopt;
  489 
  490         KASSERT(mode < IEEE80211_MODE_MAX, ("bad mode %u", mode));
  491         mopt = mopts[mode];
  492         KASSERT(mopt != 0 || mode == IEEE80211_MODE_AUTO,
  493             ("no media mapping for mode %u", mode));
  494 
  495         ADD(ic, mword, mopt);   /* e.g. 11a auto */
  496         if (ic->ic_caps & IEEE80211_C_IBSS)
  497                 ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC);
  498         if (ic->ic_caps & IEEE80211_C_HOSTAP)
  499                 ADD(ic, mword, mopt | IFM_IEEE80211_HOSTAP);
  500         if (ic->ic_caps & IEEE80211_C_AHDEMO)
  501                 ADD(ic, mword, mopt | IFM_IEEE80211_ADHOC | IFM_FLAG0);
  502         if (ic->ic_caps & IEEE80211_C_MONITOR)
  503                 ADD(ic, mword, mopt | IFM_IEEE80211_MONITOR);
  504 #undef ADD
  505 #undef TURBO
  506 }
  507 
  508 /*
  509  * Setup the media data structures according to the channel and
  510  * rate tables.  This must be called by the driver after
  511  * ieee80211_attach and before most anything else.
  512  */
  513 void
  514 ieee80211_media_init(struct ieee80211com *ic,
  515         ifm_change_cb_t media_change, ifm_stat_cb_t media_stat)
  516 {
  517         struct ifnet *ifp = ic->ic_ifp;
  518         int i, j, mode, rate, maxrate, mword, r;
  519         const struct ieee80211_rateset *rs;
  520         struct ieee80211_rateset allrates;
  521 
  522         /* NB: this works because the structure is initialized to zero */
  523         if (LIST_EMPTY(&ic->ic_media.ifm_list)) {
  524                 /*
  525                  * Do late attach work that must wait for any subclass
  526                  * (i.e. driver) work such as overriding methods.
  527                  */
  528                 ieee80211_node_lateattach(ic);
  529         } else {
  530                 /*
  531                  * We are re-initializing the channel list; clear
  532                  * the existing media state as the media routines
  533                  * don't suppress duplicates.
  534                  */
  535                 ifmedia_removeall(&ic->ic_media);
  536                 ieee80211_chan_init(ic);
  537         }
  538         ieee80211_power_lateattach(ic);
  539 
  540         /*
  541          * Fill in media characteristics.
  542          */
  543         ifmedia_init(&ic->ic_media, 0, media_change, media_stat);
  544         maxrate = 0;
  545         /*
  546          * Add media for legacy operating modes.
  547          */
  548         memset(&allrates, 0, sizeof(allrates));
  549         for (mode = IEEE80211_MODE_AUTO; mode < IEEE80211_MODE_11NA; mode++) {
  550                 if (isclr(ic->ic_modecaps, mode))
  551                         continue;
  552                 addmedia(ic, mode, IFM_AUTO);
  553                 if (mode == IEEE80211_MODE_AUTO)
  554                         continue;
  555                 rs = &ic->ic_sup_rates[mode];
  556                 for (i = 0; i < rs->rs_nrates; i++) {
  557                         rate = rs->rs_rates[i];
  558                         mword = ieee80211_rate2media(ic, rate, mode);
  559                         if (mword == 0)
  560                                 continue;
  561                         addmedia(ic, mode, mword);
  562                         /*
  563                          * Add legacy rate to the collection of all rates.
  564                          */
  565                         r = rate & IEEE80211_RATE_VAL;
  566                         for (j = 0; j < allrates.rs_nrates; j++)
  567                                 if (allrates.rs_rates[j] == r)
  568                                         break;
  569                         if (j == allrates.rs_nrates) {
  570                                 /* unique, add to the set */
  571                                 allrates.rs_rates[j] = r;
  572                                 allrates.rs_nrates++;
  573                         }
  574                         rate = (rate & IEEE80211_RATE_VAL) / 2;
  575                         if (rate > maxrate)
  576                                 maxrate = rate;
  577                 }
  578         }
  579         for (i = 0; i < allrates.rs_nrates; i++) {
  580                 mword = ieee80211_rate2media(ic, allrates.rs_rates[i],
  581                                 IEEE80211_MODE_AUTO);
  582                 if (mword == 0)
  583                         continue;
  584                 /* NB: remove media options from mword */
  585                 addmedia(ic, IEEE80211_MODE_AUTO, IFM_SUBTYPE(mword));
  586         }
  587         /*
  588          * Add HT/11n media.  Note that we do not have enough
  589          * bits in the media subtype to express the MCS so we
  590          * use a "placeholder" media subtype and any fixed MCS
  591          * must be specified with a different mechanism.
  592          */
  593         for (; mode < IEEE80211_MODE_MAX; mode++) {
  594                 if (isclr(ic->ic_modecaps, mode))
  595                         continue;
  596                 addmedia(ic, mode, IFM_AUTO);
  597                 addmedia(ic, mode, IFM_IEEE80211_MCS);
  598         }
  599         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
  600             isset(ic->ic_modecaps, IEEE80211_MODE_11NG)) {
  601                 addmedia(ic, IEEE80211_MODE_AUTO, IFM_IEEE80211_MCS);
  602                 /* XXX could walk htrates */
  603                 /* XXX known array size */
  604                 if (ieee80211_htrates[15] > maxrate)
  605                         maxrate = ieee80211_htrates[15];
  606         }
  607 
  608         /* NB: strip explicit mode; we're actually in autoselect */
  609         ifmedia_set(&ic->ic_media,
  610                 media_status(ic->ic_opmode, ic->ic_curchan) &~ IFM_MMASK);
  611 
  612         if (maxrate)
  613                 ifp->if_baudrate = IF_Mbps(maxrate);
  614 }
  615 
  616 const struct ieee80211_rateset *
  617 ieee80211_get_suprates(struct ieee80211com *ic, const struct ieee80211_channel *c)
  618 {
  619         if (IEEE80211_IS_CHAN_HALF(c))
  620                 return &ieee80211_rateset_half;
  621         if (IEEE80211_IS_CHAN_QUARTER(c))
  622                 return &ieee80211_rateset_quarter;
  623         if (IEEE80211_IS_CHAN_HTA(c))
  624                 return &ic->ic_sup_rates[IEEE80211_MODE_11A];
  625         if (IEEE80211_IS_CHAN_HTG(c)) {
  626                 /* XXX does this work for basic rates? */
  627                 return &ic->ic_sup_rates[IEEE80211_MODE_11G];
  628         }
  629         return &ic->ic_sup_rates[ieee80211_chan2mode(c)];
  630 }
  631 
  632 void
  633 ieee80211_announce(struct ieee80211com *ic)
  634 {
  635         struct ifnet *ifp = ic->ic_ifp;
  636         int i, mode, rate, mword;
  637         const struct ieee80211_rateset *rs;
  638 
  639         /* NB: skip AUTO since it has no rates */
  640         for (mode = IEEE80211_MODE_AUTO+1; mode < IEEE80211_MODE_11NA; mode++) {
  641                 if (isclr(ic->ic_modecaps, mode))
  642                         continue;
  643                 if_printf(ifp, "%s rates: ", ieee80211_phymode_name[mode]);
  644                 rs = &ic->ic_sup_rates[mode];
  645                 for (i = 0; i < rs->rs_nrates; i++) {
  646                         mword = ieee80211_rate2media(ic, rs->rs_rates[i], mode);
  647                         if (mword == 0)
  648                                 continue;
  649                         rate = ieee80211_media2rate(mword);
  650                         printf("%s%d%sMbps", (i != 0 ? " " : ""),
  651                             rate / 2, ((rate & 0x1) != 0 ? ".5" : ""));
  652                 }
  653                 printf("\n");
  654         }
  655         ieee80211_ht_announce(ic);
  656 }
  657 
  658 void
  659 ieee80211_announce_channels(struct ieee80211com *ic)
  660 {
  661         const struct ieee80211_channel *c;
  662         char type;
  663         int i, cw;
  664 
  665         printf("Chan  Freq  CW  RegPwr  MinPwr  MaxPwr\n");
  666         for (i = 0; i < ic->ic_nchans; i++) {
  667                 c = &ic->ic_channels[i];
  668                 if (IEEE80211_IS_CHAN_ST(c))
  669                         type = 'S';
  670                 else if (IEEE80211_IS_CHAN_108A(c))
  671                         type = 'T';
  672                 else if (IEEE80211_IS_CHAN_108G(c))
  673                         type = 'G';
  674                 else if (IEEE80211_IS_CHAN_HT(c))
  675                         type = 'n';
  676                 else if (IEEE80211_IS_CHAN_A(c))
  677                         type = 'a';
  678                 else if (IEEE80211_IS_CHAN_ANYG(c))
  679                         type = 'g';
  680                 else if (IEEE80211_IS_CHAN_B(c))
  681                         type = 'b';
  682                 else
  683                         type = 'f';
  684                 if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_TURBO(c))
  685                         cw = 40;
  686                 else if (IEEE80211_IS_CHAN_HALF(c))
  687                         cw = 10;
  688                 else if (IEEE80211_IS_CHAN_QUARTER(c))
  689                         cw = 5;
  690                 else
  691                         cw = 20;
  692                 printf("%4d  %4d%c %2d%c %6d  %4d.%d  %4d.%d\n"
  693                         , c->ic_ieee, c->ic_freq, type
  694                         , cw
  695                         , IEEE80211_IS_CHAN_HT40U(c) ? '+' :
  696                           IEEE80211_IS_CHAN_HT40D(c) ? '-' : ' '
  697                         , c->ic_maxregpower
  698                         , c->ic_minpower / 2, c->ic_minpower & 1 ? 5 : 0
  699                         , c->ic_maxpower / 2, c->ic_maxpower & 1 ? 5 : 0
  700                 );
  701         }
  702 }
  703 
  704 /*
  705  * Find an instance by it's mac address.
  706  */
  707 struct ieee80211com *
  708 ieee80211_find_vap(const uint8_t mac[IEEE80211_ADDR_LEN])
  709 {
  710         struct ieee80211com *ic;
  711 
  712         /* XXX lock */
  713         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  714                 if (IEEE80211_ADDR_EQ(mac, ic->ic_myaddr))
  715                         return ic;
  716         return NULL;
  717 }
  718 
  719 static struct ieee80211com *
  720 ieee80211_find_instance(struct ifnet *ifp)
  721 {
  722         struct ieee80211com *ic;
  723 
  724         /* XXX lock */
  725         /* XXX not right for multiple instances but works for now */
  726         SLIST_FOREACH(ic, &ieee80211_list, ic_next)
  727                 if (ic->ic_ifp == ifp)
  728                         return ic;
  729         return NULL;
  730 }
  731 
  732 static int
  733 findrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  734 {
  735 #define IEEERATE(_ic,_m,_i) \
  736         ((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
  737         int i, nrates = ic->ic_sup_rates[mode].rs_nrates;
  738         for (i = 0; i < nrates; i++)
  739                 if (IEEERATE(ic, mode, i) == rate)
  740                         return i;
  741         return -1;
  742 #undef IEEERATE
  743 }
  744 
  745 /*
  746  * Convert a media specification to a rate index and possibly a mode
  747  * (if the rate is fixed and the mode is specified as ``auto'' then
  748  * we need to lock down the mode so the index is meanginful).
  749  */
  750 static int
  751 checkrate(struct ieee80211com *ic, enum ieee80211_phymode mode, int rate)
  752 {
  753 
  754         /*
  755          * Check the rate table for the specified/current phy.
  756          */
  757         if (mode == IEEE80211_MODE_AUTO) {
  758                 int i;
  759                 /*
  760                  * In autoselect mode search for the rate.
  761                  */
  762                 for (i = IEEE80211_MODE_11A; i < IEEE80211_MODE_MAX; i++) {
  763                         if (isset(ic->ic_modecaps, i) &&
  764                             findrate(ic, i, rate) != -1)
  765                                 return 1;
  766                 }
  767                 return 0;
  768         } else {
  769                 /*
  770                  * Mode is fixed, check for rate.
  771                  */
  772                 return (findrate(ic, mode, rate) != -1);
  773         }
  774 }
  775 
  776 /*
  777  * Handle a media change request.
  778  */
  779 int
  780 ieee80211_media_change(struct ifnet *ifp)
  781 {
  782         struct ieee80211com *ic;
  783         struct ifmedia_entry *ime;
  784         enum ieee80211_opmode newopmode;
  785         enum ieee80211_phymode newphymode;
  786         int newrate, error = 0;
  787 
  788         ic = ieee80211_find_instance(ifp);
  789         if (!ic) {
  790                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  791                 return EINVAL;
  792         }
  793         ime = ic->ic_media.ifm_cur;
  794         /*
  795          * First, identify the phy mode.
  796          */
  797         switch (IFM_MODE(ime->ifm_media)) {
  798         case IFM_IEEE80211_11A:
  799                 newphymode = IEEE80211_MODE_11A;
  800                 break;
  801         case IFM_IEEE80211_11B:
  802                 newphymode = IEEE80211_MODE_11B;
  803                 break;
  804         case IFM_IEEE80211_11G:
  805                 newphymode = IEEE80211_MODE_11G;
  806                 break;
  807         case IFM_IEEE80211_FH:
  808                 newphymode = IEEE80211_MODE_FH;
  809                 break;
  810         case IFM_IEEE80211_11NA:
  811                 newphymode = IEEE80211_MODE_11NA;
  812                 break;
  813         case IFM_IEEE80211_11NG:
  814                 newphymode = IEEE80211_MODE_11NG;
  815                 break;
  816         case IFM_AUTO:
  817                 newphymode = IEEE80211_MODE_AUTO;
  818                 break;
  819         default:
  820                 return EINVAL;
  821         }
  822         /*
  823          * Turbo mode is an ``option''.
  824          * XXX does not apply to AUTO
  825          */
  826         if (ime->ifm_media & IFM_IEEE80211_TURBO) {
  827                 if (newphymode == IEEE80211_MODE_11A) {
  828                         if (ic->ic_flags & IEEE80211_F_TURBOP)
  829                                 newphymode = IEEE80211_MODE_TURBO_A;
  830                         else
  831                                 newphymode = IEEE80211_MODE_STURBO_A;
  832                 } else if (newphymode == IEEE80211_MODE_11G)
  833                         newphymode = IEEE80211_MODE_TURBO_G;
  834                 else
  835                         return EINVAL;
  836         }
  837         /* XXX HT40 +/- */
  838         /*
  839          * Next, the fixed/variable rate.
  840          */
  841         newrate = ic->ic_fixed_rate;
  842         if (IFM_SUBTYPE(ime->ifm_media) != IFM_AUTO) {
  843                 /*
  844                  * Convert media subtype to rate.
  845                  */
  846                 newrate = ieee80211_media2rate(ime->ifm_media);
  847                 if (newrate == 0 || !checkrate(ic, newphymode, newrate))
  848                         return EINVAL;
  849         } else
  850                 newrate = IEEE80211_FIXED_RATE_NONE;
  851 
  852         /*
  853          * Deduce new operating mode but don't install it just yet.
  854          */
  855         if ((ime->ifm_media & (IFM_IEEE80211_ADHOC|IFM_FLAG0)) ==
  856             (IFM_IEEE80211_ADHOC|IFM_FLAG0))
  857                 newopmode = IEEE80211_M_AHDEMO;
  858         else if (ime->ifm_media & IFM_IEEE80211_HOSTAP)
  859                 newopmode = IEEE80211_M_HOSTAP;
  860         else if (ime->ifm_media & IFM_IEEE80211_ADHOC)
  861                 newopmode = IEEE80211_M_IBSS;
  862         else if (ime->ifm_media & IFM_IEEE80211_MONITOR)
  863                 newopmode = IEEE80211_M_MONITOR;
  864         else
  865                 newopmode = IEEE80211_M_STA;
  866 
  867         /*
  868          * Handle phy mode change.
  869          */
  870         if (ic->ic_des_mode != newphymode) {            /* change phy mode */
  871                 ic->ic_des_mode = newphymode;
  872                 error = ENETRESET;
  873         }
  874 
  875         /*
  876          * Committed to changes, install the rate setting.
  877          */
  878         if (ic->ic_fixed_rate != newrate) {
  879                 ic->ic_fixed_rate = newrate;            /* set fixed tx rate */
  880                 error = ENETRESET;
  881         }
  882 
  883         /*
  884          * Handle operating mode change.
  885          */
  886         if (ic->ic_opmode != newopmode) {
  887                 ic->ic_opmode = newopmode;
  888                 switch (newopmode) {
  889                 case IEEE80211_M_AHDEMO:
  890                 case IEEE80211_M_HOSTAP:
  891                 case IEEE80211_M_STA:
  892                 case IEEE80211_M_MONITOR:
  893                 case IEEE80211_M_WDS:
  894                         ic->ic_flags &= ~IEEE80211_F_IBSSON;
  895                         break;
  896                 case IEEE80211_M_IBSS:
  897                         ic->ic_flags |= IEEE80211_F_IBSSON;
  898                         break;
  899                 }
  900                 /*
  901                  * Yech, slot time may change depending on the
  902                  * operating mode so reset it to be sure everything
  903                  * is setup appropriately.
  904                  */
  905                 ieee80211_reset_erp(ic);
  906                 ieee80211_wme_initparams(ic);   /* after opmode change */
  907                 error = ENETRESET;
  908         }
  909 #ifdef notdef
  910         if (error == 0)
  911                 ifp->if_baudrate = ifmedia_baudrate(ime->ifm_media);
  912 #endif
  913         return error;
  914 }
  915 
  916 /*
  917  * Common code to calculate the media status word
  918  * from the operating mode and channel state.
  919  */
  920 static int
  921 media_status(enum ieee80211_opmode opmode, const struct ieee80211_channel *chan)
  922 {
  923         int status;
  924 
  925         status = IFM_IEEE80211;
  926         switch (opmode) {
  927         case IEEE80211_M_STA:
  928                 break;
  929         case IEEE80211_M_IBSS:
  930                 status |= IFM_IEEE80211_ADHOC;
  931                 break;
  932         case IEEE80211_M_HOSTAP:
  933                 status |= IFM_IEEE80211_HOSTAP;
  934                 break;
  935         case IEEE80211_M_MONITOR:
  936                 status |= IFM_IEEE80211_MONITOR;
  937                 break;
  938         case IEEE80211_M_AHDEMO:
  939                 status |= IFM_IEEE80211_ADHOC | IFM_FLAG0;
  940                 break;
  941         case IEEE80211_M_WDS:
  942                 /* should not come here */
  943                 break;
  944         }
  945         if (IEEE80211_IS_CHAN_HTA(chan)) {
  946                 status |= IFM_IEEE80211_11NA;
  947         } else if (IEEE80211_IS_CHAN_HTG(chan)) {
  948                 status |= IFM_IEEE80211_11NG;
  949         } else if (IEEE80211_IS_CHAN_A(chan)) {
  950                 status |= IFM_IEEE80211_11A;
  951         } else if (IEEE80211_IS_CHAN_B(chan)) {
  952                 status |= IFM_IEEE80211_11B;
  953         } else if (IEEE80211_IS_CHAN_ANYG(chan)) {
  954                 status |= IFM_IEEE80211_11G;
  955         } else if (IEEE80211_IS_CHAN_FHSS(chan)) {
  956                 status |= IFM_IEEE80211_FH;
  957         }
  958         /* XXX else complain? */
  959 
  960         if (IEEE80211_IS_CHAN_TURBO(chan))
  961                 status |= IFM_IEEE80211_TURBO;
  962 
  963         return status;
  964 }
  965 
  966 void
  967 ieee80211_media_status(struct ifnet *ifp, struct ifmediareq *imr)
  968 {
  969         struct ieee80211com *ic;
  970         enum ieee80211_phymode mode;
  971         const struct ieee80211_rateset *rs;
  972 
  973         ic = ieee80211_find_instance(ifp);
  974         if (!ic) {
  975                 if_printf(ifp, "%s: no 802.11 instance!\n", __func__);
  976                 return;
  977         }
  978         imr->ifm_status = IFM_AVALID;
  979         /*
  980          * NB: use the current channel's mode to lock down a xmit
  981          * rate only when running; otherwise we may have a mismatch
  982          * in which case the rate will not be convertible.
  983          */
  984         if (ic->ic_state == IEEE80211_S_RUN) {
  985                 imr->ifm_status |= IFM_ACTIVE;
  986                 mode = ieee80211_chan2mode(ic->ic_curchan);
  987         } else
  988                 mode = IEEE80211_MODE_AUTO;
  989         imr->ifm_active = media_status(ic->ic_opmode, ic->ic_curchan);
  990         /*
  991          * Calculate a current rate if possible.
  992          */
  993         if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
  994                 /*
  995                  * A fixed rate is set, report that.
  996                  */
  997                 imr->ifm_active |= ieee80211_rate2media(ic,
  998                         ic->ic_fixed_rate, mode);
  999         } else if (ic->ic_opmode == IEEE80211_M_STA) {
 1000                 /*
 1001                  * In station mode report the current transmit rate.
 1002                  * XXX HT rate
 1003                  */
 1004                 rs = &ic->ic_bss->ni_rates;
 1005                 imr->ifm_active |= ieee80211_rate2media(ic,
 1006                         rs->rs_rates[ic->ic_bss->ni_txrate], mode);
 1007         } else
 1008                 imr->ifm_active |= IFM_AUTO;
 1009 }
 1010 
 1011 /*
 1012  * Set the current phy mode and recalculate the active channel
 1013  * set based on the available channels for this mode.  Also
 1014  * select a new default/current channel if the current one is
 1015  * inappropriate for this mode.
 1016  */
 1017 int
 1018 ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
 1019 {
 1020         /*
 1021          * Adjust basic rates in 11b/11g supported rate set.
 1022          * Note that if operating on a hal/quarter rate channel
 1023          * this is a noop as those rates sets are different
 1024          * and used instead.
 1025          */
 1026         if (mode == IEEE80211_MODE_11G || mode == IEEE80211_MODE_11B)
 1027                 ieee80211_set11gbasicrates(&ic->ic_sup_rates[mode], mode);
 1028 
 1029         ic->ic_curmode = mode;
 1030         ieee80211_reset_erp(ic);        /* reset ERP state */
 1031         ieee80211_wme_initparams(ic);   /* reset WME stat */
 1032 
 1033         return 0;
 1034 }
 1035 
 1036 /*
 1037  * Return the phy mode for with the specified channel.
 1038  */
 1039 enum ieee80211_phymode
 1040 ieee80211_chan2mode(const struct ieee80211_channel *chan)
 1041 {
 1042 
 1043         if (IEEE80211_IS_CHAN_HTA(chan))
 1044                 return IEEE80211_MODE_11NA;
 1045         else if (IEEE80211_IS_CHAN_HTG(chan))
 1046                 return IEEE80211_MODE_11NG;
 1047         else if (IEEE80211_IS_CHAN_108G(chan))
 1048                 return IEEE80211_MODE_TURBO_G;
 1049         else if (IEEE80211_IS_CHAN_ST(chan))
 1050                 return IEEE80211_MODE_STURBO_A;
 1051         else if (IEEE80211_IS_CHAN_TURBO(chan))
 1052                 return IEEE80211_MODE_TURBO_A;
 1053         else if (IEEE80211_IS_CHAN_A(chan))
 1054                 return IEEE80211_MODE_11A;
 1055         else if (IEEE80211_IS_CHAN_ANYG(chan))
 1056                 return IEEE80211_MODE_11G;
 1057         else if (IEEE80211_IS_CHAN_B(chan))
 1058                 return IEEE80211_MODE_11B;
 1059         else if (IEEE80211_IS_CHAN_FHSS(chan))
 1060                 return IEEE80211_MODE_FH;
 1061 
 1062         /* NB: should not get here */
 1063         printf("%s: cannot map channel to mode; freq %u flags 0x%x\n",
 1064                 __func__, chan->ic_freq, chan->ic_flags);
 1065         return IEEE80211_MODE_11B;
 1066 }
 1067 
 1068 struct ratemedia {
 1069         u_int   match;  /* rate + mode */
 1070         u_int   media;  /* if_media rate */
 1071 };
 1072 
 1073 static int
 1074 findmedia(const struct ratemedia rates[], int n, u_int match)
 1075 {
 1076         int i;
 1077 
 1078         for (i = 0; i < n; i++)
 1079                 if (rates[i].match == match)
 1080                         return rates[i].media;
 1081         return IFM_AUTO;
 1082 }
 1083 
 1084 /*
 1085  * Convert IEEE80211 rate value to ifmedia subtype.
 1086  * Rate is either a legacy rate in units of 0.5Mbps
 1087  * or an MCS index.
 1088  */
 1089 int
 1090 ieee80211_rate2media(struct ieee80211com *ic, int rate, enum ieee80211_phymode mode)
 1091 {
 1092 #define N(a)    (sizeof(a) / sizeof(a[0]))
 1093         static const struct ratemedia rates[] = {
 1094                 {   2 | IFM_IEEE80211_FH, IFM_IEEE80211_FH1 },
 1095                 {   4 | IFM_IEEE80211_FH, IFM_IEEE80211_FH2 },
 1096                 {   2 | IFM_IEEE80211_11B, IFM_IEEE80211_DS1 },
 1097                 {   4 | IFM_IEEE80211_11B, IFM_IEEE80211_DS2 },
 1098                 {  11 | IFM_IEEE80211_11B, IFM_IEEE80211_DS5 },
 1099                 {  22 | IFM_IEEE80211_11B, IFM_IEEE80211_DS11 },
 1100                 {  44 | IFM_IEEE80211_11B, IFM_IEEE80211_DS22 },
 1101                 {  12 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM6 },
 1102                 {  18 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM9 },
 1103                 {  24 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM12 },
 1104                 {  36 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM18 },
 1105                 {  48 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM24 },
 1106                 {  72 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM36 },
 1107                 {  96 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM48 },
 1108                 { 108 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM54 },
 1109                 {   2 | IFM_IEEE80211_11G, IFM_IEEE80211_DS1 },
 1110                 {   4 | IFM_IEEE80211_11G, IFM_IEEE80211_DS2 },
 1111                 {  11 | IFM_IEEE80211_11G, IFM_IEEE80211_DS5 },
 1112                 {  22 | IFM_IEEE80211_11G, IFM_IEEE80211_DS11 },
 1113                 {  12 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM6 },
 1114                 {  18 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM9 },
 1115                 {  24 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM12 },
 1116                 {  36 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM18 },
 1117                 {  48 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM24 },
 1118                 {  72 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM36 },
 1119                 {  96 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM48 },
 1120                 { 108 | IFM_IEEE80211_11G, IFM_IEEE80211_OFDM54 },
 1121                 {   6 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM3 },
 1122                 {   9 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM4 },
 1123                 {  54 | IFM_IEEE80211_11A, IFM_IEEE80211_OFDM27 },
 1124                 /* NB: OFDM72 doesn't realy exist so we don't handle it */
 1125         };
 1126         static const struct ratemedia htrates[] = {
 1127                 {   0, IFM_IEEE80211_MCS },
 1128                 {   1, IFM_IEEE80211_MCS },
 1129                 {   2, IFM_IEEE80211_MCS },
 1130                 {   3, IFM_IEEE80211_MCS },
 1131                 {   4, IFM_IEEE80211_MCS },
 1132                 {   5, IFM_IEEE80211_MCS },
 1133                 {   6, IFM_IEEE80211_MCS },
 1134                 {   7, IFM_IEEE80211_MCS },
 1135                 {   8, IFM_IEEE80211_MCS },
 1136                 {   9, IFM_IEEE80211_MCS },
 1137                 {  10, IFM_IEEE80211_MCS },
 1138                 {  11, IFM_IEEE80211_MCS },
 1139                 {  12, IFM_IEEE80211_MCS },
 1140                 {  13, IFM_IEEE80211_MCS },
 1141                 {  14, IFM_IEEE80211_MCS },
 1142                 {  15, IFM_IEEE80211_MCS },
 1143         };
 1144         int m;
 1145 
 1146         /*
 1147          * Check 11n rates first for match as an MCS.
 1148          */
 1149         if (mode == IEEE80211_MODE_11NA) {
 1150                 if (rate & IEEE80211_RATE_MCS) {
 1151                         rate &= ~IEEE80211_RATE_MCS;
 1152                         m = findmedia(htrates, N(htrates), rate);
 1153                         if (m != IFM_AUTO)
 1154                                 return m | IFM_IEEE80211_11NA;
 1155                 }
 1156         } else if (mode == IEEE80211_MODE_11NG) {
 1157                 /* NB: 12 is ambiguous, it will be treated as an MCS */
 1158                 if (rate & IEEE80211_RATE_MCS) {
 1159                         rate &= ~IEEE80211_RATE_MCS;
 1160                         m = findmedia(htrates, N(htrates), rate);
 1161                         if (m != IFM_AUTO)
 1162                                 return m | IFM_IEEE80211_11NG;
 1163                 }
 1164         }
 1165         rate &= IEEE80211_RATE_VAL;
 1166         switch (mode) {
 1167         case IEEE80211_MODE_11A:
 1168         case IEEE80211_MODE_11NA:
 1169         case IEEE80211_MODE_TURBO_A:
 1170         case IEEE80211_MODE_STURBO_A:
 1171                 return findmedia(rates, N(rates), rate | IFM_IEEE80211_11A);
 1172         case IEEE80211_MODE_11B:
 1173                 return findmedia(rates, N(rates), rate | IFM_IEEE80211_11B);
 1174         case IEEE80211_MODE_FH:
 1175                 return findmedia(rates, N(rates), rate | IFM_IEEE80211_FH);
 1176         case IEEE80211_MODE_AUTO:
 1177                 /* NB: ic may be NULL for some drivers */
 1178                 if (ic && ic->ic_phytype == IEEE80211_T_FH)
 1179                         return findmedia(rates, N(rates),
 1180                             rate | IFM_IEEE80211_FH);
 1181                 /* NB: hack, 11g matches both 11b+11a rates */
 1182                 /* fall thru... */
 1183         case IEEE80211_MODE_11G:
 1184         case IEEE80211_MODE_11NG:
 1185         case IEEE80211_MODE_TURBO_G:
 1186                 return findmedia(rates, N(rates), rate | IFM_IEEE80211_11G);
 1187         }
 1188         return IFM_AUTO;
 1189 #undef N
 1190 }
 1191 
 1192 int
 1193 ieee80211_media2rate(int mword)
 1194 {
 1195 #define N(a)    (sizeof(a) / sizeof(a[0]))
 1196         static const int ieeerates[] = {
 1197                 -1,             /* IFM_AUTO */
 1198                 0,              /* IFM_MANUAL */
 1199                 0,              /* IFM_NONE */
 1200                 2,              /* IFM_IEEE80211_FH1 */
 1201                 4,              /* IFM_IEEE80211_FH2 */
 1202                 2,              /* IFM_IEEE80211_DS1 */
 1203                 4,              /* IFM_IEEE80211_DS2 */
 1204                 11,             /* IFM_IEEE80211_DS5 */
 1205                 22,             /* IFM_IEEE80211_DS11 */
 1206                 44,             /* IFM_IEEE80211_DS22 */
 1207                 12,             /* IFM_IEEE80211_OFDM6 */
 1208                 18,             /* IFM_IEEE80211_OFDM9 */
 1209                 24,             /* IFM_IEEE80211_OFDM12 */
 1210                 36,             /* IFM_IEEE80211_OFDM18 */
 1211                 48,             /* IFM_IEEE80211_OFDM24 */
 1212                 72,             /* IFM_IEEE80211_OFDM36 */
 1213                 96,             /* IFM_IEEE80211_OFDM48 */
 1214                 108,            /* IFM_IEEE80211_OFDM54 */
 1215                 144,            /* IFM_IEEE80211_OFDM72 */
 1216                 0,              /* IFM_IEEE80211_DS354k */
 1217                 0,              /* IFM_IEEE80211_DS512k */
 1218                 6,              /* IFM_IEEE80211_OFDM3 */
 1219                 9,              /* IFM_IEEE80211_OFDM4 */
 1220                 54,             /* IFM_IEEE80211_OFDM27 */
 1221                 -1,             /* IFM_IEEE80211_MCS */
 1222         };
 1223         return IFM_SUBTYPE(mword) < N(ieeerates) ?
 1224                 ieeerates[IFM_SUBTYPE(mword)] : 0;
 1225 #undef N
 1226 }

Cache object: 0add08775408c28e4d4d2ce16bd012bf


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