Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 16 May 2005 18:44:36 GMT
From:      Sam Leffler <sam@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 77074 for review
Message-ID:  <200505161844.j4GIiaED033437@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=77074

Change 77074 by sam@sam_laptop on 2005/05/16 18:44:27

	First cut at background scanning; needs testing.

Affected files ...

.. //depot/projects/vap/sys/net80211/ieee80211.c#9 edit
.. //depot/projects/vap/sys/net80211/ieee80211_input.c#10 edit
.. //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#9 edit
.. //depot/projects/vap/sys/net80211/ieee80211_ioctl.h#6 edit
.. //depot/projects/vap/sys/net80211/ieee80211_output.c#11 edit
.. //depot/projects/vap/sys/net80211/ieee80211_proto.c#7 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan.c#2 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan.h#2 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan_ap.c#3 edit
.. //depot/projects/vap/sys/net80211/ieee80211_scan_sta.c#3 edit
.. //depot/projects/vap/sys/net80211/ieee80211_var.h#10 edit

Differences ...

==== //depot/projects/vap/sys/net80211/ieee80211.c#9 (text+ko) ====

@@ -278,6 +278,10 @@
 		vap->iv_flags |= IEEE80211_F_FF;
 	if (vap->iv_caps & IEEE80211_C_TURBOP)
 		vap->iv_flags |= IEEE80211_F_TURBOP;
+	/* NB: bg scanning only makes sense for station mode right now */
+	if (ic->ic_opmode == IEEE80211_M_STA &&
+	    (vap->iv_caps & IEEE80211_C_BGSCAN))
+		vap->iv_flags |= IEEE80211_F_BGSCAN;
 
 	vap->iv_des_chan = IEEE80211_CHAN_ANYC;		/* any channel is ok */
 	vap->iv_dtim_period = IEEE80211_DTIM_DEFAULT;

==== //depot/projects/vap/sys/net80211/ieee80211_input.c#10 (text+ko) ====

@@ -531,6 +531,7 @@
 		ifp->if_ipackets++;
 		IEEE80211_NODE_STAT(ni, rx_data);
 		IEEE80211_NODE_STAT_ADD(ni, rx_bytes, m->m_pkthdr.len);
+		ic->ic_lastdata = ticks;
 
 #define	FF_LLC_SIZE	(sizeof(struct ether_header) + sizeof(struct llc))
 		if (IEEE80211_ATH_CAP(vap, ni, FF) &&
@@ -2318,9 +2319,20 @@
 			}
 			if (scan.doth != NULL)
 				ieee80211_parse_dothparams(vap, scan.doth, wh);
-			/* NB: don't need the rest of this */
-			if ((ic->ic_flags & IEEE80211_F_SCAN) == 0)
+			if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
+				/*
+				 * If no data frames have come through
+				 * recently and it's been a while since the
+				 * last background scan, kick off a new
+				 * background scan.
+				 */
+				if ((vap->iv_flags & IEEE80211_F_BGSCAN) &&
+				    ticks - ic->ic_lastscan >= vap->iv_bgscanintvl &&
+				    ticks - ic->ic_lastdata >= vap->iv_bgscanidle)
+					ieee80211_bg_scan(vap);
+				/* NB: don't need the rest of this */
 				return;
+			}
 		}
 		/*
 		 * If scanning, just pass information to the scan module.

==== //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#9 (text+ko) ====

@@ -905,6 +905,15 @@
 	case IEEE80211_IOC_TURBOP:
 		ireq->i_val = (vap->iv_flags & IEEE80211_F_TURBOP) != 0;
 		break;
+	case IEEE80211_IOC_BGSCAN:
+		ireq->i_val = (vap->iv_flags & IEEE80211_F_BGSCAN) != 0;
+		break;
+	case IEEE80211_IOC_BGSCAN_IDLE:
+		ireq->i_val = vap->iv_bgscanidle*1000/hz;/* ms */
+		break;
+	case IEEE80211_IOC_BGSCAN_INTERVAL:
+		ireq->i_val = vap->iv_bgscanintvl/hz;	/* seconds */
+		break;
 	default:
 		error = EINVAL;
 		break;
