PERFORCE change 77276 for review

Sam Leffler sam at FreeBSD.org
Sun May 22 04:02:24 GMT 2005


http://perforce.freebsd.org/chv.cgi?CH=77276

Change 77276 by sam at sam_ebb on 2005/05/22 04:01:39

	Working sta mode bg scanning (mostly):
	o hide scan implementation details from scan policy modules by
	  making ic_scan a pointer to a struct that has public+private
	  sections
	o move power save work out of policy code and into the core
	o change policy scan_restart callback to be invoked when a bg
	  scan is restarted with the first entry in the channel list
	o change scan canceling to mark a flag, reset the time to fire
	  immediately, and let the work be done in the timer context
	o eliminate IEEE80211_SCAN_PWRSAV, check the actual node state
	  to see if we're in power save mode to avoid inconsistent state
	  now that other code is futzing with ps state
	o clear IEEE80211_F_SCAN before dropping out of power save mode
	  so any null data frame passing through ieee80211_start doesn't
	  cause us to try and cancel a bg scan
	o change sta policy code to purge cache entries when there's been
	  no traffic from the sta for 2 complete scans
	
	Still need to tweak the bg scan scheduling to leave more room
	to return on-channel for beacons.  Also need to improve behaviour
	when traffic preempts a bg scan.

Affected files ...

.. //depot/projects/vap/sys/net80211/ieee80211_scan.c#5 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan.h#3 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan_ap.c#4 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan_sta.c#6 edit
.. //depot/projects/vap/sys/net80211/ieee80211_var.h#14 edit

Differences ...

==== //depot/projects/vap/sys/net80211/ieee80211_scan.c#5 (text+ko) ====

@@ -50,29 +50,49 @@
 
 #include <net80211/ieee80211_var.h>
 
-static void ieee80211_next_scan(void *arg);
+struct scan_state {
+	struct ieee80211_scan_state base;	/* public state */
+
+	struct ieee80211_channel *ss_savchan;	/* saved channel setting */
+	unsigned long	ss_scanend;		/* time scan must stop */
+	unsigned long	ss_chanmindwell;	/* " " " on curchan */
+	struct callout	ss_scan_timer;		/* scan timer */
+};
+#define	SCAN_PRIVATE(ss)	((struct scan_state *) ss)
+
+static void scan_next(void *arg);
 
 MALLOC_DEFINE(M_80211_SCAN, "80211scan", "802.11 scan state");
 
 void
 ieee80211_scan_attach(struct ieee80211com *ic)
 {
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct scan_state *ss;
 
-	callout_init(&ss->ss_scan_timer, CALLOUT_MPSAFE);
+	MALLOC(ss, struct scan_state *, sizeof(struct scan_state),
+		M_80211_SCAN, M_NOWAIT | M_ZERO);
+	if (ss != NULL) {
+		callout_init(&ss->ss_scan_timer, CALLOUT_MPSAFE);
+		ic->ic_scan = &ss->base;
+	} else
+		ic->ic_scan = NULL;
 }
 
 void
 ieee80211_scan_detach(struct ieee80211com *ic)
 {
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
-	callout_drain(&ss->ss_scan_timer);
-	if (ss->ss_ops != NULL) {
-		ss->ss_ops->scan_detach(ss);
-		ss->ss_ops = NULL;
+	if (ss != NULL) {
+		callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
+		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);
 	}
-	ic->ic_flags &= ~IEEE80211_F_SCAN;
 }
 
 void
