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.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 scanning support.
   31  */
   32 #include <sys/param.h>
   33 #include <sys/systm.h> 
   34 #include <sys/kernel.h>
   35  
   36 #include <sys/socket.h>
   37 
   38 #include <net/if.h>
   39 #include <net/if_media.h>
   40 #include <net/ethernet.h>
   41 
   42 #include <net80211/ieee80211_var.h>
   43 
   44 #include <net/bpf.h>
   45 
   46 struct scan_state {
   47         struct ieee80211_scan_state base;       /* public state */
   48 
   49         u_int           ss_iflags;              /* flags used internally */
   50 #define ISCAN_MINDWELL  0x0001          /* min dwell time reached */
   51 #define ISCAN_DISCARD   0x0002          /* discard rx'd frames */
   52 #define ISCAN_CANCEL    0x0004          /* cancel current scan */
   53 #define ISCAN_START     0x0008          /* 1st time through next_scan */
   54         unsigned long   ss_chanmindwell;        /* min dwell on curchan */
   55         unsigned long   ss_scanend;             /* time scan must stop */
   56         u_int           ss_duration;            /* duration for next scan */
   57         struct callout  ss_scan_timer;          /* scan timer */
   58 };
   59 #define SCAN_PRIVATE(ss)        ((struct scan_state *) ss)
   60 
   61 /*
   62  * Amount of time to go off-channel during a background
   63  * scan.  This value should be large enough to catch most
   64  * ap's but short enough that we can return on-channel
   65  * before our listen interval expires.
   66  *
   67  * XXX tunable
   68  * XXX check against configured listen interval
   69  */
   70 #define IEEE80211_SCAN_OFFCHANNEL       msecs_to_ticks(150)
   71 
   72 /*
   73  * Roaming-related defaults.  RSSI thresholds are as returned by the
   74  * driver (dBm).  Transmit rate thresholds are IEEE rate codes (i.e
   75  * .5M units).
   76  */
   77 #define ROAM_RSSI_11A_DEFAULT           14      /* rssi threshold for 11a bss */
   78 #define ROAM_RSSI_11B_DEFAULT           14      /* rssi threshold for 11b bss */
   79 #define ROAM_RSSI_11BONLY_DEFAULT       14      /* rssi threshold for 11b-only bss */
   80 #define ROAM_RATE_11A_DEFAULT           2*12    /* tx rate thresh for 11a bss */
   81 #define ROAM_RATE_11B_DEFAULT           2*5     /* tx rate thresh for 11b bss */
   82 #define ROAM_RATE_11BONLY_DEFAULT       2*1     /* tx rate thresh for 11b-only bss */
   83 
   84 static  void scan_restart_pwrsav(void *);
   85 static  void scan_curchan(struct ieee80211com *, unsigned long);
   86 static  void scan_mindwell(struct ieee80211com *);
   87 static  void scan_next(void *);
   88 
   89 MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
   90 
   91 void
   92 ieee80211_scan_attach(struct ieee80211com *ic)
   93 {
   94         struct scan_state *ss;
   95 
   96         ic->ic_roaming = IEEE80211_ROAMING_AUTO;
   97 
   98         MALLOC(ss, struct scan_state *, sizeof(struct scan_state),
   99                 M_80211_SCAN, M_NOWAIT | M_ZERO);
  100         if (ss == NULL) {
  101                 ic->ic_scan = NULL;
  102                 return;
  103         }
  104         callout_init(&ss->ss_scan_timer, CALLOUT_MPSAFE);
  105         ic->ic_scan = &ss->base;
  106 
  107         ic->ic_scan_curchan = scan_curchan;
  108         ic->ic_scan_mindwell = scan_mindwell;
  109 
  110         ic->ic_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz;
  111         ic->ic_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz;
  112         ic->ic_scanvalid = IEEE80211_SCAN_VALID_DEFAULT*hz;
  113         ic->ic_roam.rssi11a = ROAM_RSSI_11A_DEFAULT;
  114         ic->ic_roam.rssi11b = ROAM_RSSI_11B_DEFAULT;
  115         ic->ic_roam.rssi11bOnly = ROAM_RSSI_11BONLY_DEFAULT;
  116         ic->ic_roam.rate11a = ROAM_RATE_11A_DEFAULT;
  117         ic->ic_roam.rate11b = ROAM_RATE_11B_DEFAULT;
  118         ic->ic_roam.rate11bOnly = ROAM_RATE_11BONLY_DEFAULT;
  119 }
  120 
  121 void
  122 ieee80211_scan_detach(struct ieee80211com *ic)
  123 {
  124         struct ieee80211_scan_state *ss = ic->ic_scan;
  125 
  126         if (ss != NULL) {
  127                 callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
  128                 if (ss->ss_ops != NULL) {
  129                         ss->ss_ops->scan_detach(ss);
  130                         ss->ss_ops = NULL;
  131                 }
  132                 ic->ic_flags &= ~IEEE80211_F_SCAN;
  133                 ic->ic_scan = NULL;
  134                 FREE(SCAN_PRIVATE(ss), M_80211_SCAN);
  135         }
  136 }
  137 
  138 /*
  139  * Simple-minded scanner module support.
  140  */
  141 #define IEEE80211_SCANNER_MAX   (IEEE80211_M_MONITOR+1)
  142 
  143 static const char *scan_modnames[IEEE80211_SCANNER_MAX] = {
  144         "wlan_scan_sta",        /* IEEE80211_M_IBSS */
  145         "wlan_scan_sta",        /* IEEE80211_M_STA */
  146         "wlan_scan_wds",        /* IEEE80211_M_WDS */
  147         "wlan_scan_sta",        /* IEEE80211_M_AHDEMO */
  148         "wlan_scan_4",          /* n/a */
  149         "wlan_scan_5",          /* n/a */
  150         "wlan_scan_ap",         /* IEEE80211_M_HOSTAP */
  151         "wlan_scan_7",          /* n/a */
  152         "wlan_scan_monitor",    /* IEEE80211_M_MONITOR */
  153 };
  154 static const struct ieee80211_scanner *scanners[IEEE80211_SCANNER_MAX];
  155 
  156 const struct ieee80211_scanner *
  157 ieee80211_scanner_get(enum ieee80211_opmode mode)
  158 {
  159         if (mode >= IEEE80211_SCANNER_MAX)
  160                 return NULL;
  161         /* NB: avoid monitor mode; there is no scan support */
  162         if (mode != IEEE80211_M_MONITOR && scanners[mode] == NULL)
  163                 ieee80211_load_module(scan_modnames[mode]);
  164         return scanners[mode];
  165 }
  166 
  167 void
  168 ieee80211_scanner_register(enum ieee80211_opmode mode,
  169         const struct ieee80211_scanner *scan)
  170 {
  171         if (mode >= IEEE80211_SCANNER_MAX)
  172                 return;
  173         scanners[mode] = scan;
  174 }
  175 
  176 void
  177 ieee80211_scanner_unregister(enum ieee80211_opmode mode,
  178         const struct ieee80211_scanner *scan)
  179 {
  180         if (mode >= IEEE80211_SCANNER_MAX)
  181                 return;
  182         if (scanners[mode] == scan)
  183                 scanners[mode] = NULL;
  184 }
  185 
  186 void
  187 ieee80211_scanner_unregister_all(const struct ieee80211_scanner *scan)
  188 {
  189         int m;
  190 
  191         for (m = 0; m < IEEE80211_SCANNER_MAX; m++)
  192                 if (scanners[m] == scan)
  193                         scanners[m] = NULL;
  194 }
  195 
  196 /*
  197  * Update common scanner state to reflect the current
  198  * operating mode.  This is called when the state machine
  199  * is transitioned to RUN state w/o scanning--e.g. when
  200  * operating in monitor mode.  The purpose of this is to
  201  * ensure later callbacks find ss_ops set to properly
  202  * reflect current operating mode.
  203  */
  204 int
  205 ieee80211_scan_update(struct ieee80211com *ic)
  206 {
  207         struct ieee80211_scan_state *ss = ic->ic_scan;
  208         const struct ieee80211_scanner *scan;
  209 
  210         scan = ieee80211_scanner_get(ic->ic_opmode);
  211         IEEE80211_LOCK(ic);
  212         if (scan == NULL) {
  213                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  214                     "%s: no scanner support for mode %u\n",
  215                     __func__, ic->ic_opmode);
  216                 /* XXX stat */
  217         }
  218         ss->ss_ic = ic;
  219         if (ss->ss_ops != scan) {
  220                 /* switch scanners; detach old, attach new */
  221                 if (ss->ss_ops != NULL)
  222                         ss->ss_ops->scan_detach(ss);
  223                 if (scan != NULL && !scan->scan_attach(ss)) {
  224                         /* XXX attach failure */
  225                         /* XXX stat+msg */
  226                         ss->ss_ops = NULL;
  227                 } else
  228                         ss->ss_ops = scan;
  229         }
  230         IEEE80211_UNLOCK(ic);
  231 
  232         return (scan != NULL);
  233 }
  234 
  235 static void
  236 change_channel(struct ieee80211com *ic,
  237         struct ieee80211_channel *chan)
  238 {
  239         ic->ic_curchan = chan;
  240         ic->ic_set_channel(ic);
  241 }
  242 
  243 static char
  244 channel_type(const struct ieee80211_channel *c)
  245 {
  246         if (IEEE80211_IS_CHAN_ST(c))
  247                 return 'S';
  248         if (IEEE80211_IS_CHAN_108A(c))
  249                 return 'T';
  250         if (IEEE80211_IS_CHAN_108G(c))
  251                 return 'G';
  252         if (IEEE80211_IS_CHAN_HT(c))
  253                 return 'n';
  254         if (IEEE80211_IS_CHAN_A(c))
  255                 return 'a';
  256         if (IEEE80211_IS_CHAN_ANYG(c))
  257                 return 'g';
  258         if (IEEE80211_IS_CHAN_B(c))
  259                 return 'b';
  260         return 'f';
  261 }
  262 
  263 void
  264 ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
  265 {
  266         struct ieee80211com *ic = ss->ss_ic;
  267         const char *sep;
  268         int i;
  269 
  270         sep = "";
  271         for (i = ss->ss_next; i < ss->ss_last; i++) {
  272                 const struct ieee80211_channel *c = ss->ss_chans[i];
  273 
  274                 printf("%s%u%c", sep, ieee80211_chan2ieee(ic, c),
  275                         channel_type(c));
  276                 sep = ", ";
  277         }
  278 }
  279 
  280 /*
  281  * Enable station power save mode and start/restart the scanning thread.
  282  */
  283 static void
  284 scan_restart_pwrsav(void *arg)
  285 {
  286         struct scan_state *ss = (struct scan_state *) arg;
  287         struct ieee80211com *ic = ss->base.ss_ic;
  288         int delay;
  289 
  290         ieee80211_sta_pwrsave(ic, 1);
  291         /*
  292          * Use an initial 1ms delay to insure the null
  293          * data frame has a chance to go out.
  294          * XXX 1ms is a lot, better to trigger scan
  295          * on tx complete.
  296          */
  297         delay = hz/1000;
  298         if (delay < 1)
  299                 delay = 1;
  300         ic->ic_scan_start(ic);                  /* notify driver */
  301         ss->ss_scanend = ticks + delay + ss->ss_duration;
  302         ss->ss_iflags |= ISCAN_START;
  303         callout_reset(&ss->ss_scan_timer, delay, scan_next, ss);
  304 }
  305 
  306 /*
  307  * Start/restart scanning.  If we're operating in station mode
  308  * and associated notify the ap we're going into power save mode
  309  * and schedule a callback to initiate the work (where there's a
  310  * better context for doing the work).  Otherwise, start the scan
  311  * directly.
  312  */
  313 static int
  314 scan_restart(struct scan_state *ss, u_int duration)
  315 {
  316         struct ieee80211com *ic = ss->base.ss_ic;
  317         int defer = 0;
  318 
  319         if (ss->base.ss_next == ss->base.ss_last) {
  320                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  321                         "%s: no channels to scan\n", __func__);
  322                 return 0;
  323         }
  324         if (ic->ic_opmode == IEEE80211_M_STA &&
  325             ic->ic_state == IEEE80211_S_RUN) {
  326                 if ((ic->ic_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
  327                         /*
  328                          * Initiate power save before going off-channel.
  329                          * Note that we cannot do this directly because
  330                          * of locking issues; instead we defer it to a
  331                          * tasklet.
  332                          */
  333                         ss->ss_duration = duration;
  334                         defer = 1;
  335                 }
  336         }
  337 
  338         if (!defer) {
  339                 ic->ic_scan_start(ic);          /* notify driver */
  340                 ss->ss_scanend = ticks + duration;
  341                 ss->ss_iflags |= ISCAN_START;
  342                 callout_reset(&ss->ss_scan_timer, 0, scan_next, ss);
  343         } else
  344                 scan_restart_pwrsav(ss);
  345         return 1;
  346 }
  347 
  348 static void
  349 copy_ssid(struct ieee80211com *ic, struct ieee80211_scan_state *ss,
  350         int nssid, const struct ieee80211_scan_ssid ssids[])
  351 {
  352         if (nssid > IEEE80211_SCAN_MAX_SSID) {
  353                 /* XXX printf */
  354                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  355                     "%s: too many ssid %d, ignoring all of them\n",
  356                     __func__, nssid);
  357                 return;
  358         }
  359         memcpy(ss->ss_ssid, ssids, nssid * sizeof(ssids[0]));
  360         ss->ss_nssid = nssid;
  361 }
  362 
  363 /*
  364  * Start a scan unless one is already going.
  365  */
  366 int
  367 ieee80211_start_scan(struct ieee80211com *ic, int flags, u_int duration,
  368         u_int nssid, const struct ieee80211_scan_ssid ssids[])
  369 {
  370         const struct ieee80211_scanner *scan;
  371         struct ieee80211_scan_state *ss = ic->ic_scan;
  372 
  373         scan = ieee80211_scanner_get(ic->ic_opmode);
  374         if (scan == NULL) {
  375                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  376                     "%s: no scanner support for mode %u\n",
  377                     __func__, ic->ic_opmode);
  378                 /* XXX stat */
  379                 return 0;
  380         }
  381 
  382         IEEE80211_LOCK(ic);
  383         if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
  384                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  385                     "%s: %s scan, duration %u, desired mode %s, %s%s%s%s\n"
  386                     , __func__
  387                     , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
  388                     , duration
  389                     , ieee80211_phymode_name[ic->ic_des_mode]
  390                     , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
  391                     , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
  392                     , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
  393                     , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
  394                 );
  395 
  396                 ss->ss_ic = ic;
  397                 if (ss->ss_ops != scan) {
  398                         /* switch scanners; detach old, attach new */
  399                         if (ss->ss_ops != NULL)
  400                                 ss->ss_ops->scan_detach(ss);
  401                         if (!scan->scan_attach(ss)) {
  402                                 /* XXX attach failure */
  403                                 /* XXX stat+msg */
  404                                 ss->ss_ops = NULL;
  405                         } else
  406                                 ss->ss_ops = scan;
  407                 }
  408                 if (ss->ss_ops != NULL) {
  409                         if ((flags & IEEE80211_SCAN_NOSSID) == 0)
  410                                 copy_ssid(ic, ss, nssid, ssids);
  411 
  412                         /* NB: top 4 bits for internal use */
  413                         ss->ss_flags = flags & 0xfff;
  414                         if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  415                                 ic->ic_stats.is_scan_active++;
  416                         else
  417                                 ic->ic_stats.is_scan_passive++;
  418                         if (flags & IEEE80211_SCAN_FLUSH)
  419                                 ss->ss_ops->scan_flush(ss);
  420 
  421                         /* NB: flush frames rx'd before 1st channel change */
  422                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
  423                         ss->ss_ops->scan_start(ss, ic);
  424                         if (scan_restart(SCAN_PRIVATE(ss), duration))
  425                                 ic->ic_flags |= IEEE80211_F_SCAN;
  426                 }
  427         } else {
  428                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  429                     "%s: %s scan already in progress\n", __func__,
  430                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
  431         }
  432         IEEE80211_UNLOCK(ic);
  433 
  434         /* NB: racey, does it matter? */
  435         return (ic->ic_flags & IEEE80211_F_SCAN);
  436 }
  437 
  438 /*
  439  * Check the scan cache for an ap/channel to use; if that
  440  * fails then kick off a new scan.
  441  */
  442 int
  443 ieee80211_check_scan(struct ieee80211com *ic, int flags, u_int duration,
  444         u_int nssid, const struct ieee80211_scan_ssid ssids[])
  445 {
  446         struct ieee80211_scan_state *ss = ic->ic_scan;
  447         int checkscanlist = 0;
  448 
  449         /*
  450          * Check if there's a list of scan candidates already.
  451          * XXX want more than the ap we're currently associated with
  452          */
  453 
  454         IEEE80211_LOCK(ic);
  455         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  456             "%s: %s scan, duration %u, desired mode %s, %s%s%s%s\n"
  457             , __func__
  458             , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
  459             , duration
  460             , ieee80211_phymode_name[ic->ic_des_mode]
  461             , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
  462             , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
  463             , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
  464             , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
  465         );
  466 
  467         if (ss->ss_ops != NULL) {
  468                 /* XXX verify ss_ops matches ic->ic_opmode */
  469                 if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
  470                         /*
  471                          * Update the ssid list and mark flags so if
  472                          * we call start_scan it doesn't duplicate work.
  473                          */
  474                         copy_ssid(ic, ss, nssid, ssids);
  475                         flags |= IEEE80211_SCAN_NOSSID;
  476                 }
  477                 if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
  478                      time_before(ticks, ic->ic_lastscan + ic->ic_scanvalid)) {
  479                         /*
  480                          * We're not currently scanning and the cache is
  481                          * deemed hot enough to consult.  Lock out others
  482                          * by marking IEEE80211_F_SCAN while we decide if
  483                          * something is already in the scan cache we can
  484                          * use.  Also discard any frames that might come
  485                          * in while temporarily marked as scanning.
  486                          */
  487                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
  488                         ic->ic_flags |= IEEE80211_F_SCAN;
  489                         checkscanlist = 1;
  490                 }
  491         }
  492         IEEE80211_UNLOCK(ic);
  493         if (checkscanlist) {
  494                 const struct ieee80211_scanner *scan;
  495 
  496                 scan = ieee80211_scanner_get(ic->ic_opmode);
  497                 if (scan == NULL) {
  498                         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  499                             "%s: no scanner support for mode %u\n",
  500                             __func__, ic->ic_opmode);
  501                         /* XXX stat */
  502                         return 0;
  503                 }
  504                 if (scan == ss->ss_ops && ss->ss_ops->scan_end(ss, ic)) {
  505                         /* found an ap, just clear the flag */
  506                         ic->ic_flags &= ~IEEE80211_F_SCAN;
  507                         return 1;
  508                 }
  509                 /* no ap, clear the flag before starting a scan */
  510                 ic->ic_flags &= ~IEEE80211_F_SCAN;
  511         }
  512         return ieee80211_start_scan(ic, flags, duration, nssid, ssids);
  513 }
  514 
  515 /*
  516  * Restart a previous scan.  If the previous scan completed
  517  * then we start again using the existing channel list.
  518  */
  519 int
  520 ieee80211_bg_scan(struct ieee80211com *ic)
  521 {
  522         struct ieee80211_scan_state *ss = ic->ic_scan;
  523 
  524         IEEE80211_LOCK(ic);
  525         if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
  526                 u_int duration;
  527                 /*
  528                  * Go off-channel for a fixed interval that is large
  529                  * enough to catch most ap's but short enough that
  530                  * we can return on-channel before our listen interval
  531                  * expires.
  532                  */
  533                 duration = IEEE80211_SCAN_OFFCHANNEL;
  534 
  535                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  536                     "%s: %s scan, ticks %u duration %lu\n", __func__,
  537                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
  538                     ticks, duration);
  539 
  540                 if (ss->ss_ops != NULL) {
  541                         ss->ss_ic = ic;
  542                         /*
  543                          * A background scan does not select a new sta; it
  544                          * just refreshes the scan cache.  Also, indicate
  545                          * the scan logic should follow the beacon schedule:
  546                          * we go off-channel and scan for a while, then
  547                          * return to the bss channel to receive a beacon,
  548                          * then go off-channel again.  All during this time
  549                          * we notify the ap we're in power save mode.  When
  550                          * the scan is complete we leave power save mode.
  551                          * If any beacon indicates there are frames pending
  552                          * for us then we drop out of power save mode
  553                          * (and background scan) automatically by way of the
  554                          * usual sta power save logic.
  555                          */
  556                         ss->ss_flags |= IEEE80211_SCAN_NOPICK
  557                                      |  IEEE80211_SCAN_BGSCAN;
  558                         /* if previous scan completed, restart */
  559                         if (ss->ss_next >= ss->ss_last) {
  560                                 ss->ss_next = 0;
  561                                 if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  562                                         ic->ic_stats.is_scan_active++;
  563                                 else
  564                                         ic->ic_stats.is_scan_passive++;
  565                                 ss->ss_ops->scan_restart(ss, ic);
  566                         }
  567                         /* NB: flush frames rx'd before 1st channel change */
  568                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
  569                         ss->ss_maxdwell = duration;
  570                         if (scan_restart(SCAN_PRIVATE(ss), duration)) {
  571                                 ic->ic_flags |= IEEE80211_F_SCAN;
  572                                 ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
  573                         }
  574                 } else {
  575                         /* XXX msg+stat */
  576                 }
  577         } else {
  578                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  579                     "%s: %s scan already in progress\n", __func__,
  580                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
  581         }
  582         IEEE80211_UNLOCK(ic);
  583 
  584         /* NB: racey, does it matter? */
  585         return (ic->ic_flags & IEEE80211_F_SCAN);
  586 }
  587 
  588 /*
  589  * Cancel any scan currently going on.
  590  */
  591 void
  592 ieee80211_cancel_scan(struct ieee80211com *ic)
  593 {
  594         struct ieee80211_scan_state *ss = ic->ic_scan;
  595 
  596         IEEE80211_LOCK(ic);
  597         if ((ic->ic_flags & IEEE80211_F_SCAN) &&
  598             (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0) {
  599                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  600                     "%s: cancel %s scan\n", __func__,
  601                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
  602                         "active" : "passive");
  603 
  604                 /* clear bg scan NOPICK and mark cancel request */
  605                 ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
  606                 SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
  607                 /* force it to fire asap */
  608                 callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
  609                         0, scan_next, ss);
  610         }
  611         IEEE80211_UNLOCK(ic);
  612 }
  613 
  614 /*
  615  * Public access to scan_next for drivers that manage
  616  * scanning themselves (e.g. for firmware-based devices).
  617  */
  618 void
  619 ieee80211_scan_next(struct ieee80211com *ic)
  620 {
  621         /*
  622          * XXX: We might need/want to decouple context here by either:
  623          *  callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
  624          * or using a taskqueue.  Let's see what kind of problems direct
  625          * dispatch has for now.
  626          */
  627         scan_next(ic->ic_scan);
  628 }
  629 
  630 /*
  631  * Public access to scan_next for drivers that are not able to scan single
  632  * channels (e.g. for firmware-based devices).
  633  */
  634 void
  635 ieee80211_scan_done(struct ieee80211com *ic)
  636 {
  637         struct ieee80211_scan_state *ss = ic->ic_scan;
  638 
  639         ss->ss_next = ss->ss_last; /* all channels are complete */
  640         scan_next(ss);
  641 }
  642 
  643 /*
  644  * Scan curchan.  If this is an active scan and the channel
  645  * is not marked passive then send probe request frame(s).
  646  * Arrange for the channel change after maxdwell ticks.
  647  */
  648 static void
  649 scan_curchan(struct ieee80211com *ic, unsigned long maxdwell)
  650 {
  651         struct ieee80211_scan_state *ss = ic->ic_scan;
  652 
  653         if ((ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
  654             (ic->ic_curchan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0) {
  655                 struct ifnet *ifp = ic->ic_ifp;
  656                 int i;
  657 
  658                 /*
  659                  * Send a broadcast probe request followed by
  660                  * any specified directed probe requests.
  661                  * XXX suppress broadcast probe req?
  662                  * XXX remove dependence on ic/ic->ic_bss
  663                  * XXX move to policy code?
  664                  */
  665                 ieee80211_send_probereq(ic->ic_bss,
  666                         ic->ic_myaddr, ifp->if_broadcastaddr,
  667                         ifp->if_broadcastaddr,
  668                         "", 0,
  669                         ic->ic_opt_ie, ic->ic_opt_ie_len);
  670                 for (i = 0; i < ss->ss_nssid; i++)
  671                         ieee80211_send_probereq(ic->ic_bss,
  672                                 ic->ic_myaddr, ifp->if_broadcastaddr,
  673                                 ifp->if_broadcastaddr,
  674                                 ss->ss_ssid[i].ssid,
  675                                 ss->ss_ssid[i].len,
  676                                 ic->ic_opt_ie, ic->ic_opt_ie_len);
  677         }
  678         callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
  679                 maxdwell, scan_next, ss);
  680 }
  681 
  682 /*
  683  * Handle mindwell requirements completed; initiate a channel
  684  * change to the next channel asap.
  685  */
  686 static void
  687 scan_mindwell(struct ieee80211com *ic)
  688 {
  689         struct ieee80211_scan_state *ss = ic->ic_scan;
  690 
  691         callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
  692 }
  693 
  694 /*
  695  * Switch to the next channel marked for scanning.
  696  */
  697 static void
  698 scan_next(void *arg)
  699 {
  700 #define ISCAN_REP       (ISCAN_MINDWELL | ISCAN_START | ISCAN_DISCARD)
  701         struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
  702         struct ieee80211com *ic = ss->ss_ic;
  703         struct ieee80211_channel *chan;
  704         unsigned long maxdwell, scanend;
  705         int scanning, scandone;
  706 
  707         IEEE80211_LOCK(ic);
  708         scanning = (ic->ic_flags & IEEE80211_F_SCAN) != 0;
  709         IEEE80211_UNLOCK(ic);
  710         if (!scanning)                  /* canceled */
  711                 return;
  712 
  713 again:
  714         scandone = (ss->ss_next >= ss->ss_last) ||
  715                 (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
  716         scanend = SCAN_PRIVATE(ss)->ss_scanend;
  717         if (!scandone &&
  718             (ss->ss_flags & IEEE80211_SCAN_GOTPICK) == 0 &&
  719             ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_START) ||
  720              time_before(ticks + ss->ss_mindwell, scanend))) {
  721                 chan = ss->ss_chans[ss->ss_next++];
  722 
  723                 /*
  724                  * Watch for truncation due to the scan end time.
  725                  */
  726                 if (time_after(ticks + ss->ss_maxdwell, scanend))
  727                         maxdwell = scanend - ticks;
  728                 else
  729                         maxdwell = ss->ss_maxdwell;
  730 
  731                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  732                     "%s: chan %3d%c -> %3d%c [%s, dwell min %lu max %lu]\n",
  733                     __func__,
  734                     ieee80211_chan2ieee(ic, ic->ic_curchan),
  735                         channel_type(ic->ic_curchan),
  736                     ieee80211_chan2ieee(ic, chan), channel_type(chan),
  737                     (ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
  738                         (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ?
  739                         "active" : "passive",
  740                     ss->ss_mindwell, maxdwell);
  741 
  742                 /*
  743                  * Potentially change channel and phy mode.
  744                  */
  745                 change_channel(ic, chan);
  746 
  747                 /*
  748                  * Scan curchan.  Drivers for "intelligent hardware"
  749                  * override ic_scan_curchan to tell the device to do
  750                  * the work.  Otherwise we manage the work outselves;
  751                  * sending a probe request (as needed), and arming the
  752                  * timeout to switch channels after maxdwell ticks.
  753                  */
  754                 ic->ic_scan_curchan(ic, maxdwell);
  755 
  756                 SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
  757                 /* clear mindwell lock and initial channel change flush */
  758                 SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
  759         } else {
  760                 ic->ic_scan_end(ic);            /* notify driver */
  761                 /*
  762                  * Record scan complete time.  Note that we also do
  763                  * this when canceled so any background scan will
  764                  * not be restarted for a while.
  765                  */
  766                 if (scandone)
  767                         ic->ic_lastscan = ticks;
  768                 /* return to the bss channel */
  769                 if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
  770                     ic->ic_curchan != ic->ic_bsschan)
  771                         change_channel(ic, ic->ic_bsschan);
  772                 /* clear internal flags and any indication of a pick */
  773                 SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
  774                 ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
  775 
  776                 /*
  777                  * If not canceled and scan completed, do post-processing.
  778                  * If the callback function returns 0, then it wants to
  779                  * continue/restart scanning.  Unfortunately we needed to
  780                  * notify the driver to end the scan above to avoid having
  781                  * rx frames alter the scan candidate list.
  782                  */
  783                 if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 &&
  784                     !ss->ss_ops->scan_end(ss, ic) &&
  785                     (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
  786                     time_before(ticks + ss->ss_mindwell, scanend)) {
  787                         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  788                             "%s: done, restart "
  789                             "[ticks %u, dwell min %lu scanend %lu]\n",
  790                             __func__,
  791                             ticks, ss->ss_mindwell, scanend);
  792                         ss->ss_next = 0;        /* reset to begining */
  793                         if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  794                                 ic->ic_stats.is_scan_active++;
  795                         else
  796                                 ic->ic_stats.is_scan_passive++;
  797 
  798                         ic->ic_scan_start(ic);  /* notify driver */
  799                         goto again;
  800                 } else {
  801                         /* past here, scandone is ``true'' if not in bg mode */
  802                         if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
  803                                 scandone = 1;
  804 
  805                         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  806                             "%s: %s, "
  807                             "[ticks %u, dwell min %lu scanend %lu]\n",
  808                             __func__, scandone ? "done" : "stopped",
  809                             ticks, ss->ss_mindwell, scanend);
  810 
  811                         /*
  812                          * Clear the SCAN bit first in case frames are
  813                          * pending on the station power save queue.  If
  814                          * we defer this then the dispatch of the frames
  815                          * may generate a request to cancel scanning.
  816                          */
  817                         ic->ic_flags &= ~IEEE80211_F_SCAN;
  818                         /*
  819                          * Drop out of power save mode when a scan has
  820                          * completed.  If this scan was prematurely terminated
  821                          * because it is a background scan then don't notify
  822                          * the ap; we'll either return to scanning after we
  823                          * receive the beacon frame or we'll drop out of power
  824                          * save mode because the beacon indicates we have frames
  825                          * waiting for us.
  826                          */
  827                         if (scandone) {
  828                                 ieee80211_sta_pwrsave(ic, 0);
  829                                 if (ss->ss_next >= ss->ss_last) {
  830                                         ieee80211_notify_scan_done(ic);
  831                                         ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
  832                                 }
  833                         }
  834                         SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
  835                         ss->ss_flags &=
  836                             ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
  837                 }
  838         }
  839 #undef ISCAN_REP
  840 }
  841 
  842 #ifdef IEEE80211_DEBUG
  843 static void
  844 dump_probe_beacon(uint8_t subtype, int isnew,
  845         const uint8_t mac[IEEE80211_ADDR_LEN],
  846         const struct ieee80211_scanparams *sp)
  847 {
  848 
  849         printf("[%s] %s%s on chan %u (bss chan %u) ",
  850             ether_sprintf(mac), isnew ? "new " : "",
  851             ieee80211_mgt_subtype_name[subtype >> IEEE80211_FC0_SUBTYPE_SHIFT],
  852             IEEE80211_CHAN2IEEE(sp->curchan), sp->bchan);
  853         ieee80211_print_essid(sp->ssid + 2, sp->ssid[1]);
  854         printf("\n");
  855 
  856         if (isnew) {
  857                 printf("[%s] caps 0x%x bintval %u erp 0x%x", 
  858                         ether_sprintf(mac), sp->capinfo, sp->bintval, sp->erp);
  859                 if (sp->country != NULL) {
  860 #ifdef __FreeBSD__
  861                         printf(" country info %*D",
  862                                 sp->country[1], sp->country+2, " ");
  863 #else
  864                         int i;
  865                         printf(" country info");
  866                         for (i = 0; i < sp->country[1]; i++)
  867                                 printf(" %02x", sp->country[i+2]);
  868 #endif
  869                 }
  870                 printf("\n");
  871         }
  872 }
  873 #endif /* IEEE80211_DEBUG */
  874 
  875 /*
  876  * Process a beacon or probe response frame.
  877  */
  878 void
  879 ieee80211_add_scan(struct ieee80211com *ic,
  880         const struct ieee80211_scanparams *sp,
  881         const struct ieee80211_frame *wh,
  882         int subtype, int rssi, int noise, int rstamp)
  883 {
  884         struct ieee80211_scan_state *ss = ic->ic_scan;
  885 
  886         /*
  887          * Frames received during startup are discarded to avoid
  888          * using scan state setup on the initial entry to the timer
  889          * callback.  This can occur because the device may enable
  890          * rx prior to our doing the initial channel change in the
  891          * timer routine (we defer the channel change to the timer
  892          * code to simplify locking on linux).
  893          */
  894         if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD)
  895                 return;
  896 #ifdef IEEE80211_DEBUG
  897         if (ieee80211_msg_scan(ic) && (ic->ic_flags & IEEE80211_F_SCAN))
  898                 dump_probe_beacon(subtype, 1, wh->i_addr2, sp);
  899 #endif
  900         if (ss->ss_ops != NULL &&
  901             ss->ss_ops->scan_add(ss, sp, wh, subtype, rssi, noise, rstamp)) {
  902                 /*
  903                  * If we've reached the min dwell time terminate
  904                  * the timer so we'll switch to the next channel.
  905                  */
  906                 if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 &&
  907                     time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
  908                         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  909                             "%s: chan %3d%c min dwell met (%u > %lu)\n",
  910                             __func__,
  911                             ieee80211_chan2ieee(ic, ic->ic_curchan),
  912                                 channel_type(ic->ic_curchan),
  913                             ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
  914                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL;
  915                         /*
  916                          * NB: trigger at next clock tick or wait for the
  917                          * hardware
  918                          */
  919                         ic->ic_scan_mindwell(ic);
  920                 }
  921         }
  922 }
  923 
  924 /*
  925  * Timeout/age scan cache entries; called from sta timeout
  926  * timer (XXX should be self-contained).
  927  */
  928 void
  929 ieee80211_scan_timeout(struct ieee80211com *ic)
  930 {
  931         struct ieee80211_scan_state *ss = ic->ic_scan;
  932 
  933         if (ss->ss_ops != NULL)
  934                 ss->ss_ops->scan_age(ss);
  935 }
  936 
  937 /*
  938  * Mark a scan cache entry after a successful associate.
  939  */
  940 void
  941 ieee80211_scan_assoc_success(struct ieee80211com *ic, const uint8_t mac[])
  942 {
  943         struct ieee80211_scan_state *ss = ic->ic_scan;
  944 
  945         if (ss->ss_ops != NULL) {
  946                 IEEE80211_NOTE_MAC(ic, IEEE80211_MSG_SCAN,
  947                         mac, "%s",  __func__);
  948                 ss->ss_ops->scan_assoc_success(ss, mac);
  949         }
  950 }
  951 
  952 /*
  953  * Demerit a scan cache entry after failing to associate.
  954  */
  955 void
  956 ieee80211_scan_assoc_fail(struct ieee80211com *ic,
  957         const uint8_t mac[], int reason)
  958 {
  959         struct ieee80211_scan_state *ss = ic->ic_scan;
  960 
  961         if (ss->ss_ops != NULL) {
  962                 IEEE80211_NOTE_MAC(ic, IEEE80211_MSG_SCAN, mac,
  963                         "%s: reason %u", __func__, reason);
  964                 ss->ss_ops->scan_assoc_fail(ss, mac, reason);
  965         }
  966 }
  967 
  968 /*
  969  * Iterate over the contents of the scan cache.
  970  */
  971 void
  972 ieee80211_scan_iterate(struct ieee80211com *ic,
  973         ieee80211_scan_iter_func *f, void *arg)
  974 {
  975         struct ieee80211_scan_state *ss = ic->ic_scan;
  976 
  977         if (ss->ss_ops != NULL)
  978                 ss->ss_ops->scan_iterate(ss, f, arg);
  979 }
  980 
  981 /*
  982  * Flush the contents of the scan cache.
  983  */
  984 void
  985 ieee80211_scan_flush(struct ieee80211com *ic)
  986 {
  987         struct ieee80211_scan_state *ss = ic->ic_scan;
  988 
  989         if (ss->ss_ops != NULL) {
  990                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN,
  991                         "%s\n",  __func__);
  992                 ss->ss_ops->scan_flush(ss);
  993         }
  994 }

Cache object: 15f6991f09c10f52e762aa2cd15fe82f


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