Add automatic scanning support
authorTomasz Bursztyka <tomasz.bursztyka@linux.intel.com>
Tue, 26 Jun 2012 15:55:41 +0000 (18:55 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 26 Jun 2012 15:55:41 +0000 (18:55 +0300)
Like bgscan, autoscan is an optional module based feature to automate
scanning but while disconnected or inactive.

Instead of requesting directly a scan, it only sets the scan_interval
and the sched_scan_interval. So, if the driver supports sched_scan,
autoscan will be able to tweak its interval. Otherwise, the tweaked
scan_interval will be used. If scan parameters needs to be tweaked, an
autoscan_params pointer in wpa_s will provide those. So req_scan /
req_sched_scan will not set the scan parameters as they usually do, but
instead will use this pointer.

Modules will not have to request a scan directly, like bgscan does.
Instead, it will need to return the interval it wants after each
notification.

Signed-hostap: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>

wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/autoscan.c [new file with mode: 0644]
wpa_supplicant/autoscan.h [new file with mode: 0644]
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/defconfig
wpa_supplicant/events.c
wpa_supplicant/scan.c
wpa_supplicant/wpa_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index e611d36..995089a 100644 (file)
@@ -1304,6 +1304,11 @@ L_CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.c
 endif
 
+ifdef NEED_AUTOSCAN
+L_CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.c
+endif
+
 ifdef NEED_GAS
 OBJS += ../src/common/gas.c
 OBJS += gas_query.c
index ab2dc85..d06a15b 100644 (file)
@@ -1321,6 +1321,11 @@ CFLAGS += -DCONFIG_BGSCAN
 OBJS += bgscan.o
 endif
 
+ifdef NEED_AUTOSCAN
+CFLAGS += -DCONFIG_AUTOSCAN
+OBJS += autoscan.o
+endif
+
 ifdef NEED_GAS
 OBJS += ../src/common/gas.o
 OBJS += gas_query.o
diff --git a/wpa_supplicant/autoscan.c b/wpa_supplicant/autoscan.c
new file mode 100644 (file)
index 0000000..2d4249c
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "scan.h"
+#include "autoscan.h"
+
+static const struct autoscan_ops * autoscan_modules[] = {
+       NULL
+};
+
+
+static void request_scan(struct wpa_supplicant *wpa_s)
+{
+       wpa_s->scan_req = 2;
+
+       if (wpa_supplicant_req_sched_scan(wpa_s))
+               wpa_supplicant_req_scan(wpa_s, wpa_s->scan_interval, 0);
+}
+
+
+int autoscan_init(struct wpa_supplicant *wpa_s)
+{
+       const char *name = wpa_s->conf->autoscan;
+       const char *params;
+       size_t nlen;
+       int i;
+       const struct autoscan_ops *ops = NULL;
+
+       if (wpa_s->autoscan && wpa_s->autoscan_priv)
+               return 0;
+
+       if (name == NULL)
+               return 0;
+
+       params = os_strchr(name, ':');
+       if (params == NULL) {
+               params = "";
+               nlen = os_strlen(name);
+       } else {
+               nlen = params - name;
+               params++;
+       }
+
+       for (i = 0; autoscan_modules[i]; i++) {
+               if (os_strncmp(name, autoscan_modules[i]->name, nlen) == 0) {
+                       ops = autoscan_modules[i];
+                       break;
+               }
+       }
+
+       if (ops == NULL) {
+               wpa_printf(MSG_ERROR, "autoscan: Could not find module "
+                          "matching the parameter '%s'", name);
+               return -1;
+       }
+
+       wpa_s->autoscan_params = NULL;
+
+       wpa_s->autoscan_priv = ops->init(wpa_s, params);
+       if (wpa_s->autoscan_priv == NULL)
+               return -1;
+       wpa_s->autoscan = ops;
+
+       wpa_printf(MSG_DEBUG, "autoscan: Initialized module '%s' with "
+                  "parameters '%s'", ops->name, params);
+
+       /*
+        * Cancelling existing scan requests, if any.
+        */
+       wpa_supplicant_cancel_sched_scan(wpa_s);
+       wpa_supplicant_cancel_scan(wpa_s);
+
+       /*
+        * Firing first scan, which will lead to call autoscan_notify_scan.
+        */
+       request_scan(wpa_s);
+
+       return 0;
+}
+
+
+void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+       if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+               wpa_printf(MSG_DEBUG, "autoscan: Deinitializing module '%s'",
+                          wpa_s->autoscan->name);
+               wpa_s->autoscan->deinit(wpa_s->autoscan_priv);
+               wpa_s->autoscan = NULL;
+               wpa_s->autoscan_priv = NULL;
+
+               wpa_s->scan_interval = 5;
+               wpa_s->sched_scan_interval = 0;
+       }
+}
+
+
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+                        struct wpa_scan_results *scan_res)
+{
+       int interval;
+
+       if (wpa_s->autoscan && wpa_s->autoscan_priv) {
+               interval = wpa_s->autoscan->notify_scan(wpa_s->autoscan_priv,
+                                                       scan_res);
+
+               if (interval <= 0)
+                       return -1;
+
+               wpa_s->scan_interval = interval;
+               wpa_s->sched_scan_interval = interval;
+
+               request_scan(wpa_s);
+       }
+
+       return 0;
+}
diff --git a/wpa_supplicant/autoscan.h b/wpa_supplicant/autoscan.h
new file mode 100644 (file)
index 0000000..e2fde8e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+       const char *name;
+
+       void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+       void (*deinit)(void *priv);
+
+       int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+                        struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s)
+{
+       return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+                                      struct wpa_scan_results *scan_res)
+{
+       return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */
index 3a5bcab..1c7592d 100644 (file)
@@ -28,6 +28,7 @@
 #include "../bss.h"
 #include "../scan.h"
 #include "../ctrl_iface.h"
+#include "../autoscan.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -1287,6 +1288,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
                        /* Add wildcard ssid */
                        params.num_ssids++;
                }
