bgscan: Add signal strength change events

This allows bgscan modules to use more information to decide on when
to perform background scans. bgscan_simple can now change between
short and long background scan intervals based on signal strength
and in addition, it can trigger immediate scans when the signal
strength is detected to be dropping.

bgscan_simple takes following parameters now:
short interval:signal strength threshold:long interval
For example:
	bgscan="simple:30:-45:300"
This commit is contained in:
Jouni Malinen 2010-03-28 15:32:34 -07:00
parent b625473c6c
commit e2f74005f5
4 changed files with 109 additions and 16 deletions

View file

@ -1,6 +1,6 @@
/*
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009-2010, 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
@ -103,8 +103,8 @@ void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
}
void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above)
{
if (wpa_s->bgscan && wpa_s->bgscan_priv)
wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv);
wpa_s->bgscan->notify_signal_change(wpa_s->bgscan_priv, above);
}

View file

@ -1,6 +1,6 @@
/*
* WPA Supplicant - background scan and roaming interface
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009-2010, 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
@ -27,7 +27,7 @@ struct bgscan_ops {
int (*notify_scan)(void *priv);
void (*notify_beacon_loss)(void *priv);
void (*notify_signal_change)(void *priv);
void (*notify_signal_change)(void *priv, int above);
};
#ifdef CONFIG_BGSCAN
@ -36,7 +36,7 @@ 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);
void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above);
#else /* CONFIG_BGSCAN */
@ -59,7 +59,8 @@ static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
{
}
static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s)
static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
int above)
{
}

View file

@ -1,6 +1,6 @@
/*
* WPA Supplicant - background scan and roaming module: simple
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
* Copyright (c) 2009-2010, 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
@ -19,6 +19,7 @@
#include "drivers/driver.h"
#include "config_ssid.h"
#include "wpa_supplicant_i.h"
#include "driver_i.h"
#include "scan.h"
#include "bgscan.h"
@ -26,6 +27,10 @@ struct bgscan_simple_data {
struct wpa_supplicant *wpa_s;
const struct wpa_ssid *ssid;
int scan_interval;
int signal_threshold;
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
struct os_time last_bgscan;
};
@ -52,7 +57,36 @@ static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan");
eloop_register_timeout(data->scan_interval, 0,
bgscan_simple_timeout, data, NULL);
} else
os_get_time(&data->last_bgscan);
}
static int bgscan_simple_get_params(struct bgscan_simple_data *data,
const char *params)
{
const char *pos;
if (params == NULL)
return 0;
data->short_interval = atoi(params);
pos = os_strchr(params, ':');
if (pos == NULL)
return 0;
pos++;
data->signal_threshold = atoi(pos);
pos = os_strchr(pos, ':');
if (pos == NULL) {
wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval "
"for high signal");
return -1;
}
pos++;
data->long_interval = atoi(pos);
return 0;
}
@ -67,10 +101,27 @@ static void * bgscan_simple_init(struct wpa_supplicant *wpa_s,
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;
if (bgscan_simple_get_params(data, params) < 0) {
os_free(data);
return NULL;
}
if (data->short_interval <= 0)
data->short_interval = 30;
if (data->long_interval <= 0)
data->long_interval = 30;
wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d "
"Short bgscan interval %d Long bgscan interval %d",
data->signal_threshold, data->short_interval,
data->long_interval);
if (data->signal_threshold &&
wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable "
"signal strength monitoring");
}
data->scan_interval = data->short_interval;
eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout,
data, NULL);
return data;
@ -81,6 +132,8 @@ static void bgscan_simple_deinit(void *priv)
{
struct bgscan_simple_data *data = priv;
eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
if (data->signal_threshold)
wpa_drv_signal_monitor(data->wpa_s, 0, 0);
os_free(data);
}
@ -113,11 +166,46 @@ static void bgscan_simple_notify_beacon_loss(void *priv)
}
static void bgscan_simple_notify_signal_change(void *priv)
static void bgscan_simple_notify_signal_change(void *priv, int above)
{
wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed");
/* TODO: if signal strength dropped enough, speed up background
* scanning */
struct bgscan_simple_data *data = priv;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
return;
wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed "
"(above=%d)", above);
if (data->scan_interval == data->long_interval && !above) {
wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan "
"and start using short bgscan interval");
data->scan_interval = data->short_interval;
eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
eloop_register_timeout(0, 0, bgscan_simple_timeout, data,
NULL);
} else if (data->scan_interval == data->short_interval && above) {
wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan "
"interval");
data->scan_interval = data->long_interval;
eloop_cancel_timeout(bgscan_simple_timeout, data, NULL);
eloop_register_timeout(data->scan_interval, 0,
bgscan_simple_timeout, data, NULL);
} else if (!above) {
struct os_time now;
/*
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
os_get_time(&now);
if (now.sec > data->last_bgscan.sec + 10) {
wpa_printf(MSG_DEBUG, "bgscan simple: Trigger "
"immediate scan");
eloop_cancel_timeout(bgscan_simple_timeout, data,
NULL);
eloop_register_timeout(0, 0, bgscan_simple_timeout,
data, NULL);
}
}
}

View file

@ -1740,6 +1740,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->eapol_rx.data,
data->eapol_rx.data_len);
break;
case EVENT_SIGNAL_CHANGE:
bgscan_notify_signal_change(
wpa_s, data->signal_change.above_threshold);
break;
default:
wpa_printf(MSG_INFO, "Unknown event %d", event);
break;