@@ -86,12 +106,12 @@
 ieee80211_scan_vdetach(struct ieee80211vap *vap)
 {
 	struct ieee80211com *ic = vap->iv_ic;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	IEEE80211_LOCK(ic);
 	if (ss->ss_vap == vap) {
 		if (ic->ic_flags & IEEE80211_F_SCAN) {
-			callout_drain(&ss->ss_scan_timer);
+			callout_drain(&SCAN_PRIVATE(ss)->ss_scan_timer);
 			ic->ic_flags &= ~IEEE80211_F_SCAN;
 		}
 		if (ss->ss_ops != NULL) {
@@ -203,27 +223,37 @@
 }
 
 /*
- * Kick off the scanning thread.
+ * Start/restart scanning.  If we're operating in station mode
+ * and associated notify the ap we're going into power save mode.
+ * Otherwise, start the scan directly.
  */
 static void
-start_timer(struct ieee80211_scan_state *ss, u_int duration)
+scan_restart(struct scan_state *ss, u_int duration)
 {
-	int delay;
+	struct ieee80211vap *vap = ss->base.ss_vap;
+	struct ieee80211com *ic = vap->iv_ic;
+	int delay = 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.
+			 * Use an initial 1ms delay to insure the null
+			 * data frame has a chance to go out.
+			 * XXX bogus, need to trigger on on tx complete.
+			 */
+			ieee80211_sta_pwrsave(vap, 1);
+			delay = hz/1000;
+			if (delay < 1)
+				delay = 1;
+		}
+	}
 
-	if (ss->ss_flags & IEEE80211_SCAN_PWRSAV) {
-		/*
-		 * Use an initial 1ms delay to insure any
-		 * power save frame has a chance to go out.
-		 * XXX 1ms is a lot, better to trigger scan
-		 * on tx complete.
-		 */
-		delay = hz/1000;
-		if (delay < 1)
-			delay = 1;
-	} else
-		delay = 1;
+	ss->ss_savchan = ic->ic_curchan;
+	ic->ic_scan_start(ic);		/* notify driver */
 	ss->ss_scanend = ticks + delay + duration;
-	callout_reset(&ss->ss_scan_timer, delay, ieee80211_next_scan, ss);
+	callout_reset(&ss->ss_scan_timer, delay, scan_next, &ss->base);
 }
 
 /*
@@ -234,7 +264,7 @@
 {
 	struct ieee80211com *ic = vap->iv_ic;
 	const struct ieee80211_scanner *scan;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	scan = ieee80211_scanner_get(vap->iv_opmode);
 	if (scan == NULL) {
@@ -277,14 +307,14 @@
 				vap->iv_stats.is_scan_active++;
 			else
 				vap->iv_stats.is_scan_passive++;
-			ss->ss_savchan = ic->ic_curchan;
+			SCAN_PRIVATE(ss)->ss_savchan = ic->ic_curchan;
 			if (flags & IEEE80211_SCAN_FLUSH)
 				ss->ss_ops->scan_flush(ss);
 
 			/* NB: flush frames rx'd before 1st channel change */
 			ss->ss_flags |= IEEE80211_SCAN_DISCARD;
 			ss->ss_ops->scan_start(ss, vap);
