diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/ap/acs.c | 109 | ||||
| -rw-r--r-- | src/ap/acs.h | 2 | ||||
| -rw-r--r-- | src/ap/hw_features.c | 17 | ||||
| -rw-r--r-- | src/eap_peer/eap_proxy.h | 3 | ||||
| -rw-r--r-- | src/eap_peer/eap_proxy_dummy.c | 3 | ||||
| -rw-r--r-- | src/eapol_supp/eapol_supp_sm.c | 12 | ||||
| -rw-r--r-- | src/eapol_supp/eapol_supp_sm.h | 1 | ||||
| -rw-r--r-- | src/p2p/p2p_go_neg.c | 12 | ||||
| -rw-r--r-- | src/p2p/p2p_i.h | 2 | ||||
| -rw-r--r-- | src/p2p/p2p_utils.c | 33 | ||||
| -rw-r--r-- | src/utils/common.c | 96 | ||||
| -rw-r--r-- | src/utils/common.h | 14 |
12 files changed, 244 insertions, 60 deletions
diff --git a/src/ap/acs.c b/src/ap/acs.c index d5e3f596..8536e481 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -352,16 +352,6 @@ acs_survey_chan_interference_factor(struct hostapd_iface *iface, } -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_is_sufficient(struct freq_survey *survey) } +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 @@ static struct hostapd_channel_data *acs_find_chan(struct hostapd_iface *iface, 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_chan(struct hostapd_iface *iface, 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 @@ acs_find_ideal_chan(struct hostapd_iface *iface) 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 @@ acs_find_ideal_chan(struct hostapd_iface *iface) 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 @@ acs_find_ideal_chan(struct hostapd_iface *iface) 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 @@ acs_find_ideal_chan(struct hostapd_iface *iface) 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 @@ static void acs_study(struct hostapd_iface *iface) 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 @@ static void acs_study(struct hostapd_iface *iface) 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 0d1d0f1a..a41f17f3 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 9e5becc3..609ed535 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -758,9 +758,12 @@ static void hostapd_notify_bad_chans(struct hostapd_iface *iface) } -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 @@ int hostapd_acs_completed(struct hostapd_iface *iface) 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 3b4dceff..23cdbe69 100644 --- a/src/eap_peer/eap_proxy.h +++ b/src/eap_peer/eap_proxy.h @@ -40,7 +40,8 @@ eap_proxy_packet_update(struct eap_proxy_sm *eap_proxy, u8 *eapReqData, 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 cd97fb66..d84f0123 100644 --- a/src/eap_peer/eap_proxy_dummy.c +++ b/src/eap_peer/eap_proxy_dummy.c @@ -63,7 +63,8 @@ int eap_proxy_sm_get_status(struct eap_proxy_sm *sm, char *buf, size_t buflen, } -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 03ec2cb4..9d7aef04 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -2051,3 +2051,15 @@ int eapol_sm_failed(struct eapol_sm *sm) 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 6faf816d..54e8a271 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -292,6 +292,7 @@ const char * eapol_sm_get_method_name(struct eapol_sm *sm); 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 bd583be8..eea946fa 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -471,9 +471,11 @@ static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, 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 @@ static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev, 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 f323ef72..f9b1e686 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -580,6 +580,8 @@ void p2p_channels_intersect(const struct p2p_channels *a, 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 a4c48f67..8c2d2de2 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -310,3 +310,36 @@ unsigned int p2p_get_pref_freq(struct p2p_data *p2p, 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 207d4778..5734de71 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -624,3 +624,99 @@ char * dup_binstr(const void *src, size_t len) 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 29f0b953..399ab796 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -505,6 +505,20 @@ static inline int is_broadcast_ether_addr(const u8 *a) #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 |
