From 4b37d242857d7e5825faa26b09017b64beb230fb Mon Sep 17 00:00:00 2001 From: Seevalamuthu Mariappan Date: Fri, 13 Dec 2019 15:46:41 +0530 Subject: [PATCH] hostapd: Fix to downgrade bandwidth in radar detection Upon radar detection we used to search channels with the same bandwidth. This way we might not find any other channels. If there are no channels available with that bandwidth the AP service will be stopped. To avoid this problem, also search a suitable channel by downgrading the bandwidth. This scenario is applicable during CAC as well. Signed-off-by: Seevalamuthu Mariappan --- src/ap/dfs.c | 90 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 67 insertions(+), 23 deletions(-) diff --git a/src/ap/dfs.c b/src/ap/dfs.c index 554231e18..d0b448e29 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -851,6 +851,41 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq, } +static struct hostapd_channel_data * +dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, + u8 *oper_centr_freq_seg0_idx, + u8 *oper_centr_freq_seg1_idx, int *skip_radar) +{ + struct hostapd_channel_data *channel; + + for (;;) { + channel = dfs_get_valid_channel(iface, secondary_channel, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, + *skip_radar); + if (channel) { + wpa_printf(MSG_DEBUG, "DFS: Selected channel: %d", + channel->chan); + return channel; + } + + if (*skip_radar) { + *skip_radar = 0; + } else { + if (iface->conf->vht_oper_chwidth == CHANWIDTH_USE_HT) + break; + *skip_radar = 1; + iface->conf->vht_oper_chwidth--; + } + } + + wpa_printf(MSG_INFO, + "%s: no DFS channels left, waiting for NOP to finish", + __func__); + return NULL; +} + + static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; @@ -868,8 +903,14 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) skip_radar); if (!channel) { - wpa_printf(MSG_ERROR, "No valid channel available"); - return err; + channel = dfs_downgrade_bandwidth(iface, &secondary_channel, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &skip_radar); + if (!channel) { + wpa_printf(MSG_ERROR, "No valid channel available"); + return err; + } } wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", @@ -898,11 +939,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) int secondary_channel; u8 oper_centr_freq_seg0_idx; u8 oper_centr_freq_seg1_idx; + u8 new_vht_oper_chwidth; int skip_radar = 1; struct csa_settings csa_settings; unsigned int i; int err = 1; struct hostapd_hw_modes *cmode = iface->current_mode; + u8 current_vht_oper_chwidth = iface->conf->vht_oper_chwidth; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -936,28 +979,25 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) * requires to perform a CAC first. */ skip_radar = 0; - channel = dfs_get_valid_channel(iface, &secondary_channel, - &oper_centr_freq_seg0_idx, - &oper_centr_freq_seg1_idx, - skip_radar); - if (!channel) { - wpa_printf(MSG_INFO, - "%s: no DFS channels left, waiting for NOP to finish", - __func__); + channel = dfs_downgrade_bandwidth(iface, &secondary_channel, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &skip_radar); + if (!channel) return err; + if (!skip_radar) { + iface->freq = channel->freq; + iface->conf->channel = channel->chan; + iface->conf->secondary_channel = secondary_channel; + hostapd_set_oper_centr_freq_seg0_idx( + iface->conf, oper_centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx( + iface->conf, oper_centr_freq_seg1_idx); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + return 0; } - - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - hostapd_set_oper_centr_freq_seg0_idx(iface->conf, - oper_centr_freq_seg0_idx); - hostapd_set_oper_centr_freq_seg1_idx(iface->conf, - oper_centr_freq_seg1_idx); - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; } wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", @@ -966,6 +1006,9 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) "freq=%d chan=%d sec_chan=%d", channel->freq, channel->chan, secondary_channel); + new_vht_oper_chwidth = iface->conf->vht_oper_chwidth; + iface->conf->vht_oper_chwidth = current_vht_oper_chwidth; + /* Setup CSA request */ os_memset(&csa_settings, 0, sizeof(csa_settings)); csa_settings.cs_count = 5; @@ -980,7 +1023,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) iface->conf->ieee80211ac, iface->conf->ieee80211ax, secondary_channel, - hostapd_get_oper_chwidth(iface->conf), + new_vht_oper_chwidth, oper_centr_freq_seg0_idx, oper_centr_freq_seg1_idx, cmode->vht_capab, @@ -1004,6 +1047,7 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) iface->freq = channel->freq; iface->conf->channel = channel->chan; iface->conf->secondary_channel = secondary_channel; + iface->conf->vht_oper_chwidth = new_vht_oper_chwidth; hostapd_set_oper_centr_freq_seg0_idx(iface->conf, oper_centr_freq_seg0_idx); hostapd_set_oper_centr_freq_seg1_idx(iface->conf,