[][MAC80211][WiFi6][hostapd][core][Fix dead lock issue during post CSA radar detection]

[Description]
Fix dead lock issue during post CSA radar detection
1. Allow channel switch during post CSA radar detection.
2. Remove flush_delayed_work for DFS channel update work to avoid dead
lock. Instead, enqueue a DFS channel update work to reset the DFS state
of original channel from AVAILABLE to USABLE. This avoids AP jumping back to the original channel without performing CAC.
3. Add wait mechanism for immediate CSA finalize; otherwise channel
switch would fail due to the fact that other interfaces are not ready to switch.

[Release-log]
N/A

Change-Id: I19de89ae79bec235e55f0812895c6f875d487d87
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/8851056
diff --git a/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0024-mac80211-mtk-add-DFS-CAC-countdown-in-CSA-flow.patch b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0024-mac80211-mtk-add-DFS-CAC-countdown-in-CSA-flow.patch
index f2fde36..beead44 100644
--- a/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0024-mac80211-mtk-add-DFS-CAC-countdown-in-CSA-flow.patch
+++ b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0024-mac80211-mtk-add-DFS-CAC-countdown-in-CSA-flow.patch
@@ -1,20 +1,20 @@
-From d10310d3eb842ebc449271b45ad2f47634149385 Mon Sep 17 00:00:00 2001
+From bb918e40dcc7d082f898234cf29cd545de78621e Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Wed, 15 Nov 2023 15:05:17 +0800
 Subject: [PATCH] mac80211: mtk: add DFS CAC countdown in CSA flow
 
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 ---
- include/net/cfg80211.h     | 32 +++++++++++++++++
- net/mac80211/cfg.c         | 45 +++++++++++++++++++++++-
- net/mac80211/ieee80211_i.h |  2 ++
- net/mac80211/iface.c       |  2 ++
- net/mac80211/mlme.c        |  6 +++-
- net/mac80211/util.c        | 11 +++++-
- net/wireless/chan.c        | 71 ++++++++++++++++++++++++++++++++++++++
- net/wireless/nl80211.c     |  5 +--
- net/wireless/rdev-ops.h    | 17 +++++++++
- 9 files changed, 186 insertions(+), 5 deletions(-)
+ include/net/cfg80211.h     | 32 +++++++++++++++
+ net/mac80211/cfg.c         | 84 +++++++++++++++++++++++++++++++++++---
+ net/mac80211/ieee80211_i.h |  2 +
+ net/mac80211/iface.c       |  2 +
+ net/mac80211/mlme.c        |  6 ++-
+ net/mac80211/util.c        | 11 ++++-
+ net/wireless/chan.c        | 72 ++++++++++++++++++++++++++++++++
+ net/wireless/nl80211.c     |  5 ++-
+ net/wireless/rdev-ops.h    | 17 ++++++++
+ 9 files changed, 221 insertions(+), 10 deletions(-)
 
 diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
 index 03f072f..a443b0d 100644
@@ -67,7 +67,7 @@
   * cfg80211_ch_switch_notify - update wdev channel and notify userspace
   * @dev: the device which switched channels
 diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
-index 56381f8..3e6e903 100644
+index 56381f8..7a30ca6 100644
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
 @@ -3328,6 +3328,39 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_sub_if_data *sdata,
@@ -122,7 +122,78 @@
  	sdata->vif.csa_active = false;
  
  	err = ieee80211_set_after_csa_beacon(sdata, &changed);
