Introduce the capability to perfrom radar/CAC detection on a offchannel radar chain available on some hw (e.g. mt7915). This feature allows to avoid CAC downtime switching on a different channel during CAC detection on the selected radar channel. Tested-by: Owen Peng <owen.peng@xxxxxxxxxxxx> Signed-off-by: Lorenzo Bianconi <lorenzo@xxxxxxxxxx> --- src/ap/ap_drv_ops.c | 9 ++- src/ap/ap_drv_ops.h | 3 +- src/ap/dfs.c | 129 ++++++++++++++++++++++++++++++++++- src/ap/hostapd.h | 15 ++++ src/drivers/driver.h | 5 ++ src/drivers/driver_nl80211.c | 5 ++ 6 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index e91773666..63791330b 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -812,7 +812,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int channel, int ht_enabled, int vht_enabled, int he_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1) + int center_segment0, int center_segment1, + int radar_background) { struct hostapd_data *hapd = iface->bss[0]; struct hostapd_freq_params data; @@ -838,10 +839,14 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, wpa_printf(MSG_ERROR, "Can't set freq params"); return -1; } + data.radar_background = radar_background; res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data); if (!res) { - iface->cac_started = 1; + if (radar_background) + iface->radar_background.cac_started = 1; + else + iface->cac_started = 1; os_get_reltime(&iface->dfs_cac_start); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 61c8f64eb..92842a1dc 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -130,7 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface, int channel, int ht_enabled, int vht_enabled, int he_enabled, int sec_channel_offset, int oper_chwidth, - int center_segment0, int center_segment1); + int center_segment0, int center_segment1, + int radar_offchan); int hostapd_drv_do_acs(struct hostapd_data *hapd); int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer, u16 reason_code, const u8 *ie, size_t ielen); diff --git a/src/ap/dfs.c b/src/ap/dfs.c index 5ce5489b2..94ef87d87 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -870,7 +870,9 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) /* Finally start CAC */ hostapd_set_state(iface, HAPD_IFACE_DFS); - wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz", iface->freq); + wpa_printf(MSG_DEBUG, "DFS start CAC on %d MHz background %d", + iface->freq, + !!(iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND)); wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START "freq=%d chan=%d sec_chan=%d, width=%d, seg0=%d, seg1=%d, cac_time=%ds", iface->freq, @@ -887,13 +889,37 @@ int hostapd_handle_dfs(struct hostapd_iface *iface) iface->conf->secondary_channel, hostapd_get_oper_chwidth(iface->conf), hostapd_get_oper_centr_freq_seg0_idx(iface->conf), - hostapd_get_oper_centr_freq_seg1_idx(iface->conf)); + hostapd_get_oper_centr_freq_seg1_idx(iface->conf), + !!(iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND)); if (res) { wpa_printf(MSG_ERROR, "DFS start_dfs_cac() failed, %d", res); return -1; } + if (iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) { + /* Cache background radar parameters */ + iface->radar_background.channel = iface->conf->channel; + iface->radar_background.secondary_channel = + iface->conf->secondary_channel; + iface->radar_background.freq = iface->freq; + iface->radar_background.centr_freq_seg0_idx = + hostapd_get_oper_centr_freq_seg0_idx(iface->conf); + iface->radar_background.centr_freq_seg1_idx = + hostapd_get_oper_centr_freq_seg1_idx(iface->conf); + + /* + * Let's select a random channel for the moment + * and perform CAC on dedicated radar chain + */ + res = dfs_set_valid_channel(iface, 1); + if (res < 0) + return res; + + iface->radar_background.temp_ch = 1; + return 1; + } + return 0; } @@ -915,6 +941,78 @@ int hostapd_is_dfs_chan_available(struct hostapd_iface *iface) } +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); + +static void +hostpad_dfs_update_background_chain(struct hostapd_iface *iface) +{ + struct hostapd_channel_data *channel; + int sec = 0, flags = 2; + u8 cf1 = 0, cf2 = 0; + + channel = dfs_get_valid_channel(iface, &sec, &cf1, &cf2, 2); + if (!channel || channel->chan == iface->conf->channel) + channel = dfs_downgrade_bandwidth(iface, &sec, &cf1, &cf2, + &flags); + if (!channel || + hostapd_start_dfs_cac(iface, iface->conf->hw_mode, + channel->freq, channel->chan, + iface->conf->ieee80211n, + iface->conf->ieee80211ac, + iface->conf->ieee80211ax, + sec, hostapd_get_oper_chwidth(iface->conf), + cf1, cf2, 1)) { + /* + * Toggle interface state to enter DFS state + * until NOP is finished. + */ + wpa_printf(MSG_ERROR, "DFS failed start CAC offchannel"); + return; + } + + wpa_printf(MSG_DEBUG, + "%s: setting background chain to chan %d (%d MHz)", + __func__, channel->chan, channel->freq); + + iface->radar_background.channel = channel->chan; + iface->radar_background.freq = channel->freq; + iface->radar_background.secondary_channel = sec; + iface->radar_background.centr_freq_seg0_idx = cf1; + iface->radar_background.centr_freq_seg1_idx = cf2; +} + +/* XXX: check if all channel bandwith */ +static int +hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq) +{ + if (iface->radar_background.freq != freq) + return 0; + + return 1; +} + +static int +hostapd_dfs_start_channel_switch_background(struct hostapd_iface *iface) +{ + iface->conf->channel = iface->radar_background.channel; + iface->freq = iface->radar_background.freq; + iface->conf->secondary_channel = + iface->radar_background.secondary_channel; + hostapd_set_oper_centr_freq_seg0_idx(iface->conf, + iface->radar_background.centr_freq_seg0_idx); + hostapd_set_oper_centr_freq_seg1_idx(iface->conf, + iface->radar_background.centr_freq_seg1_idx); + + hostpad_dfs_update_background_chain(iface); + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); + + return 0; +} + int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) @@ -935,6 +1033,23 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_AVAILABLE); + + /* + * radar event from background chain for selected + * channel. Perfrom CSA, move main chain to selected + * channel and configure background chain to a new DFS + * channel + */ + if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) && + hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + if (!iface->radar_background.temp_ch) + return 0; + + iface->radar_background.temp_ch = 0; + return hostapd_dfs_start_channel_switch_background(iface); + } + /* * Just mark the channel available when CAC completion * event is received in enabled state. CAC result could @@ -951,6 +1066,10 @@ int hostapd_dfs_complete_cac(struct hostapd_iface *iface, int success, int freq, iface->cac_started = 0; } } + } else if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) && + hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 0; + hostpad_dfs_update_background_chain(iface); } return 0; @@ -1308,7 +1427,11 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, "seg1=%d cac_time=%ds", freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, iface->dfs_cac_ms / 1000); - iface->cac_started = 1; + + if (hostapd_dfs_is_background_event(iface, freq)) + iface->radar_background.cac_started = 1; + else + iface->cac_started = 1; os_get_reltime(&iface->dfs_cac_start); return 0; } diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index f3ca7529a..72b6035d6 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -520,6 +520,21 @@ struct hostapd_iface { int *basic_rates; int freq; + /* Background radar configuration */ + struct { + int channel; + int secondary_channel; + int freq; + int centr_freq_seg0_idx; + int centr_freq_seg1_idx; + /* Main chain is on temporary channel during + * CAC detection on radar offchain. + */ + unsigned int temp_ch:1; + /* CAC started on radar offchain */ + unsigned int cac_started:1; + } radar_background; + u16 hw_flags; /* Number of associated Non-ERP stations (i.e., stations using 802.11b diff --git a/src/drivers/driver.h b/src/drivers/driver.h index fa28b03db..10dc84994 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -782,6 +782,11 @@ struct hostapd_freq_params { * for IEEE 802.11ay EDMG configuration. */ struct ieee80211_edmg_config edmg; + + /** + * radar_background - Whether radar/CAC background is requested + */ + int radar_background; }; /** diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index aec179ac3..e8e06cf17 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4896,6 +4896,8 @@ static int nl80211_put_freq_params(struct nl_msg *msg, wpa_printf(MSG_DEBUG, " * he_enabled=%d", freq->he_enabled); wpa_printf(MSG_DEBUG, " * vht_enabled=%d", freq->vht_enabled); wpa_printf(MSG_DEBUG, " * ht_enabled=%d", freq->ht_enabled); + wpa_printf(MSG_DEBUG, " * radar_background=%d", + freq->radar_background); hw_mode = ieee80211_freq_to_chan(freq->freq, &channel); is_24ghz = hw_mode == HOSTAPD_MODE_IEEE80211G || @@ -4973,6 +4975,9 @@ static int nl80211_put_freq_params(struct nl_msg *msg, NL80211_CHAN_NO_HT)) return -ENOBUFS; } + if (freq->radar_background) + nla_put_flag(msg, NL80211_ATTR_RADAR_BACKGROUND); + return 0; } -- 2.33.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap