Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 14 Apr 2009 05:12:01 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r191046 - user/thompsa/vaptq/sys/net80211
Message-ID:  <200904140512.n3E5C1Vs095253@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Tue Apr 14 05:12:01 2009
New Revision: 191046
URL: http://svn.freebsd.org/changeset/base/191046

Log:
  Move scanning to a taskqueue thread. This now does the full scan within the one
  execution rather than rearming timers, the thread will be signalled to move on
  to the next channel.
  
  This may block the ic taskqueue for too long since a state change does not
  cancel the scan first.

Modified:
  user/thompsa/vaptq/sys/net80211/ieee80211_scan.c

Modified: user/thompsa/vaptq/sys/net80211/ieee80211_scan.c
==============================================================================
--- user/thompsa/vaptq/sys/net80211/ieee80211_scan.c	Tue Apr 14 05:09:09 2009	(r191045)
+++ user/thompsa/vaptq/sys/net80211/ieee80211_scan.c	Tue Apr 14 05:12:01 2009	(r191046)
@@ -33,7 +33,10 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h> 
+#include <sys/proc.h>
 #include <sys/kernel.h>
+#include <sys/taskqueue.h>
+#include <sys/condvar.h>
  
 #include <sys/socket.h>
 
@@ -52,10 +55,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 +93,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,6 +112,8 @@ ieee80211_scan_attach(struct ieee80211co
 		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;
 
 	ic->ic_scan_curchan = scan_curchan;
@@ -119,12 +126,15 @@ ieee80211_scan_detach(struct ieee80211co
 	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);
+		taskqueue_drain(ic->ic_tq, &SCAN_PRIVATE(ss)->ss_scan_task);
 		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 +184,8 @@ ieee80211_scan_vdetach(struct ieee80211v
 	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);
@@ -352,76 +361,6 @@ scan_dump(struct ieee80211_scan_state *s
 }
 #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,6 +424,7 @@ start_scan_locked(const struct ieee80211
 
 			/* 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;
@@ -493,8 +433,9 @@ start_scan_locked(const struct ieee80211
 			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;
+			taskqueue_enqueue(ic->ic_tq,
+			    &SCAN_PRIVATE(ss)->ss_scan_task);
 		}
 	} else {
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
@@ -716,11 +657,12 @@ ieee80211_bg_scan(struct ieee80211vap *v
 			}
 			/* 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;
+			taskqueue_enqueue(ic->ic_tq,
+			    &SCAN_PRIVATE(ss)->ss_scan_task);
 		} else {
 			/* XXX msg+stat */
 		}
@@ -756,9 +698,8 @@ ieee80211_cancel_scan(struct ieee80211va
 		/* 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 +724,8 @@ ieee80211_cancel_anyscan(struct ieee8021
 		/* 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 +740,10 @@ ieee80211_scan_next(struct ieee80211vap 
 	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 +759,7 @@ ieee80211_scan_done(struct ieee80211vap 
 	IEEE80211_LOCK(ic);
 	ss = ic->ic_scan;
 	ss->ss_next = ss->ss_last; /* all channels are complete */
-	scan_next(ss);
+	ieee80211_scan_next(vap);
 	IEEE80211_UNLOCK(ic);
 }
 
@@ -871,7 +814,17 @@ scan_curchan(struct ieee80211_scan_state
 	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);
+}
+
+static void
+scan_signal(void *arg)
+{
+	struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg;
+
+	IEEE80211_LOCK_ASSERT(ss->ss_vap->iv_ic);
+
+	cv_signal(&SCAN_PRIVATE(ss)->ss_scan_cv);
 }
 
 /*
@@ -881,35 +834,66 @@ scan_curchan(struct ieee80211_scan_state
 static void
 scan_mindwell(struct ieee80211_scan_state *ss)
 {
-	callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 0, scan_next, ss);
+	struct ieee80211vap *vap = ss->ss_vap;
+	struct ieee80211com *ic = vap->iv_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 ieee80211_channel *chan;
 	unsigned long maxdwell, scanend;
-	int scandone;
+	int scandone = 0;
 
-	IEEE80211_LOCK_ASSERT(ic);
+	IEEE80211_LOCK(ic);
+	if ((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 */
+			printf("ieee80211_sta_pwrsave(vap, 1)\n");
+			ieee80211_sta_pwrsave(vap, 1);
+			/*
+			 * Use an 1ms delay so the null data frame has a chance
+			 * to go out.
+			 */
+			cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv,
+			    IEEE80211_LOCK_OBJ(ic), hz / 1000);
+			if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)
+				goto done;
+		}
+	}
+
+	printf("%s: starting scan loop\n", __func__);
+	scanend = ticks + SCAN_PRIVATE(ss)->ss_duration;
+	ic->ic_scan_start(ic);		/* notify driver */
+
+	for (;;) {
+		scandone = (ss->ss_next >= ss->ss_last) ||
+		    (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0;
+		if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) ||
+		     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++];
 
 		/*
@@ -948,87 +932,96 @@ again:
 		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++;
+		/* 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;
+	}
+	ic->ic_scan_end(ic);		/* notify driver */
 
-			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;
+	/*
+	 * 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;
 
-			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);
+	/*
+	 * 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++;
 
-			/*
-			 * 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);
+		ss->ss_ops->scan_restart(ss, vap);	/* XXX? */
+		taskqueue_enqueue(ic->ic_tq, &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:
+	printf("%s: finished, cancel=%d abort=%d\n", __func__,
+	    (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0,
+	    (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) != 0);
+	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
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200904140512.n3E5C1Vs095253>