summaryrefslogtreecommitdiffstats
path: root/sys/net80211/ieee80211_scan.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211/ieee80211_scan.c')
-rw-r--r--sys/net80211/ieee80211_scan.c407
1 files changed, 207 insertions, 200 deletions
diff --git a/sys/net80211/ieee80211_scan.c b/sys/net80211/ieee80211_scan.c
index 7ce2d31..c1f4a13 100644
--- a/sys/net80211/ieee80211_scan.c
+++ b/sys/net80211/ieee80211_scan.c
@@ -33,7 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/proc.h>
#include <sys/kernel.h>
+#include <sys/condvar.h>
#include <sys/socket.h>
@@ -52,10 +54,12 @@ struct scan_state {
#define ISCAN_MINDWELL 0x0001 /* min dwell time reached */
#define ISCAN_DISCARD 0x0002 /* discard rx'd frames */
#define ISCAN_CANCEL 0x0004 /* cancel current scan */
-#define ISCAN_START 0x0008 /* 1st time through next_scan */
+#define ISCAN_ABORT 0x0008 /* end the scan immediately */
unsigned long ss_chanmindwell; /* min dwell on curchan */
unsigned long ss_scanend; /* time scan must stop */
u_int ss_duration; /* duration for next scan */
+ struct task ss_scan_task; /* scan execution */
+ struct cv ss_scan_cv; /* scan signal */
struct callout ss_scan_timer; /* scan timer */
};
#define SCAN_PRIVATE(ss) ((struct scan_state *) ss)
@@ -88,10 +92,10 @@ struct scan_state {
#define ROAM_RATE_QUARTER_DEFAULT 2*3 /* quarter-width 11a/g bss */
#define ROAM_MCS_11N_DEFAULT (1 | IEEE80211_RATE_MCS) /* 11n bss */
-static void scan_restart_pwrsav(void *);
static void scan_curchan(struct ieee80211_scan_state *, unsigned long);
static void scan_mindwell(struct ieee80211_scan_state *);
-static void scan_next(void *);
+static void scan_signal(void *);
+static void scan_task(void *, int);
MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
@@ -107,7 +111,10 @@ ieee80211_scan_attach(struct ieee80211com *ic)
return;
}
callout_init_mtx(&ss->ss_scan_timer, IEEE80211_LOCK_OBJ(ic), 0);
+ cv_init(&ss->ss_scan_cv, "scan");
+ TASK_INIT(&ss->ss_scan_task, 0, scan_task, ss);
ic->ic_scan = &ss->base;
+ ss->base.ss_ic = ic;
ic->ic_scan_curchan = scan_curchan;
ic->ic_scan_mindwell = scan_mindwell;
@@ -119,12 +126,17 @@ ieee80211_scan_detach(struct ieee80211com *ic)
struct ieee80211_scan_state *ss = ic->ic_scan;
if (ss != NULL) {
- callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
+ IEEE80211_LOCK(ic);
+ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT;
+ scan_signal(ss);
+ IEEE80211_UNLOCK(ic);
+ ieee80211_draintask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
+ KASSERT((ic->ic_flags & IEEE80211_F_SCAN) == 0,
+ ("scan still running"));
if (ss->ss_ops != NULL) {
ss->ss_ops->scan_detach(ss);
ss->ss_ops = NULL;
}
- ic->ic_flags &= ~IEEE80211_F_SCAN;
ic->ic_scan = NULL;
free(SCAN_PRIVATE(ss), M_80211_SCAN);
}
@@ -174,9 +186,8 @@ ieee80211_scan_vdetach(struct ieee80211vap *vap)
ss = ic->ic_scan;
if (ss != NULL && ss->ss_vap == vap) {
if (ic->ic_flags & IEEE80211_F_SCAN) {
- /* XXX callout_drain */
- callout_stop(&SCAN_PRIVATE(ss)->ss_scan_timer);
- ic->ic_flags &= ~IEEE80211_F_SCAN;
+ SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_ABORT;
+ scan_signal(ss);
}
if (ss->ss_ops != NULL) {
ss->ss_ops->scan_detach(ss);
@@ -293,15 +304,6 @@ scan_update_locked(struct ieee80211vap *vap,
}
}
-static void
-change_channel(struct ieee80211com *ic,
- struct ieee80211_channel *chan)
-{
- ic->ic_curchan = chan;
- ic->ic_rt = ieee80211_get_ratetable(chan);
- ic->ic_set_channel(ic);
-}
-
static char
channel_type(const struct ieee80211_channel *c)
{
@@ -325,7 +327,7 @@ channel_type(const struct ieee80211_channel *c)
void
ieee80211_scan_dump_channels(const struct ieee80211_scan_state *ss)
{
- struct ieee80211com *ic = ss->ss_vap->iv_ic;
+ struct ieee80211com *ic = ss->ss_ic;
const char *sep;
int i;
@@ -352,76 +354,6 @@ scan_dump(struct ieee80211_scan_state *ss)
}
#endif /* IEEE80211_DEBUG */
-/*
- * Enable station power save mode and start/restart the scanning thread.
- */
-static void
-scan_restart_pwrsav(void *arg)
-{
- struct scan_state *ss = (struct scan_state *) arg;
- struct ieee80211vap *vap = ss->base.ss_vap;
- struct ieee80211com *ic = vap->iv_ic;
- int ticksdelay;
-
- ieee80211_sta_pwrsave(vap, 1);
- /*
- * Use an initial 1ms delay so the null
- * data frame has a chance to go out.
- * XXX 1ms is a lot, better to trigger scan
- * on tx complete.
- */
- ticksdelay = msecs_to_ticks(1);
- if (ticksdelay < 1)
- ticksdelay = 1;
- ic->ic_scan_start(ic); /* notify driver */
- ss->ss_scanend = ticks + ticksdelay + ss->ss_duration;
- ss->ss_iflags |= ISCAN_START;
- callout_reset(&ss->ss_scan_timer, ticksdelay, scan_next, ss);
-}
-
-/*
- * Start/restart scanning. If we're operating in station mode
- * and associated notify the ap we're going into power save mode
- * and schedule a callback to initiate the work (where there's a
- * better context for doing the work). Otherwise, start the scan
- * directly.
- */
-static int
-scan_restart(struct scan_state *ss, u_int duration)
-{
- struct ieee80211vap *vap = ss->base.ss_vap;
- struct ieee80211com *ic = vap->iv_ic;
- int defer = 0;
-
- if (ss->base.ss_next == ss->base.ss_last) {
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
- "%s: no channels to scan\n", __func__);
- return 0;
- }
- if (vap->iv_opmode == IEEE80211_M_STA &&
- vap->iv_state == IEEE80211_S_RUN) {
- if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
- /*
- * Initiate power save before going off-channel.
- * Note that we cannot do this directly because
- * of locking issues; instead we defer it to a
- * tasklet.
- */
- ss->ss_duration = duration;
- defer = 1;
- }
- }
-
- if (!defer) {
- ic->ic_scan_start(ic); /* notify driver */
- ss->ss_scanend = ticks + duration;
- ss->ss_iflags |= ISCAN_START;
- callout_reset(&ss->ss_scan_timer, 0, scan_next, ss);
- } else
- scan_restart_pwrsav(ss);
- return 1;
-}
-
static void
copy_ssid(struct ieee80211vap *vap, struct ieee80211_scan_state *ss,
int nssid, const struct ieee80211_scan_ssid ssids[])
@@ -485,16 +417,18 @@ start_scan_locked(const struct ieee80211_scanner *scan,
/* NB: flush frames rx'd before 1st channel change */
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
+ SCAN_PRIVATE(ss)->ss_duration = duration;
ss->ss_next = 0;
ss->ss_mindwell = mindwell;
ss->ss_maxdwell = maxdwell;
+ /* NB: scan_start must be before the scan runtask */
ss->ss_ops->scan_start(ss, vap);
#ifdef IEEE80211_DEBUG
if (ieee80211_msg_scan(vap))
scan_dump(ss);
#endif /* IEEE80211_DEBUG */
- if (scan_restart(SCAN_PRIVATE(ss), duration))
- ic->ic_flags |= IEEE80211_F_SCAN;
+ ic->ic_flags |= IEEE80211_F_SCAN;
+ ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
}
} else {
IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
@@ -716,11 +650,11 @@ ieee80211_bg_scan(struct ieee80211vap *vap, int flags)
}
/* NB: flush frames rx'd before 1st channel change */
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_DISCARD;
+ SCAN_PRIVATE(ss)->ss_duration = duration;
ss->ss_maxdwell = duration;
- if (scan_restart(SCAN_PRIVATE(ss), duration)) {
- ic->ic_flags |= IEEE80211_F_SCAN;
- ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
- }
+ ic->ic_flags |= IEEE80211_F_SCAN;
+ ic->ic_flags_ext |= IEEE80211_FEXT_BGSCAN;
+ ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
} else {
/* XXX msg+stat */
}
@@ -756,9 +690,8 @@ ieee80211_cancel_scan(struct ieee80211vap *vap)
/* clear bg scan NOPICK and mark cancel request */
ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
- /* force it to fire asap */
- callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
- 0, scan_next, ss);
+ /* wake up the scan task */
+ scan_signal(ss);
}
IEEE80211_UNLOCK(ic);
}
@@ -783,9 +716,8 @@ ieee80211_cancel_anyscan(struct ieee80211vap *vap)
/* clear bg scan NOPICK and mark cancel request */
ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
SCAN_PRIVATE(ss)->ss_iflags |= ISCAN_CANCEL;
- /* force it to fire asap */
- callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
- 0, scan_next, ss);
+ /* wake up the scan task */
+ scan_signal(ss);
}
IEEE80211_UNLOCK(ic);
}
@@ -800,7 +732,10 @@ ieee80211_scan_next(struct ieee80211vap *vap)
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211_scan_state *ss = ic->ic_scan;
- callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
+ /* wake up the scan task */
+ IEEE80211_LOCK(ic);
+ scan_signal(ss);
+ IEEE80211_UNLOCK(ic);
}
/*
@@ -816,7 +751,7 @@ ieee80211_scan_done(struct ieee80211vap *vap)
IEEE80211_LOCK(ic);
ss = ic->ic_scan;
ss->ss_next = ss->ss_last; /* all channels are complete */
- scan_next(ss);
+ scan_signal(ss);
IEEE80211_UNLOCK(ic);
}
@@ -866,12 +801,22 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
{
struct ieee80211vap *vap = ss->ss_vap;
- IEEE80211_LOCK_ASSERT(vap->iv_ic);
-
+ IEEE80211_LOCK(vap->iv_ic);
if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
ieee80211_probe_curchan(vap, 0);
callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer,
- maxdwell, scan_next, ss);
+ maxdwell, scan_signal, ss);
+ IEEE80211_UNLOCK(vap->iv_ic);
+}
+
+static void
+scan_signal(void *arg)
+{
+ struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
+
+ IEEE80211_LOCK_ASSERT(ss->ss_ic);
+
+ cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv);
}
/*
@@ -881,35 +826,67 @@ scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
static void
scan_mindwell(struct ieee80211_scan_state *ss)
{
- callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
+ struct ieee80211com *ic = ss->ss_ic;
+
+ IEEE80211_LOCK(ic);
+ scan_signal(ss);
+ IEEE80211_UNLOCK(ic);
}
-/*
- * Switch to the next channel marked for scanning.
- */
static void
-scan_next(void *arg)
+scan_task(void *arg, int pending)
{
-#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_START | ISCAN_DISCARD)
+#define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD)
struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
struct ieee80211vap *vap = ss->ss_vap;
- struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211com *ic = ss->ss_ic;
struct ieee80211_channel *chan;
unsigned long maxdwell, scanend;
- int scandone;
+ int scandone = 0;
- IEEE80211_LOCK_ASSERT(ic);
+ IEEE80211_LOCK(ic);
+ if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 ||
+ (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) {
+ /* Cancelled before we started */
+ goto done;
+ }
+
+ if (ss->ss_next == ss->ss_last) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+ "%s: no channels to scan\n", __func__);
+ goto done;
+ }
+
+ if (vap->iv_opmode == IEEE80211_M_STA &&
+ vap->iv_state == IEEE80211_S_RUN) {
+ if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
+ /* Enable station power save mode */
+ ieee80211_sta_pwrsave(vap, 1);
+ /*
+ * Use an 1ms delay so the null data frame has a chance
+ * to go out.
+ * XXX Should use M_TXCB mechanism to eliminate this.
+ */
+ cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv,
+ IEEE80211_LOCK_OBJ(ic), hz / 1000);
+ if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
+ goto done;
+ }
+ }
+
+ scanend = ticks + SCAN_PRIVATE(ss)->ss_duration;
+ IEEE80211_UNLOCK(ic);
+ ic->ic_scan_start(ic); /* notify driver */
+ IEEE80211_LOCK(ic);
+
+ for (;;) {
+ scandone = (ss->ss_next >= ss->ss_last) ||
+ (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
+ if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
+ (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) ||
+ time_after(ticks + ss->ss_mindwell, scanend))
+ break;
- if ((ic->ic_flags & IEEE80211_F_SCAN) == 0)
- return;
-again:
- scandone = (ss->ss_next >= ss->ss_last) ||
- (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
- scanend = SCAN_PRIVATE(ss)->ss_scanend;
- if (!scandone &&
- (ss->ss_flags & IEEE80211_SCAN_GOTPICK) == 0 &&
- ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_START) ||
- time_before(ticks + ss->ss_mindwell, scanend))) {
chan = ss->ss_chans[ss->ss_next++];
/*
@@ -934,7 +911,15 @@ again:
/*
* Potentially change channel and phy mode.
*/
- change_channel(ic, chan);
+ ic->ic_curchan = chan;
+ ic->ic_rt = ieee80211_get_ratetable(chan);
+ IEEE80211_UNLOCK(ic);
+ /*
+ * Perform the channel change and scan unlocked so the driver
+ * may sleep. Once set_channel returns the hardware has
+ * completed the channel change.
+ */
+ ic->ic_set_channel(ic);
/*
* Scan curchan. Drivers for "intelligent hardware"
@@ -942,93 +927,115 @@ again:
* the work. Otherwise we manage the work outselves;
* sending a probe request (as needed), and arming the
* timeout to switch channels after maxdwell ticks.
+ *
+ * scan_curchan should only pause for the time required to
+ * prepare/initiate the hardware for the scan (if at all), the
+ * below condvar is used to sleep for the channels dwell time
+ * and allows it to be signalled for abort.
*/
ic->ic_scan_curchan(ss, maxdwell);
+ IEEE80211_LOCK(ic);
SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
/* clear mindwell lock and initial channel change flush */
SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
- } else {
- ic->ic_scan_end(ic); /* notify driver */
- /*
- * Record scan complete time. Note that we also do
- * this when canceled so any background scan will
- * not be restarted for a while.
- */
- if (scandone)
- ic->ic_lastscan = ticks;
- /* return to the bss channel */
- if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
- ic->ic_curchan != ic->ic_bsschan)
- ieee80211_setcurchan(ic, ic->ic_bsschan);
- /* clear internal flags and any indication of a pick */
- SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
- ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
- /*
- * If not canceled and scan completed, do post-processing.
- * If the callback function returns 0, then it wants to
- * continue/restart scanning. Unfortunately we needed to
- * notify the driver to end the scan above to avoid having
- * rx frames alter the scan candidate list.
- */
- if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 &&
- !ss->ss_ops->scan_end(ss, vap) &&
- (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
- time_before(ticks + ss->ss_mindwell, scanend)) {
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
- "%s: done, restart "
- "[ticks %u, dwell min %lu scanend %lu]\n",
- __func__,
- ticks, ss->ss_mindwell, scanend);
- ss->ss_next = 0; /* reset to begining */
- if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
- vap->iv_stats.is_scan_active++;
- else
- vap->iv_stats.is_scan_passive++;
+ if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT)))
+ continue;
- ss->ss_ops->scan_restart(ss, vap); /* XXX? */
- ic->ic_scan_start(ic); /* notify driver */
- goto again;
- } else {
- /* past here, scandone is ``true'' if not in bg mode */
- if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
- scandone = 1;
+ /* Wait to be signalled to scan the next channel */
+ cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv, IEEE80211_LOCK_OBJ(ic));
+ }
+ if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
+ goto done;
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
- "%s: %s, "
- "[ticks %u, dwell min %lu scanend %lu]\n",
- __func__, scandone ? "done" : "stopped",
- ticks, ss->ss_mindwell, scanend);
+ IEEE80211_UNLOCK(ic);
+ ic->ic_scan_end(ic); /* notify driver */
+ IEEE80211_LOCK(ic);
- /*
- * Clear the SCAN bit first in case frames are
- * pending on the station power save queue. If
- * we defer this then the dispatch of the frames
- * may generate a request to cancel scanning.
- */
- ic->ic_flags &= ~IEEE80211_F_SCAN;
- /*
- * Drop out of power save mode when a scan has
- * completed. If this scan was prematurely terminated
- * because it is a background scan then don't notify
- * the ap; we'll either return to scanning after we
- * receive the beacon frame or we'll drop out of power
- * save mode because the beacon indicates we have frames
- * waiting for us.
- */
- if (scandone) {
- ieee80211_sta_pwrsave(vap, 0);
- if (ss->ss_next >= ss->ss_last) {
- ieee80211_notify_scan_done(vap);
- ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
- }
- }
- SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_CANCEL;
- ss->ss_flags &=
- ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
+ /*
+ * Record scan complete time. Note that we also do
+ * this when canceled so any background scan will
+ * not be restarted for a while.
+ */
+ if (scandone)
+ ic->ic_lastscan = ticks;
+ /* return to the bss channel */
+ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
+ ic->ic_curchan != ic->ic_bsschan) {
+ ieee80211_setupcurchan(ic, ic->ic_bsschan);
+ IEEE80211_UNLOCK(ic);
+ ic->ic_set_channel(ic);
+ IEEE80211_LOCK(ic);
+ }
+ /* clear internal flags and any indication of a pick */
+ SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP;
+ ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK;
+
+ /*
+ * If not canceled and scan completed, do post-processing.
+ * If the callback function returns 0, then it wants to
+ * continue/restart scanning. Unfortunately we needed to
+ * notify the driver to end the scan above to avoid having
+ * rx frames alter the scan candidate list.
+ */
+ if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 &&
+ !ss->ss_ops->scan_end(ss, vap) &&
+ (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
+ time_before(ticks + ss->ss_mindwell, scanend)) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+ "%s: done, restart "
+ "[ticks %u, dwell min %lu scanend %lu]\n",
+ __func__,
+ ticks, ss->ss_mindwell, scanend);
+ ss->ss_next = 0; /* reset to begining */
+ if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
+ vap->iv_stats.is_scan_active++;
+ else
+ vap->iv_stats.is_scan_passive++;
+
+ ss->ss_ops->scan_restart(ss, vap); /* XXX? */
+ ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task);
+ IEEE80211_UNLOCK(ic);
+ return;
+ }
+
+ /* past here, scandone is ``true'' if not in bg mode */
+ if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
+ scandone = 1;
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
+ "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n",
+ __func__, scandone ? "done" : "stopped",
+ ticks, ss->ss_mindwell, scanend);
+
+ /*
+ * Clear the SCAN bit first in case frames are
+ * pending on the station power save queue. If
+ * we defer this then the dispatch of the frames
+ * may generate a request to cancel scanning.
+ */
+done:
+ ic->ic_flags &= ~IEEE80211_F_SCAN;
+ /*
+ * Drop out of power save mode when a scan has
+ * completed. If this scan was prematurely terminated
+ * because it is a background scan then don't notify
+ * the ap; we'll either return to scanning after we
+ * receive the beacon frame or we'll drop out of power
+ * save mode because the beacon indicates we have frames
+ * waiting for us.
+ */
+ if (scandone) {
+ ieee80211_sta_pwrsave(vap, 0);
+ if (ss->ss_next >= ss->ss_last) {
+ ieee80211_notify_scan_done(vap);
+ ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
}
}
+ SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT);
+ ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST);
+ IEEE80211_UNLOCK(ic);
#undef ISCAN_REP
}
OpenPOWER on IntegriCloud