@@ -1708,7 +1717,9 @@
 		break;
 	case IEEE80211_IOC_SCAN_REQ:
 		error = ieee80211_start_scan(vap,
-			IEEE80211_SCAN_NOPICK|IEEE80211_SCAN_ACTIVE);
+				IEEE80211_SCAN_ACTIVE |
+				IEEE80211_SCAN_NOPICK |
+				IEEE80211_SCAN_ONCE, IEEE80211_SCAN_FOREVER);
 		break;
 	case IEEE80211_IOC_ADDMAC:
 	case IEEE80211_IOC_DELMAC:
@@ -1768,6 +1779,26 @@
 			vap->iv_flags &= ~IEEE80211_F_TURBOP;
 		error = ENETRESET;		/* XXX maybe not for station? */
 		break;
+	case IEEE80211_IOC_BGSCAN:
+		if (ireq->i_val) {
+			if ((vap->iv_caps & IEEE80211_C_BGSCAN) == 0)
+				return EINVAL;
+			vap->iv_flags |= IEEE80211_F_BGSCAN;
+		} else
+			vap->iv_flags &= ~IEEE80211_F_BGSCAN;
+		break;
+	case IEEE80211_IOC_BGSCAN_IDLE:
+		if (ireq->i_val >= IEEE80211_BGSCAN_IDLE_MIN)
+			vap->iv_bgscanidle = ireq->i_val*hz/1000;
+		else
+			error = EINVAL;
+		break;
+	case IEEE80211_IOC_BGSCAN_INTERVAL:
+		if (ireq->i_val >= IEEE80211_BGSCAN_INTVAL_MIN)
+			vap->iv_bgscanintvl = ireq->i_val*hz;
+		else
+			error = EINVAL;
+		break;
 	default:
 		error = EINVAL;
 		break;

==== //depot/projects/vap/sys/net80211/ieee80211_ioctl.h#6 (text+ko) ====

@@ -434,6 +434,9 @@
 #define	IEEE80211_IOC_TURBOP		57	/* ATH turbo' (on, off) */
 #define	IEEE80211_IOC_WDS		58	/* WDS/4-address handling */
 #define	IEEE80211_IOC_PUREG		59	/* pure 11g (no 11b stations) */
+#define	IEEE80211_IOC_BGSCAN		60	/* bg scanning (on, off) */
+#define	IEEE80211_IOC_BGSCAN_IDLE	61	/* bg scan idle threshold */
+#define	IEEE80211_IOC_BGSCAN_INTERVAL	62	/* bg scan interval */
 
 /*
  * Scan result data returned for IEEE80211_IOC_SCAN_RESULTS.

==== //depot/projects/vap/sys/net80211/ieee80211_output.c#11 (text+ko) ====

@@ -217,6 +217,9 @@
 	/* NB: parent must be up and running */
 	if ((parent->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
 		return;
+	if (vap->iv_state == IEEE80211_S_RUN &&
+	    (ic->ic_flags & IEEE80211_F_SCAN))		/* cancel bg scan */
+		ieee80211_cancel_scan(vap);
 	for (;;) {
 		/*
 		 * No data frames go out unless we're running.
@@ -290,6 +293,7 @@
 		} else
 			ifp->if_opackets++;
 	}
+	ic->ic_lastdata = ticks;
 }
 
 /*

==== //depot/projects/vap/sys/net80211/ieee80211_proto.c#7 (text+ko) ====

@@ -1136,6 +1136,9 @@
 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s\n", __func__,
 		ieee80211_state_name[ostate], ieee80211_state_name[nstate]);
 	vap->iv_state = nstate;			/* state transition */
+	callout_stop(&vap->iv_mgtsend);
+	if (ostate != IEEE80211_S_SCAN)
+		ieee80211_cancel_scan(vap);	/* background scan */
 	ni = vap->iv_bss;			/* NB: no reference held */
 	switch (nstate) {
 	case IEEE80211_S_INIT:
@@ -1195,10 +1198,6 @@
 			goto reset;
 		case IEEE80211_S_AUTH:
 		reset:
-			callout_stop(&vap->iv_mgtsend);
-#if 0
-			IF_DRAIN(&ic->ic_mgtq);		/* XXX multi-bss */
-#endif
 			ieee80211_reset_bss(vap);
 			break;
 		}
@@ -1220,7 +1219,8 @@
 			} else {
 				ieee80211_check_scan(vap,
 					IEEE80211_SCAN_ACTIVE | 
-					IEEE80211_SCAN_FLUSH);
+					IEEE80211_SCAN_FLUSH,
+					IEEE80211_SCAN_FOREVER);
 			}
 			break;
 		case IEEE80211_S_SCAN:
@@ -1238,7 +1238,8 @@
 		case IEEE80211_S_ASSOC:
 			/* timeout restart scan */
 			ieee80211_scan_assocfail(ic, vap->iv_bss->ni_macaddr);
-			ieee80211_check_scan(vap, IEEE80211_SCAN_ACTIVE | arg);
+			ieee80211_check_scan(vap, IEEE80211_SCAN_ACTIVE | arg,
+				IEEE80211_SCAN_FOREVER);
 			break;
 		}
 		break;
