$search
00001 /* 00002 * WPA Supplicant - background scan and roaming module: simple 00003 * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eloop.h" 00019 #include "drivers/driver.h" 00020 #include "config_ssid.h" 00021 #include "wpa_supplicant_i.h" 00022 #include "driver_i.h" 00023 #include "scan.h" 00024 #include "bgscan.h" 00025 00026 struct bgscan_simple_data { 00027 struct wpa_supplicant *wpa_s; 00028 const struct wpa_ssid *ssid; 00029 int scan_interval; 00030 int signal_threshold; 00031 int short_interval; /* use if signal < threshold */ 00032 int long_interval; /* use if signal > threshold */ 00033 struct os_time last_bgscan; 00034 }; 00035 00036 00037 static void bgscan_simple_timeout(void *eloop_ctx, void *timeout_ctx) 00038 { 00039 struct bgscan_simple_data *data = eloop_ctx; 00040 struct wpa_supplicant *wpa_s = data->wpa_s; 00041 struct wpa_driver_scan_params params; 00042 00043 os_memset(¶ms, 0, sizeof(params)); 00044 params.num_ssids = 1; 00045 params.ssids[0].ssid = data->ssid->ssid; 00046 params.ssids[0].ssid_len = data->ssid->ssid_len; 00047 params.freqs = data->ssid->scan_freq; 00048 00049 /* 00050 * A more advanced bgscan module would learn about most like channels 00051 * over time and request scans only for some channels (probing others 00052 * every now and then) to reduce effect on the data connection. 00053 */ 00054 00055 wpa_printf(MSG_DEBUG, "bgscan simple: Request a background scan"); 00056 if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) { 00057 wpa_printf(MSG_DEBUG, "bgscan simple: Failed to trigger scan"); 00058 eloop_register_timeout(data->scan_interval, 0, 00059 bgscan_simple_timeout, data, NULL); 00060 } else 00061 os_get_time(&data->last_bgscan); 00062 } 00063 00064 00065 static int bgscan_simple_get_params(struct bgscan_simple_data *data, 00066 const char *params) 00067 { 00068 const char *pos; 00069 00070 if (params == NULL) 00071 return 0; 00072 00073 data->short_interval = atoi(params); 00074 00075 pos = os_strchr(params, ':'); 00076 if (pos == NULL) 00077 return 0; 00078 pos++; 00079 data->signal_threshold = atoi(pos); 00080 pos = os_strchr(pos, ':'); 00081 if (pos == NULL) { 00082 wpa_printf(MSG_ERROR, "bgscan simple: Missing scan interval " 00083 "for high signal"); 00084 return -1; 00085 } 00086 pos++; 00087 data->long_interval = atoi(pos); 00088 00089 return 0; 00090 } 00091 00092 00093 static void * bgscan_simple_init(struct wpa_supplicant *wpa_s, 00094 const char *params, 00095 const struct wpa_ssid *ssid) 00096 { 00097 struct bgscan_simple_data *data; 00098 00099 data = os_zalloc(sizeof(*data)); 00100 if (data == NULL) 00101 return NULL; 00102 data->wpa_s = wpa_s; 00103 data->ssid = ssid; 00104 if (bgscan_simple_get_params(data, params) < 0) { 00105 os_free(data); 00106 return NULL; 00107 } 00108 if (data->short_interval <= 0) 00109 data->short_interval = 30; 00110 if (data->long_interval <= 0) 00111 data->long_interval = 30; 00112 00113 wpa_printf(MSG_DEBUG, "bgscan simple: Signal strength threshold %d " 00114 "Short bgscan interval %d Long bgscan interval %d", 00115 data->signal_threshold, data->short_interval, 00116 data->long_interval); 00117 00118 if (data->signal_threshold && 00119 wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) { 00120 wpa_printf(MSG_ERROR, "bgscan simple: Failed to enable " 00121 "signal strength monitoring"); 00122 } 00123 00124 data->scan_interval = data->short_interval; 00125 eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, 00126 data, NULL); 00127 return data; 00128 } 00129 00130 00131 static void bgscan_simple_deinit(void *priv) 00132 { 00133 struct bgscan_simple_data *data = priv; 00134 eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); 00135 if (data->signal_threshold) 00136 wpa_drv_signal_monitor(data->wpa_s, 0, 0); 00137 os_free(data); 00138 } 00139 00140 00141 static int bgscan_simple_notify_scan(void *priv) 00142 { 00143 struct bgscan_simple_data *data = priv; 00144 00145 wpa_printf(MSG_DEBUG, "bgscan simple: scan result notification"); 00146 00147 eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); 00148 eloop_register_timeout(data->scan_interval, 0, bgscan_simple_timeout, 00149 data, NULL); 00150 00151 /* 00152 * A more advanced bgscan could process scan results internally, select 00153 * the BSS and request roam if needed. This sample uses the existing 00154 * BSS/ESS selection routine. Change this to return 1 if selection is 00155 * done inside the bgscan module. 00156 */ 00157 00158 return 0; 00159 } 00160 00161 00162 static void bgscan_simple_notify_beacon_loss(void *priv) 00163 { 00164 wpa_printf(MSG_DEBUG, "bgscan simple: beacon loss"); 00165 /* TODO: speed up background scanning */ 00166 } 00167 00168 00169 static void bgscan_simple_notify_signal_change(void *priv, int above) 00170 { 00171 struct bgscan_simple_data *data = priv; 00172 00173 if (data->short_interval == data->long_interval || 00174 data->signal_threshold == 0) 00175 return; 00176 00177 wpa_printf(MSG_DEBUG, "bgscan simple: signal level changed " 00178 "(above=%d)", above); 00179 if (data->scan_interval == data->long_interval && !above) { 00180 wpa_printf(MSG_DEBUG, "bgscan simple: Trigger immediate scan " 00181 "and start using short bgscan interval"); 00182 data->scan_interval = data->short_interval; 00183 eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); 00184 eloop_register_timeout(0, 0, bgscan_simple_timeout, data, 00185 NULL); 00186 } else if (data->scan_interval == data->short_interval && above) { 00187 wpa_printf(MSG_DEBUG, "bgscan simple: Start using long bgscan " 00188 "interval"); 00189 data->scan_interval = data->long_interval; 00190 eloop_cancel_timeout(bgscan_simple_timeout, data, NULL); 00191 eloop_register_timeout(data->scan_interval, 0, 00192 bgscan_simple_timeout, data, NULL); 00193 } else if (!above) { 00194 struct os_time now; 00195 /* 00196 * Signal dropped further 4 dB. Request a new scan if we have 00197 * not yet scanned in a while. 00198 */ 00199 os_get_time(&now); 00200 if (now.sec > data->last_bgscan.sec + 10) { 00201 wpa_printf(MSG_DEBUG, "bgscan simple: Trigger " 00202 "immediate scan"); 00203 eloop_cancel_timeout(bgscan_simple_timeout, data, 00204 NULL); 00205 eloop_register_timeout(0, 0, bgscan_simple_timeout, 00206 data, NULL); 00207 } 00208 } 00209 } 00210 00211 00212 const struct bgscan_ops bgscan_simple_ops = { 00213 .name = "simple", 00214 .init = bgscan_simple_init, 00215 .deinit = bgscan_simple_deinit, 00216 .notify_scan = bgscan_simple_notify_scan, 00217 .notify_beacon_loss = bgscan_simple_notify_beacon_loss, 00218 .notify_signal_change = bgscan_simple_notify_signal_change, 00219 };