diff mbox series

[v2,2/5] DFS: configure background radar/cac detection.

Message ID fc20457dbd69903ca94b33937d2cd5fd6d71441f.1646594636.git.lorenzo@kernel.org
State Accepted
Headers show
Series introduce background radar detection support | expand

Commit Message

lorenzo@kernel.org March 6, 2022, 7:34 p.m. UTC
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@mediatek.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
 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 mbox series

Patch

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;
 }