aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--wpa_supplicant/Makefile11
-rw-r--r--wpa_supplicant/bgscan.c110
-rw-r--r--wpa_supplicant/bgscan.h68
-rw-r--r--wpa_supplicant/bgscan_simple.c130
-rw-r--r--wpa_supplicant/config.c4
-rw-r--r--wpa_supplicant/config_ssid.h9
-rw-r--r--wpa_supplicant/events.c24
-rw-r--r--wpa_supplicant/scan.c43
-rw-r--r--wpa_supplicant/wpa_supplicant.c2
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h7
10 files changed, 393 insertions, 15 deletions
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 74b2689..354f917 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1037,6 +1037,17 @@ OBJS_p += ../src/crypto/aes-internal-dec.o
OBJS_p += ../src/crypto/aes-internal-enc.o
endif
+ifdef CONFIG_BGSCAN_SIMPLE
+CFLAGS += -DCONFIG_BGSCAN_SIMPLE
+OBJS += bgscan_simple.o
+NEED_BGSCAN=y
+endif
+
+ifdef NEED_BGSCAN
+CFLAGS += -DCONFIG_BGSCAN
+OBJS += bgscan.o
+endif
+
OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
ifdef CONFIG_AUTHENTICATOR
diff --git a/wpa_supplicant/bgscan.c b/wpa_supplicant/bgscan.c
new file mode 100644
index 0000000..60dcd0d
--- /dev/null
+++ b/wpa_supplicant/bgscan.c
@@ -0,0 +1,110 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "wpa_supplicant_i.h"
+#include "config_ssid.h"
+#include "bgscan.h"
+
+#ifdef CONFIG_BGSCAN_SIMPLE
+extern const struct bgscan_ops bgscan_simple_ops;
+#endif /* CONFIG_BGSCAN_SIMPLE */
+
+static const struct bgscan_ops * bgscan_modules[] = {
+#ifdef CONFIG_BGSCAN_SIMPLE
+ &bgscan_simple_ops,
+#endif /* CONFIG_BGSCAN_SIMPLE */
+ NULL
+};
+
+
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+ const char *name = ssid->bgscan;
+ const char *params;
+ size_t nlen;
+ int i;
+ const struct bgscan_ops *ops = NULL;
+
+ bgscan_deinit(wpa_s);
+ 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; bgscan_modules[i]; i++) {
+ if (os_strncmp(name, bgscan_modules[i]->name, nlen) == 0) {
+ ops = bgscan_modules[i];
+ break;
+ }
+ }
+
+ if (ops == NULL) {
+ wpa_printf(MSG_ERROR, "bgscan: Could not find module "
+ "matching the parameter '%s'", name);
+ return -1;
+ }
+
+ wpa_s->bgscan_priv = ops->init(wpa_s, params, ssid);
+ if (wpa_s->bgscan_priv == NULL)
+ return -1;
+ wpa_s->bgscan = ops;
+ wpa_printf(MSG_DEBUG, "bgscan: Initialized module '%s' with "
+ "parameters '%s'", ops->name, params);
+
+ return 0;
+}
+
+
+void bgscan_deinit(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan && wpa_s->bgscan_priv) {
+ wpa_printf(MSG_DEBUG, "bgscan: Deinitializing module '%s'",
+ wpa_s->bgscan->name);
+ wpa_s->bgscan->deinit(wpa_s->bgscan_priv);
+ wpa_s->bgscan = NULL;
+ wpa_s->bgscan_priv = NULL;
+ }
+}
+
+
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan && wpa_s->bgscan_priv)
+ return wpa_s->bgscan->notify_scan(wpa_s->bgscan_priv);
+ return 0;
+}
+
+
+void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan && wpa_s->bgscan_priv)
+ wpa_s->bgscan->notify_beacon_loss(wpa_s->bgscan_priv);
+}
+
+
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->bgscan && wpa_s->bgscan_priv)
+ wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv);
+}
diff --git a/wpa_supplicant/bgscan.h b/wpa_supplicant/bgscan.h
new file mode 100644
index 0000000..dfd4cab
--- /dev/null
+++ b/wpa_supplicant/bgscan.h
@@ -0,0 +1,68 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * 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 BGSCAN_H
+#define BGSCAN_H
+
+struct wpa_supplicant;
+struct wpa_ssid;
+
+struct bgscan_ops {
+ const char *name;
+
+ void * (*init)(struct wpa_supplicant *wpa_s, const char *params,
+ const struct wpa_ssid *ssid);
+ void (*deinit)(void *priv);
+
+ int (*notify_scan)(void *priv);
+ void (*notify_beacon_loss)(void *priv);
+ void (*notify_signal_change)(void *priv);
+};
+
+#ifdef CONFIG_BGSCAN
+
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+void bgscan_deinit(struct wpa_supplicant *wpa_s);
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s);
+void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s);
+
+#else /* CONFIG_BGSCAN */
+
+static inline int bgscan_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ return 0;
+}
+
+static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
+{
+}
+
+#endif /* CONFIG_BGSCAN */
+
+#endif /* BGSCAN_H */
diff --git a/wpa_supplicant/bgscan_simple.c b/wpa_supplicant/bgscan_simple.c
new file mode 100644
index 0000000..dacddff
--- /dev/null
+++ b/wpa_supplicant/bgscan_simple.c
@@ -0,0 +1,130 @@
+/*
+ * WPA Supplicant - background scan and roaming module: simple
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * 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 "eloop.h"
+#include "drivers/driver.h"
+#include "config_ssid.h"
+#include "wpa_supplicant_i.h"
+#include "bgscan.h"
+
+struct bgscan_simple_data {
+ struct wpa_supplicant *wpa_s;
+ const struct wpa_ssid *ssid;
+ int scan_interval;
+};
+
+
+static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct bgscan_simple_data *data = eloop_ctx;
+ struct wpa_supplicant *wpa_s = data->wpa_s;
+ struct wpa_driver_scan_params params;
+
+ os_memset(&params, 0, sizeof(params));
+ params.num_ssids = 1;
+ params.ssids[0].ssid = data->ssid->ssid;
+ params.ssids[0].ssid_len = data->ssid->ssid_len;
+ params.freqs = data->ssid->scan_freq;
+
+ /*
+ * A more advanced bgscan module would learn about most like channels
+ * over time and request scans only for some channels (probing others
+ * every now and then) to reduce effect on the data connection.
+ */
+
+ wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan");
+ if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
+ wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
+ eloop_register_timeout(data->scan_interval, 0,
+ bgscan_simple_timeout, data, NULL);
+ }
+}
+
+
+static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
+ const char *params,
+ const struct wpa_ssid *ssid)
+{
+ struct bgscan_simple_data *data;
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->wpa_s = wpa_s;
+ data->ssid = ssid;
+ if (params)
+ data->scan_interval = atoi(params);
+ if (data->scan_interval <= 0)
+ data->scan_interval = 30;
+ eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
+ data, NULL);
+ return data;
+}
+
+
+static void bgscan_simple_deinit(void *priv)
+{
+ struct bgscan_simple_data *data = priv;
+ eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+ os_free(data);
+}
+
+
+static int bgscan_simple_notify_scan(void *priv)
+{
+ struct bgscan_simple_data *data = priv;
+
+ wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification");
+
+ eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
+ eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
+ data, NULL);
+
+ /*
+ * A more advanced bgscan could process scan results internally, select
+ * the BSS and request roam if needed. This sample uses the existing
+ * BSS/ESS selection routine. Change this to return 1 if selection is
+ * done inside the bgscan module.
+ */
+
+ return 0;
+}
+
+
+static void bgscan_simple_notify_beacon_loss(void *priv)
+{
+ wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss");
+ /* TODO: speed up background scanning */
+}
+
+
+static void bgscan_simple_notify_signal_change(void *priv)
+{
+ wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed");
+ /* TODO: if signal strength dropped enough, speed up background
+ * scanning */
+}
+
+
+const struct bgscan_ops bgscan_simple_ops = {
+ .name = "simple",
+ .init = bgscan_simple_init,
+ .deinit = bgscan_simple_deinit,
+ .notify_scan = bgscan_simple_notify_scan,
+ .notify_beacon_loss = bgscan_simple_notify_beacon_loss,
+ .notify_signal_change = bgscan_simple_notify_signal_change,
+};
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 5f7f34f..97c303d 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1458,7 +1458,8 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(peerkey, 0, 1) },
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 10000) },
- { INT(wpa_ptk_rekey) }
+ { INT(wpa_ptk_rekey) },
+ { STR(bgscan) },
};
#undef OFFSET
@@ -1623,6 +1624,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
#endif /* IEEE8021X_EAPOL */
os_free(ssid->id_str);
os_free(ssid->scan_freq);
+ os_free(ssid->bgscan);
os_free(ssid);
}
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c120360..e09e3ed 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -350,6 +350,15 @@ struct wpa_ssid {
* known to not use all possible channels.
*/
int *scan_freq;
+
+ /**
+ * bgscan - Background scan and roaming parameters or %NULL if none
+ *
+ * This is an optional set of parameters for background scanning and
+ * roaming within a network (ESS) in following format:
+ * <bgscan module name>:<module parameters>
+ */
+ char *bgscan;
};
#endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 03d0e1f..de4c6fb 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -34,6 +34,7 @@
#include "wps_supplicant.h"
#include "ibss_rsn.h"
#include "sme.h"
+#include "bgscan.h"
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -658,6 +659,9 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
return;
}
+ if (bgscan_notify_scan(wpa_s) == 1)
+ return;
+
while (selected == NULL) {
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
selected = wpa_supplicant_select_bss(
@@ -981,6 +985,25 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpabuf_free(wpa_s->pending_eapol_rx);
wpa_s->pending_eapol_rx = NULL;
}
+
+#ifdef CONFIG_BGSCAN
+ if (wpa_s->current_ssid != wpa_s->bgscan_ssid) {
+ bgscan_deinit(wpa_s);
+ if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+ if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+ wpa_printf(MSG_DEBUG, "Failed to initialize "
+ "bgscan");
+ /*
+ * Live without bgscan; it is only used as a
+ * roaming optimization, so the initial
+ * connection is not affected.
+ */
+ } else
+ wpa_s->bgscan_ssid = wpa_s->current_ssid;
+ } else
+ wpa_s->bgscan_ssid = NULL;
+ }
+#endif /* CONFIG_BGSCAN */
}
@@ -1018,6 +1041,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
wpa_supplicant_mark_disassoc(wpa_s);
+ bgscan_deinit(wpa_s);
}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index e122e67..b39b8ee 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -178,6 +178,34 @@ static void int_array_sort_unique(int *a)
}
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params)
+{
+ int ret;
+
+ wpa_supplicant_notify_scanning(wpa_s, 1);
+
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
+ ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies,
+ params->extra_ies_len);
+ ret = ieee80211_sta_req_scan(wpa_s, params->ssids[0].ssid,
+ params->ssids[0].ssid_len);
+ } else {
+ wpa_drv_set_probe_req_ie(wpa_s, params->extra_ies,
+ params->extra_ies_len);
+ ret = wpa_drv_scan(wpa_s, params);
+ }
+
+ if (ret) {
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+ wpas_notify_scan_done(wpa_s, 0);
+ } else
+ wpa_s->scan_runs++;
+
+ return ret;
+}
+
+
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
@@ -335,26 +363,13 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#endif /* CONFIG_WPS */
- wpa_supplicant_notify_scanning(wpa_s, 1);
-
- if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
- ieee80211_sta_set_probe_req_ie(wpa_s, params.extra_ies,
- params.extra_ies_len);
- ret = ieee80211_sta_req_scan(wpa_s, params.ssids[0].ssid,
- params.ssids[0].ssid_len);
- } else {
- wpa_drv_set_probe_req_ie(wpa_s, params.extra_ies,
- params.extra_ies_len);
- ret = wpa_drv_scan(wpa_s, &params);
- }
+ ret = wpa_supplicant_trigger_scan(wpa_s, &params);
wpabuf_free(wps_ie);
os_free(params.freqs);
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
- wpa_supplicant_notify_scanning(wpa_s, 0);
- wpas_notify_scan_done(wpa_s, 0);
wpa_supplicant_req_scan(wpa_s, 10, 0);
} else
wpa_s->scan_runs++;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index df1d182..c2e5e55 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -44,6 +44,7 @@
#include "sme.h"
#include "ap.h"
#include "notify.h"
+#include "bgscan.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
@@ -362,6 +363,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
+ bgscan_deinit(wpa_s);
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index a5eaaf1..0872efc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -388,6 +388,10 @@ struct wpa_supplicant {
#ifdef CONFIG_AP
struct hostapd_iface *ap_iface;
#endif /* CONFIG_AP */
+
+ struct wpa_ssid *bgscan_ssid;
+ const struct bgscan_ops *bgscan;
+ void *bgscan_priv;
};
@@ -450,6 +454,9 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
int scanning);
+struct wpa_driver_scan_params;
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_scan_params *params);
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);