diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2010-11-03 10:43:38 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2010-11-03 10:43:38 +0000 |
commit | e0d70c33109c041ff2046fe529eb8e3c0f2acec1 (patch) | |
tree | bf6082c2ad69b06fcb45c37be7157b66ffbd4fc7 /contrib/wpa/wpa_supplicant/bgscan_simple.c | |
parent | 6ddde2168bc79a10ab0937ba69afe0a74559eea0 (diff) | |
parent | 14ab4e9475c66439a7a011706ada056765de1555 (diff) | |
download | FreeBSD-src-e0d70c33109c041ff2046fe529eb8e3c0f2acec1.zip FreeBSD-src-e0d70c33109c041ff2046fe529eb8e3c0f2acec1.tar.gz |
Merge wpa_supplicant and hostapd 0.7.3.
Diffstat (limited to 'contrib/wpa/wpa_supplicant/bgscan_simple.c')
-rw-r--r-- | contrib/wpa/wpa_supplicant/bgscan_simple.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/contrib/wpa/wpa_supplicant/bgscan_simple.c b/contrib/wpa/wpa_supplicant/bgscan_simple.c new file mode 100644 index 0000000..8e80b12 --- /dev/null +++ b/contrib/wpa/wpa_supplicant/bgscan_simple.c @@ -0,0 +1,230 @@ +/* + * WPA Supplicant - background scan and roaming module: simple + * 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 + * 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 "driver_i.h" +#include "scan.h" +#include "bgscan.h" + +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; +}; + + +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(¶ms, 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, ¶ms)) { + 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; +} + + +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 (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); + + /* + * This function is called immediately after an association, so it is + * reasonable to assume that a scan was completed recently. This makes + * us skip an immediate new scan in cases where the current signal + * level is below the bgscan threshold. + */ + os_get_time(&data->last_bgscan); + + return data; +} + + +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); +} + + +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, int above) +{ + struct bgscan_simple_data *data = priv; + int scan = 0; + struct os_time now; + + 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: Start using short " + "bgscan interval"); + data->scan_interval = data->short_interval; + os_get_time(&now); + if (now.sec > data->last_bgscan.sec + 1) + scan = 1; + } 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) { + /* + * 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) + scan = 1; + } + + if (scan) { + 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); + } +} + + +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, +}; |