-			start_timer(ss, duration);
+			scan_restart(SCAN_PRIVATE(ss), duration);
 			ic->ic_flags |= IEEE80211_F_SCAN;
 		}
 	} else {
@@ -306,7 +336,7 @@
 ieee80211_check_scan(struct ieee80211vap *vap, int flags, u_int duration)
 {
 	struct ieee80211com *ic = vap->iv_ic;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 	int checkscanlist = 0;
 
 	/*
@@ -352,7 +382,7 @@
 ieee80211_bg_scan(struct ieee80211vap *vap)
 {
 	struct ieee80211com *ic = vap->iv_ic;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	IEEE80211_LOCK(ic);
 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
@@ -378,7 +408,7 @@
 
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
 		    "%s: %s scan, duration %lu\n", __func__,
-		    ic->ic_flags & IEEE80211_F_SCAN ? "active" : "passive",
+		    ss->ss_flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive",
 		    duration);
 
 		if (ss->ss_ops != NULL) {
@@ -406,11 +436,11 @@
 					vap->iv_stats.is_scan_active++;
 				else
 					vap->iv_stats.is_scan_passive++;
+				ss->ss_ops->scan_restart(ss, vap);
 			}
 			/* NB: flush frames rx'd before 1st channel change */
 			ss->ss_flags |= IEEE80211_SCAN_DISCARD;
-			ss->ss_ops->scan_restart(ss, vap);
-			start_timer(ss, duration);
+			scan_restart(SCAN_PRIVATE(ss), duration);
 			ic->ic_flags |= IEEE80211_F_SCAN;
 		} else {
 			/* XXX msg+stat */
@@ -433,30 +463,21 @@
 ieee80211_cancel_scan(struct ieee80211vap *vap)
 {
 	struct ieee80211com *ic = vap->iv_ic;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	IEEE80211_LOCK(ic);
 	if (ic->ic_flags & IEEE80211_F_SCAN) {
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
 		    "%s: cancel %s scan\n", __func__,
-		    ss->ss_flags&IEEE80211_SCAN_ACTIVE ?  "active" : "passive");
+		    ss->ss_flags & IEEE80211_SCAN_ACTIVE ?
+			"active" : "passive");
 
-		callout_drain(&ss->ss_scan_timer);
-		/* XXX maybe this should be handled in the timer routine? */
-		ic->ic_flags &= ~IEEE80211_F_SCAN;
-		ss->ss_ops->scan_cancel(ss, vap);
-		/* return to previous channel if needed */
-		if (ss->ss_savchan != ic->ic_curchan)
-			change_channel(ic, ss->ss_savchan);
-		ic->ic_scan_end(ic);		/* notify driver */
-		/* XXX ieee80211_end_scan or otherwise notify? */
-		if (ss->ss_flags & IEEE80211_SCAN_PWRSAV) {
-			ieee80211_sta_pwrsave(vap, 0);
-			ss->ss_flags &= ~IEEE80211_SCAN_PWRSAV;
-		}
-		/* clear ephemeral state bits */
-		ss->ss_flags &= ~(IEEE80211_SCAN_MINDWELL |
-			IEEE80211_SCAN_BGSCAN | IEEE80211_SCAN_ONCE);
+		/* clear bg scan NOPICK and mark cancel request */
+		ss->ss_flags &= ~IEEE80211_SCAN_NOPICK;
+		ss->ss_flags |= IEEE80211_SCAN_CANCEL;
+		/* NB: trigger at next clock tick */
+		callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 1,
+			scan_next, ss);
 	}
 	IEEE80211_UNLOCK(ic);
 }
@@ -465,13 +486,13 @@
  * Switch to the next channel marked for scanning.
  */
 static void
