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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

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

Cache object: 67fefd899f1c076e46161f8c127ecc4d


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