Cumulative patch from commit fa56315cfc9ebaff2b210ed99d43dda9b16bdf56
fa56315 eap_proxy: Add context data pointer to the get_imsi call
07041c6 eap_proxy: Confirm eap_proxy initialization before reading SIM info
47d986e P2P: Check Action frame payload match before accepted TX status
d259249 Fix ENABLE_NETWORK not to reconnect in disconnected state
677cf19 hostapd: Select any supported channel if ACS fails
20f9cb1 hostapd: Allow ACS to deal with partial survey data
3645fd5 hostapd: Propagate ACS errors to iface setup
0e1d0b3 hostapd: Don't get stuck after failed ACS
af8a827 Make frequency range list routines more general
941dae0 P2P: Add more user friendly debug print of channel lists
Change-Id: I942dbbc0cb92f4e09626ec6ea17f6ea583c17f1a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index d5e3f59..8536e48 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -352,16 +352,6 @@
}
-static int acs_usable_chan(struct hostapd_channel_data *chan)
-{
- if (dl_list_empty(&chan->survey_list))
- return 0;
- if (chan->flag & HOSTAPD_CHAN_DISABLED)
- return 0;
- return 1;
-}
-
-
static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
{
const int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149,
@@ -398,28 +388,54 @@
}
+static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
+{
+ struct freq_survey *survey;
+
+ dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
+ {
+ if (!acs_survey_is_sufficient(survey)) {
+ wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data",
+ chan->chan);
+ return 0;
+ }
+ }
+
+ return 1;
+
+}
+
+
static int acs_surveys_are_sufficient(struct hostapd_iface *iface)
{
int i;
struct hostapd_channel_data *chan;
- struct freq_survey *survey;
+ int valid = 0;
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
- dl_list_for_each(survey, &chan->survey_list,
- struct freq_survey, list)
- {
- if (!acs_survey_is_sufficient(survey)) {
- wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data",
- chan->chan);
- return 0;
- }
- }
+ if (!acs_survey_list_is_sufficient(chan))
+ continue;
+
+ valid++;
}
+ /* We need at least survey data for one channel */
+ return !!valid;
+}
+
+
+static int acs_usable_chan(struct hostapd_channel_data *chan)
+{
+ if (dl_list_empty(&chan->survey_list))
+ return 0;
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
+ return 0;
+ if (!acs_survey_list_is_sufficient(chan))
+ return 0;
return 1;
}
@@ -456,7 +472,7 @@
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
- if (!acs_usable_chan(chan))
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
if (chan->freq == freq)
@@ -476,7 +492,8 @@
static struct hostapd_channel_data *
acs_find_ideal_chan(struct hostapd_iface *iface)
{
- struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL;
+ struct hostapd_channel_data *chan, *adj_chan, *ideal_chan = NULL,
+ *rand_chan = NULL;
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
@@ -508,9 +525,10 @@
for (i = 0; i < iface->current_mode->num_channels; i++) {
chan = &iface->current_mode->channels[i];
- if (!acs_usable_chan(chan))
+ if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
+
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A &&
@@ -522,14 +540,17 @@
continue;
}
- factor = chan->interference_factor;
+ factor = 0;
+ if (acs_usable_chan(chan))
+ factor = chan->interference_factor;
for (j = 1; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
if (!adj_chan)
break;
- factor += adj_chan->interference_factor;
+ if (acs_usable_chan(adj_chan))
+ factor += adj_chan->interference_factor;
}
if (j != n_chans) {
@@ -548,22 +569,22 @@
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
- if (adj_chan)
+ if (adj_chan && acs_usable_chan(adj_chan))
factor += adj_chan->interference_factor;
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 10);
- if (adj_chan)
+ if (adj_chan && acs_usable_chan(adj_chan))
factor += adj_chan->interference_factor;
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 5);
- if (adj_chan)
+ if (adj_chan && acs_usable_chan(adj_chan))
factor += adj_chan->interference_factor;
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 10);
- if (adj_chan)
+ if (adj_chan && acs_usable_chan(adj_chan))
factor += adj_chan->interference_factor;
}
}
@@ -571,17 +592,24 @@
wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg",
chan->chan, factor);
- if (!ideal_chan || factor < ideal_factor) {
+ if (acs_usable_chan(chan) &&
+ (!ideal_chan || factor < ideal_factor)) {
ideal_factor = factor;
ideal_chan = chan;
}
+
+ /* This channel would at least be usable */
+ if (!rand_chan)
+ rand_chan = chan;
}
- if (ideal_chan)
+ if (ideal_chan) {
wpa_printf(MSG_DEBUG, "ACS: Ideal channel is %d (%d MHz) with total interference factor of %Lg",
ideal_chan->chan, ideal_chan->freq, ideal_factor);
+ return ideal_chan;
+ }
- return ideal_chan;
+ return rand_chan;
}
@@ -655,6 +683,7 @@
ideal_chan = acs_find_ideal_chan(iface);
if (!ideal_chan) {
wpa_printf(MSG_ERROR, "ACS: Failed to compute ideal channel");
+ err = -1;
goto fail;
}
@@ -663,24 +692,20 @@
if (iface->conf->ieee80211ac)
acs_adjust_vht_center_freq(iface);
+ err = 0;
+fail:
/*
* hostapd_setup_interface_complete() will return -1 on failure,
* 0 on success and 0 is HOSTAPD_CHAN_VALID :)
*/
- switch (hostapd_acs_completed(iface)) {
- case HOSTAPD_CHAN_VALID:
+ if (hostapd_acs_completed(iface, err) == HOSTAPD_CHAN_VALID) {
acs_cleanup(iface);
return;
- case HOSTAPD_CHAN_INVALID:
- case HOSTAPD_CHAN_ACS:
- default:
- /* This can possibly happen if channel parameters (secondary
- * channel, center frequencies) are misconfigured */
- wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
- goto fail;
}
-fail:
+ /* This can possibly happen if channel parameters (secondary
+ * channel, center frequencies) are misconfigured */
+ wpa_printf(MSG_ERROR, "ACS: Possibly channel configuration is invalid, please report this along with your config file.");
acs_fail(iface);
}
diff --git a/src/ap/acs.h b/src/ap/acs.h
index 0d1d0f1..a41f17f 100644
--- a/src/ap/acs.h
+++ b/src/ap/acs.h
@@ -13,7 +13,7 @@
#ifdef CONFIG_ACS
enum hostapd_chan_status acs_init(struct hostapd_iface *iface);
-int hostapd_acs_completed(struct hostapd_iface *iface);
+int hostapd_acs_completed(struct hostapd_iface *iface, int err);
#else /* CONFIG_ACS */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 9e5becc..609ed53 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -758,9 +758,12 @@
}
-int hostapd_acs_completed(struct hostapd_iface *iface)
+int hostapd_acs_completed(struct hostapd_iface *iface, int err)
{
- int ret;
+ int ret = -1;
+
+ if (err)
+ goto out;
switch (hostapd_check_chans(iface)) {
case HOSTAPD_CHAN_VALID:
@@ -768,23 +771,25 @@
case HOSTAPD_CHAN_ACS:
wpa_printf(MSG_ERROR, "ACS error - reported complete, but no result available");
hostapd_notify_bad_chans(iface);
- return -1;
+ goto out;
case HOSTAPD_CHAN_INVALID:
default:
wpa_printf(MSG_ERROR, "ACS picked unusable channels");
hostapd_notify_bad_chans(iface);
- return -1;
+ goto out;
}
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
- return -1;
+ goto out;
if (ret == 1) {
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback");
return 0;
}
- return hostapd_setup_interface_complete(iface, 0);
+ ret = 0;
+out:
+ return hostapd_setup_interface_complete(iface, ret);
}