Current Path : /usr/src/contrib/wpa/wpa_supplicant/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/contrib/wpa/wpa_supplicant/bgscan_simple.c |
/* * 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, };