[][MAC80211][core][Add sta-assisted DFS state update mechansim in core]

[Description]
Add sta-assisted DFS state update mechansim in core

[Release-log]
N/A

Change-Id: I1ea733b645436bb0b051b5748160ac45e78d35b0
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7156687
diff --git a/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0014-mac80211-mtk-add-sta-assisted-DFS-state-update-mecha.patch b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0014-mac80211-mtk-add-sta-assisted-DFS-state-update-mecha.patch
new file mode 100644
index 0000000..2006b27
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/mtk-0014-mac80211-mtk-add-sta-assisted-DFS-state-update-mecha.patch
@@ -0,0 +1,176 @@
+From 8fdded8b5d47f1ab5fb7ab1fd2a4247cd81edad0 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Mon, 20 Feb 2023 14:25:24 +0800
+Subject: [PATCH] mac80211: mtk: add sta-assisted DFS state update mechanism
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ include/net/cfg80211.h       | 14 +++++++++
+ include/uapi/linux/nl80211.h |  6 ++++
+ net/mac80211/mlme.c          | 11 +++++++
+ net/wireless/chan.c          | 60 ++++++++++++++++++++++++++++++++++++
+ 4 files changed, 91 insertions(+)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index b97ddbd..02ad2b2 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -7641,6 +7641,20 @@ void cfg80211_cac_event(struct net_device *netdev,
+ 			const struct cfg80211_chan_def *chandef,
+ 			enum nl80211_radar_event event, gfp_t gfp);
+ 
++/**
++ * cfg80211_sta_update_dfs_state - Update channel's DFS state during STA channel switch,
++ *				   association, and disassociation
++ * @wdev: the wireless device
++ * @bss_chandef: the current BSS channel definition
++ * @csa_chandef: the CSA channel definition
++ * @associated: whether STA is during association or disassociation process
++ *
++ */
++void cfg80211_sta_update_dfs_state(struct wireless_dev *wdev,
++				   const struct cfg80211_chan_def *bss_chandef,
++				   const struct cfg80211_chan_def *csa_chandef,
++				   bool associated);
++
+ /**
+  * cfg80211_background_cac_abort - Channel Availability Check offchan abort event
+  * @wiphy: the wiphy
+diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
+index e674aa7..3e348a5 100644
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -6294,6 +6294,10 @@ enum nl80211_smps_mode {
+  *	applicable for ETSI dfs domain where pre-CAC is valid for ever.
+  * @NL80211_RADAR_CAC_STARTED: Channel Availability Check has been started,
+  *	should be generated by HW if NL80211_EXT_FEATURE_DFS_OFFLOAD is enabled.
++ * @NL80211_RADAR_STA_CAC_SKIPPED: STA set the DFS state to available
++ *	when receiving CSA/assoc resp
++ * @NL80211_RADAR_STA_CAC_EXPIRED: STA set the DFS state to usable
++ *	when STA is disconnected or leaving the channel
+  */
+ enum nl80211_radar_event {
+ 	NL80211_RADAR_DETECTED,
+@@ -6302,6 +6306,8 @@ enum nl80211_radar_event {
+ 	NL80211_RADAR_NOP_FINISHED,
+ 	NL80211_RADAR_PRE_CAC_EXPIRED,
+ 	NL80211_RADAR_CAC_STARTED,
++	NL80211_RADAR_STA_CAC_SKIPPED,
++	NL80211_RADAR_STA_CAC_EXPIRED,
+ };
+ 
+ /**
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 8ee325a..48053e4 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -1442,6 +1442,10 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+ 					  IEEE80211_QUEUE_STOP_REASON_CSA);
+ 	mutex_unlock(&local->mtx);
+ 
++	cfg80211_sta_update_dfs_state(&sdata->wdev,
++				      &sdata->vif.bss_conf.chandef,
++				      &sdata->csa_chandef,
++				      sdata->vif.bss_conf.assoc);
+ 	cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chandef,
+ 					  csa_ie.count, csa_ie.mode);
+ 
+@@ -2420,6 +2424,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
+ 	cancel_delayed_work_sync(&ifmgd->tx_tspec_wk);
+ 
+ 	sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
++
++	cfg80211_sta_update_dfs_state(&sdata->wdev,
++				      &sdata->vif.bss_conf.chandef,
++				      NULL, sdata->vif.bss_conf.assoc);
+ }
+ 
+ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
+@@ -3782,6 +3790,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+ 		event.u.mlme.status = MLME_SUCCESS;
+ 		drv_event_callback(sdata->local, sdata, &event);
+ 		sdata_info(sdata, "associated\n");
++		cfg80211_sta_update_dfs_state(&sdata->wdev,
++					      &sdata->vif.bss_conf.chandef,
++					      NULL, sdata->vif.bss_conf.assoc);
+ 
+ 		/*
+ 		 * destroy assoc_data afterwards, as otherwise an idle
+diff --git a/net/wireless/chan.c b/net/wireless/chan.c
+index 5f50ac4..0309758 100644
+--- a/net/wireless/chan.c
++++ b/net/wireless/chan.c
+@@ -14,6 +14,7 @@
+ #include <net/cfg80211.h>
+ #include "core.h"
+ #include "rdev-ops.h"
++#include "nl80211.h"
+ 
+ static bool cfg80211_valid_60g_freq(u32 freq)
+ {
+@@ -1386,3 +1387,62 @@ bool cfg80211_any_usable_channels(struct wiphy *wiphy,
+ 	return false;
+ }
+ EXPORT_SYMBOL(cfg80211_any_usable_channels);
++
++static void cfg80211_sta_radar_notify(struct wiphy *wiphy,
++				      const struct cfg80211_chan_def *chandef,
++				      enum nl80211_radar_event event)
++{
++	struct wireless_dev *wdev;
++
++	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
++		if (cfg80211_chandef_dfs_required(wiphy, chandef, wdev->iftype) > 0) {
++			nl80211_radar_notify(wiphy_to_rdev(wiphy), chandef,
++					     event, wdev->netdev, GFP_KERNEL);
++			return;
++		}
++	}
++}
++
++void cfg80211_sta_update_dfs_state(struct wireless_dev *wdev,
++				   const struct cfg80211_chan_def *bss_chandef,
++				   const struct cfg80211_chan_def *csa_chandef,
++				   bool associated)
++{
++	bool csa_active = !!csa_chandef;
++	enum nl80211_dfs_state dfs_state = NL80211_DFS_USABLE;
++	enum nl80211_radar_event event = NL80211_RADAR_STA_CAC_EXPIRED;
++
++	if (!bss_chandef)
++		return;
++
++	/* assume csa channel is cac completed */
++	if (csa_active &&
++	    (cfg80211_chandef_dfs_usable(wdev->wiphy, csa_chandef) ||
++	    cfg80211_chandef_dfs_available(wdev->wiphy, csa_chandef))) {
++		cfg80211_set_dfs_state(wdev->wiphy, csa_chandef, NL80211_DFS_AVAILABLE);
++		cfg80211_sta_radar_notify(wdev->wiphy, csa_chandef,
++					  NL80211_RADAR_STA_CAC_SKIPPED);
++		netdev_info(wdev->netdev, "Set CSA channel's DFS state to available\n");
++	}
++
++	/* avoid updating the dfs state during nop */
++	if (!cfg80211_chandef_dfs_usable(wdev->wiphy, bss_chandef) &&
++	    !cfg80211_chandef_dfs_available(wdev->wiphy, bss_chandef))
++		return;
++
++	if (associated && !csa_active) {
++		dfs_state = NL80211_DFS_AVAILABLE;
++		event = NL80211_RADAR_STA_CAC_SKIPPED;
++	}
++
++	cfg80211_set_dfs_state(wdev->wiphy, bss_chandef, dfs_state);
++	cfg80211_sta_radar_notify(wdev->wiphy, bss_chandef, event);
++
++	if (csa_active)
++		netdev_info(wdev->netdev, "Set origin channel's DFS state to usable\n");
++	else
++		netdev_info(wdev->netdev, "Set BSS channel's DFS state to %s due to %s\n",
++			    (dfs_state == NL80211_DFS_USABLE) ? "usable" : "available",
++			    associated ? "association" : "disassociation");
++}
++EXPORT_SYMBOL(cfg80211_sta_update_dfs_state);
+-- 
+2.18.0
+