diff options
Diffstat (limited to 'src/ap/acs.c')
| -rw-r--r-- | src/ap/acs.c | 109 |
1 files changed, 67 insertions, 42 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); } |