-@@ -4538,7 +4576,11 @@ ieee80211_skip_cac(struct wireless_dev *wdev)
+@@ -3428,6 +3466,11 @@ static int ieee80211_set_csa_beacon(struct ieee80211_sub_if_data *sdata,
+ 
+ 	switch (sdata->vif.type) {
+ 	case NL80211_IFTYPE_AP:
++		if (sdata->u.ap.next_beacon) {
++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
++			kfree(sdata->u.ap.next_beacon);
++			sdata->u.ap.next_beacon = NULL;
++		}
+ 		sdata->u.ap.next_beacon =
+ 			cfg80211_beacon_dup(&params->beacon_after);
+ 		if (!sdata->u.ap.next_beacon)
+@@ -3586,15 +3629,14 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ 	if (!list_empty(&local->roc_list) || local->scanning)
+ 		return -EBUSY;
+ 
+-	if (sdata->wdev.cac_started)
+-		return -EBUSY;
+-
+ 	if (cfg80211_chandef_identical(&params->chandef,
+ 				       &sdata->vif.bss_conf.chandef))
+ 		return -EINVAL;
+ 
+-	/* don't allow another channel switch if one is already active. */
+-	if (sdata->vif.csa_active)
++	/* don't allow another channel switch if one is already active
++	 * unless its during post CSA radar detection.
++	 */
++	if (sdata->vif.csa_active && !sdata->wdev.cac_started)
+ 		return -EBUSY;
+ 
+ 	mutex_lock(&local->chanctx_mtx);
+@@ -3646,6 +3688,14 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ 		goto out;
+ 	}
+ 
++	/* Finalize CSA immediately if CAC is started during last channel switch */
++	if (sdata->wdev.cac_started) {
++		ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA);
++		cancel_delayed_work(&sdata->dfs_cac_timer_work);
++		sdata->wdev.cac_started = false;
++		changed = 0;
++	}
++
+ 	sdata->csa_chandef = params->chandef;
+ 	sdata->csa_block_tx = params->block_tx;
+ 	sdata->vif.csa_active = true;
+@@ -3661,6 +3711,23 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ 		ieee80211_bss_info_change_notify(sdata, changed);
+ 		drv_channel_switch_beacon(sdata, &params->chandef);
+ 	} else {
++		struct ieee80211_sub_if_data *tmp;
++		int n_assigned = 0, n_reserved = 0;
++
++		list_for_each_entry(tmp, &chanctx->assigned_vifs,
++				    assigned_chanctx_list) {
++			n_assigned++;
++			if (tmp->reserved_chanctx)
++				n_reserved++;
++		}
++
++		/* Wait for all interfaces to be ready */
++		if (n_assigned != n_reserved) {
++			sdata->reserved_ready = true;
++			err = 0;
++			goto out;
++		}
++
+ 		/* if the beacon didn't change, we can finalize immediately */
+ 		ieee80211_csa_finalize(sdata);
+ 	}
+@@ -4538,7 +4605,11 @@ ieee80211_skip_cac(struct wireless_dev *wdev)
  
  	cancel_delayed_work(&sdata->dfs_cac_timer_work);
  	if (wdev->cac_started) {
@@ -135,7 +206,7 @@
  		cac_time_ms = wdev->cac_time_ms;
  		wdev->cac_start_time = jiffies -
  				       msecs_to_jiffies(cac_time_ms + 1);
-@@ -4630,6 +4672,7 @@ const struct cfg80211_ops mac80211_config_ops = {
+@@ -4630,6 +4701,7 @@ const struct cfg80211_ops mac80211_config_ops = {
  #endif
  	.get_channel = ieee80211_cfg_get_channel,
  	.start_radar_detection = ieee80211_start_radar_detection,
@@ -184,7 +255,7 @@
  	INIT_LIST_HEAD(&sdata->assigned_chanctx_list);
  	INIT_LIST_HEAD(&sdata->reserved_chanctx_list);
 diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
-index 48053e4..e9ec32d 100644
+index 2dbc18c..ed81ebf 100644
 --- a/net/mac80211/mlme.c
 +++ b/net/mac80211/mlme.c
 @@ -1870,7 +1870,11 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
@@ -223,10 +294,10 @@
  					   &chandef,
  					   NL80211_RADAR_CAC_ABORTED,
 diff --git a/net/wireless/chan.c b/net/wireless/chan.c
-index 9f651f9..88dd69e 100644
+index 9f651f9..f02598b 100644
 --- a/net/wireless/chan.c
 +++ b/net/wireless/chan.c
-@@ -1262,6 +1262,77 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
+@@ -1262,6 +1262,78 @@ bool cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
  }
  EXPORT_SYMBOL(cfg80211_reg_can_beacon_relax);
  
@@ -267,11 +338,12 @@
 +	enum nl80211_dfs_regions dfs_region;
 +	int ret = 0;
 +
++	/* Update DFS channel state especially when original channel include DFS channel */
++	cfg80211_sched_dfs_chan_update(rdev);
++
 +	if (cfg80211_chandef_dfs_available(wiphy, chandef))
 +		goto out;
 +
-+	flush_delayed_work(&rdev->dfs_update_channels_wk);
-+
 +	dfs_region = reg_get_dfs_region(wiphy);
 +	if (dfs_region == NL80211_DFS_UNSET)
 +		goto out;
diff --git a/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0048-hostapd-mtk-add-support-for-channel-switching-with-c.patch b/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0048-hostapd-mtk-add-support-for-channel-switching-with-c.patch
index 0dbdaca..fc37d6c 100644
--- a/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0048-hostapd-mtk-add-support-for-channel-switching-with-c.patch
+++ b/autobuild_mac80211_release/package/network/services/hostapd/patches/mtk-0048-hostapd-mtk-add-support-for-channel-switching-with-c.patch
@@ -1,4 +1,4 @@
-From a0538a9373ec7def76048e020fcb6ecfec53f3db Mon Sep 17 00:00:00 2001
+From 5d4d4397d0628a1aa83f83163e97ff34a0a5de43 Mon Sep 17 00:00:00 2001
 From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 Date: Thu, 16 Nov 2023 13:18:48 +0800
 Subject: [PATCH] hostapd: mtk: add support for channel switching with csa sent
@@ -6,14 +6,15 @@
 
 Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
 ---
- hostapd/ctrl_iface.c   |  82 +++++++++++++++++-----
+ hostapd/ctrl_iface.c   |  84 +++++++++++++++++-----
  src/ap/ctrl_iface_ap.c |   5 +-
  src/ap/dfs.c           | 156 +++++++++++++++++++++++++++++++++++------
  src/ap/dfs.h           |   9 ++-
- 4 files changed, 212 insertions(+), 40 deletions(-)
+ src/ap/hostapd.c       |   8 ++-
+ 5 files changed, 221 insertions(+), 41 deletions(-)
 
 diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
-index 0afa6a2..44903e0 100644
+index 96b593a..445cb34 100644
 --- a/hostapd/ctrl_iface.c
 +++ b/hostapd/ctrl_iface.c
 @@ -2742,11 +2742,12 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
@@ -105,10 +106,13 @@
  	}
  
  	for (i = 0; i < iface->num_bss; i++) {
-@@ -2826,6 +2844,36 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
+@@ -2825,6 +2843,38 @@ static int hostapd_ctrl_iface_chan_switch(struct hostapd_iface *iface,
+ 			return ret;
  		}
  	}
- 
++	/* Clear the CAC flag once all BSSes are switched to the new channel */
++	iface->cac_started = 0;
++
 +	if (background_radar) {
 +		u8 seg0, seg1;
 +
@@ -138,10 +142,9 @@
 +		iface->radar_background.centr_freq_seg0_idx = seg0;
 +		iface->radar_background.centr_freq_seg1_idx = seg1;
 +	}
-+
+ 
  	return 0;
  #else /* NEED_AP_MLME */
- 	return -1;
 diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
 index 86e8729..005c9fa 100644
 --- a/src/ap/ctrl_iface_ap.c
@@ -166,7 +169,7 @@
  		return -1;
  	}
 diff --git a/src/ap/dfs.c b/src/ap/dfs.c