-ieee80211_next_scan(void *arg)
+scan_next(void *arg)
 {
 	struct ieee80211_scan_state *ss = arg;
 	struct ieee80211vap *vap = ss->ss_vap;
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ieee80211_channel *chan;
-	unsigned long maxdwell;
+	unsigned long maxdwell, scanend;
 	int scanning, scandone, i;
 
 	IEEE80211_LOCK(ic);
@@ -482,15 +503,17 @@
 
 	/* XXX if taking first candidate check for a valid result */
 again:
-	scandone = (ss->ss_next >= ss->ss_last);
-	if (!scandone && time_before(ticks + ss->ss_mindwell, ss->ss_scanend)) {
+	scandone = (ss->ss_next >= ss->ss_last) ||
+		(ss->ss_flags & IEEE80211_SCAN_CANCEL) != 0;
+	scanend = SCAN_PRIVATE(ss)->ss_scanend;
+	if (!scandone && time_before(ticks + ss->ss_mindwell, scanend)) {
 		chan = ss->ss_chans[ss->ss_next++];
 
 		/*
 		 * Watch for truncation due to the scan end time.
 		 */
-		if (time_after(ticks + ss->ss_maxdwell, ss->ss_scanend))
-			maxdwell = ss->ss_scanend - ticks;
+		if (time_after(ticks + ss->ss_maxdwell, scanend))
+			maxdwell = scanend - ticks;
 		else
 			maxdwell = ss->ss_maxdwell;
 
@@ -538,39 +561,44 @@
 					ss->ss_probe_ssid[i].len,
 					vap->iv_opt_ie, vap->iv_opt_ie_len);
 		}
-		ss->ss_chanmindwell = ticks + ss->ss_mindwell;
-		callout_reset(&ss->ss_scan_timer, maxdwell,
-			ieee80211_next_scan, ss);
+		SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell;
+		callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, maxdwell,
+			scan_next, ss);
 		/* clear mindwell lock and initial channel change flush */
 		ss->ss_flags &=
 			~(IEEE80211_SCAN_MINDWELL | IEEE80211_SCAN_DISCARD);
 	} else {
+		ic->ic_scan_end(ic);		/* notify driver */
 		/*
-		 * Scan completed, do post-processing.  If the callback
-		 * function returns 0, then it wants to continue/restart
-		 * scanning.  Unfortunately we need to notify the driver
-		 * to end the scan before we invoke the callback method
-		 * to avoid having rx frames alter the scan candidate
-		 * list (maybe we could use a flag to have them discarded?).
+		 * Record scan complete time.  Note that we also do
+		 * this when canceled so any background scan will
+		 * not be restarted for a while.
 		 */
-		ic->ic_scan_end(ic);		/* notify driver */
-		if (scandone)			/* record scan complete time */
+		if (scandone)
 			ic->ic_lastscan = ticks;
 		/* return to the original channel */
-		if (ss->ss_savchan != ic->ic_curchan)
-			change_channel(ic, ss->ss_savchan);
+		if (SCAN_PRIVATE(ss)->ss_savchan != ic->ic_curchan)
+			change_channel(ic, SCAN_PRIVATE(ss)->ss_savchan);
 		/* clear mindwell lock and initial channel change flush */
 		ss->ss_flags &=
 			~(IEEE80211_SCAN_MINDWELL | IEEE80211_SCAN_DISCARD);
 
-		if (!ss->ss_ops->scan_end(ss, vap) &&
+		/*
+		 * 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 ((ss->ss_flags & IEEE80211_SCAN_CANCEL) == 0 &&
+		    !ss->ss_ops->scan_end(ss, vap) &&
 		    (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
-		    time_before(ticks + ss->ss_mindwell, ss->ss_scanend)) {
+		    time_before(ticks + ss->ss_mindwell, scanend)) {
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
 			    "%s: done, restart "
 			    "[ticks %lu, dwell min %lu scanend %lu]\n",
 			    __func__,
-			    ticks, ss->ss_mindwell, ss->ss_scanend);
+			    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++;
@@ -583,14 +611,20 @@
 			/* past here, scandone is ``true'' if not in bg mode */
 			if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0)
 				scandone = 1;
-			ss->ss_flags &= ~IEEE80211_SCAN_ONCE;
 
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
 			    "%s: %s, [ticks %lu, dwell min %lu scanend %lu]\n",
 			    __func__, scandone ? "done" : "stopped",
-			    ticks, ss->ss_mindwell, ss->ss_scanend);
+			    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.
+			 */
+			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
@@ -599,15 +633,13 @@
 			 * save mode because the beacon indicates we have frames
 			 * waiting for us.
 			 */
-			if (scandone &&
-			    (ss->ss_flags & IEEE80211_SCAN_PWRSAV)) {
+			if (scandone) {
 				ieee80211_sta_pwrsave(vap, 0);
-				ss->ss_flags &= ~IEEE80211_SCAN_PWRSAV;
+				if (ss->ss_next >= ss->ss_last)
+					ieee80211_notify_scan_done(vap);
 			}
-			ic->ic_flags &= ~IEEE80211_F_SCAN;
-			/* NB: suppress notification during bg scan */
-			if (scandone)
-				ieee80211_notify_scan_done(vap);
+			ss->ss_flags &=
+				~(IEEE80211_SCAN_CANCEL | IEEE80211_SCAN_ONCE);
 		}
 	}
 }
