* WPA Supplicant - background scan and roaming module: learn
* 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.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "includes.h"
int signal_threshold;
int short_interval; /* use if signal < threshold */
int long_interval; /* use if signal > threshold */
- struct os_time last_bgscan;
+ struct os_reltime last_bgscan;
char *fname;
struct dl_list bss;
int *supp_freqs;
if (bssid_in_array(bss->neigh, bss->num_neigh, bssid))
return;
- n = os_realloc(bss->neigh, (bss->num_neigh + 1) * ETH_ALEN);
+ n = os_realloc_array(bss->neigh, bss->num_neigh + 1, ETH_ALEN);
if (n == NULL)
return;
dl_list_for_each(bss, &data->bss, struct bgscan_learn_bss, list) {
if (in_array(freqs, bss->freq))
continue;
- n = os_realloc(freqs, (*count + 2) * sizeof(int));
+ n = os_realloc_array(freqs, *count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
if (data->supp_freqs == NULL)
return freqs;
- idx = data->probe_idx + 1;
- while (idx != data->probe_idx) {
- if (data->supp_freqs[idx] == 0)
- idx = 0;
+ idx = data->probe_idx;
+ do {
if (!in_array(freqs, data->supp_freqs[idx])) {
wpa_printf(MSG_DEBUG, "bgscan learn: Probe new freq "
"%u", data->supp_freqs[idx]);
- data->probe_idx = idx;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
+ data->probe_idx = idx + 1;
+ if (data->supp_freqs[data->probe_idx] == 0)
+ data->probe_idx = 0;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
if (n == NULL)
return freqs;
freqs = n;
}
idx++;
- }
+ if (data->supp_freqs[idx] == 0)
+ idx = 0;
+ } while (idx != data->probe_idx);
return freqs;
}
int ret;
ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
freqs[i]);
- if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+ if (os_snprintf_error(msg + sizeof(msg) - pos, ret))
break;
pos += ret;
}
eloop_register_timeout(data->scan_interval, 0,
bgscan_learn_timeout, data, NULL);
} else
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
os_free(freqs);
}
static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
{
struct hostapd_hw_modes *modes;
- u16 num_modes, flags;
int i, j, *freqs = NULL, *n;
size_t count = 0;
- modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
- if (!modes)
+ modes = wpa_s->hw.modes;
+ if (modes == NULL)
return NULL;
- for (i = 0; i < num_modes; i++) {
+ for (i = 0; i < wpa_s->hw.num_modes; i++) {
for (j = 0; j < modes[i].num_channels; j++) {
if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
continue;
- n = os_realloc(freqs, (count + 2) * sizeof(int));
- if (!n)
+ /* some hw modes (e.g. 11b & 11g) contain same freqs */
+ if (in_array(freqs, modes[i].channels[j].freq))
+ continue;
+ n = os_realloc_array(freqs, count + 2, sizeof(int));
+ if (n == NULL)
continue;
freqs = n;
count++;
freqs[count] = 0;
}
- os_free(modes[i].channels);
- os_free(modes[i].rates);
}
- os_free(modes);
return freqs;
}
data->supp_freqs = bgscan_learn_get_supp_freqs(wpa_s);
data->scan_interval = data->short_interval;
+ if (data->signal_threshold) {
+ /* Poll for signal info to set initial scan interval */
+ struct wpa_signal_info siginfo;
+ if (wpa_drv_signal_poll(wpa_s, &siginfo) == 0 &&
+ siginfo.current_signal >= data->signal_threshold)
+ data->scan_interval = data->long_interval;
+ }
+
eloop_register_timeout(data->scan_interval, 0, bgscan_learn_timeout,
data, NULL);
* us skip an immediate new scan in cases where the current signal
* level is below the bgscan threshold.
*/
- os_get_time(&data->last_bgscan);
+ os_get_reltime(&data->last_bgscan);
return data;
}
static void bgscan_learn_notify_signal_change(void *priv, int above,
- int current_signal)
+ int current_signal,
+ int current_noise,
+ int current_txrate)
{
struct bgscan_learn_data *data = priv;
- struct os_time now;
+ int scan = 0;
+ struct os_reltime now;
if (data->short_interval == data->long_interval ||
data->signal_threshold == 0)
return;
wpa_printf(MSG_DEBUG, "bgscan learn: signal level changed "
- "(above=%d current_signal=%d)", above, current_signal);
+ "(above=%d current_signal=%d current_noise=%d "
+ "current_txrate=%d)", above, current_signal,
+ current_noise, current_txrate);
if (data->scan_interval == data->long_interval && !above) {
wpa_printf(MSG_DEBUG, "bgscan learn: Start using short bgscan "
"interval");
data->scan_interval = data->short_interval;
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 1)
scan = 1;
} else if (data->scan_interval == data->short_interval && above) {
* Signal dropped further 4 dB. Request a new scan if we have
* not yet scanned in a while.
*/
- os_get_time(&now);
+ os_get_reltime(&now);
if (now.sec > data->last_bgscan.sec + 10)
scan = 1;
}