@@ -1309,7 +1310,6 @@
 		if (vap->iv_flags & IEEE80211_F_WPA) {
 			/* XXX validate prerequisites */
 		}
-		callout_stop(&vap->iv_mgtsend);
 		ifp->if_flags &= ~IFF_OACTIVE;
 		switch (ostate) {
 		case IEEE80211_S_INIT:
@@ -1358,7 +1358,8 @@
 		 * AP.  We delay until here to allow configuration to
 		 * happen out of order.
 		 */
-		if (vap->iv_opmode == IEEE80211_M_HOSTAP && /* XXX IBSS/AHDEMO */
+		if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+		    /* XXX IBSS/AHDEMO */
 		    vap->iv_auth->ia_attach != NULL) {
 			/* XXX check failure */
 			vap->iv_auth->ia_attach(vap);

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

@@ -78,6 +78,8 @@
 void
 ieee80211_scan_vattach(struct ieee80211vap *vap)
 {
+	vap->iv_bgscanidle = (IEEE80211_BGSCAN_IDLE_DEFAULT*1000)/hz;
+	vap->iv_bgscanintvl = IEEE80211_BGSCAN_INTVAL_DEFAULT*hz;
 }
 
 void
@@ -204,7 +206,7 @@
  * Kick off the scanning thread.
  */
 static void
-start_timer(struct ieee80211_scan_state *ss)
+start_timer(struct ieee80211_scan_state *ss, u_int duration)
 {
 	int delay;
 
@@ -215,9 +217,12 @@
 		 * XXX 1ms is a lot, better to trigger scan
 		 * on tx complete.
 		 */
-		delay = hz/100;
+		delay = hz/1000;
+		if (delay < 1)
+			delay = 1;
 	} else
 		delay = 1;
+	ss->ss_scanend = ticks + delay + duration;
 	callout_reset(&ss->ss_scan_timer, delay, ieee80211_next_scan, ss);
 }
 
@@ -225,7 +230,7 @@
  * Start a scan unless one is already going.
  */
 int
-ieee80211_start_scan(struct ieee80211vap *vap, int flags)
+ieee80211_start_scan(struct ieee80211vap *vap, int flags, u_int duration)
 {
 	struct ieee80211com *ic = vap->iv_ic;
 	const struct ieee80211_scanner *scan;
@@ -243,12 +248,14 @@
 	IEEE80211_LOCK(ic);
 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-		    "%s: %s scan, desired mode %s, %s%s\n"
+		    "%s: %s scan, duration %lu, desired mode %s, %s%s%s\n"
 		    , __func__
 		    , flags & IEEE80211_SCAN_ACTIVE ? "active" : "passive"
+		    , duration
 		    , ieee80211_phymode_name[vap->iv_des_mode]
 		    , flags & IEEE80211_SCAN_FLUSH ? "flush" : "append"
 		    , flags & IEEE80211_SCAN_NOPICK ? ", nopick" : ""
+		    , flags & IEEE80211_SCAN_ONCE ? ", once" : ""
 		);
 
 		ss->ss_vap = vap;
@@ -277,7 +284,7 @@
 			/* 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);
+			start_timer(ss, duration);
 			ic->ic_flags |= IEEE80211_F_SCAN;
 		}
 	} else {
@@ -296,7 +303,7 @@
  * fails then kick off a new scan.
  */
 int
-ieee80211_check_scan(struct ieee80211vap *vap, int flags)
+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;
@@ -334,37 +341,76 @@
 		/* no ap, clear the flag before starting a scan */
 		ic->ic_flags &= ~IEEE80211_F_SCAN;
 	}
-	return ieee80211_start_scan(vap, flags);
+	return ieee80211_start_scan(vap, flags, duration);
 }
 
 /*
- * Restart a previous scan.  The existing scan state is left
- * untouched, we just restart the thread and it will pickup
- * where we left off.
+ * Restart a previous scan.  If the previous scan completed
+ * then we start again using the existing channel list.
  */
 int
-ieee80211_restart_scan(struct ieee80211vap *vap)
+ieee80211_bg_scan(struct ieee80211vap *vap)
 {
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ieee80211_scan_state *ss = &ic->ic_scan;
 
 	IEEE80211_LOCK(ic);
 	if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) {
+		u_int duration, fudge;
+
+		/*
+		 * Calculate the schedule for going off-channel.  We
+		 * need to return in time to receive the next beacon
+		 * so we use the beacon interval minus the time required
+		 * to be ready to rx the beacon.  This is device-dependent
+		 * but for now we use 1ms.  Note that this only works
+		 * because we are called on receipt of a beacon frame;
+		 * otherwise we'd need to check TSF and calculate nexttbtt
+		 * or (more likely) arrange to start at the next beacon.
+		 */
+		duration = IEEE80211_TU_TO_TICKS(vap->iv_bss->ni_intval);
+		fudge = hz/1000;
+		if (fudge == 0)
+			fudge = 1;
+		if (duration > fudge)
+			duration -= fudge;
+		/* XXX do we sanity check beacon interval anywhere? */
+
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-		    "%s: %s scan\n", __func__,
-		    ic->ic_flags & IEEE80211_F_SCAN ? "active" : "passive");
+		    "%s: %s scan, duration %lu\n", __func__,
+		    ic->ic_flags & IEEE80211_F_SCAN ? "active" : "passive",
+		    duration);
 
 		if (ss->ss_ops != NULL) {
-			ss->ss_vap = vap;	/* XXX temporary */
-			if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
-				vap->iv_stats.is_scan_active++;
-			else
-				vap->iv_stats.is_scan_passive++;
-
+			ss->ss_vap = vap;
+			/*
+			 * A background scan does not select a new sta; it
+			 * just refreshes the scan cache.  Also, indicate
+			 * the scan logic should follow the beacon schedule:
+			 * we go off-channel and scan for as much of the
+			 * beacon interval as we can, return to the bss channel
+			 * to receive the beacon, then go off-channel again.
+			 * All during this time we notify the ap we're in power
+			 * save mode.  When the scan is complete we leave power
+			 * save mode.  If any beacon indicates there are frames
+			 * pending for us then we drop out of power save mode
+			 * (and background scan) automatically by way of the
+			 * usual sta power save logic.
+			 */
+			ss->ss_flags |= IEEE80211_SCAN_NOPICK
+				     |  IEEE80211_SCAN_BGSCAN;
+			/* if previous scan completed, restart */
+			if (ss->ss_next >= ss->ss_last) {
+				ss->ss_next = 0;
+				if (ss->ss_flags & IEEE80211_SCAN_ACTIVE)
+					vap->iv_stats.is_scan_active++;
+				else
+					vap->iv_stats.is_scan_passive++;
+			}
 			/* 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);
+			start_timer(ss, duration);
 			ic->ic_flags |= IEEE80211_F_SCAN;
 		} else {
 			/* XXX msg+stat */
@@ -381,7 +427,7 @@
 }
 
 /*
- * Cancel any active scan.
+ * Cancel any scan currently going on.
  */
 void
 ieee80211_cancel_scan(struct ieee80211vap *vap)
