2 * WPA Supplicant - background scan and roaming module: simple
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_simple_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
;
37 static void bgscan_simple_timeout(void *eloop_ctx
, void *timeout_ctx
)
39 struct bgscan_simple_data
*data
= eloop_ctx
;
40 struct wpa_supplicant
*wpa_s
= data
->wpa_s
;
41 struct wpa_driver_scan_params params
;
43 os_memset(¶ms
, 0, sizeof(params
));
45 params
.ssids
[0].ssid
= data
->ssid
->ssid
;
46 params
.ssids
[0].ssid_len
= data
->ssid
->ssid_len
;
47 params
.freqs
= data
->ssid
->scan_freq
;
50 * A more advanced bgscan module would learn about most like channels
51 * over time and request scans only for some channels (probing others
52 * every now and then) to reduce effect on the data connection.
55 wpa_printf(MSG_DEBUG
, "bgscan simple: Request a background scan");
56 if (wpa_supplicant_trigger_scan(wpa_s
, ¶ms
)) {
57 wpa_printf(MSG_DEBUG
, "bgscan simple: Failed to trigger scan");
58 eloop_register_timeout(data
->scan_interval
, 0,
59 bgscan_simple_timeout
, data
, NULL
);
61 os_get_time(&data
->last_bgscan
);
65 static int bgscan_simple_get_params(struct bgscan_simple_data
*data
,
73 data
->short_interval
= atoi(params
);
75 pos
= os_strchr(params
, ':');
79 data
->signal_threshold
= atoi(pos
);
80 pos
= os_strchr(pos
, ':');
82 wpa_printf(MSG_ERROR
, "bgscan simple: Missing scan interval "
87 data
->long_interval
= atoi(pos
);
93 static void * bgscan_simple_init(struct wpa_supplicant
*wpa_s
,
95 const struct wpa_ssid
*ssid
)
97 struct bgscan_simple_data
*data
;
99 data
= os_zalloc(sizeof(*data
));
104 if (bgscan_simple_get_params(data
, params
) < 0) {
108 if (data
->short_interval
<= 0)
109 data
->short_interval
= 30;
110 if (data
->long_interval
<= 0)
111 data
->long_interval
= 30;
113 wpa_printf(MSG_DEBUG
, "bgscan simple: Signal strength threshold %d "
114 "Short bgscan interval %d Long bgscan interval %d",
115 data
->signal_threshold
, data
->short_interval
,
116 data
->long_interval
);
118 if (data
->signal_threshold
&&
119 wpa_drv_signal_monitor(wpa_s
, data
->signal_threshold
, 4) < 0) {
120 wpa_printf(MSG_ERROR
, "bgscan simple: Failed to enable "
121 "signal strength monitoring");
124 data
->scan_interval
= data
->short_interval
;
125 eloop_register_timeout(data
->scan_interval
, 0, bgscan_simple_timeout
,
129 * This function is called immediately after an association, so it is
130 * reasonable to assume that a scan was completed recently. This makes
131 * us skip an immediate new scan in cases where the current signal
132 * level is below the bgscan threshold.
134 os_get_time(&data
->last_bgscan
);
140 static void bgscan_simple_deinit(void *priv
)
142 struct bgscan_simple_data
*data
= priv
;
143 eloop_cancel_timeout(bgscan_simple_timeout
, data
, NULL
);
144 if (data
->signal_threshold
)
145 wpa_drv_signal_monitor(data
->wpa_s
, 0, 0);
150 static int bgscan_simple_notify_scan(void *priv
)
152 struct bgscan_simple_data
*data
= priv
;
154 wpa_printf(MSG_DEBUG
, "bgscan simple: scan result notification");
156 eloop_cancel_timeout(bgscan_simple_timeout
, data
, NULL
);
157 eloop_register_timeout(data
->scan_interval
, 0, bgscan_simple_timeout
,
161 * A more advanced bgscan could process scan results internally, select
162 * the BSS and request roam if needed. This sample uses the existing
163 * BSS/ESS selection routine. Change this to return 1 if selection is
164 * done inside the bgscan module.
171 static void bgscan_simple_notify_beacon_loss(void *priv
)
173 wpa_printf(MSG_DEBUG
, "bgscan simple: beacon loss");
174 /* TODO: speed up background scanning */
178 static void bgscan_simple_notify_signal_change(void *priv
, int above
)
180 struct bgscan_simple_data
*data
= priv
;
184 if (data
->short_interval
== data
->long_interval
||
185 data
->signal_threshold
== 0)
188 wpa_printf(MSG_DEBUG
, "bgscan simple: signal level changed "
189 "(above=%d)", above
);
190 if (data
->scan_interval
== data
->long_interval
&& !above
) {
191 wpa_printf(MSG_DEBUG
, "bgscan simple: Start using short "
193 data
->scan_interval
= data
->short_interval
;
195 if (now
.sec
> data
->last_bgscan
.sec
+ 1)
197 } else if (data
->scan_interval
== data
->short_interval
&& above
) {
198 wpa_printf(MSG_DEBUG
, "bgscan simple: Start using long bgscan "
200 data
->scan_interval
= data
->long_interval
;
201 eloop_cancel_timeout(bgscan_simple_timeout
, data
, NULL
);
202 eloop_register_timeout(data
->scan_interval
, 0,
203 bgscan_simple_timeout
, data
, NULL
);
206 * Signal dropped further 4 dB. Request a new scan if we have
207 * not yet scanned in a while.
210 if (now
.sec
> data
->last_bgscan
.sec
+ 10)
215 wpa_printf(MSG_DEBUG
, "bgscan simple: Trigger immediate scan");
216 eloop_cancel_timeout(bgscan_simple_timeout
, data
, NULL
);
217 eloop_register_timeout(0, 0, bgscan_simple_timeout
, data
,
223 const struct bgscan_ops bgscan_simple_ops
= {
225 .init
= bgscan_simple_init
,
226 .deinit
= bgscan_simple_deinit
,
227 .notify_scan
= bgscan_simple_notify_scan
,
228 .notify_beacon_loss
= bgscan_simple_notify_beacon_loss
,
229 .notify_signal_change
= bgscan_simple_notify_signal_change
,