]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Add support for multiple scan plans for scheduled scan
authorAvraham Stern <avraham.stern@intel.com>
Tue, 17 Nov 2015 13:08:23 +0000 (15:08 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 30 Nov 2015 12:03:28 +0000 (14:03 +0200)
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@intel.com>
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_capa.c
src/drivers/driver_nl80211_scan.c
wpa_supplicant/driver_i.h
wpa_supplicant/scan.c

index 403dfa3c5c5d31649fee52ba713b63e43b20be0d..6fd72c5aa61e5dd83c7bd04f1582db6abe25896d 100644 (file)
@@ -416,6 +416,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
+        */
+        unsigned int 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
@@ -1242,6 +1264,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 */
+       unsigned int 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;
 
@@ -3004,7 +3035,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
@@ -3015,8 +3045,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
index bcb09217b1499e6cd3d193a011c3e3e6e60d2a0f..0fa2c7ea8a6a7c05363ea85b73eaf9f96b0a17ae 100644 (file)
@@ -7545,7 +7545,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=%u\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,
@@ -7564,7 +7567,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;
index ed03ac4e9db4ee3e9c8e234ce780d52d9de649a0..f042c3c9fe9203258ad085c1dd24e49f332c1fc1 100644 (file)
@@ -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);
index 1b5752fbba58ffa8b239915716cfced3baa7bc25..c74ed5ff7f5206c13a60f74f273f1a1b0577b383 100644 (file)
@@ -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;
 }
 
index ec2eb2835012d389e8ba7395cb11877fbf65f7ac..2ff254e43ec1db5c666d477169c941f1ffb76c26 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright(c) 2015 Intel Deutschland GmbH
  * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
  * Copyright (c) 2009-2010, Atheros Communications
@@ -308,16 +309,82 @@ fail:
 }
 
 
+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;
+       unsigned int 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: sched scan plan no. %u: 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: sched scan plan no. %u: 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 sched 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 +399,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 sched scan plans: %u",
+                          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 +482,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);
index b9d213a986e2425adcf8afe1fbeca8faac2d73ba..699fd4f766e108a51e31719eadb07f13c41b3706 100644 (file)
@@ -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;
 }
 
index a39922fd5fe05420cfc9cc4d0e0948d9e71f1277..25a1011b32873006defd21ac26b2519393893ba1 100644 (file)
@@ -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