@@ -396,6 +442,7 @@
 	IEEE80211_LOCK(ic);
 	if (ic->ic_flags & IEEE80211_F_SCAN) {
 		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 */
@@ -405,7 +452,9 @@
 		/* XXX ieee80211_end_scan or otherwise notify? */
 		if (ss->ss_flags & IEEE80211_SCAN_PWRSAV)
 			ieee80211_sta_pwrsave(vap, 0);
-		ss->ss_flags &= ~IEEE80211_SCAN_MINDWELL;
+		/* clear ephemeral state bits */
+		ss->ss_flags &= ~(IEEE80211_SCAN_MINDWELL |
+			IEEE80211_SCAN_BGSCAN | IEEE80211_SCAN_ONCE);
 	}
 	IEEE80211_UNLOCK(ic);
 }
@@ -421,7 +470,7 @@
 	struct ieee80211com *ic = vap->iv_ic;
 	struct ieee80211_channel *chan;
 	unsigned long maxdwell;
-	int scanning, i;
+	int scanning, scandone, i;
 
 	IEEE80211_LOCK(ic);
 	scanning = (ic->ic_flags & IEEE80211_F_SCAN) != 0;
@@ -431,8 +480,8 @@
 
 	/* XXX if taking first candidate check for a valid result */
 again:
-	if (ss->ss_next < ss->ss_last &&
-	    time_before(ticks + ss->ss_mindwell, ss->ss_scanend)) {
+	scandone = (ss->ss_next >= ss->ss_last);
+	if (!scandone && time_before(ticks + ss->ss_mindwell, ss->ss_scanend)) {
 		chan = ss->ss_chans[ss->ss_next++];
 
 		/*
@@ -444,7 +493,7 @@
 			maxdwell = ss->ss_maxdwell;
 
 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-		    "%s: chan %3d%c -> %3d%c [%s, dwell min %ld max %ld]\n",
+		    "%s: chan %3d%c -> %3d%c [%s, dwell min %lu max %lu]\n",
 		    __func__,
 		    ieee80211_chan2ieee(ic, ic->ic_curchan),
 		        channel_type(ic->ic_curchan),
@@ -506,13 +555,16 @@
 		 *     ss_scan_end may decide differently.
 		 */
 		ic->ic_scan_end(ic);		/* notify driver */
+		if (scandone)			/* record scan complete time */
+			ic->ic_lastscan = ticks;
 		/* 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) &&
+		    (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 &&
 		    time_before(ticks + ss->ss_mindwell, ss->ss_scanend)) {
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-			    "%s: scan done, restart "
+			    "%s: done, restart "
 			    "[ticks %lu, dwell min %lu scanend %lu]\n",
 			    __func__,
 			    ticks, ss->ss_mindwell, ss->ss_scanend);
@@ -525,18 +577,34 @@
 			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;
+			ss->ss_flags &= ~IEEE80211_SCAN_ONCE;
+
 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN,
-			    "%s: scan done, completed "
-			    "[ticks %lu, dwell min %lu scanend %lu]\n",
-			    __func__,
+			    "%s: %s, [ticks %lu, dwell min %lu scanend %lu]\n",
+			    __func__, scandone ? "done" : "stopped",
 			    ticks, ss->ss_mindwell, ss->ss_scanend);
-			if (ss->ss_flags & IEEE80211_SCAN_PWRSAV) {
-				if (ss->ss_savchan != ic->ic_curchan)
-					change_channel(ic, ss->ss_savchan);
+
+			/* return to the original channel */
+			if (ss->ss_savchan != ic->ic_curchan)
+				change_channel(ic, ss->ss_savchan);
+			/*
+			 * 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 && (ss->ss_flags & IEEE80211_SCAN_PWRSAV))
 				ieee80211_sta_pwrsave(vap, 0);
-			}
 			ic->ic_flags &= ~IEEE80211_F_SCAN;
-			ieee80211_notify_scan_done(vap);
+			/* NB: suppress notification during bg scan */
+			if (scandone)
+				ieee80211_notify_scan_done(vap);
 		}
 	}
 }

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

@@ -43,6 +43,9 @@
 	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 */
@@ -81,9 +84,10 @@
 
 void	ieee80211_scan_dump_channels(const struct ieee80211_scan_state *);
 
