Add automatic scanning support

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>
This commit is contained in:
Tomasz Bursztyka 2012-06-26 18:55:41 +03:00 committed by Jouni Malinen
parent b0786fba71
commit 7c865c6853
10 changed files with 252 additions and 4 deletions

View file

@ -1304,6 +1304,11 @@ L_CFLAGS += -DCONFIG_BGSCAN
OBJS += bgscan.c OBJS += bgscan.c
endif endif
ifdef NEED_AUTOSCAN
L_CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.c
endif
ifdef NEED_GAS ifdef NEED_GAS
OBJS += ../src/common/gas.c OBJS += ../src/common/gas.c
OBJS += gas_query.c OBJS += gas_query.c

View file

@ -1321,6 +1321,11 @@ CFLAGS += -DCONFIG_BGSCAN
OBJS += bgscan.o OBJS += bgscan.o
endif endif
ifdef NEED_AUTOSCAN
CFLAGS += -DCONFIG_AUTOSCAN
OBJS += autoscan.o
endif
ifdef NEED_GAS ifdef NEED_GAS
OBJS += ../src/common/gas.o OBJS += ../src/common/gas.o
OBJS += gas_query.o OBJS += gas_query.o

127
wpa_supplicant/autoscan.c Normal file
View file

@ -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;
}

49
wpa_supplicant/autoscan.h Normal file
View file

@ -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 */

View file

@ -28,6 +28,7 @@
#include "../bss.h" #include "../bss.h"
#include "../scan.h" #include "../scan.h"
#include "../ctrl_iface.h" #include "../ctrl_iface.h"
#include "../autoscan.h"
#include "dbus_new_helpers.h" #include "dbus_new_helpers.h"
#include "dbus_new.h" #include "dbus_new.h"
#include "dbus_new_handlers.h" #include "dbus_new_handlers.h"
@ -1287,6 +1288,9 @@ DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
/* Add wildcard ssid */ /* Add wildcard ssid */
params.num_ssids++; params.num_ssids++;
} }
#ifdef CONFIG_AUTOSCAN
autoscan_deinit(wpa_s);
#endif /* CONFIG_AUTOSCAN */
wpa_supplicant_trigger_scan(wpa_s, &params); wpa_supplicant_trigger_scan(wpa_s, &params);
} else { } else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: " wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "

View file

@ -500,3 +500,8 @@ CONFIG_PEERKEY=y
# This can be used to enable P2P support in wpa_supplicant. See README-P2P for # This can be used to enable P2P support in wpa_supplicant. See README-P2P for
# more information on P2P operations. # more information on P2P operations.
#CONFIG_P2P=y #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

View file

@ -35,6 +35,7 @@
#include "gas_query.h" #include "gas_query.h"
#include "p2p_supplicant.h" #include "p2p_supplicant.h"
#include "bgscan.h" #include "bgscan.h"
#include "autoscan.h"
#include "ap.h" #include "ap.h"
#include "bss.h" #include "bss.h"
#include "scan.h" #include "scan.h"
@ -1095,6 +1096,11 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
return 0; return 0;
} }
if (autoscan_notify_scan(wpa_s, scan_res)) {
wpa_scan_results_free(scan_res);
return 0;
}
if (wpa_s->disconnected) { if (wpa_s->disconnected) {
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED); wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
wpa_scan_results_free(scan_res); wpa_scan_results_free(scan_res);

View file

@ -434,6 +434,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
int scan_req = 0, ret; int scan_req = 0, ret;
struct wpabuf *extra_ie; struct wpabuf *extra_ie;
struct wpa_driver_scan_params params; struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
size_t max_ssids; size_t max_ssids;
enum wpa_states prev_state; 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_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 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) { if (scan_req != 2 && wpa_s->connect_without_scan) {
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) { for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
if (ssid == wpa_s->connect_without_scan) if (ssid == wpa_s->connect_without_scan)
@ -659,7 +668,10 @@ ssid_list_set:
} }
#endif /* CONFIG_P2P */ #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); wpabuf_free(extra_ie);
os_free(params.freqs); 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) int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
{ {
struct wpa_driver_scan_params params; struct wpa_driver_scan_params params;
struct wpa_driver_scan_params *scan_params;
enum wpa_states prev_state; enum wpa_states prev_state;
struct wpa_ssid *ssid; struct wpa_ssid *ssid = NULL;
struct wpabuf *wps_ie = NULL; struct wpabuf *wps_ie = NULL;
int ret; int ret;
unsigned int max_sched_scan_ssids; 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_s->wpa_state == WPA_INACTIVE)
wpa_supplicant_set_state(wpa_s, WPA_SCANNING); 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 */ /* Find the starting point from which to continue scanning */
ssid = wpa_s->conf->ssid; ssid = wpa_s->conf->ssid;
if (wpa_s->prev_sched_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) { if (!ssid || !wpa_s->prev_sched_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list"); 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->sched_scan_timeout = max_sched_scan_ssids * 2;
wpa_s->first_sched_scan = 1; wpa_s->first_sched_scan = 1;
ssid = wpa_s->conf->ssid; ssid = wpa_s->conf->ssid;
@ -909,6 +928,9 @@ int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
if (wpa_s->wps) if (wpa_s->wps)
wps_ie = wpa_supplicant_extra_ies(wpa_s, &params); wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
scan_params = &params;
scan:
if (ssid || !wpa_s->first_sched_scan) { if (ssid || !wpa_s->first_sched_scan) {
wpa_dbg(wpa_s, MSG_DEBUG, wpa_dbg(wpa_s, MSG_DEBUG,
"Starting sched scan: interval %d timeout %d", "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); 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); wpa_s->sched_scan_interval);
wpabuf_free(wps_ie); wpabuf_free(wps_ie);
os_free(params.filter_ssids); os_free(params.filter_ssids);

View file

@ -42,6 +42,7 @@
#include "p2p_supplicant.h" #include "p2p_supplicant.h"
#include "notify.h" #include "notify.h"
#include "bgscan.h" #include "bgscan.h"
#include "autoscan.h"
#include "bss.h" #include "bss.h"
#include "scan.h" #include "scan.h"
#include "offchannel.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) static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{ {
bgscan_deinit(wpa_s); bgscan_deinit(wpa_s);
autoscan_deinit(wpa_s);
scard_deinit(wpa_s->scard); scard_deinit(wpa_s->scard);
wpa_s->scard = NULL; wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, 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 */ #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_supplicant_set_state - Set current connection state
* @wpa_s: Pointer to wpa_supplicant data * @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); wpa_supplicant_stop_bgscan(wpa_s);
#endif /* CONFIG_BGSCAN */ #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) { if (wpa_s->wpa_state != old_state) {
wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state); wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);

View file

@ -538,6 +538,10 @@ struct wpa_supplicant {
const struct bgscan_ops *bgscan; const struct bgscan_ops *bgscan;
void *bgscan_priv; void *bgscan_priv;
const struct autoscan_ops *autoscan;
struct wpa_driver_scan_params *autoscan_params;
void *autoscan_priv;
struct wpa_ssid *connect_without_scan; struct wpa_ssid *connect_without_scan;
int after_wps; int after_wps;