@@ -720,7 +752,7 @@
 	int subtype, int rssi, int rstamp)
 {
 	struct ieee80211com *ic = vap->iv_ic;
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	/*
 	 * Frames received during startup are discarded to avoid
@@ -743,13 +775,13 @@
 		 * the timer so we'll switch to the next channel.
 		 */
 		if ((ss->ss_flags & IEEE80211_SCAN_MINDWELL) == 0 &&
-		    time_after_eq(ticks, ss->ss_chanmindwell)) {
+		    time_after_eq(ticks, SCAN_PRIVATE(ss)->ss_chanmindwell)) {
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
 			    "%s: chan %3d%c min dwell met (%lu > %lu)\n",
 			    __func__,
 			    ieee80211_chan2ieee(ic, ic->ic_curchan),
 				channel_type(ic->ic_curchan),
-			    ticks, ss->ss_chanmindwell);
+			    ticks, SCAN_PRIVATE(ss)->ss_chanmindwell);
 			/*
 			 * XXX
 			 * We want to just kick the timer and still
@@ -762,8 +794,8 @@
 			ss->ss_flags |= IEEE80211_SCAN_DISCARD;
 #endif
 			/* NB: trigger at next clock tick */
-			callout_reset(&ss->ss_scan_timer, 1,
-				ieee80211_next_scan, ss);
+			callout_reset(&SCAN_PRIVATE(ss)->ss_scan_timer, 1,
+				scan_next, ss);
 		}
 	}
 }
@@ -775,7 +807,7 @@
 void
 ieee80211_scan_timeout(struct ieee80211com *ic)
 {
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	if (ss->ss_ops != NULL)
 		ss->ss_ops->scan_age(ss);
@@ -787,7 +819,7 @@
 void
 ieee80211_scan_assocfail(struct ieee80211com *ic, const u_int8_t mac[])
 {
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	if (ss->ss_ops != NULL)
 		ss->ss_ops->scan_assocfail(ss, mac);
@@ -800,7 +832,7 @@
 ieee80211_scan_iterate(struct ieee80211com *ic,
 	ieee80211_scan_iter_func *f, void *arg)
 {
-	struct ieee80211_scan_state *ss = &ic->ic_scan;
+	struct ieee80211_scan_state *ss = ic->ic_scan;
 
 	if (ss->ss_ops != NULL)
 		ss->ss_ops->scan_iterate(ss, f, arg);

==== //depot/projects/vap/sys/net80211/ieee80211_scan.h#3 (text+ko) ====

@@ -40,15 +40,16 @@
 struct ieee80211_scan_state {
 	struct ieee80211vap *ss_vap;
 	const struct ieee80211_scanner *ss_ops;	/* policy hookup, see below */
+	void		*ss_priv;		/* scanner private state */
 	u_int16_t	ss_flags;
 #define	IEEE80211_SCAN_NOPICK	0x0001		/* scan only, no selection */
 #define	IEEE80211_SCAN_ACTIVE	0x0002		/* active scan (probe req) */
 #define	IEEE80211_SCAN_PICK1ST	0x0004		/* ``hey sailor'' mode */
 #define	IEEE80211_SCAN_BGSCAN	0x0008		/* bg scan, exit ps at end */
 #define	IEEE80211_SCAN_ONCE	0x0010		/* do one complete pass */
-#define	IEEE80211_SCAN_PWRSAV	0x1000		/* exit power save mode */
-#define	IEEE80211_SCAN_MINDWELL	0x2000		/* min dwell time reached */
-#define	IEEE80211_SCAN_DISCARD	0x4000		/* discard rx'd frames */
+#define	IEEE80211_SCAN_MINDWELL	0x1000		/* min dwell time reached */
+#define	IEEE80211_SCAN_DISCARD	0x2000		/* discard rx'd frames */
+#define	IEEE80211_SCAN_CANCEL	0x4000		/* cancel current scan */
 	u_int8_t	ss_pad;
 	u_int8_t	ss_nprobe_ssid;		/* # ssid's to probe */
 	struct {
@@ -60,12 +61,8 @@
 	struct ieee80211_channel *ss_chans[IEEE80211_SCAN_MAX];
 	u_int16_t	ss_next;		/* ix of next chan to scan */
 	u_int16_t	ss_last;		/* ix+1 of last chan to scan */
-	unsigned long	ss_scanend;		/* time scan must stop */
 	unsigned long	ss_mindwell;		/* min dwell on channel */
-	unsigned long	ss_chanmindwell;	/* " " " on curchan */
 	unsigned long	ss_maxdwell;		/* max dwell on channel */
-	struct callout	ss_scan_timer;		/* scan timer */
-	void		*ss_priv;		/* scanner private state */
 };
 
 /*

==== //depot/projects/vap/sys/net80211/ieee80211_scan_ap.c#4 (text+ko) ====

@@ -97,21 +97,6 @@
 	return 0;
 }
 
-/*
- * Restart a previous scan.
- */
-static int
-ap_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
-{
-	struct ieee80211com *ic = vap->iv_ic;
-
-	ss->ss_flags &= ~IEEE80211_SCAN_PWRSAV;
-	ss->ss_savchan = ic->ic_curchan;
-	ic->ic_scan_start(ic);			/* notify driver */
-
-	return 0;
-}
-
 static struct ieee80211_channel *
 find11gchannel(struct ieee80211com *ic, int i, int freq)
 {
@@ -304,11 +289,20 @@
 	}
 #endif /* IEEE80211_DEBUG */
 
-	return ap_restart(ss, vap);
+	return 0;
 #undef N
 }
 
 /*
+ * Restart a previous scan.
+ */
+static int
+ap_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+{
+	return 0;
+}
+
+/*
  * Cancel an ongoing scan.
  */
 static int

==== //depot/projects/vap/sys/net80211/ieee80211_scan_sta.c#6 (text+ko) ====

@@ -60,7 +60,7 @@
  *   (background) scans is discarded
  * o after STA_FAILS_AGE seconds we clear the failure count
  */
-#define	STA_FAILS_MAX	2		/* assoc failures before purge */
+#define	STA_FAILS_MAX	2		/* assoc failures before ignored */
 #define	STA_FAILS_AGE	(2*60)		/* time before clearing fails (secs) */
 #define	STA_PURGE_SCANS	2		/* age for purging entries (scans) */
 
@@ -81,6 +81,8 @@
 	TAILQ_ENTRY(sta_entry) se_list;
 	LIST_ENTRY(sta_entry) se_hash;
 	u_int8_t	se_fails;		/* failure to associate count */
+	u_int8_t	se_seen;		/* seen during current scan */
+	u_int8_t	se_notseen;		/* not seen in previous scans */
 	u_int32_t	se_avgrssi;		/* LPF rssi state */
 	u_int32_t	se_lastupdate;		/* time of last update */
 	u_int32_t	se_lastfail;		/* time of last failure */
@@ -98,6 +100,7 @@
 	LIST_HEAD(, sta_entry) st_hash[STA_HASHSIZE];
 	struct mtx	st_scanlock;		/* on st_scangen */
 	u_int		st_scangen;		/* gen# for iterator */
+	int		st_newscan;
 };
 
 static void sta_flush_table(struct sta_table *);
@@ -254,6 +257,7 @@
 		se->se_fails = 0;
 
 	se->se_lastupdate = ticks;		/* update time */
+	se->se_seen = 1;
 
 	mtx_unlock(&st->st_lock);
 #if 0
@@ -271,28 +275,27 @@
 #undef ISPROBE
 }
 
-/*
- * Restart a previous scan.
- */
-static int
-sta_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+static void
+sta_clearseen(struct sta_table *st)
 {
-	struct ieee80211com *ic = vap->iv_ic;
+	struct sta_entry *se;
 
-	if (vap->iv_opmode == IEEE80211_M_STA &&
-	    vap->iv_state == IEEE80211_S_RUN) {
-		if ((ss->ss_flags & IEEE80211_SCAN_PWRSAV) == 0) {
-			/* initiate power save before going off-channel */
-			ieee80211_sta_pwrsave(vap, 1);
-			ss->ss_flags |= IEEE80211_SCAN_PWRSAV;
-		}
-	} else
-		ss->ss_flags &= ~IEEE80211_SCAN_PWRSAV;
+	mtx_lock(&st->st_lock);
+	TAILQ_FOREACH(se, &st->st_entry, se_list)
+		se->se_seen = 0;
+	mtx_unlock(&st->st_lock);
+}
 
-	ss->ss_savchan = ic->ic_curchan;
-	ic->ic_scan_start(ic);			/* notify driver */
+static void
+sta_updateseen(struct sta_table *st)
+{
+	struct sta_entry *se;
 
-	return 0;
+	mtx_lock(&st->st_lock);
+	TAILQ_FOREACH(se, &st->st_entry, se_list)
+		if (!se->se_seen)
+			se->se_notseen++;
+	mtx_unlock(&st->st_lock);
 }
 
 static struct ieee80211_channel *
@@ -423,6 +426,7 @@
 {
 #define	N(a)	(sizeof(a)/sizeof(a[0]))
 	struct ieee80211com *ic = vap->iv_ic;
+	struct sta_table *st = ss->ss_priv;
 	enum ieee80211_phymode mode;
 	int i;
 
@@ -487,11 +491,27 @@
 	}
 #endif /* IEEE80211_DEBUG */
 
-	return sta_restart(ss, vap);
+	sta_clearseen(st);
+	st->st_newscan = 1;
+
+	return 0;
 #undef N
 }
 
 /*
+ * Restart a bg scan.
+ */
+static int
+sta_restart(struct ieee80211_scan_state *ss, struct ieee80211vap *vap)
+{
+	struct sta_table *st = ss->ss_priv;
+
+	sta_clearseen(st);
+	st->st_newscan = 1;
+	return 0;
+}
+
+/*
  * Cancel an ongoing scan.
  */
 static int
