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);
}
diff --git a/src/eap_peer/eap_proxy.h b/src/eap_peer/eap_proxy.h
index 3b4dcef..23cdbe6 100644
--- a/src/eap_peer/eap_proxy.h
+++ b/src/eap_peer/eap_proxy.h
@@ -40,7 +40,8 @@
int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen,
int verbose);
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len);
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+ size_t *imsi_len);
int eap_proxy_notify_config(struct eap_proxy_sm *sm,
struct eap_peer_config *config);
diff --git a/src/eap_peer/eap_proxy_dummy.c b/src/eap_peer/eap_proxy_dummy.c
index cd97fb6..d84f012 100644
--- a/src/eap_peer/eap_proxy_dummy.c
+++ b/src/eap_peer/eap_proxy_dummy.c
@@ -63,7 +63,8 @@
}
-int eap_proxy_get_imsi(char *imsi_buf, size_t *imsi_len)
+int eap_proxy_get_imsi(struct eap_proxy_sm *eap_proxy, char *imsi_buf,
+ size_t *imsi_len)
{
return -1;
}
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 03ec2cb..9d7aef0 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -2051,3 +2051,15 @@
return 0;
return !sm->eapSuccess && sm->eapFail;
}
+
+
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
+{
+#ifdef CONFIG_EAP_PROXY
+ if (sm->eap_proxy == NULL)
+ return -1;
+ return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
+#else /* CONFIG_EAP_PROXY */
+ return -1;
+#endif /* CONFIG_EAP_PROXY */
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 6faf816..54e8a27 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -292,6 +292,7 @@
void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
struct ext_password_data *ext);
int eapol_sm_failed(struct eapol_sm *sm);
+int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index bd583be..eea946f 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -471,9 +471,11 @@
u8 *status)
{
struct p2p_channels intersection;
- size_t i;
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &dev->channels);
p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
+ p2p_channels_dump(p2p, "intersection", &intersection);
if (intersection.reg_classes == 0 ||
intersection.reg_class[0].channels == 0) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
@@ -481,14 +483,6 @@
return -1;
}
- for (i = 0; i < intersection.reg_classes; i++) {
- struct p2p_reg_class *c;
- c = &intersection.reg_class[i];
- p2p_dbg(p2p, "reg_class %u", c->reg_class);
- wpa_hexdump(MSG_DEBUG, "P2P: channels",
- c->channel, c->channels);
- }
-
if (!p2p_channels_includes(&intersection, p2p->op_reg_class,
p2p->op_channel)) {
if (dev->flags & P2P_DEV_FORCE_FREQ) {
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index f323ef7..f9b1e68 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -580,6 +580,8 @@
struct p2p_channels *res);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan);
#ifdef ANDROID_P2P
size_t p2p_copy_reg_class(struct p2p_reg_class *dc, struct p2p_reg_class *sc);
#endif
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a4c48f6..8c2d2de 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -310,3 +310,36 @@
return 0;
}
+
+
+void p2p_channels_dump(struct p2p_data *p2p, const char *title,
+ const struct p2p_channels *chan)
+{
+ char buf[500], *pos, *end;
+ size_t i, j;
+ int ret;
+
+ pos = buf;
+ end = pos + sizeof(buf);
+
+ for (i = 0; i < chan->reg_classes; i++) {
+ const struct p2p_reg_class *c;
+ c = &chan->reg_class[i];
+ ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+
+ for (j = 0; j < c->channels; j++) {
+ ret = os_snprintf(pos, end - pos, "%s%u",
+ j == 0 ? "" : ",",
+ c->channel[j]);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+ }
+ }
+ *pos = '\0';
+
+ p2p_dbg(p2p, "%s:%s", title, buf);
+}
diff --git a/src/utils/common.c b/src/utils/common.c
index 207d477..5734de7 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -624,3 +624,99 @@
return res;
}
+
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value)
+{
+ struct wpa_freq_range *freq = NULL, *n;
+ unsigned int count = 0;
+ const char *pos, *pos2, *pos3;
+
+ /*
+ * Comma separated list of frequency ranges.
+ * For example: 2412-2432,2462,5000-6000
+ */
+ pos = value;
+ while (pos && pos[0]) {
+ n = os_realloc_array(freq, count + 1,
+ sizeof(struct wpa_freq_range));
+ if (n == NULL) {
+ os_free(freq);
+ return -1;
+ }
+ freq = n;
+ freq[count].min = atoi(pos);
+ pos2 = os_strchr(pos, '-');
+ pos3 = os_strchr(pos, ',');
+ if (pos2 && (!pos3 || pos2 < pos3)) {
+ pos2++;
+ freq[count].max = atoi(pos2);
+ } else
+ freq[count].max = freq[count].min;
+ pos = pos3;
+ if (pos)
+ pos++;
+ count++;
+ }
+
+ os_free(res->range);
+ res->range = freq;
+ res->num = count;
+
+ return 0;
+}
+
+
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+ unsigned int freq)
+{
+ unsigned int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0; i < list->num; i++) {
+ if (freq >= list->range[i].min && freq <= list->range[i].max)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+char * freq_range_list_str(const struct wpa_freq_range_list *list)
+{
+ char *buf, *pos, *end;
+ size_t maxlen;
+ unsigned int i;
+ int res;
+
+ if (list->num == 0)
+ return NULL;
+
+ maxlen = list->num * 30;
+ buf = os_malloc(maxlen);
+ if (buf == NULL)
+ return NULL;
+ pos = buf;
+ end = buf + maxlen;
+
+ for (i = 0; i < list->num; i++) {
+ struct wpa_freq_range *range = &list->range[i];
+
+ if (range->min == range->max)
+ res = os_snprintf(pos, end - pos, "%s%u",
+ i == 0 ? "" : ",", range->min);
+ else
+ res = os_snprintf(pos, end - pos, "%s%u-%u",
+ i == 0 ? "" : ",",
+ range->min, range->max);
+ if (res < 0 || res > end - pos) {
+ os_free(buf);
+ return NULL;
+ }
+ pos += res;
+ }
+
+ return buf;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 29f0b95..399ab79 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -505,6 +505,20 @@
#include "wpa_debug.h"
+struct wpa_freq_range_list {
+ struct wpa_freq_range {
+ unsigned int min;
+ unsigned int max;
+ } *range;
+ unsigned int num;
+};
+
+int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
+int freq_range_list_includes(const struct wpa_freq_range_list *list,
+ unsigned int freq);
+char * freq_range_list_str(const struct wpa_freq_range_list *list);
+
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
* networking socket uses that do not really result in a real problem and