Add support for specifying subset of enabled frequencies to scan
A new network block parameter, scan_freq, can be used to specify subset of frequencies to scan. This can speed up scanning process considerably if it is known that only a small subset of channels is actually used in the network. A union of configured frequencies for all enabled network blocks is used in scan requests. Currently, only driver_nl80211.c has support for this functionality. For example, following parameter marks 2.4 GHz channels 1, 6, 11 to be scanned: scan_freq=2412 2437 2462
This commit is contained in:
parent
2d5b792d2b
commit
d3a9822542
6 changed files with 201 additions and 3 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* WPA Supplicant - driver interface definition
|
* WPA Supplicant - driver interface definition
|
||||||
* Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -188,6 +188,13 @@ struct wpa_driver_scan_params {
|
||||||
* extra_ies_len - Length of extra_ies in octets
|
* extra_ies_len - Length of extra_ies in octets
|
||||||
*/
|
*/
|
||||||
size_t extra_ies_len;
|
size_t extra_ies_len;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* freqs - Array of frequencies to scan or %NULL for all frequencies
|
||||||
|
*
|
||||||
|
* The frequency is set in MHz. The array is zero-terminated.
|
||||||
|
*/
|
||||||
|
int *freqs;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1596,14 +1596,16 @@ static int wpa_driver_nl80211_scan(void *priv,
|
||||||
{
|
{
|
||||||
struct wpa_driver_nl80211_data *drv = priv;
|
struct wpa_driver_nl80211_data *drv = priv;
|
||||||
int ret = 0, timeout;
|
int ret = 0, timeout;
|
||||||
struct nl_msg *msg, *ssids;
|
struct nl_msg *msg, *ssids, *freqs;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
msg = nlmsg_alloc();
|
msg = nlmsg_alloc();
|
||||||
ssids = nlmsg_alloc();
|
ssids = nlmsg_alloc();
|
||||||
if (!msg || !ssids) {
|
freqs = nlmsg_alloc();
|
||||||
|
if (!msg || !ssids || !freqs) {
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
nlmsg_free(ssids);
|
nlmsg_free(ssids);
|
||||||
|
nlmsg_free(freqs);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1624,6 +1626,12 @@ static int wpa_driver_nl80211_scan(void *priv,
|
||||||
params->extra_ies);
|
params->extra_ies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params->freqs) {
|
||||||
|
for (i = 0; params->freqs[i]; i++)
|
||||||
|
NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
|
||||||
|
nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
|
||||||
|
}
|
||||||
|
|
||||||
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
|
||||||
msg = NULL;
|
msg = NULL;
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -1652,6 +1660,7 @@ static int wpa_driver_nl80211_scan(void *priv,
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
nlmsg_free(ssids);
|
nlmsg_free(ssids);
|
||||||
nlmsg_free(msg);
|
nlmsg_free(msg);
|
||||||
|
nlmsg_free(freqs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -917,6 +917,87 @@ static char * wpa_config_write_auth_alg(const struct parse_data *data,
|
||||||
#endif /* NO_CONFIG_WRITE */
|
#endif /* NO_CONFIG_WRITE */
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_config_parse_scan_freq(const struct parse_data *data,
|
||||||
|
struct wpa_ssid *ssid, int line,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
int *freqs;
|
||||||
|
size_t used, len;
|
||||||
|
const char *pos;
|
||||||
|
|
||||||
|
used = 0;
|
||||||
|
len = 10;
|
||||||
|
freqs = os_zalloc((len + 1) * sizeof(int));
|
||||||
|
if (freqs == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pos = value;
|
||||||
|
while (pos) {
|
||||||
|
while (*pos == ' ')
|
||||||
|
pos++;
|
||||||
|
if (used == len) {
|
||||||
|
int *n;
|
||||||
|
size_t i;
|
||||||
|
n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
|
||||||
|
if (n == NULL) {
|
||||||
|
os_free(freqs);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for (i = len; i <= len * 2; i++)
|
||||||
|
n[i] = 0;
|
||||||
|
freqs = n;
|
||||||
|
len *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
freqs[used] = atoi(pos);
|
||||||
|
if (freqs[used] == 0)
|
||||||
|
break;
|
||||||
|
used++;
|
||||||
|
pos = os_strchr(pos + 1, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
os_free(ssid->scan_freq);
|
||||||
|
ssid->scan_freq = freqs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NO_CONFIG_WRITE
|
||||||
|
static char * wpa_config_write_scan_freq(const struct parse_data *data,
|
||||||
|
struct wpa_ssid *ssid)
|
||||||
|
{
|
||||||
|
char *buf, *pos, *end;
|
||||||
|
int i, ret;
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
if (ssid->scan_freq == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
for (i = 0; ssid->scan_freq[i]; i++)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
pos = buf = os_zalloc(10 * count + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
return NULL;
|
||||||
|
end = buf + 10 * count + 1;
|
||||||
|
|
||||||
|
for (i = 0; ssid->scan_freq[i]; i++) {
|
||||||
|
ret = os_snprintf(pos, end - pos, "%s%u",
|
||||||
|
i == 0 ? "" : " ", ssid->scan_freq[i]);
|
||||||
|
if (ret < 0 || ret >= end - pos) {
|
||||||
|
end[-1] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
#endif /* NO_CONFIG_WRITE */
|
||||||
|
|
||||||
|
|
||||||
#ifdef IEEE8021X_EAPOL
|
#ifdef IEEE8021X_EAPOL
|
||||||
static int wpa_config_parse_eap(const struct parse_data *data,
|
static int wpa_config_parse_eap(const struct parse_data *data,
|
||||||
struct wpa_ssid *ssid, int line,
|
struct wpa_ssid *ssid, int line,
|
||||||
|
@ -1317,6 +1398,7 @@ static const struct parse_data ssid_fields[] = {
|
||||||
{ FUNC(pairwise) },
|
{ FUNC(pairwise) },
|
||||||
{ FUNC(group) },
|
{ FUNC(group) },
|
||||||
{ FUNC(auth_alg) },
|
{ FUNC(auth_alg) },
|
||||||
|
{ FUNC(scan_freq) },
|
||||||
#ifdef IEEE8021X_EAPOL
|
#ifdef IEEE8021X_EAPOL
|
||||||
{ FUNC(eap) },
|
{ FUNC(eap) },
|
||||||
{ STR_LENe(identity) },
|
{ STR_LENe(identity) },
|
||||||
|
@ -1540,6 +1622,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
|
||||||
eap_peer_config_free(&ssid->eap);
|
eap_peer_config_free(&ssid->eap);
|
||||||
#endif /* IEEE8021X_EAPOL */
|
#endif /* IEEE8021X_EAPOL */
|
||||||
os_free(ssid->id_str);
|
os_free(ssid->id_str);
|
||||||
|
os_free(ssid->scan_freq);
|
||||||
os_free(ssid);
|
os_free(ssid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -340,6 +340,16 @@ struct wpa_ssid {
|
||||||
* attacks against TKIP deficiencies.
|
* attacks against TKIP deficiencies.
|
||||||
*/
|
*/
|
||||||
int wpa_ptk_rekey;
|
int wpa_ptk_rekey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scan_freq - Array of frequencies to scan or %NULL for all
|
||||||
|
*
|
||||||
|
* This is an optional zero-terminated array of frequencies in
|
||||||
|
* megahertz (MHz) to include in scan requests when searching for this
|
||||||
|
* network. This can be used to speed up scanning when the network is
|
||||||
|
* known to not use all possible channels.
|
||||||
|
*/
|
||||||
|
int *scan_freq;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_SSID_H */
|
#endif /* CONFIG_SSID_H */
|
||||||
|
|
|
@ -107,6 +107,73 @@ static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int int_array_len(const int *a)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; a && a[i]; i++)
|
||||||
|
;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void int_array_concat(int **res, const int *a)
|
||||||
|
{
|
||||||
|
int reslen, alen, i;
|
||||||
|
int *n;
|
||||||
|
|
||||||
|
reslen = int_array_len(*res);
|
||||||
|
alen = int_array_len(a);
|
||||||
|
|
||||||
|
n = os_realloc(*res, (reslen + alen + 1) * sizeof(int));
|
||||||
|
if (n == NULL) {
|
||||||
|
os_free(*res);
|
||||||
|
*res = NULL;
|
||||||
|
}
|
||||||
|
for (i = 0; i <= alen; i++)
|
||||||
|
n[reslen + i] = a[i];
|
||||||
|
*res = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int freq_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
int _a = *(int *) a;
|
||||||
|
int _b = *(int *) b;
|
||||||
|
|
||||||
|
if (_a == 0)
|
||||||
|
return 1;
|
||||||
|
if (_b == 0)
|
||||||
|
return -1;
|
||||||
|
return _a - _b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void int_array_sort_unique(int *a)
|
||||||
|
{
|
||||||
|
int alen;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (a == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
alen = int_array_len(a);
|
||||||
|
qsort(a, alen, sizeof(int), freq_cmp);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
j = 1;
|
||||||
|
while (a[i] && a[j]) {
|
||||||
|
if (a[i] == a[j]) {
|
||||||
|
j++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
a[++i] = a[j++];
|
||||||
|
}
|
||||||
|
if (a[i])
|
||||||
|
i++;
|
||||||
|
a[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
|
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
|
||||||
{
|
{
|
||||||
struct wpa_supplicant *wpa_s = eloop_ctx;
|
struct wpa_supplicant *wpa_s = eloop_ctx;
|
||||||
|
@ -198,6 +265,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
|
||||||
ssid = NULL;
|
ssid = NULL;
|
||||||
} else {
|
} else {
|
||||||
struct wpa_ssid *start = ssid;
|
struct wpa_ssid *start = ssid;
|
||||||
|
int freqs_set = 0;
|
||||||
if (ssid == NULL && max_ssids > 1)
|
if (ssid == NULL && max_ssids > 1)
|
||||||
ssid = wpa_s->conf->ssid;
|
ssid = wpa_s->conf->ssid;
|
||||||
while (ssid) {
|
while (ssid) {
|
||||||
|
@ -219,6 +287,20 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
|
||||||
start != wpa_s->conf->ssid)
|
start != wpa_s->conf->ssid)
|
||||||
ssid = wpa_s->conf->ssid;
|
ssid = wpa_s->conf->ssid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
|
||||||
|
if (ssid->disabled)
|
||||||
|
continue;
|
||||||
|
if ((params.freqs || !freqs_set) && ssid->scan_freq) {
|
||||||
|
int_array_concat(¶ms.freqs,
|
||||||
|
ssid->scan_freq);
|
||||||
|
} else {
|
||||||
|
os_free(params.freqs);
|
||||||
|
params.freqs = NULL;
|
||||||
|
}
|
||||||
|
freqs_set = 1;
|
||||||
|
}
|
||||||
|
int_array_sort_unique(params.freqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssid) {
|
if (ssid) {
|
||||||
|
@ -258,6 +340,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
wpabuf_free(wps_ie);
|
wpabuf_free(wps_ie);
|
||||||
|
os_free(params.freqs);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
|
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
|
||||||
|
|
|
@ -256,6 +256,12 @@ fast_reauth=1
|
||||||
# an IBSS network with the configured SSID is already present, the frequency of
|
# an IBSS network with the configured SSID is already present, the frequency of
|
||||||
# the network will be used instead of this configured value.
|
# the network will be used instead of this configured value.
|
||||||
#
|
#
|
||||||
|
# scan_freq: List of frequencies to scan
|
||||||
|
# Space-separated list of frequencies in MHz to scan when searching for this
|
||||||
|
# BSS. If the subset of channels used by the network is known, this option can
|
||||||
|
# be used to optimize scanning to not occur on channels that the network does
|
||||||
|
# not use. Example: scan_freq=2412 2437 2462
|
||||||
|
#
|
||||||
# proto: list of accepted protocols
|
# proto: list of accepted protocols
|
||||||
# WPA = WPA/IEEE 802.11i/D3.0
|
# WPA = WPA/IEEE 802.11i/D3.0
|
||||||
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
|
# RSN = WPA2/IEEE 802.11i (also WPA2 can be used as an alias for RSN)
|
||||||
|
|
Loading…
Reference in a new issue