[PATCH 1/2] driver: Add support for multiple scan plans for scheduled scan

Ilan Peer ilan.peer at intel.com
Tue Nov 17 05:08:23 PST 2015


From: Avraham Stern <avraham.stern at intel.com>

Add 'scan plans' to driver scan parameters for scheduled scan.
Each 'scan plan' specifies the number of iterations to run the scan
request and the interval between iterations. When a scan plan
finishes (i.e., it was run for the specified number of iterations),
the next scan plan is executed. The last scan plan will run
infinitely.

The maximum number of supported scan plans, the maximum number of
iterations for a single scan plan and the maximum scan interval
are advertised by the driver.

Signed-off-by: Avraham Stern <avraham.stern at intel.com>
---
 src/drivers/driver.h              | 35 +++++++++++++--
 src/drivers/driver_nl80211.c      | 10 ++++-
 src/drivers/driver_nl80211.h      |  3 +-
 src/drivers/driver_nl80211_capa.c | 19 ++++++++
 src/drivers/driver_nl80211_scan.c | 94 ++++++++++++++++++++++++++++++++++++---
 wpa_supplicant/driver_i.h         |  6 +--
 wpa_supplicant/scan.c             | 25 ++++++++++-
 7 files changed, 173 insertions(+), 19 deletions(-)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 09c4fa1..252a9fc 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -407,6 +407,28 @@ struct wpa_driver_scan_params {
 	 */
 	const u8 *mac_addr_mask;
 
+	/**
+	 * sched_scan_plans - scan plans for scheduled scan
+	 *
+	 * Each scan plan consists of the number of iterations to scan and the
+	 * interval between scans. When a scan plan finishes (i.e., it was run
+	 * for the specified number of iterations), the next scan plan is
+	 * executed. The scan plans are executed in the order they appear in
+	 * the array (lower index first). The last scan plan will run infinitely
+	 * (until requested to stop), thus must not specify the number of
+	 * iterations. All other scan plans must specify the number of
+	 * iterations.
+	 */
+	struct sched_scan_plan {
+		 u32 interval; /* in seconds */
+		 u32 iterations; /* Zero to run infinitely */
+	 } *sched_scan_plans;
+
+	/**
+	 * sched_scan_plans_num - number of scan plans in sched_scan_plans array
+	 */
+	 size_t sched_scan_plans_num;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -1233,6 +1255,15 @@ struct wpa_driver_capa {
 	/** Maximum number of supported active probe SSIDs for sched_scan */
 	int max_sched_scan_ssids;
 
+	/** Maximum number of supported scan plans for scheduled scan */
+	size_t max_sched_scan_plans;
+
+	/** Maximum interval in a scan plan. In seconds */
+	u32 max_sched_scan_plan_interval;
+
+	/** Maximum number of iterations in a single scan plan */
+	u32 max_sched_scan_plan_iterations;
+
 	/** Whether sched_scan (offloaded scanning) is supported */
 	int sched_scan_supported;
 
@@ -2994,7 +3025,6 @@ struct wpa_driver_ops {
 	 * sched_scan - Request the driver to initiate scheduled scan
 	 * @priv: Private driver interface data
 	 * @params: Scan parameters
-	 * @interval: Interval between scan cycles in milliseconds
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This operation should be used for scheduled scan offload to
@@ -3005,8 +3035,7 @@ struct wpa_driver_ops {
 	 * and if not provided or if it returns -1, we fall back to
 	 * normal host-scheduled scans.
 	 */
-	int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
-			  u32 interval);
+	int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params);
 
 	/**
 	 * stop_sched_scan - Request the driver to stop a scheduled scan
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e83a3df..5dbc80c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -7540,7 +7540,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
 				  "capa.mac_addr_rand_scan_supported=%d\n"
 				  "capa.conc_capab=%u\n"
 				  "capa.max_conc_chan_2_4=%u\n"
-				  "capa.max_conc_chan_5_0=%u\n",
+				  "capa.max_conc_chan_5_0=%u\n"
+				  "capa.max_sched_scan_plans=%zu\n"
+				  "capa.max_sched_scan_plan_interval=%u\n"
+				  "capa.max_sched_scan_plan_iterations=%u\n",
 				  drv->capa.key_mgmt,
 				  drv->capa.enc,
 				  drv->capa.auth,
@@ -7559,7 +7562,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
 				  drv->capa.mac_addr_rand_scan_supported,
 				  drv->capa.conc_capab,
 				  drv->capa.max_conc_chan_2_4,
-				  drv->capa.max_conc_chan_5_0);
+				  drv->capa.max_conc_chan_5_0,
+				  drv->capa.max_sched_scan_plans,
+				  drv->capa.max_sched_scan_plan_interval,
+				  drv->capa.max_sched_scan_plan_iterations);
 		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index ea5f058..a7e11a8 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -276,8 +276,7 @@ void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
 int wpa_driver_nl80211_scan(struct i802_bss *bss,
 			    struct wpa_driver_scan_params *params);
 int wpa_driver_nl80211_sched_scan(void *priv,
-				  struct wpa_driver_scan_params *params,
-				  u32 interval);
+				  struct wpa_driver_scan_params *params);
 int wpa_driver_nl80211_stop_sched_scan(void *priv);
 struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
 void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 59a8efb..a576d6c 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -499,6 +499,19 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
 		capa->max_sched_scan_ssids =
 			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
 
+	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS] &&
+	    tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL] &&
+	    tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]) {
+		capa->max_sched_scan_plans =
+			nla_get_u32(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_PLANS]);
+
+		capa->max_sched_scan_plan_interval =
+			nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_INTERVAL]);
+
+		capa->max_sched_scan_plan_iterations =
+			nla_get_u32(tb[NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS]);
+	}
+
 	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
 		capa->max_match_sets =
 			nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
@@ -711,6 +724,12 @@ static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
 			drv->capa.max_csa_counters = 1;
 	}
 
+	if (!drv->capa.max_sched_scan_plans) {
+		drv->capa.max_sched_scan_plans = 1;
+		drv->capa.max_sched_scan_plan_interval = UINT32_MAX;
+		drv->capa.max_sched_scan_plan_iterations = 0;
+	}
+
 	return 0;
 }
 
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index dd1993c..9994a08 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -1,5 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright(c) 2015 Intel Deutschland GmbH
  * Copyright (c) 2002-2014, Jouni Malinen <j at w1.fi>
  * Copyright (c) 2007, Johannes Berg <johannes at sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
@@ -307,17 +308,81 @@ fail:
 	return ret;
 }
 
+static int
+nl80211_sched_scan_add_scan_plans(struct wpa_driver_nl80211_data *drv,
+				  struct nl_msg *msg,
+				  struct wpa_driver_scan_params *params)
+{
+	struct nlattr *plans;
+	struct sched_scan_plan *scan_plans = params->sched_scan_plans;
+	size_t i;
+
+	plans = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_PLANS);
+	if (!plans)
+		return -1;
+
+	for (i = 0; i < params->sched_scan_plans_num; i++) {
+		struct nlattr *plan = nla_nest_start(msg, i + 1);
+
+		if (!plan)
+			return -1;
+
+		if (!scan_plans[i].interval ||
+		    scan_plans[i].interval >
+		    drv->capa.max_sched_scan_plan_interval) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: scan plan no. %zu: Invalid interval: %u",
+				   i, scan_plans[i].interval);
+			return -1;
+		}
+
+		if (nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_INTERVAL,
+				scan_plans[i].interval))
+			return -1;
+
+		if (scan_plans[i].iterations >
+		    drv->capa.max_sched_scan_plan_iterations) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: scan plan no. %zu: Invalid number of iterations: %u",
+				   i, scan_plans[i].iterations);
+			return -1;
+		}
+
+		if (scan_plans[i].iterations &&
+		    nla_put_u32(msg, NL80211_SCHED_SCAN_PLAN_ITERATIONS,
+				scan_plans[i].iterations))
+			return -1;
+
+		nla_nest_end(msg, plan);
+
+		/*
+		 * All the scan plans must specify the number of iterations
+		 * except the last plan, which will run infinitely. So if the
+		 * number of iterations is not specified, this ought to be the
+		 * last scan plan.
+		 */
+		if (!scan_plans[i].iterations)
+			break;
+	}
+
+	if (i != params->sched_scan_plans_num - 1) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: All scan plans but the last must specify number of iterations");
+		return -1;
+	}
+
+	nla_nest_end(msg, plans);
+	return 0;
+}
 
 /**
  * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
  * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
  * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
  * Returns: 0 on success, -1 on failure or if not supported
  */
 int wpa_driver_nl80211_sched_scan(void *priv,
-				  struct wpa_driver_scan_params *params,
-				  u32 interval)
+				  struct wpa_driver_scan_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -332,11 +397,27 @@ int wpa_driver_nl80211_sched_scan(void *priv,
 		return android_pno_start(bss, params);
 #endif /* ANDROID */
 
+	if (!params->sched_scan_plans_num ||
+	    params->sched_scan_plans_num > drv->capa.max_sched_scan_plans) {
+		wpa_printf(MSG_ERROR,
+			   "nl80211: Invalid number of scan plans: %zu",
+			   params->sched_scan_plans_num);
+		return -1;
+	}
+
 	msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
-	if (!msg ||
-	    nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+	if (!msg)
 		goto fail;
 
+	if (drv->capa.max_sched_scan_plan_iterations) {
+		if (nl80211_sched_scan_add_scan_plans(drv, msg, params))
+			goto fail;
+	} else {
+		if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL,
+				params->sched_scan_plans[0].interval * 1000))
+			goto fail;
+	}
+
 	if ((drv->num_filter_ssids &&
 	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
 	    params->filter_rssi) {
@@ -399,8 +480,7 @@ int wpa_driver_nl80211_sched_scan(void *priv,
 		goto fail;
 	}
 
-	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
-		   "scan interval %d msec", ret, interval);
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - ", ret);
 
 fail:
 	nlmsg_free(msg);
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index f325154..6599623 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -100,12 +100,10 @@ static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
 }
 
 static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
