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_scan_ap.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) 2002-2007 Sam Leffler, Errno Consulting
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD$");
   28 
   29 /*
   30  * IEEE 802.11 ap scanning support.
   31  */
   32 #include <sys/param.h>
   33 #include <sys/systm.h> 
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36  
   37 #include <sys/socket.h>
   38 
   39 #include <net/if.h>
   40 #include <net/if_media.h>
   41 #include <net/ethernet.h>
   42 
   43 #include <net80211/ieee80211_var.h>
   44 
   45 #include <net/bpf.h>
   46 
   47 struct ap_state {
   48         int     as_maxrssi[IEEE80211_CHAN_MAX];
   49 };
   50 
   51 static int ap_flush(struct ieee80211_scan_state *);
   52 
   53 /* number of references from net80211 layer */
   54 static  int nrefs = 0;
   55 
   56 /*
   57  * Attach prior to any scanning work.
   58  */
   59 static int
   60 ap_attach(struct ieee80211_scan_state *ss)
   61 {
   62         struct ap_state *as;
   63 
   64         MALLOC(as, struct ap_state *, sizeof(struct ap_state),
   65                 M_80211_SCAN, M_NOWAIT);
   66         ss->ss_priv = as;
   67         ap_flush(ss);
   68         nrefs++;                        /* NB: we assume caller locking */
   69         return 1;
   70 }
   71 
   72 /*
   73  * Cleanup any private state.
   74  */
   75 static int
   76 ap_detach(struct ieee80211_scan_state *ss)
   77 {
   78         struct ap_state *as = ss->ss_priv;
   79 
   80         if (as != NULL) {
   81                 KASSERT(nrefs > 0, ("imbalanced attach/detach"));
   82                 nrefs--;                /* NB: we assume caller locking */
   83                 FREE(as, M_80211_SCAN);
   84         }
   85         return 1;
   86 }
   87 
   88 /*
   89  * Flush all per-scan state.
   90  */
   91 static int
   92 ap_flush(struct ieee80211_scan_state *ss)
   93 {
   94         struct ap_state *as = ss->ss_priv;
   95 
   96         memset(as->as_maxrssi, 0, sizeof(as->as_maxrssi));
   97         ss->ss_last = 0;                /* insure no channel will be picked */
   98         return 0;
   99 }
  100 
  101 static int
  102 find11gchannel(struct ieee80211com *ic, int i, int freq)
  103 {
  104         const struct ieee80211_channel *c;
  105         int j;
  106 
  107         /*
  108          * The normal ordering in the channel list is b channel
  109          * immediately followed by g so optimize the search for
  110          * this.  We'll still do a full search just in case.
  111          */
  112         for (j = i+1; j < ic->ic_nchans; j++) {
  113                 c = &ic->ic_channels[j];
  114                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
  115                         return 1;
  116         }
  117         for (j = 0; j < i; j++) {
  118                 c = &ic->ic_channels[j];
  119                 if (c->ic_freq == freq && IEEE80211_IS_CHAN_ANYG(c))
  120                         return 1;
  121         }
  122         return 0;
  123 }
  124 
  125 /*
  126  * Start an ap scan by populating the channel list.
  127  */
  128 static int
  129 ap_start(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
  130 {
  131         struct ieee80211_channel *c;
  132         int i;
  133 
  134         ss->ss_last = 0;
  135         if (ic->ic_des_mode == IEEE80211_MODE_AUTO) {
  136                 for (i = 0; i < ic->ic_nchans; i++) {
  137                         c = &ic->ic_channels[i];
  138                         if (IEEE80211_IS_CHAN_TURBO(c)) {
  139 #ifdef IEEE80211_F_XR
  140                                 /* XR is not supported on turbo channels */
  141                                 if (ic->ic_flags & IEEE80211_F_XR)
  142                                         continue;
  143 #endif
  144                                 /* dynamic channels are scanned in base mode */
  145                                 if (!IEEE80211_IS_CHAN_ST(c))
  146                                         continue;
  147                         } else if (IEEE80211_IS_CHAN_HT(c)) {
  148                                 /* HT channels are scanned in legacy */
  149                                 continue;
  150                         } else {
  151                                 /*
  152                                  * Use any 11g channel instead of 11b one.
  153                                  */
  154                                 if (IEEE80211_IS_CHAN_B(c) &&
  155                                     find11gchannel(ic, i, c->ic_freq))
  156                                         continue;
  157                         }
  158                         if (ss->ss_last >= IEEE80211_SCAN_MAX)
  159                                 break;
  160                         ss->ss_chans[ss->ss_last++] = c;
  161                 }
  162         } else {
  163                 static const u_int chanflags[IEEE80211_MODE_MAX] = {
  164                         0,                      /* IEEE80211_MODE_AUTO */
  165                         IEEE80211_CHAN_A,       /* IEEE80211_MODE_11A */
  166                         IEEE80211_CHAN_B,       /* IEEE80211_MODE_11B */
  167                         IEEE80211_CHAN_G,       /* IEEE80211_MODE_11G */
  168                         IEEE80211_CHAN_FHSS,    /* IEEE80211_MODE_FH */
  169                         IEEE80211_CHAN_108A,    /* IEEE80211_MODE_TURBO_A */
  170                         IEEE80211_CHAN_108G,    /* IEEE80211_MODE_TURBO_G */
  171                         IEEE80211_CHAN_ST,      /* IEEE80211_MODE_STURBO_A */
  172                         IEEE80211_CHAN_A,       /* IEEE80211_MODE_11NA */
  173                         IEEE80211_CHAN_G,       /* IEEE80211_MODE_11NG */
  174                 };
  175                 u_int modeflags;
  176 
  177                 modeflags = chanflags[ic->ic_des_mode];
  178                 if ((ic->ic_flags & IEEE80211_F_TURBOP) &&
  179                     modeflags != IEEE80211_CHAN_ST) {
  180                         if (ic->ic_des_mode == IEEE80211_MODE_11G)
  181                                 modeflags = IEEE80211_CHAN_108G;
  182                         else
  183                                 modeflags = IEEE80211_CHAN_108A;
  184                 }
  185                 for (i = 0; i < ic->ic_nchans; i++) {
  186                         c = &ic->ic_channels[i];
  187                         if ((c->ic_flags & modeflags) != modeflags)
  188                                 continue;
  189 #ifdef IEEE80211_F_XR
  190                         /* XR is not supported on turbo channels */
  191                         if (IEEE80211_IS_CHAN_TURBO(c) &&
  192                             (ic->ic_flags & IEEE80211_F_XR))
  193                                 continue;
  194 #endif
  195                         if (ss->ss_last >= IEEE80211_SCAN_MAX)
  196                                 break;
  197                         /* 
  198                          * Do not select static turbo channels if
  199                          * the mode is not static turbo.
  200                          */
  201                         if (IEEE80211_IS_CHAN_STURBO(c) &&
  202                             ic->ic_des_mode != IEEE80211_MODE_STURBO_A)
  203                                 continue;
  204                         ss->ss_chans[ss->ss_last++] = c;
  205                 }
  206         }
  207         ss->ss_next = 0;
  208         /* XXX tunables */
  209         ss->ss_mindwell = msecs_to_ticks(200);          /* 200ms */
  210         ss->ss_maxdwell = msecs_to_ticks(300);          /* 300ms */
  211 
  212 #ifdef IEEE80211_DEBUG
  213         if (ieee80211_msg_scan(ic)) {
  214                 if_printf(ic->ic_ifp, "scan set ");
  215                 ieee80211_scan_dump_channels(ss);
  216                 printf(" dwell min %ld max %ld\n",
  217                         ss->ss_mindwell, ss->ss_maxdwell);
  218         }
  219 #endif /* IEEE80211_DEBUG */
  220 
  221         return 0;
  222 }
  223 
  224 /*
  225  * Restart a bg scan.
  226  */
  227 static int
  228 ap_restart(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
  229 {
  230         return 0;
  231 }
  232 
  233 /*
  234  * Cancel an ongoing scan.
  235  */
  236 static int
  237 ap_cancel(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
  238 {
  239         return 0;
  240 }
  241 
  242 /*
  243  * Record max rssi on channel.
  244  */
  245 static int
  246 ap_add(struct ieee80211_scan_state *ss,
  247         const struct ieee80211_scanparams *sp,
  248         const struct ieee80211_frame *wh,
  249         int subtype, int rssi, int noise, int rstamp)
  250 {
  251         struct ap_state *as = ss->ss_priv;
  252         struct ieee80211com *ic = ss->ss_ic;
  253         int chan;
  254 
  255         chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
  256         /* XXX better quantification of channel use? */
  257         /* XXX count bss's? */
  258         if (rssi > as->as_maxrssi[chan])
  259                 as->as_maxrssi[chan] = rssi;
  260         /* XXX interference, turbo requirements */
  261         return 1;
  262 }
  263 
  264 /*
  265  * Pick a quiet channel to use for ap operation.
  266  */
  267 static int
  268 ap_end(struct ieee80211_scan_state *ss, struct ieee80211com *ic)
  269 {
  270         struct ap_state *as = ss->ss_priv;
  271         int i, chan, bestchan, bestchanix;
  272 
  273         KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP,
  274                 ("wrong opmode %u", ic->ic_opmode));
  275         /* XXX select channel more intelligently, e.g. channel spread, power */
  276         bestchan = -1;
  277         bestchanix = 0;         /* NB: silence compiler */
  278         /* NB: use scan list order to preserve channel preference */
  279         for (i = 0; i < ss->ss_last; i++) {
  280                 /*
  281                  * If the channel is unoccupied the max rssi
  282                  * should be zero; just take it.  Otherwise
  283                  * track the channel with the lowest rssi and
  284                  * use that when all channels appear occupied.
  285                  */
  286                 /* XXX channel have interference? */
  287                 chan = ieee80211_chan2ieee(ic, ss->ss_chans[i]);
  288 
  289                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  290                     "%s: channel %u rssi %d bestchan %d bestchan rssi %d\n",
  291                     __func__, chan, as->as_maxrssi[chan],
  292                     bestchan, bestchan != -1 ? as->as_maxrssi[bestchan] : 0);
  293 
  294                 if (as->as_maxrssi[chan] == 0) {
  295                         bestchan = chan;
  296                         bestchanix = i;
  297                         /* XXX use other considerations */
  298                         break;
  299                 }
  300                 if (bestchan == -1 ||
  301                     as->as_maxrssi[chan] < as->as_maxrssi[bestchan])
  302                         bestchan = chan;
  303         }
  304         if (bestchan == -1) {
  305                 /* no suitable channel, should not happen */
  306                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  307                     "%s: no suitable channel! (should not happen)\n", __func__);
  308                 /* XXX print something? */
  309                 return 0;                       /* restart scan */
  310         } else {
  311                 struct ieee80211_channel *c;
  312 
  313                 /* XXX notify all vap's? */
  314                 /*
  315                  * If this is a dynamic turbo frequency,
  316                  * start with normal mode first.
  317                  */
  318                 c = ss->ss_chans[bestchanix];
  319                 if (IEEE80211_IS_CHAN_TURBO(c) &&
  320                     !IEEE80211_IS_CHAN_STURBO(c)) { 
  321                         c = ieee80211_find_channel(ic, c->ic_freq,
  322                                 c->ic_flags & ~IEEE80211_CHAN_TURBO);
  323                         if (c == NULL) {
  324                                 /* should never happen ?? */
  325                                 return 0;
  326                         }
  327                 }
  328                 ieee80211_create_ibss(ic,
  329                     ieee80211_ht_adjust_channel(ic, c, ic->ic_flags_ext));
  330                 return 1;
  331         }
  332 }
  333 
  334 static void
  335 ap_age(struct ieee80211_scan_state *ss)
  336 {
  337         /* XXX is there anything meaningful to do? */
  338 }
  339 
  340 static void
  341 ap_iterate(struct ieee80211_scan_state *ss,
  342         ieee80211_scan_iter_func *f, void *arg)
  343 {
  344         /* NB: nothing meaningful we can do */
  345 }
  346 
  347 static void
  348 ap_assoc_success(struct ieee80211_scan_state *ss,
  349         const uint8_t macaddr[IEEE80211_ADDR_LEN])
  350 {
  351         /* should not be called */
  352 }
  353 
  354 static void
  355 ap_assoc_fail(struct ieee80211_scan_state *ss,
  356         const uint8_t macaddr[IEEE80211_ADDR_LEN], int reason)
  357 {
  358         /* should not be called */
  359 }
  360 
  361 static const struct ieee80211_scanner ap_default = {
  362         .scan_name              = "default",
  363         .scan_attach            = ap_attach,
  364         .scan_detach            = ap_detach,
  365         .scan_start             = ap_start,
  366         .scan_restart           = ap_restart,
  367         .scan_cancel            = ap_cancel,
  368         .scan_end               = ap_end,
  369         .scan_flush             = ap_flush,
  370         .scan_add               = ap_add,
  371         .scan_age               = ap_age,
  372         .scan_iterate           = ap_iterate,
  373         .scan_assoc_success     = ap_assoc_success,
  374         .scan_assoc_fail        = ap_assoc_fail,
  375 };
  376 
  377 /*
  378  * Module glue.
  379  */
  380 static int
  381 wlan_modevent(module_t mod, int type, void *unused)
  382 {
  383         switch (type) {
  384         case MOD_LOAD:
  385                 ieee80211_scanner_register(IEEE80211_M_HOSTAP, &ap_default);
  386                 return 0;
  387         case MOD_UNLOAD:
  388         case MOD_QUIESCE:
  389                 if (nrefs) {
  390                         printf("wlan_scan_ap: still in use (%u dynamic refs)\n",
  391                                 nrefs);
  392                         return EBUSY;
  393                 }
  394                 if (type == MOD_UNLOAD)
  395                         ieee80211_scanner_unregister_all(&ap_default);
  396                 return 0;
  397         }
  398         return EINVAL;
  399 }
  400 
  401 static moduledata_t wlan_mod = {
  402         "wlan_scan_ap",
  403         wlan_modevent,
  404         0
  405 };
  406 DECLARE_MODULE(wlan_scan_ap, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
  407 MODULE_VERSION(wlan_scan_ap, 1);
  408 MODULE_DEPEND(wlan_scan_ap, wlan, 1, 1, 1);

Cache object: 6cdc6b975c2184677b08c254134cc305


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