-int	ieee80211_start_scan(struct ieee80211vap *, int flags);
-int	ieee80211_check_scan(struct ieee80211vap *, int flags);
-int	ieee80211_restart_scan(struct ieee80211vap *);
+#define	IEEE80211_SCAN_FOREVER	0x7fffffff
+int	ieee80211_start_scan(struct ieee80211vap *, int flags, u_int duration);
+int	ieee80211_bg_scan(struct ieee80211vap *);
+int	ieee80211_check_scan(struct ieee80211vap *, int flags, u_int duration);
 void	ieee80211_cancel_scan(struct ieee80211vap *);
 
 int	ieee80211_match_bss(struct ieee80211vap *, struct ieee80211_node *);

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

@@ -294,15 +294,13 @@
 	/* XXX tunables */
 	ss->ss_mindwell = 200*hz/1000;	/* 200ms */
 	ss->ss_maxdwell = 300*hz/1000;	/* 300ms */
-	/* arrange to scan only once */
-	ss->ss_scanend = ticks + ss->ss_last * ss->ss_maxdwell;
 
 #ifdef IEEE80211_DEBUG
 	if (ieee80211_msg_scan(vap)) {
 		if_printf(&vap->iv_if, "scan set ");
 		ieee80211_scan_dump_channels(ss);
-		printf(" dwell min %ld max %ld scanend %ld\n",
-			ss->ss_mindwell, ss->ss_maxdwell, ss->ss_scanend);
+		printf(" dwell min %ld max %ld\n",
+			ss->ss_mindwell, ss->ss_maxdwell);
 	}
 #endif /* IEEE80211_DEBUG */
 

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

@@ -88,6 +88,7 @@
 };
 
 static void sta_flush_table(struct sta_table *);
+static int match_bss(struct ieee80211vap *, struct ieee80211_scan_entry *);
 
 /*
  * Attach prior to any scanning work.
@@ -178,7 +179,8 @@
 #define	ISPROBE(_st)	((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
 	struct sta_table *st = ss->ss_priv;
 	const u_int8_t *macaddr = wh->i_addr2;
-	struct ieee80211com *ic = ss->ss_vap->iv_ic;
+	struct ieee80211vap *vap = ss->ss_vap;
+	struct ieee80211com *ic = vap->iv_ic;
 	struct sta_entry *se;
 	struct ieee80211_scan_entry *ise;
 	int hash;
@@ -238,7 +240,17 @@
 	se->se_lastupdate = ticks;		/* update time */
 
 	mtx_unlock(&st->st_lock);
-
+#if 0
+	/*
+	 * If scanning for the first acceptable candidate,
+	 * check capabilities and verify the rssi is acceptable.
+	 */
+	if ((ss->ss_flags & IEEE80211_SCAN_PICK1ST) &&
+	    match_bss(vap, ise) == 0 &&
+	    RSSI_GET(se->se_avgrssi) >= RSSI_MINACCEPTABLE) {
+		/* arrange to terminate scan and associate */
+	}
+#endif
 	return 1;
 #undef ISPROBE
 }
