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 | 161 ++++++++++++++++++++++++++++++++--- src/ap/hostapd.h | 15 ++++ src/drivers/driver.h | 5 ++ src/drivers/driver_nl80211.c | 5 ++ 6 files changed, 185 insertions(+), 13 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..4ac2fb67a 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_background); 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 2d0e72bd6..29c3bb4b3 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -860,7 +860,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, @@ -877,13 +879,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 according to the + * regulations 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; } @@ -905,6 +931,88 @@ 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 *channel_type); + +static void +hostpad_dfs_update_background_chain(struct hostapd_iface *iface) +{ + int sec = 0, channel_type = DFS_NO_CAC_YET; + struct hostapd_channel_data *channel; + u8 oper_centr_freq_seg0_idx = 0; + u8 oper_centr_freq_seg1_idx = 0; + + /* + * Allow selection of DFS channel in ETSI to comply with + * uniform spreading. + */ + if (iface->dfs_domain == HOSTAPD_DFS_REGION_ETSI) + channel_type = DFS_ANY_CHANNEL; + + channel = dfs_get_valid_channel(iface, &sec, &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, channel_type); + if (!channel || + channel->chan == iface->conf->channel || + channel->chan == iface->radar_background.channel) + channel = dfs_downgrade_bandwidth(iface, &sec, + &oper_centr_freq_seg0_idx, + &oper_centr_freq_seg1_idx, + &channel_type); + 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), + oper_centr_freq_seg0_idx, + oper_centr_freq_seg1_idx, 1)) { + wpa_printf(MSG_ERROR, "DFS failed start CAC offchannel"); + iface->radar_background.channel = -1; + return; + } + + 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 = oper_centr_freq_seg0_idx; + iface->radar_background.centr_freq_seg1_idx = oper_centr_freq_seg1_idx; + + wpa_printf(MSG_DEBUG, + "%s: setting background chain to chan %d (%d MHz)", + __func__, channel->chan, channel->freq); +} + +static int +hostapd_dfs_is_background_event(struct hostapd_iface *iface, int freq) +{ + if (iface->radar_background.channel == -1 || + 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) @@ -925,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 @@ -941,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; @@ -1248,9 +1377,14 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, cf1, cf2, HOSTAPD_CHAN_DFS_USABLE); - /* Handle cases where all channels were initially unavailable */ - if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) + if (iface->state == HAPD_IFACE_DFS && !iface->cac_started) { + /* Handle cases where all channels were initially unavailable */ hostapd_handle_dfs(iface); + } else if ((iface->drv_flags2 & WPA_DRIVER_RADAR_BACKGROUND) && + iface->radar_background.channel == -1) { + /* Reset radar background chanin if disabled */ + hostpad_dfs_update_background_chain(iface); + } return 0; } @@ -1288,17 +1422,24 @@ int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq, int ht_enabled, int chan_offset, int chan_width, int cf1, int cf2) { - /* This is called when the driver indicates that an offloaded DFS has - * started CAC. */ - hostapd_set_state(iface, HAPD_IFACE_DFS); + if (hostapd_dfs_is_background_event(iface, freq)) { + iface->radar_background.cac_started = 1; + } else { + /* This is called when the driver indicates that + * an offloaded DFS has started CAC. + */ + hostapd_set_state(iface, HAPD_IFACE_DFS); + iface->cac_started = 1; + } /* TODO: How to check CAC time for ETSI weather channels? */ iface->dfs_cac_ms = 60000; wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START "freq=%d chan=%d chan_offset=%d width=%d seg0=%d " - "seg1=%d cac_time=%ds", + "seg1=%d cac_time=%ds background event %d", freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, - iface->dfs_cac_ms / 1000); - iface->cac_started = 1; + iface->dfs_cac_ms / 1000, + !!hostapd_dfs_is_background_event(iface, freq)); + 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 e3b4262b5..e4b69563e 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 5b01e2b3e..403972985 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4912,6 +4912,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 || @@ -4989,6 +4991,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.35.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap