2 * WPA Supplicant - background scan and roaming module: learn
3 * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "drivers/driver.h"
20 #include "config_ssid.h"
21 #include "wpa_supplicant_i.h"
26 struct bgscan_learn_data {
27 struct wpa_supplicant *wpa_s;
28 const struct wpa_ssid *ssid;
31 int short_interval; /* use if signal < threshold */
32 int long_interval; /* use if signal > threshold */
33 struct os_time last_bgscan;
38 static int bgscan_learn_load(struct bgscan_learn_data *data)
43 if (data->fname == NULL)
46 f = fopen(data->fname, "r");
50 wpa_printf(MSG_DEBUG, "bgscan learn: Loading data from %s",
53 if (fgets(buf, sizeof(buf), f) == NULL ||
54 os_strncmp(buf, "wpa_supplicant-bgscan-learn\n", 28) != 0) {
55 wpa_printf(MSG_INFO, "bgscan learn: Invalid data file %s",
66 static void bgscan_learn_save(struct bgscan_learn_data *data)
70 if (data->fname == NULL)
73 wpa_printf(MSG_DEBUG, "bgscan learn: Saving data to %s",
76 f = fopen(data->fname, "w");
79 fprintf(f, "wpa_supplicant-bgscan-learn\n");
85 static void bgscan_learn_timeout(void *eloop_ctx, void *timeout_ctx)
87 struct bgscan_learn_data *data = eloop_ctx;
88 struct wpa_supplicant *wpa_s = data->wpa_s;
89 struct wpa_driver_scan_params params;
91 os_memset(¶ms, 0, sizeof(params));
93 params.ssids[0].ssid = data->ssid->ssid;
94 params.ssids[0].ssid_len = data->ssid->ssid_len;
95 params.freqs = data->ssid->scan_freq;
98 * A more advanced bgscan module would learn about most like channels
99 * over time and request scans only for some channels (probing others
100 * every now and then) to reduce effect on the data connection.
103 wpa_printf(MSG_DEBUG, "bgscan learn: Request a background scan");
104 if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
105 wpa_printf(MSG_DEBUG, "bgscan learn: Failed to trigger scan");
106 eloop_register_timeout(data->scan_interval, 0,
107 bgscan_learn_timeout, data, NULL);
109 os_get_time(&data->last_bgscan);
113 static int bgscan_learn_get_params(struct bgscan_learn_data *data,
121 data->short_interval = atoi(params);
123 pos = os_strchr(params, ':');
127 data->signal_threshold = atoi(pos);
128 pos = os_strchr(pos, ':');
130 wpa_printf(MSG_ERROR, "bgscan learn: Missing scan interval "
135 data->long_interval = atoi(pos);
136 pos = os_strchr(pos, ':');
139 data->fname = os_strdup(pos);
146 static void * bgscan_learn_init(struct wpa_supplicant *wpa_s,
148 const struct wpa_ssid *ssid)
150 struct bgscan_learn_data *data;
152 data = os_zalloc(sizeof(*data));
157 if (bgscan_learn_get_params(data, params) < 0) {
158 os_free(data->fname);
162 if (data->short_interval <= 0)
163 data->short_interval = 30;
164 if (data->long_interval <= 0)
165 data->long_interval = 30;
167 if (bgscan_learn_load(data) < 0) {
168 os_free(data->fname);
173 wpa_printf(MSG_DEBUG, "bgscan learn: Signal strength threshold %d "
174 "Short bgscan interval %d Long bgscan interval %d",
175 data->signal_threshold, data->short_interval,
176 data->long_interval);
178 if (data->signal_threshold &&
179 wpa_drv_signal_monitor(wpa_s, data->signal_threshold, 4) < 0) {
180 wpa_printf(MSG_ERROR, "bgscan learn: Failed to enable "
181 "signal strength monitoring");
184 data->scan_interval = data->short_interval;
185 eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
191 static void bgscan_learn_deinit(void *priv)
193 struct bgscan_learn_data *data = priv;
194 bgscan_learn_save(data);
195 eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
196 if (data->signal_threshold)
197 wpa_drv_signal_monitor(data->wpa_s, 0, 0);
198 os_free(data->fname);
203 static int bgscan_learn_notify_scan(void *priv,
204 struct wpa_scan_results *scan_res)
206 struct bgscan_learn_data *data = priv;
208 wpa_printf(MSG_DEBUG, "bgscan learn: scan result notification");
210 eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
211 eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
215 * A more advanced bgscan could process scan results internally, select
216 * the BSS and request roam if needed. This sample uses the existing
217 * BSS/ESS selection routine. Change this to return 1 if selection is
218 * done inside the bgscan module.
225 static void bgscan_learn_notify_beacon_loss(void *priv)
227 wpa_printf(MSG_DEBUG, "bgscan learn: beacon loss");
228 /* TODO: speed up background scanning */
232 static void bgscan_learn_notify_signal_change(void *priv, int above)
234 struct bgscan_learn_data *data = priv;
236 if (data->short_interval == data->long_interval ||
237 data->signal_threshold == 0)
240 wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed "
241 "(above=%d)", above);
242 if (data->scan_interval == data->long_interval && !above) {
243 wpa_printf(MSG_DEBUG, "bgscan learn: Trigger immediate scan "
244 "and start using short bgscan interval");
245 data->scan_interval = data->short_interval;
246 eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
247 eloop_register_timeout(0, 0, bgscan_learn_timeout, data,
249 } else if (data->scan_interval == data->short_interval && above) {
250 wpa_printf(MSG_DEBUG, "bgscan learn: Start using long bgscan "
252 data->scan_interval = data->long_interval;
253 eloop_cancel_timeout(bgscan_learn_timeout, data, NULL);
254 eloop_register_timeout(data->scan_interval, 0,
255 bgscan_learn_timeout, data, NULL);
259 * Signal dropped further 4 dB. Request a new scan if we have
260 * not yet scanned in a while.
263 if (now.sec > data->last_bgscan.sec + 10) {
264 wpa_printf(MSG_DEBUG, "bgscan learn: Trigger "
266 eloop_cancel_timeout(bgscan_learn_timeout, data,
268 eloop_register_timeout(0, 0, bgscan_learn_timeout,
275 const struct bgscan_ops bgscan_learn_ops = {
277 .init = bgscan_learn_init,
278 .deinit = bgscan_learn_deinit,
279 .notify_scan = bgscan_learn_notify_scan,
280 .notify_beacon_loss = bgscan_learn_notify_beacon_loss,
281 .notify_signal_change = bgscan_learn_notify_signal_change,