@@ -253,9 +265,11 @@
 
 	if (vap->iv_opmode == IEEE80211_M_STA &&
 	    vap->iv_state == IEEE80211_S_RUN) {
-		/* initiate power save before going off-channel */
-		ieee80211_sta_pwrsave(vap, 1);
-		ss->ss_flags |= IEEE80211_SCAN_PWRSAV;
+		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;
 
@@ -447,14 +461,13 @@
 	/* XXX tunables */
 	ss->ss_mindwell = 20*hz/1000;			/* 20ms */
 	ss->ss_maxdwell = 200*hz/1000;			/* 200ms */
-	ss->ss_scanend = ticks+0x7fffffff;		/* scan ``forever'' */
 
 #ifdef IEEE80211_DEBUG
 	if (ieee80211_msg_scan(vap)) {
 		if_printf(&vap->iv_if, "scan set ");
 		ieee80211_scan_dump_channels(ss);
-		printf(" dwell min %ld max %ld scanend %ld\n",
-			ss->ss_mindwell, ss->ss_maxdwell, ss->ss_scanend);
+		printf(" dwell min %ld max %ld\n",
+			ss->ss_mindwell, ss->ss_maxdwell);
 	}
 #endif /* IEEE80211_DEBUG */
 

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

@@ -70,11 +70,18 @@
 #define	IEEE80211_BINTVAL_MIN	25	/* min beacon interval (TU's) */
 #define	IEEE80211_BINTVAL_DEFAULT 100	/* default beacon interval (TU's) */
 
+#define	IEEE80211_BGSCAN_INTVAL_MIN	30	/* min bg scan intvl (secs) */
+#define	IEEE80211_BGSCAN_INTVAL_DEFAULT	(5*60)	/* default bg scan intvl */
+
+#define	IEEE80211_BGSCAN_IDLE_MIN	500	/* min idle time (ms) */
+#define	IEEE80211_BGSCAN_IDLE_DEFAULT	(10*1000) /* default idle time (ms) */
+
 #define	IEEE80211_PS_SLEEP	0x1	/* STA is in power saving mode */
 #define	IEEE80211_PS_MAX_QUEUE	50	/* maximum saved packets */
 
 #define	IEEE80211_MS_TO_TU(x)	(((x) * 1000) / 1024)
 #define	IEEE80211_TU_TO_MS(x)	(((x) * 1024) / 1000)
+#define	IEEE80211_TU_TO_TICKS(x) ((IEEE80211_TU_TO_MS(x) * hz) / 1000)
 
 #define IEEE80211_PWRCONSTRAINT_VAL(ic) \
 	(((ic)->ic_bsschan->ic_maxregpower > (ic)->ic_curchanmaxpwr) ? \
@@ -151,6 +158,8 @@
 	/* scan-related 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 */
 
 	/* NB: this is the union of all vap stations/neighbors */
 	struct ieee80211_node_table ic_sta;	/* stations/neighbors */
@@ -248,6 +257,8 @@
 	u_int16_t		iv_des_mode;	/* desired mode */
 	int			iv_nicknamelen;	/* XXX junk */
 	u_int8_t		iv_nickname[IEEE80211_NWID_LEN];
+	u_int			iv_bgscanidle;	/* bg scan idle threshold */
+	u_int			iv_bgscanintvl;	/* bg scan min interval */
 
 	u_int32_t		*iv_aid_bitmap;	/* association id map */
 	u_int16_t		iv_max_aid;
@@ -305,6 +316,7 @@
 #define	IEEE80211_F_PMGTON	0x00000800	/* CONF: Power mgmt enable */
 #define	IEEE80211_F_DESBSSID	0x00001000	/* CONF: des_bssid is set */
 #define	IEEE80211_F_WME		0x00002000	/* CONF: enable WME use */
+#define	IEEE80211_F_BGSCAN	0x00004000	/* CONF: bg scan enabled */
 #define	IEEE80211_F_SWRETRY	0x00008000	/* CONF: sw tx retry enabled */
 #define IEEE80211_F_TXPOW_FIXED	0x00010000	/* TX Power: fixed rate */
 #define	IEEE80211_F_IBSSON	0x00020000	/* CONF: IBSS creation enable */
@@ -348,6 +360,7 @@
 #define	IEEE80211_C_BURST	0x02000000	/* CAPABILITY: frame bursting */
 #define	IEEE80211_C_WME		0x04000000	/* CAPABILITY: WME avail */
 #define	IEEE80211_C_WDS		0x08000000	/* CAPABILITY: 4-addr support */
+#define	IEEE80211_C_BGSCAN	0x10000000	/* CAPABILITY: bg scanning */
 /* XXX protection/barker? */
 
 #define	IEEE80211_C_CRYPTO	0x0000002f	/* CAPABILITY: crypto alg's */
@@ -355,7 +368,8 @@
 	(IEEE80211_C_CRYPTO | IEEE80211_C_FF | IEEE80211_C_TURBOP | \
 	 IEEE80211_C_PMGT | IEEE80211_C_SWRETRY | IEEE80211_C_TXPMGT | \
 	 IEEE80211_C_SHSLOT | IEEE80211_C_SHPREAMBLE | IEEE80211_C_TKIPMIC | \
-	 IEEE80211_C_WPA | IEEE80211_C_BURST | IEEE80211_C_WME)
+	 IEEE80211_C_WPA | IEEE80211_C_BURST | IEEE80211_C_WME | \
+	 IEEE80211_C_BGSCAN)
 
 /* check if a capability was negotiated for use */
 #define	IEEE80211_ATH_CAP(vap, ni, bit) \



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