+#ifdef CONFIG_AUTOSCAN
+               autoscan_deinit(wpa_s);
+#endif /* CONFIG_AUTOSCAN */
                wpa_supplicant_trigger_scan(wpa_s, &params);
        } else {
                wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
index b7a7c8c..d7b679e 100644 (file)
@@ -500,3 +500,8 @@ CONFIG_PEERKEY=y
 # This can be used to enable P2P support in wpa_supplicant. See README-P2P for
 # more information on P2P operations.
 #CONFIG_P2P=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#CONFIG_AUTOSCAN=y
index 19c8280..513a8e8 100644 (file)
@@ -35,6 +35,7 @@
 #include "gas_query.h"
 #include "p2p_supplicant.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "ap.h"
 #include "bss.h"
 #include "scan.h"
@@ -1095,6 +1096,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
                return 0;
        }
 
+       if (autoscan_notify_scan(wpa_s, scan_res)) {
+               wpa_scan_results_free(scan_res);
+               return 0;
+       }
+
        if (wpa_s->disconnected) {
                wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
                wpa_scan_results_free(scan_res);
index e66eed1..477db11 100644 (file)
@@ -434,6 +434,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
        int scan_req = 0, ret;
        struct wpabuf *extra_ie;
        struct wpa_driver_scan_params params;
+       struct wpa_driver_scan_params *scan_params;
        size_t max_ssids;
        enum wpa_states prev_state;
 
@@ -499,6 +500,14 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
            wpa_s->wpa_state == WPA_INACTIVE)
                wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 
+       /*
+        * If autoscan has set its own scanning parameters
+        */
+       if (wpa_s->autoscan_params != NULL) {
+               scan_params = wpa_s->autoscan_params;
+               goto scan;
+       }
+
        if (scan_req != 2 && wpa_s->connect_without_scan) {
                for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
                        if (ssid == wpa_s->connect_without_scan)
@@ -659,7 +668,10 @@ ssid_list_set:
        }
 #endif /* CONFIG_P2P */
 
-       ret = wpa_supplicant_trigger_scan(wpa_s, &params);
+       scan_params = &params;
+
+scan:
+       ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
 
        wpabuf_free(extra_ie);
        os_free(params.freqs);
@@ -748,8 +760,9 @@ int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
 int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
 {
        struct wpa_driver_scan_params params;
+       struct wpa_driver_scan_params *scan_params;
        enum wpa_states prev_state;
-       struct wpa_ssid *ssid;
+       struct wpa_ssid *ssid = NULL;
        struct wpabuf *wps_ie = NULL;
        int ret;
        unsigned int max_sched_scan_ssids;
@@ -825,6 +838,11 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
            wpa_s->wpa_state == WPA_INACTIVE)
                wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
 
+       if (wpa_s->autoscan_params != NULL) {
+               scan_params = wpa_s->autoscan_params;
+               goto scan;
+       }
+
        /* Find the starting point from which to continue scanning */
        ssid = wpa_s->conf->ssid;
        if (wpa_s->prev_sched_ssid) {
@@ -840,7 +858,8 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        if (!ssid || !wpa_s->prev_sched_ssid) {
                wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
 
-               wpa_s->sched_scan_interval = 10;
+               if (wpa_s->sched_scan_interval == 0)
+                       wpa_s->sched_scan_interval = 10;
                wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
                wpa_s->first_sched_scan = 1;
                ssid = wpa_s->conf->ssid;
@@ -909,6 +928,9 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
        if (wpa_s->wps)
                wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
 
+       scan_params = &params;
+
+scan:
        if (ssid || !wpa_s->first_sched_scan) {
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "Starting sched scan: interval %d timeout %d",
@@ -919,7 +941,7 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
                        wpa_s->sched_scan_interval);
        }
 
-       ret = wpa_supplicant_start_sched_scan(wpa_s, &params,
+       ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
                                              wpa_s->sched_scan_interval);
        wpabuf_free(wps_ie);
        os_free(params.filter_ssids);
index fa14239..a043208 100644 (file)
@@ -42,6 +42,7 @@
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "bss.h"
 #include "scan.h"
 #include "offchannel.h"
@@ -368,6 +369,7 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
        bgscan_deinit(wpa_s);
+       autoscan_deinit(wpa_s);
        scard_deinit(wpa_s->scard);
        wpa_s->scard = NULL;
        wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
@@ -570,6 +572,19 @@ static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
 #endif /* CONFIG_BGSCAN */
 
 
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+       if (autoscan_init(wpa_s))
+               wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+       autoscan_deinit(wpa_s);
+}
+
+
 /**
  * wpa_supplicant_set_state - Set current connection state
  * @wpa_s: Pointer to wpa_supplicant data
@@ -630,6 +645,12 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
                wpa_supplicant_stop_bgscan(wpa_s);
 #endif /* CONFIG_BGSCAN */
 
+       if (state == WPA_AUTHENTICATING)
+               wpa_supplicant_stop_autoscan(wpa_s);
+
+       if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+               wpa_supplicant_start_autoscan(wpa_s);
+
        if (wpa_s->wpa_state != old_state) {
                wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
index 8121501..cce897e 100644 (file)
@@ -538,6 +538,10 @@ struct wpa_supplicant {
        const struct bgscan_ops *bgscan;
        void *bgscan_priv;
 
+       const struct autoscan_ops *autoscan;
+       struct wpa_driver_scan_params *autoscan_params;
+       void *autoscan_priv;
+
        struct wpa_ssid *connect_without_scan;
 
        int after_wps;