Patchwork [2/7] Automatic Scanning support added

login
register
mail settings
Submitter Tomasz Bursztyka
Date April 20, 2012, 11:23 a.m.
Message ID <1334921008-6654-3-git-send-email-tomasz.bursztyka@linux.intel.com>
Download mbox | patch
Permalink /patch/154022/
State Superseded
Headers show

Comments

Tomasz Bursztyka - April 20, 2012, 11:23 a.m.
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/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                   |   28 ++++++-
 wpa_supplicant/wpa_supplicant.c         |   23 ++++++
 wpa_supplicant/wpa_supplicant_i.h       |    4 +
 8 files changed, 253 insertions(+), 3 deletions(-)
 create mode 100644 wpa_supplicant/autoscan.c
 create mode 100644 wpa_supplicant/autoscan.h

Patch

diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 22df8a0..6128282 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1284,6 +1284,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 b662fa4..8f4a5af 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -29,6 +29,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]: "
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 1c3b9eb..584f74e 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -41,6 +41,7 @@ 
 #include "gas_query.h"
 #include "p2p_supplicant.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "ap.h"
 #include "bss.h"
 #include "scan.h"
@@ -1086,6 +1087,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 afa3be4..512e4fb 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -425,6 +425,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;
 
@@ -490,6 +491,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)
@@ -610,7 +619,10 @@  static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 	}
 #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);
@@ -698,8 +710,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;
@@ -726,6 +739,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) {
@@ -741,7 +759,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 = 2;
+		if (wpa_s->sched_scan_interval == 0)
+			wpa_s->sched_scan_interval = 2;
 		wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
 		wpa_s->first_sched_scan = 1;
 		ssid = wpa_s->conf->ssid;
@@ -789,6 +808,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:
 	wpa_dbg(wpa_s, MSG_DEBUG,
 		"Starting sched scan: interval %d timeout %d",
 		wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index cddc694..c85c108 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -48,6 +48,7 @@ 
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
+#include "autoscan.h"
 #include "bss.h"
 #include "scan.h"
 #include "offchannel.h"
@@ -389,6 +390,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);
@@ -592,6 +594,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
@@ -649,6 +666,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 9698c68..cb84bb6 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -484,6 +484,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;