This is a preliminary patch to add Channel Switch Announcement for background radar detection. Tested-by: Owen Peng <owen.peng@xxxxxxxxxxxx> Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> --- src/ap/dfs.c | 159 +++++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 75 deletions(-) diff --git a/src/ap/dfs.c b/src/ap/dfs.c index 94ef87d87..bd8a2484d 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -940,6 +940,85 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) return dfs_check_chans_available(iface, start_chan_idx, n_chans); } +static int hostapd_dfs_request_channel_switch(struct hostapd_iface *iface, + int channel, int freq, + int secondary_channel, + u8 oper_centr_freq_seg0_idx, + u8 oper_centr_freq_seg1_idx) +{ + struct hostapd_hw_modes *cmode = iface->current_mode; + int ieee80211_mode = IEEE80211_MODE_AP, err, i; + struct csa_settings csa_settings; + u8 new_vht_oper_chwidth; + + wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", channel); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL + "freq=%d chan=%d sec_chan=%d", freq, channel, + secondary_channel); + + new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); + hostapd_set_oper_chwidth(iface->conf, + hostapd_get_oper_chwidth(iface->conf)); + + /* Setup CSA request */ + os_memset(&csa_settings, 0, sizeof(csa_settings)); + csa_settings.cs_count = 5; + csa_settings.block_tx = 1; +#ifdef CONFIG_MESH + if (iface->mconf) + ieee80211_mode = IEEE80211_MODE_MESH; +#endif /* CONFIG_MESH */ + err = hostapd_set_freq_params(&csa_settings.freq_params, + iface->conf->hw_mode, + freq, channel, + iface->conf->enable_edmg, + iface->conf->edmg_channel, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + secondary_channel, + new_vht_oper_chwidth, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, + cmode->vht_capab, + &cmode->he_capab[ieee80211_mode]); + + if (err) { + wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); + hostapd_disable_iface(iface); + return err; + } + + for (i = 0; i < iface->num_bss; i++) { + err = hostapd_switch_channel(iface->bss[i], &csa_settings); + if (err) + break; + } + + if (err) { + wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", + err); + iface->freq = freq; + iface->conf->channel = channel; + iface->conf->secondary_channel = secondary_channel; + hostapd_set_oper_chwidth(iface->conf, 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, + oper_centr_freq_seg1_idx); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + + return 0; + } + + /* Channel configuration will be updated once CSA completes and + * ch_switch_notify event is received */ + wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); + + return 0; +} static struct hostapd_channel_data * dfs_downgrade_bandwidth(struct hostapd_iface *iface, int *secondary_channel, @@ -1179,21 +1258,13 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) return err; } - static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; 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 = hostapd_get_oper_chwidth(iface->conf); - int ieee80211_mode = IEEE80211_MODE_AP; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", @@ -1256,73 +1327,11 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) } } - wpa_printf(MSG_DEBUG, "DFS will switch to a new channel %d", - channel->chan); - wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NEW_CHANNEL - "freq=%d chan=%d sec_chan=%d", channel->freq, - channel->chan, secondary_channel); - - new_vht_oper_chwidth = hostapd_get_oper_chwidth(iface->conf); - hostapd_set_oper_chwidth(iface->conf, current_vht_oper_chwidth); - - /* Setup CSA request */ - os_memset(&csa_settings, 0, sizeof(csa_settings)); - csa_settings.cs_count = 5; - csa_settings.block_tx = 1; -#ifdef CONFIG_MESH - if (iface->mconf) - ieee80211_mode = IEEE80211_MODE_MESH; -#endif /* CONFIG_MESH */ - err = hostapd_set_freq_params(&csa_settings.freq_params, - iface->conf->hw_mode, - channel->freq, - channel->chan, - iface->conf->enable_edmg, - iface->conf->edmg_channel, - iface->conf->ieee80211n, - iface->conf->ieee80211ac, - iface->conf->ieee80211ax, - secondary_channel, - new_vht_oper_chwidth, - oper_centr_freq_seg0_idx, - oper_centr_freq_seg1_idx, - cmode->vht_capab, - &cmode->he_capab[ieee80211_mode]); - - if (err) { - wpa_printf(MSG_ERROR, "DFS failed to calculate CSA freq params"); - hostapd_disable_iface(iface); - return err; - } - - for (i = 0; i < iface->num_bss; i++) { - err = hostapd_switch_channel(iface->bss[i], &csa_settings); - if (err) - break; - } - - if (err) { - wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", - err); - iface->freq = channel->freq; - iface->conf->channel = channel->chan; - iface->conf->secondary_channel = secondary_channel; - hostapd_set_oper_chwidth(iface->conf, 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, - oper_centr_freq_seg1_idx); - - hostapd_disable_iface(iface); - hostapd_enable_iface(iface); - return 0; - } - - /* Channel configuration will be updated once CSA completes and - * ch_switch_notify event is received */ - - wpa_printf(MSG_DEBUG, "DFS waiting channel switch event"); - return 0; + return hostapd_dfs_request_channel_switch(iface, channel->chan, + channel->freq, + secondary_channel, + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx); } -- 2.33.1