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_sw.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-2008 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: releng/12.0/sys/net80211/ieee80211_scan_sw.c 308007 2016-10-28 02:09:45Z adrian $");
   28 
   29 /*
   30  * IEEE 802.11 scanning support.
   31  */
   32 #include "opt_wlan.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h> 
   36 #include <sys/proc.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/condvar.h>
   40  
   41 #include <sys/socket.h>
   42 
   43 #include <net/if.h>
   44 #include <net/if_var.h>
   45 #include <net/if_media.h>
   46 #include <net/ethernet.h>
   47 
   48 #include <net80211/ieee80211_var.h>
   49 
   50 #include <net80211/ieee80211_scan_sw.h>
   51 
   52 #include <net/bpf.h>
   53 
   54 struct scan_state {
   55         struct ieee80211_scan_state base;       /* public state */
   56 
   57         u_int                   ss_iflags;      /* flags used internally */
   58 #define ISCAN_MINDWELL          0x0001          /* min dwell time reached */
   59 #define ISCAN_DISCARD           0x0002          /* discard rx'd frames */
   60 #define ISCAN_INTERRUPT         0x0004          /* interrupt current scan */
   61 #define ISCAN_CANCEL            0x0008          /* cancel current scan */
   62 #define ISCAN_PAUSE             (ISCAN_INTERRUPT | ISCAN_CANCEL)
   63 #define ISCAN_ABORT             0x0010          /* end the scan immediately */
   64 #define ISCAN_RUNNING           0x0020          /* scan was started */
   65 
   66         unsigned long           ss_chanmindwell;  /* min dwell on curchan */
   67         unsigned long           ss_scanend;     /* time scan must stop */
   68         u_int                   ss_duration;    /* duration for next scan */
   69         struct task             ss_scan_start;  /* scan start */
   70         struct timeout_task     ss_scan_curchan;  /* scan execution */
   71 };
   72 #define SCAN_PRIVATE(ss)        ((struct scan_state *) ss)
   73 
   74 /*
   75  * Amount of time to go off-channel during a background
   76  * scan.  This value should be large enough to catch most
   77  * ap's but short enough that we can return on-channel
   78  * before our listen interval expires.
   79  *
   80  * XXX tunable
   81  * XXX check against configured listen interval
   82  */
   83 #define IEEE80211_SCAN_OFFCHANNEL       msecs_to_ticks(150)
   84 
   85 static  void scan_curchan(struct ieee80211_scan_state *, unsigned long);
   86 static  void scan_mindwell(struct ieee80211_scan_state *);
   87 static  void scan_signal(struct ieee80211_scan_state *, int);
   88 static  void scan_signal_locked(struct ieee80211_scan_state *, int);
   89 static  void scan_start(void *, int);
   90 static  void scan_curchan_task(void *, int);
   91 static  void scan_end(struct ieee80211_scan_state *, int);
   92 static  void scan_done(struct ieee80211_scan_state *, int);
   93 
   94 MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
   95 
   96 static void
   97 ieee80211_swscan_detach(struct ieee80211com *ic)
   98 {
   99         struct ieee80211_scan_state *ss = ic->ic_scan;
  100 
  101         if (ss != NULL) {
  102                 scan_signal(ss, ISCAN_ABORT);
  103                 ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_start);
  104                 taskqueue_drain_timeout(ic->ic_tq,
  105                     &SCAN_PRIVATE(ss)->ss_scan_curchan);
  106                 KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0,
  107                     ("scan still running"));
  108 
  109                 /*
  110                  * For now, do the ss_ops detach here rather
  111                  * than ieee80211_scan_detach().
  112                  *
  113                  * I'll figure out how to cleanly split things up
  114                  * at a later date.
  115                  */
  116                 if (ss->ss_ops != NULL) {
  117                         ss->ss_ops->scan_detach(ss);
  118                         ss->ss_ops = NULL;
  119                 }
  120                 ic->ic_scan = NULL;
  121                 IEEE80211_FREE(SCAN_PRIVATE(ss), M_80211_SCAN);
  122         }
  123 }
  124 
  125 static void
  126 ieee80211_swscan_vattach(struct ieee80211vap *vap)
  127 {
  128         /* nothing to do for now */
  129         /*
  130          * TODO: all of the vap scan calls should be methods!
  131          */
  132 
  133 }
  134 
  135 static void
  136 ieee80211_swscan_vdetach(struct ieee80211vap *vap)
  137 {
  138         struct ieee80211com *ic = vap->iv_ic;
  139         struct ieee80211_scan_state *ss = ic->ic_scan;
  140 
  141         IEEE80211_LOCK_ASSERT(ic);
  142 
  143         if (ss != NULL && ss->ss_vap == vap &&
  144             (ic->ic_flags & IEEE80211_F_SCAN))
  145                 scan_signal_locked(ss, ISCAN_ABORT);
  146 }
  147 
  148 static void
  149 ieee80211_swscan_set_scan_duration(struct ieee80211vap *vap, u_int duration)
  150 {
  151         struct ieee80211com *ic = vap->iv_ic;
  152         struct ieee80211_scan_state *ss = ic->ic_scan;
  153 
  154         IEEE80211_LOCK_ASSERT(ic);
  155 
  156         /* NB: flush frames rx'd before 1st channel change */
  157         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
  158         SCAN_PRIVATE(ss)->ss_duration = duration;
  159 }
  160 
  161 /*
  162  * Start a scan unless one is already going.
  163  */
  164 static int
  165 ieee80211_swscan_start_scan_locked(const struct ieee80211_scanner *scan,
  166         struct ieee80211vap *vap, int flags, u_int duration,
  167         u_int mindwell, u_int maxdwell,
  168         u_int nssid, const struct ieee80211_scan_ssid ssids[])
  169 {
  170         struct ieee80211com *ic = vap->iv_ic;
  171         struct ieee80211_scan_state *ss = ic->ic_scan;
  172 
  173         IEEE80211_LOCK_ASSERT(ic);
  174 
  175         if (ic->ic_flags & IEEE80211_F_CSAPENDING) {
  176                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  177                     "%s: scan inhibited by pending channel change\n", __func__);
  178         } else if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
  179                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  180                     "%s: %s scan, duration %u mindwell %u maxdwell %u, desired mode %s, %s%s%s%s%s%s\n"
  181                     , __func__
  182                     , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
  183                     , duration, mindwell, maxdwell
  184                     , ieee80211_phymode_name[vap->iv_des_mode]
  185                     , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
  186                     , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
  187                     , flags & IEEE80211_SCAN_NOJOIN ? ", nojoin" : ""
  188                     , flags & IEEE80211_SCAN_NOBCAST ? ", nobcast" : ""
  189                     , flags & IEEE80211_SCAN_PICK1ST ? ", pick1st" : ""
  190                     , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
  191                 );
  192 
  193                 ieee80211_scan_update_locked(vap, scan);
  194                 if (ss->ss_ops != NULL) {
  195                         if ((flags & IEEE80211_SCAN_NOSSID) == 0)
  196                                 ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);
  197 
  198                         /* NB: top 4 bits for internal use */
  199                         ss->ss_flags = flags & 0xfff;
  200                         if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  201                                 vap->iv_stats.is_scan_active++;
  202                         else
  203                                 vap->iv_stats.is_scan_passive++;
  204                         if (flags & IEEE80211_SCAN_FLUSH)
  205                                 ss->ss_ops->scan_flush(ss);
  206                         if (flags & IEEE80211_SCAN_BGSCAN)
  207                                 ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
  208 
  209                         /* Set duration for this particular scan */
  210                         ieee80211_swscan_set_scan_duration(vap, duration);
  211 
  212                         ss->ss_next = 0;
  213                         ss->ss_mindwell = mindwell;
  214                         ss->ss_maxdwell = maxdwell;
  215                         /* NB: scan_start must be before the scan runtask */
  216                         ss->ss_ops->scan_start(ss, vap);
  217 #ifdef IEEE80211_DEBUG
  218                         if (ieee80211_msg_scan(vap))
  219                                 ieee80211_scan_dump(ss);
  220 #endif /* IEEE80211_DEBUG */
  221                         ic->ic_flags |= IEEE80211_F_SCAN;
  222 
  223                         /* Start scan task */
  224                         ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_start);
  225                 }
  226                 return 1;
  227         } else {
  228                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  229                     "%s: %s scan already in progress\n", __func__,
  230                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
  231         }
  232         return 0;
  233 }
  234 
  235 
  236 /*
  237  * Start a scan unless one is already going.
  238  *
  239  * Called without the comlock held; grab the comlock as appropriate.
  240  */
  241 static int
  242 ieee80211_swscan_start_scan(const struct ieee80211_scanner *scan,
  243     struct ieee80211vap *vap, int flags,
  244     u_int duration, u_int mindwell, u_int maxdwell,
  245     u_int nssid, const struct ieee80211_scan_ssid ssids[])
  246 {
  247         struct ieee80211com *ic = vap->iv_ic;
  248         int result;
  249 
  250         IEEE80211_UNLOCK_ASSERT(ic);
  251 
  252         IEEE80211_LOCK(ic);
  253         result = ieee80211_swscan_start_scan_locked(scan, vap, flags, duration,
  254             mindwell, maxdwell, nssid, ssids);
  255         IEEE80211_UNLOCK(ic);
  256 
  257         return result;
  258 }
  259 
  260 /*
  261  * Check the scan cache for an ap/channel to use; if that
  262  * fails then kick off a new scan.
  263  *
  264  * Called with the comlock held.
  265  *
  266  * XXX TODO: split out!
  267  */
  268 static int
  269 ieee80211_swscan_check_scan(const struct ieee80211_scanner *scan,
  270     struct ieee80211vap *vap, int flags,
  271     u_int duration, u_int mindwell, u_int maxdwell,
  272     u_int nssid, const struct ieee80211_scan_ssid ssids[])
  273 {
  274         struct ieee80211com *ic = vap->iv_ic;
  275         struct ieee80211_scan_state *ss = ic->ic_scan;
  276         int result;
  277 
  278         IEEE80211_LOCK_ASSERT(ic);
  279 
  280         if (ss->ss_ops != NULL) {
  281                 /* XXX verify ss_ops matches vap->iv_opmode */
  282                 if ((flags & IEEE80211_SCAN_NOSSID) == 0) {
  283                         /*
  284                          * Update the ssid list and mark flags so if
  285                          * we call start_scan it doesn't duplicate work.
  286                          */
  287                         ieee80211_scan_copy_ssid(vap, ss, nssid, ssids);
  288                         flags |= IEEE80211_SCAN_NOSSID;
  289                 }
  290                 if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
  291                     (flags & IEEE80211_SCAN_FLUSH) == 0 &&
  292                     ieee80211_time_before(ticks, ic->ic_lastscan + vap->iv_scanvalid)) {
  293                         /*
  294                          * We're not currently scanning and the cache is
  295                          * deemed hot enough to consult.  Lock out others
  296                          * by marking IEEE80211_F_SCAN while we decide if
  297                          * something is already in the scan cache we can
  298                          * use.  Also discard any frames that might come
  299                          * in while temporarily marked as scanning.
  300                          */
  301                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
  302                         ic->ic_flags |= IEEE80211_F_SCAN;
  303 
  304                         /* NB: need to use supplied flags in check */
  305                         ss->ss_flags = flags & 0xff;
  306                         result = ss->ss_ops->scan_end(ss, vap);
  307 
  308                         ic->ic_flags &= ~IEEE80211_F_SCAN;
  309                         SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_DISCARD;
  310                         if (result) {
  311                                 ieee80211_notify_scan_done(vap);
  312                                 return 1;
  313                         }
  314                 }
  315         }
  316         result = ieee80211_swscan_start_scan_locked(scan, vap, flags, duration,
  317             mindwell, maxdwell, nssid, ssids);
  318 
  319         return result;
  320 }
  321 
  322 /*
  323  * Restart a previous scan.  If the previous scan completed
  324  * then we start again using the existing channel list.
  325  */
  326 static int
  327 ieee80211_swscan_bg_scan(const struct ieee80211_scanner *scan,
  328     struct ieee80211vap *vap, int flags)
  329 {
  330         struct ieee80211com *ic = vap->iv_ic;
  331         struct ieee80211_scan_state *ss = ic->ic_scan;
  332 
  333         /* XXX assert unlocked? */
  334         // IEEE80211_UNLOCK_ASSERT(ic);
  335 
  336         IEEE80211_LOCK(ic);
  337         if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
  338                 u_int duration;
  339                 /*
  340                  * Go off-channel for a fixed interval that is large
  341                  * enough to catch most ap's but short enough that
  342                  * we can return on-channel before our listen interval
  343                  * expires.
  344                  */
  345                 duration = IEEE80211_SCAN_OFFCHANNEL;
  346 
  347                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  348                     "%s: %s scan, ticks %u duration %u\n", __func__,
  349                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
  350                     ticks, duration);
  351 
  352                 ieee80211_scan_update_locked(vap, scan);
  353                 if (ss->ss_ops != NULL) {
  354                         ss->ss_vap = vap;
  355                         /*
  356                          * A background scan does not select a new sta; it
  357                          * just refreshes the scan cache.  Also, indicate
  358                          * the scan logic should follow the beacon schedule:
  359                          * we go off-channel and scan for a while, then
  360                          * return to the bss channel to receive a beacon,
  361                          * then go off-channel again.  All during this time
  362                          * we notify the ap we're in power save mode.  When
  363                          * the scan is complete we leave power save mode.
  364                          * If any beacon indicates there are frames pending
  365                          * for us then we drop out of power save mode
  366                          * (and background scan) automatically by way of the
  367                          * usual sta power save logic.
  368                          */
  369                         ss->ss_flags |= IEEE80211_SCAN_NOPICK
  370                                      |  IEEE80211_SCAN_BGSCAN
  371                                      |  flags
  372                                      ;
  373                         /* if previous scan completed, restart */
  374                         if (ss->ss_next >= ss->ss_last) {
  375                                 if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  376                                         vap->iv_stats.is_scan_active++;
  377                                 else
  378                                         vap->iv_stats.is_scan_passive++;
  379                                 /*
  380                                  * NB: beware of the scan cache being flushed;
  381                                  *     if the channel list is empty use the
  382                                  *     scan_start method to populate it.
  383                                  */
  384                                 ss->ss_next = 0;
  385                                 if (ss->ss_last != 0)
  386                                         ss->ss_ops->scan_restart(ss, vap);
  387                                 else {
  388                                         ss->ss_ops->scan_start(ss, vap);
  389 #ifdef IEEE80211_DEBUG
  390                                         if (ieee80211_msg_scan(vap))
  391                                                 ieee80211_scan_dump(ss);
  392 #endif /* IEEE80211_DEBUG */
  393                                 }
  394                         }
  395                         ieee80211_swscan_set_scan_duration(vap, duration);
  396                         ss->ss_maxdwell = duration;
  397                         ic->ic_flags |= IEEE80211_F_SCAN;
  398                         ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
  399                         ieee80211_runtask(ic,
  400                             &SCAN_PRIVATE(ss)->ss_scan_start);
  401                 } else {
  402                         /* XXX msg+stat */
  403                 }
  404         } else {
  405                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  406                     "%s: %s scan already in progress\n", __func__,
  407                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive");
  408         }
  409         IEEE80211_UNLOCK(ic);
  410 
  411         /* NB: racey, does it matter? */
  412         return (ic->ic_flags & IEEE80211_F_SCAN);
  413 }
  414 
  415 /*
  416  * Taskqueue work to cancel a scan.
  417  *
  418  * Note: for offload scan devices, we may want to call into the
  419  * driver to try and cancel scanning, however it may not be cancelable.
  420  */
  421 static void
  422 cancel_scan(struct ieee80211vap *vap, int any, const char *func)
  423 {
  424         struct ieee80211com *ic = vap->iv_ic;
  425         struct ieee80211_scan_state *ss = ic->ic_scan;
  426         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  427         int signal;
  428 
  429         IEEE80211_LOCK(ic);
  430         signal = any ? ISCAN_PAUSE : ISCAN_CANCEL;
  431         if ((ic->ic_flags & IEEE80211_F_SCAN) &&
  432             (any || ss->ss_vap == vap) &&
  433             (ss_priv->ss_iflags & signal) == 0) {
  434                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  435                     "%s: %s %s scan\n", func,
  436                     any ? "pause" : "cancel",
  437                     ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
  438                         "active" : "passive");
  439 
  440                 /* clear bg scan NOPICK */
  441                 ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
  442                 /* mark request and wake up the scan task */
  443                 scan_signal_locked(ss, signal);
  444         } else {
  445                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  446                     "%s: called; F_SCAN=%d, vap=%s, signal=%d\n",
  447                         func,
  448                         !! (ic->ic_flags & IEEE80211_F_SCAN),
  449                         (ss->ss_vap == vap ? "match" : "nomatch"),
  450                         !! (ss_priv->ss_iflags & signal));
  451         }
  452         IEEE80211_UNLOCK(ic);
  453 }
  454 
  455 /*
  456  * Cancel any scan currently going on for the specified vap.
  457  */
  458 static void
  459 ieee80211_swscan_cancel_scan(struct ieee80211vap *vap)
  460 {
  461         cancel_scan(vap, 0, __func__);
  462 }
  463 
  464 /*
  465  * Cancel any scan currently going on.
  466  */
  467 static void
  468 ieee80211_swscan_cancel_anyscan(struct ieee80211vap *vap)
  469 {
  470 
  471         /* XXX for now - just don't do this per packet. */
  472         if (vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD)
  473                 return;
  474 
  475         cancel_scan(vap, 1, __func__);
  476 }
  477 
  478 /*
  479  * Manually switch to the next channel in the channel list.
  480  * Provided for drivers that manage scanning themselves
  481  * (e.g. for firmware-based devices).
  482  */
  483 static void
  484 ieee80211_swscan_scan_next(struct ieee80211vap *vap)
  485 {
  486         struct ieee80211_scan_state *ss = vap->iv_ic->ic_scan;
  487 
  488         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: called\n", __func__);
  489 
  490         /* wake up the scan task */
  491         scan_signal(ss, 0);
  492 }
  493 
  494 /*
  495  * Manually stop a scan that is currently running.
  496  * Provided for drivers that are not able to scan single channels
  497  * (e.g. for firmware-based devices).
  498  */
  499 static void
  500 ieee80211_swscan_scan_done(struct ieee80211vap *vap)
  501 {
  502         struct ieee80211com *ic = vap->iv_ic;
  503         struct ieee80211_scan_state *ss = ic->ic_scan;
  504 
  505         IEEE80211_LOCK_ASSERT(ic);
  506 
  507         scan_signal_locked(ss, 0);
  508 }
  509 
  510 /*
  511  * Probe the current channel, if allowed, while scanning.
  512  * If the channel is not marked passive-only then send
  513  * a probe request immediately.  Otherwise mark state and
  514  * listen for beacons on the channel; if we receive something
  515  * then we'll transmit a probe request.
  516  */
  517 static void
  518 ieee80211_swscan_probe_curchan(struct ieee80211vap *vap, int force)
  519 {
  520         struct ieee80211com *ic = vap->iv_ic;
  521         struct ieee80211_scan_state *ss = ic->ic_scan;
  522         struct ifnet *ifp = vap->iv_ifp;
  523         int i;
  524 
  525         /*
  526          * Full-offload scan devices don't require this.
  527          */
  528         if (vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD)
  529                 return;
  530 
  531         /*
  532          * Send directed probe requests followed by any
  533          * broadcast probe request.
  534          * XXX remove dependence on ic/vap->iv_bss
  535          */
  536         for (i = 0; i < ss->ss_nssid; i++)
  537                 ieee80211_send_probereq(vap->iv_bss,
  538                         vap->iv_myaddr, ifp->if_broadcastaddr,
  539                         ifp->if_broadcastaddr,
  540                         ss->ss_ssid[i].ssid, ss->ss_ssid[i].len);
  541         if ((ss->ss_flags & IEEE80211_SCAN_NOBCAST) == 0)
  542                 ieee80211_send_probereq(vap->iv_bss,
  543                         vap->iv_myaddr, ifp->if_broadcastaddr,
  544                         ifp->if_broadcastaddr,
  545                         "", 0);
  546 }
  547 
  548 /*
  549  * Scan curchan.  If this is an active scan and the channel
  550  * is not marked passive then send probe request frame(s).
  551  * Arrange for the channel change after maxdwell ticks.
  552  */
  553 static void
  554 scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
  555 {
  556         struct ieee80211vap *vap  = ss->ss_vap;
  557         struct ieee80211com *ic = ss->ss_ic;
  558 
  559         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  560             "%s: calling; maxdwell=%lu\n",
  561             __func__,
  562             maxdwell);
  563         IEEE80211_LOCK(ic);
  564         if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  565                 ieee80211_probe_curchan(vap, 0);
  566         taskqueue_enqueue_timeout(ic->ic_tq,
  567             &SCAN_PRIVATE(ss)->ss_scan_curchan, maxdwell);
  568         IEEE80211_UNLOCK(ic);
  569 }
  570 
  571 static void
  572 scan_signal(struct ieee80211_scan_state *ss, int iflags)
  573 {
  574         struct ieee80211com *ic = ss->ss_ic;
  575 
  576         IEEE80211_UNLOCK_ASSERT(ic);
  577 
  578         IEEE80211_LOCK(ic);
  579         scan_signal_locked(ss, iflags);
  580         IEEE80211_UNLOCK(ic);
  581 }
  582 
  583 static void
  584 scan_signal_locked(struct ieee80211_scan_state *ss, int iflags)
  585 {
  586         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  587         struct timeout_task *scan_task = &ss_priv->ss_scan_curchan;
  588         struct ieee80211com *ic = ss->ss_ic;
  589 
  590         IEEE80211_LOCK_ASSERT(ic);
  591 
  592         ss_priv->ss_iflags |= iflags;
  593         if (ss_priv->ss_iflags & ISCAN_RUNNING) {
  594                 if (taskqueue_cancel_timeout(ic->ic_tq, scan_task, NULL) == 0)
  595                         taskqueue_enqueue_timeout(ic->ic_tq, scan_task, 0);
  596         }
  597 }
  598 
  599 /*
  600  * Handle mindwell requirements completed; initiate a channel
  601  * change to the next channel asap.
  602  */
  603 static void
  604 scan_mindwell(struct ieee80211_scan_state *ss)
  605 {
  606 
  607         IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN, "%s: called\n",
  608             __func__);
  609 
  610         scan_signal(ss, 0);
  611 }
  612 
  613 static void
  614 scan_start(void *arg, int pending)
  615 {
  616 #define ISCAN_REP       (ISCAN_MINDWELL | ISCAN_DISCARD)
  617         struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
  618         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  619         struct ieee80211vap *vap = ss->ss_vap;
  620         struct ieee80211com *ic = ss->ss_ic;
  621 
  622         IEEE80211_LOCK(ic);
  623         if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
  624             (ss_priv->ss_iflags & ISCAN_ABORT)) {
  625                 /* Cancelled before we started */
  626                 scan_done(ss, 0);
  627                 return;
  628         }
  629 
  630         if (ss->ss_next == ss->ss_last) {
  631                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  632                         "%s: no channels to scan\n", __func__);
  633                 scan_done(ss, 1);
  634                 return;
  635         }
  636 
  637         /*
  638          * Put the station into power save mode.
  639          *
  640          * This is only required if we're not a full-offload devices;
  641          * those devices manage scan/traffic differently.
  642          */
  643         if (((vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0) &&
  644             vap->iv_opmode == IEEE80211_M_STA &&
  645             vap->iv_state == IEEE80211_S_RUN) {
  646                 if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
  647                         /* Enable station power save mode */
  648                         vap->iv_sta_ps(vap, 1);
  649                         /* Wait until null data frame will be ACK'ed */
  650                         mtx_sleep(vap, IEEE80211_LOCK_OBJ(ic), PCATCH,
  651                             "sta_ps", msecs_to_ticks(10));
  652                         if (ss_priv->ss_iflags & ISCAN_ABORT) {
  653                                 scan_done(ss, 0);
  654                                 return;
  655                         }
  656                 }
  657         }
  658 
  659         ss_priv->ss_scanend = ticks + ss_priv->ss_duration;
  660 
  661         /* XXX scan state can change! Re-validate scan state! */
  662 
  663         IEEE80211_UNLOCK(ic);
  664 
  665         ic->ic_scan_start(ic);          /* notify driver */
  666 
  667         scan_curchan_task(ss, 0);
  668 }
  669 
  670 static void
  671 scan_curchan_task(void *arg, int pending)
  672 {
  673         struct ieee80211_scan_state *ss = arg;
  674         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  675         struct ieee80211com *ic = ss->ss_ic;
  676         struct ieee80211_channel *chan;
  677         unsigned long maxdwell;
  678         int scandone;
  679 
  680         IEEE80211_LOCK(ic);
  681 end:
  682         scandone = (ss->ss_next >= ss->ss_last) ||
  683             (ss_priv->ss_iflags & ISCAN_CANCEL) != 0;
  684 
  685         IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN,
  686             "%s: loop start; scandone=%d\n",
  687             __func__,
  688             scandone);
  689 
  690         if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
  691             (ss_priv->ss_iflags & ISCAN_ABORT) ||
  692              ieee80211_time_after(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
  693                 ss_priv->ss_iflags &= ~ISCAN_RUNNING;
  694                 scan_end(ss, scandone);
  695                 return;
  696         } else
  697                 ss_priv->ss_iflags |= ISCAN_RUNNING;
  698 
  699         chan = ss->ss_chans[ss->ss_next++];
  700 
  701         /*
  702          * Watch for truncation due to the scan end time.
  703          */
  704         if (ieee80211_time_after(ticks + ss->ss_maxdwell, ss_priv->ss_scanend))
  705                 maxdwell = ss_priv->ss_scanend - ticks;
  706         else
  707                 maxdwell = ss->ss_maxdwell;
  708 
  709         IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN,
  710             "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n",
  711             __func__,
  712             ieee80211_chan2ieee(ic, ic->ic_curchan),
  713             ieee80211_channel_type_char(ic->ic_curchan),
  714             ieee80211_chan2ieee(ic, chan),
  715             ieee80211_channel_type_char(chan),
  716             (ss->ss_flags & IEEE80211_SCAN_ACTIVE) &&
  717                 (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ?
  718                 "active" : "passive",
  719             ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell));
  720 
  721         /*
  722          * Potentially change channel and phy mode.
  723          */
  724         ic->ic_curchan = chan;
  725         ic->ic_rt = ieee80211_get_ratetable(chan);
  726         IEEE80211_UNLOCK(ic);
  727         /*
  728          * Perform the channel change and scan unlocked so the driver
  729          * may sleep. Once set_channel returns the hardware has
  730          * completed the channel change.
  731          */
  732         ic->ic_set_channel(ic);
  733         ieee80211_radiotap_chan_change(ic);
  734 
  735         /*
  736          * Scan curchan.  Drivers for "intelligent hardware"
  737          * override ic_scan_curchan to tell the device to do
  738          * the work.  Otherwise we manage the work ourselves;
  739          * sending a probe request (as needed), and arming the
  740          * timeout to switch channels after maxdwell ticks.
  741          *
  742          * scan_curchan should only pause for the time required to
  743          * prepare/initiate the hardware for the scan (if at all).
  744          */
  745         ic->ic_scan_curchan(ss, maxdwell);
  746         IEEE80211_LOCK(ic);
  747 
  748         /* XXX scan state can change! Re-validate scan state! */
  749 
  750         ss_priv->ss_chanmindwell = ticks + ss->ss_mindwell;
  751         /* clear mindwell lock and initial channel change flush */
  752         ss_priv->ss_iflags &= ~ISCAN_REP;
  753 
  754         if (ss_priv->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)) {
  755                 taskqueue_cancel_timeout(ic->ic_tq, &ss_priv->ss_scan_curchan,
  756                     NULL);
  757                 goto end;
  758         }
  759 
  760         IEEE80211_DPRINTF(ss->ss_vap, IEEE80211_MSG_SCAN, "%s: waiting\n",
  761             __func__);
  762         IEEE80211_UNLOCK(ic);
  763 }
  764 
  765 static void
  766 scan_end(struct ieee80211_scan_state *ss, int scandone)
  767 {
  768         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  769         struct ieee80211vap *vap = ss->ss_vap;
  770         struct ieee80211com *ic = ss->ss_ic;
  771 
  772         IEEE80211_LOCK_ASSERT(ic);
  773 
  774         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: out\n", __func__);
  775 
  776         if (ss_priv->ss_iflags & ISCAN_ABORT) {
  777                 scan_done(ss, scandone);
  778                 return;
  779         }
  780 
  781         IEEE80211_UNLOCK(ic);
  782         ic->ic_scan_end(ic);            /* notify driver */
  783         IEEE80211_LOCK(ic);
  784         /* XXX scan state can change! Re-validate scan state! */
  785 
  786         /*
  787          * Since a cancellation may have occurred during one of the
  788          * driver calls (whilst unlocked), update scandone.
  789          */
  790         if (scandone == 0 && (ss_priv->ss_iflags & ISCAN_CANCEL) != 0) {
  791                 /* XXX printf? */
  792                 if_printf(vap->iv_ifp,
  793                     "%s: OOPS! scan cancelled during driver call (1)!\n",
  794                     __func__);
  795                 scandone = 1;
  796         }
  797 
  798         /*
  799          * Record scan complete time.  Note that we also do
  800          * this when canceled so any background scan will
  801          * not be restarted for a while.
  802          */
  803         if (scandone)
  804                 ic->ic_lastscan = ticks;
  805         /* return to the bss channel */
  806         if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
  807             ic->ic_curchan != ic->ic_bsschan) {
  808                 ieee80211_setupcurchan(ic, ic->ic_bsschan);
  809                 IEEE80211_UNLOCK(ic);
  810                 ic->ic_set_channel(ic);
  811                 ieee80211_radiotap_chan_change(ic);
  812                 IEEE80211_LOCK(ic);
  813         }
  814         /* clear internal flags and any indication of a pick */
  815         ss_priv->ss_iflags &= ~ISCAN_REP;
  816         ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
  817 
  818         /*
  819          * If not canceled and scan completed, do post-processing.
  820          * If the callback function returns 0, then it wants to
  821          * continue/restart scanning.  Unfortunately we needed to
  822          * notify the driver to end the scan above to avoid having
  823          * rx frames alter the scan candidate list.
  824          */
  825         if ((ss_priv->ss_iflags & ISCAN_CANCEL) == 0 &&
  826             !ss->ss_ops->scan_end(ss, vap) &&
  827             (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
  828             ieee80211_time_before(ticks + ss->ss_mindwell, ss_priv->ss_scanend)) {
  829                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  830                     "%s: done, restart "
  831                     "[ticks %u, dwell min %lu scanend %lu]\n",
  832                     __func__,
  833                     ticks, ss->ss_mindwell, ss_priv->ss_scanend);
  834                 ss->ss_next = 0;        /* reset to beginning */
  835                 if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
  836                         vap->iv_stats.is_scan_active++;
  837                 else
  838                         vap->iv_stats.is_scan_passive++;
  839 
  840                 ss->ss_ops->scan_restart(ss, vap);      /* XXX? */
  841                 ieee80211_runtask(ic, &ss_priv->ss_scan_start);
  842                 IEEE80211_UNLOCK(ic);
  843                 return;
  844         }
  845 
  846         /* past here, scandone is ``true'' if not in bg mode */
  847         if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
  848                 scandone = 1;
  849 
  850         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  851             "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n",
  852             __func__, scandone ? "done" : "stopped",
  853             ticks, ss->ss_mindwell, ss_priv->ss_scanend);
  854 
  855         /*
  856          * Since a cancellation may have occurred during one of the
  857          * driver calls (whilst unlocked), update scandone.
  858          */
  859         if (scandone == 0 && (ss_priv->ss_iflags & ISCAN_CANCEL) != 0) {
  860                 /* XXX printf? */
  861                 if_printf(vap->iv_ifp,
  862                     "%s: OOPS! scan cancelled during driver call (2)!\n",
  863                     __func__);
  864                 scandone = 1;
  865         }
  866 
  867         scan_done(ss, scandone);
  868 }
  869 
  870 static void
  871 scan_done(struct ieee80211_scan_state *ss, int scandone)
  872 {
  873         struct scan_state *ss_priv = SCAN_PRIVATE(ss);
  874         struct ieee80211com *ic = ss->ss_ic;
  875         struct ieee80211vap *vap = ss->ss_vap;
  876 
  877         IEEE80211_LOCK_ASSERT(ic);
  878 
  879         /*
  880          * Clear the SCAN bit first in case frames are
  881          * pending on the station power save queue.  If
  882          * we defer this then the dispatch of the frames
  883          * may generate a request to cancel scanning.
  884          */
  885         ic->ic_flags &= ~IEEE80211_F_SCAN;
  886 
  887         /*
  888          * Drop out of power save mode when a scan has
  889          * completed.  If this scan was prematurely terminated
  890          * because it is a background scan then don't notify
  891          * the ap; we'll either return to scanning after we
  892          * receive the beacon frame or we'll drop out of power
  893          * save mode because the beacon indicates we have frames
  894          * waiting for us.
  895          */
  896         if (scandone) {
  897                 /*
  898                  * If we're not a scan offload device, come back out of
  899                  * station powersave.  Offload devices handle this themselves.
  900                  */
  901                 if ((vap->iv_flags_ext & IEEE80211_FEXT_SCAN_OFFLOAD) == 0)
  902                         vap->iv_sta_ps(vap, 0);
  903                 if (ss->ss_next >= ss->ss_last)
  904                         ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
  905 
  906                 /* send 'scan done' event if not interrupted due to traffic. */
  907                 if (!(ss_priv->ss_iflags & ISCAN_INTERRUPT))
  908                         ieee80211_notify_scan_done(vap);
  909         }
  910         ss_priv->ss_iflags &= ~(ISCAN_PAUSE | ISCAN_ABORT);
  911         ss_priv->ss_scanend = 0;
  912         ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
  913         IEEE80211_UNLOCK(ic);
  914 #undef ISCAN_REP
  915 }
  916 
  917 /*
  918  * Process a beacon or probe response frame.
  919  */
  920 static void
  921 ieee80211_swscan_add_scan(struct ieee80211vap *vap,
  922         struct ieee80211_channel *curchan,
  923         const struct ieee80211_scanparams *sp,
  924         const struct ieee80211_frame *wh,
  925         int subtype, int rssi, int noise)
  926 {
  927         struct ieee80211com *ic = vap->iv_ic;
  928         struct ieee80211_scan_state *ss = ic->ic_scan;
  929 
  930         /* XXX locking */
  931         /*
  932          * Frames received during startup are discarded to avoid
  933          * using scan state setup on the initial entry to the timer
  934          * callback.  This can occur because the device may enable
  935          * rx prior to our doing the initial channel change in the
  936          * timer routine.
  937          */
  938         if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_DISCARD)
  939                 return;
  940 #ifdef IEEE80211_DEBUG
  941         if (ieee80211_msg_scan(vap) && (ic->ic_flags & IEEE80211_F_SCAN))
  942                 ieee80211_scan_dump_probe_beacon(subtype, 1, wh->i_addr2, sp, rssi);
  943 #endif
  944         if (ss->ss_ops != NULL &&
  945             ss->ss_ops->scan_add(ss, curchan, sp, wh, subtype, rssi, noise)) {
  946                 /*
  947                  * If we've reached the min dwell time terminate
  948                  * the timer so we'll switch to the next channel.
  949                  */
  950                 if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_MINDWELL) == 0 &&
  951                     ieee80211_time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
  952                         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
  953                             "%s: chan %3d%c min dwell met (%u > %lu)\n",
  954                             __func__,
  955                             ieee80211_chan2ieee(ic, ic->ic_curchan),
  956                             ieee80211_channel_type_char(ic->ic_curchan),
  957                             ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
  958                         SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_MINDWELL;
  959                         /*
  960                          * NB: trigger at next clock tick or wait for the
  961                          * hardware.
  962                          */
  963                         ic->ic_scan_mindwell(ss);
  964                 }
  965         }
  966 }
  967 
  968 static struct ieee80211_scan_methods swscan_methods = {
  969         .sc_attach = ieee80211_swscan_attach,
  970         .sc_detach = ieee80211_swscan_detach,
  971         .sc_vattach = ieee80211_swscan_vattach,
  972         .sc_vdetach = ieee80211_swscan_vdetach,
  973         .sc_set_scan_duration = ieee80211_swscan_set_scan_duration,
  974         .sc_start_scan = ieee80211_swscan_start_scan,
  975         .sc_check_scan = ieee80211_swscan_check_scan,
  976         .sc_bg_scan = ieee80211_swscan_bg_scan,
  977         .sc_cancel_scan = ieee80211_swscan_cancel_scan,
  978         .sc_cancel_anyscan = ieee80211_swscan_cancel_anyscan,
  979         .sc_scan_next = ieee80211_swscan_scan_next,
  980         .sc_scan_done = ieee80211_swscan_scan_done,
  981         .sc_scan_probe_curchan = ieee80211_swscan_probe_curchan,
  982         .sc_add_scan = ieee80211_swscan_add_scan
  983 };
  984 
  985 /*
  986  * Default scan attach method.
  987  */
  988 void
  989 ieee80211_swscan_attach(struct ieee80211com *ic)
  990 {
  991         struct scan_state *ss;
  992 
  993         /*
  994          * Setup the default methods
  995          */
  996         ic->ic_scan_methods = &swscan_methods;
  997 
  998         /* Allocate initial scan state */
  999         ss = (struct scan_state *) IEEE80211_MALLOC(sizeof(struct scan_state),
 1000                 M_80211_SCAN, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
 1001         if (ss == NULL) {
 1002                 ic->ic_scan = NULL;
 1003                 return;
 1004         }
 1005         TASK_INIT(&ss->ss_scan_start, 0, scan_start, ss);
 1006         TIMEOUT_TASK_INIT(ic->ic_tq, &ss->ss_scan_curchan, 0,
 1007             scan_curchan_task, ss);
 1008 
 1009         ic->ic_scan = &ss->base;
 1010         ss->base.ss_ic = ic;
 1011 
 1012         ic->ic_scan_curchan = scan_curchan;
 1013         ic->ic_scan_mindwell = scan_mindwell;
 1014 }

Cache object: 5fb999c50bb95ec6e4beed4c5154c6c6


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