/* * At this point it's assumed chan->interface_factor has been computed. * This function should be reusable regardless of interference computation * option (survey, BSS, spectral, ...). chan->interference factor must be * summable (i.e., must be always greater than zero). */ static struct hostapd_channel_data * acs_find_ideal_chan(struct hostapd_iface *iface) { 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; unsigned int k; /* TODO: HT40- support */ if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) { wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); return NULL; } if (iface->conf->ieee80211n && iface->conf->secondary_channel) n_chans = 2; if (iface->conf->ieee80211ac && iface->conf->vht_oper_chwidth == 1) n_chans = 4; /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */ wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz", n_chans == 1 ? 20 : n_chans == 2 ? 40 : n_chans == 4 ? 80 : -1); for (i = 0; i < iface->current_mode->num_channels; i++) { double total_weight; struct acs_bias *bias, tmp_bias; chan = &iface->current_mode->channels[i]; if (chan->flag & HOSTAPD_CHAN_DISABLED) continue; if (!is_in_chanlist(iface, chan)) 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 && iface->conf->ieee80211n && iface->conf->secondary_channel && !acs_usable_ht40_chan(chan)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40", chan->chan); continue; } if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && iface->conf->ieee80211ac && iface->conf->vht_oper_chwidth == 1 && !acs_usable_vht80_chan(chan)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80", chan->chan); continue; } factor = 0; if (acs_usable_chan(chan)) factor = chan->interference_factor; total_weight = 1; for (j = 1; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20)); if (!adj_chan) break; if (acs_usable_chan(adj_chan)) { factor += adj_chan->interference_factor; total_weight += 1; } } if (j != n_chans) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", chan->chan); continue; } /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ if (is_24ghz_mode(iface->current_mode->mode)) { for (j = 0; j < n_chans; j++) { adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_ADJ_WEIGHT * adj_chan->interference_factor; total_weight += ACS_ADJ_WEIGHT; } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 10); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_NEXT_ADJ_WEIGHT * adj_chan->interference_factor; total_weight += ACS_NEXT_ADJ_WEIGHT; } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 5); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_ADJ_WEIGHT * adj_chan->interference_factor; total_weight += ACS_ADJ_WEIGHT; } adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 10); if (adj_chan && acs_usable_chan(adj_chan)) { factor += ACS_NEXT_ADJ_WEIGHT * adj_chan->interference_factor; total_weight += ACS_NEXT_ADJ_WEIGHT; } } } factor /= total_weight; bias = NULL; if (iface->conf->acs_chan_bias) { for (k = 0; k < iface->conf->num_acs_chan_bias; k++) { bias = &iface->conf->acs_chan_bias[k]; if (bias->channel == chan->chan) break; bias = NULL; } } else if (is_24ghz_mode(iface->current_mode->mode) && is_common_24ghz_chan(chan->chan)) { tmp_bias.channel = chan->chan; tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11; bias = &tmp_bias; } if (bias) { factor *= bias->bias; wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg (%f bias)", chan->chan, factor, bias->bias); } else { wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg", chan->chan, 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) { 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 rand_chan; }
/* * At this point it's assumed chan->interface_factor has been computed. * This function should be reusable regardless of interference computation * option (survey, BSS, spectral, ...). chan->interference factor must be * summable (i.e., must be always greater than zero). */ static struct hostapd_channel_data * acs_find_ideal_chan(struct hostapd_iface *iface) { 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; /* TODO: HT40- support */ if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) { wpa_printf(MSG_ERROR, "ACS: HT40- is not supported yet. Please try HT40+"); return NULL; } if (iface->conf->ieee80211n && iface->conf->secondary_channel) n_chans = 2; if (iface->conf->ieee80211ac && iface->conf->vht_oper_chwidth == 1) n_chans = 4; /* TODO: VHT80+80, VHT160. Update acs_adjust_vht_center_freq() too. */ wpa_printf(MSG_DEBUG, "ACS: Survey analysis for selected bandwidth %d MHz", n_chans == 1 ? 20 : n_chans == 2 ? 40 : n_chans == 4 ? 80 : -1); for (i = 0; i < iface->current_mode->num_channels; i++) { chan = &iface->current_mode->channels[i]; 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 && iface->conf->ieee80211n && iface->conf->secondary_channel && !acs_usable_ht40_chan(chan)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for HT40", chan->chan); continue; } if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A && iface->conf->ieee80211ac && iface->conf->vht_oper_chwidth == 1 && !acs_usable_vht80_chan(chan)) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not allowed as primary channel for VHT80", chan->chan); continue; } 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; if (acs_usable_chan(adj_chan)) factor += adj_chan->interference_factor; } if (j != n_chans) { wpa_printf(MSG_DEBUG, "ACS: Channel %d: not enough bandwidth", chan->chan); continue; } /* 2.4 GHz has overlapping 20 MHz channels. Include adjacent * channel interference factor. */ if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B || iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) { for (j = 0; j < n_chans; j++) { /* TODO: perhaps a multiplier should be used * here? */ adj_chan = acs_find_chan(iface, chan->freq + (j * 20) - 5); 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 && acs_usable_chan(adj_chan)) factor += adj_chan->interference_factor; adj_chan = acs_find_chan(iface, chan->freq + (j * 20) + 5); 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 && acs_usable_chan(adj_chan)) factor += adj_chan->interference_factor; } } wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg", chan->chan, 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) { 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 rand_chan; }