source: rtems-libbsd/freebsd/sys/net80211/ieee80211_scan_sw.c @ a241ea8

55-freebsd-126-freebsd-12
Last change on this file since a241ea8 was a241ea8, checked in by Christian Mauderer <Christian.Mauderer@…>, on 11/14/16 at 12:46:13

Import IEEE 802.11 from FreeBSD.

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