[PATCH 2/7] Automatic Scanning support added
Tomasz Bursztyka
tomasz.bursztyka
Thu May 3 06:16:51 PDT 2012
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 at linux.intel.com>
---
wpa_supplicant/Makefile | 5 +
wpa_supplicant/autoscan.c | 132 +++++++++++++++++++++++++++++++
wpa_supplicant/autoscan.h | 54 +++++++++++++
wpa_supplicant/dbus/dbus_new_handlers.c | 4 +
wpa_supplicant/events.c | 6 ++
wpa_supplicant/scan.c | 30 ++++++-
wpa_supplicant/wpa_supplicant.c | 23 ++++++
wpa_supplicant/wpa_supplicant_i.h | 4 +
8 files changed, 254 insertions(+), 4 deletions(-)
create mode 100644 wpa_supplicant/autoscan.c
create mode 100644 wpa_supplicant/autoscan.h
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index b3a9d55..d281ddb 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1311,6 +1311,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
index 0000000..a586f41
--- /dev/null
+++ b/wpa_supplicant/autoscan.c
@@ -0,0 +1,132 @@
+/*
+ * WPA Supplicant - auto scan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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
index 0000000..4efb869
--- /dev/null
+++ b/wpa_supplicant/autoscan.h
@@ -0,0 +1,54 @@
+/*
+ * WPA Supplicant - auto scan
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING 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 */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 3a5bcab..1c7592d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -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, ¶ms);
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index da9cf2b..e1b36ff 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -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"
@@ -1082,6 +1083,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);
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 4fd129a..3273996 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -433,6 +433,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;
@@ -498,6 +499,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)
@@ -652,7 +661,10 @@ ssid_list_set:
}
#endif /* CONFIG_P2P */
- ret = wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+ scan_params = ¶ms;
+
+scan:
+ ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.freqs);
@@ -740,8 +752,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;
@@ -815,6 +828,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) {
@@ -830,7 +848,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;
@@ -898,6 +917,9 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (wpa_s->wps)
wps_ie = wpa_supplicant_extra_ies(wpa_s, ¶ms);
+ scan_params = ¶ms;
+
+scan:
if (ssid || !wpa_s->first_sched_scan) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Starting sched scan: interval %d timeout %d",
@@ -908,7 +930,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, ¶ms,
+ ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
wpa_s->sched_scan_interval);
wpabuf_free(wps_ie);
os_free(params.filter_ssids);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 8c8de26..34dc975 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -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"
@@ -367,6 +368,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);
@@ -567,6 +569,21 @@ 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
@@ -624,6 +641,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);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 2795004..48375de 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -525,6 +525,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;
--
1.7.8.5
More information about the Hostap
mailing list