-index 012050c..5108e0a 100644
+index d490032..26ce229 100644
 --- a/src/ap/dfs.c
 +++ b/src/ap/dfs.c
 @@ -248,14 +248,15 @@ static int is_in_chanlist(struct hostapd_iface *iface,
@@ -215,7 +218,7 @@
  			if (chan2 && abs(chan2->chan - chan->chan) > 12) {
  				/* two channels are not adjacent */
  				sec_chan_idx_80p80 = chan2->chan;
-@@ -1302,6 +1303,9 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
+@@ -1304,6 +1305,9 @@ int hostapd_dfs_pre_cac_expired(struct hostapd_iface *iface, int freq,
  	set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
  		      cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
  
@@ -225,7 +228,7 @@
  	return 0;
  }
  
-@@ -1715,14 +1719,15 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
+@@ -1717,14 +1721,15 @@ int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
  }
  
  
@@ -245,7 +248,7 @@
  
  	if (!iface->conf->ieee80211h || !mode ||
  	    mode->mode != HOSTAPD_MODE_IEEE80211A)
-@@ -1755,18 +1760,129 @@ int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
+@@ -1757,18 +1762,129 @@ int hostapd_is_dfs_overlap(struct hostapd_iface *iface, enum chan_width width,
  		if (!(chan->flag & HOSTAPD_CHAN_RADAR))
  			continue;
  
@@ -404,6 +407,25 @@
 +
  
  #endif /* DFS_H */
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 250c168..d983902 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -3708,7 +3708,13 @@ static int hostapd_fill_csa_settings(struct hostapd_data *hapd,
+ 	u8 chan, bandwidth;
+ 
+ 	os_memset(&old_freq, 0, sizeof(old_freq));
+-	if (!iface || !iface->freq || hapd->csa_in_progress)
++	if (!iface || !iface->freq)
++		return -1;
++
++	/* Allow another channel switch if the previous
++	 * channel switch is waiting for post-CSA radar detection
++	 */
++	if (hapd->csa_in_progress && !iface->cac_started)
+ 		return -1;
+ 
+ 	switch (settings->freq_params.bandwidth) {
 -- 
 2.18.0