-				     struct wpa_driver_scan_params *params,
-				     u32 interval)
+				     struct wpa_driver_scan_params *params)
 {
 	if (wpa_s->driver->sched_scan)
-		return wpa_s->driver->sched_scan(wpa_s->drv_priv,
-						 params, interval);
+		return wpa_s->driver->sched_scan(wpa_s->drv_priv, params);
 	return -1;
 }
 
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 076766e..9f908e2 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -271,14 +271,23 @@ int wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
 				    int interval)
 {
 	int ret;
+	struct sched_scan_plan scan_plan = {
+		.interval = interval,
+		.iterations = 0,
+	};
+
+	params->sched_scan_plans = &scan_plan;
+	params->sched_scan_plans_num = 1;
 
 	wpa_supplicant_notify_scanning(wpa_s, 1);
-	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+	ret = wpa_drv_sched_scan(wpa_s, params);
 	if (ret)
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 	else
 		wpa_s->sched_scanning = 1;
 
+	params->sched_scan_plans = NULL;
+	params->sched_scan_plans_num = 0;
 	return ret;
 }
 
@@ -2217,6 +2226,19 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
 	params->only_new_results = src->only_new_results;
 	params->low_priority = src->low_priority;
 
+	if (src->sched_scan_plans_num > 0) {
+		params->sched_scan_plans =
+			os_malloc(sizeof(*src->sched_scan_plans) *
+				  src->sched_scan_plans_num);
+		if (!params->sched_scan_plans)
+			goto failed;
+
+		os_memcpy(params->sched_scan_plans, src->sched_scan_plans,
+			  sizeof(*src->sched_scan_plans) *
+			  src->sched_scan_plans_num);
+		params->sched_scan_plans_num = src->sched_scan_plans_num;
+	}
+
 	if (src->mac_addr_rand) {
 		params->mac_addr_rand = src->mac_addr_rand;
 
@@ -2254,6 +2276,7 @@ void wpa_scan_free_params(struct wpa_driver_scan_params *params)
 	os_free((u8 *) params->extra_ies);
 	os_free(params->freqs);
 	os_free(params->filter_ssids);
+	os_free(params->sched_scan_plans);
 
 	/*
 	 * Note: params->mac_addr_mask points to same memory allocation and
-- 
1.9.1




More information about the Hostap mailing list