@@ -655,6 +675,8 @@
 		fail |= 0x20;
 	if (se0->se_fails >= STA_FAILS_MAX)
 		fail |= 0x40;
+	if (se0->se_notseen >= STA_PURGE_SCANS)
+		fail |= 0x80;
 #ifdef IEEE80211_DEBUG
 	if (ieee80211_msg_scan(vap)) {
 		/* XXX se_fails */
@@ -696,6 +718,10 @@
 	KASSERT(vap->iv_opmode != IEEE80211_M_HOSTAP,
 		("wrong opmode %u", vap->iv_opmode));
 
+	if (st->st_newscan) {
+		sta_updateseen(st);
+		st->st_newscan = 0;
+	}
 	if (ss->ss_flags & IEEE80211_SCAN_NOPICK) {
 		/*
 		 * Manual/background scan, don't select+join the
@@ -755,13 +781,10 @@
 {
 	struct sta_table *st = ss->ss_priv;
 	struct sta_entry *se, *next;
-	u_int32_t droptime;
 
-	droptime = ticks - (STA_PURGE_SCANS * ss->ss_vap->iv_bgscanintvl);
-
 	mtx_lock(&st->st_lock);
 	TAILQ_FOREACH_SAFE(se, &st->st_entry, se_list, next) {
-		if (time_before(se->se_lastupdate, droptime)) {
+		if (se->se_notseen > STA_PURGE_SCANS) {
 			TAILQ_REMOVE(&st->st_entry, se, se_list);
 			LIST_REMOVE(se, se_hash);
 			FREE(se, M_80211_SCAN);

==== //depot/projects/vap/sys/net80211/ieee80211_var.h#14 (text+ko) ====

@@ -156,7 +156,7 @@
 	struct ieee80211_channel *ic_prevchan;	/* previous channel */
 
 	/* scan-related state */
-	struct ieee80211_scan_state ic_scan;	/* scan state */
+	struct ieee80211_scan_state *ic_scan;	/* scan state */
 	enum ieee80211_roamingmode ic_roaming;	/* roaming mode */
 	int			ic_lastdata;	/* time of last data frame */
 	int			ic_lastscan;	/* time last scan completed */


More information about the p4-projects mailing list