[][MAC80211][core][Add DFS status show, cac and nop skip command]

[Description]
Add DFS status show, cac/nop skip command via debugfs in cfg80211

[Release-log]
N/A

Change-Id: I693b54c3d74ef932a7ba1ef864d24ab237b49dee
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/6590829
Build: srv_hbgsm110
diff --git a/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/914-cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/914-cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch
new file mode 100644
index 0000000..2aaf114
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mac80211/patches/subsys/914-cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch
@@ -0,0 +1,256 @@
+From eca521242b94855825f085d1bca67a5958420baa Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 22 Sep 2022 14:27:41 +0800
+Subject: [PATCH] cfg80211: implement DFS status show, cac and nop skip command
+ via debugfs
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ net/wireless/debugfs.c | 228 +++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 221 insertions(+), 7 deletions(-)
+
+diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
+index aab4346..19c3091 100644
+--- a/net/wireless/debugfs.c
++++ b/net/wireless/debugfs.c
+@@ -95,16 +95,230 @@ static const struct file_operations ht40allow_map_ops = {
+ 	.llseek = default_llseek,
+ };
+ 
+-#define DEBUGFS_ADD(name)						\
+-	debugfs_create_file(#name, 0444, phyd, &rdev->wiphy, &name## _ops)
++static int dfs_print_chan(struct ieee80211_channel *chan, int remain_time,
++			  char *buf, int buf_size, int offset)
++{
++	if (WARN_ON(offset > buf_size))
++		return 0;
++
++	if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
++		offset += scnprintf(buf + offset, buf_size - offset,
++				    "	Channel = %d, DFS_state = Unavailable",
++				    chan->hw_value);
++		if (remain_time > 0)
++			offset += scnprintf(buf + offset, buf_size - offset,
++					    ", Non-occupancy Remain Time = %d [sec]\n",
++					    remain_time);
++		else
++			offset += scnprintf(buf + offset, buf_size - offset,
++					    ", Changing state...\n");
++	} else if (chan->dfs_state == NL80211_DFS_USABLE) {
++		offset += scnprintf(buf + offset, buf_size - offset,
++				    "	Channel = %d, DFS_state = Usable",
++				    chan->hw_value);
++		if (remain_time > 0)
++			offset += scnprintf(buf + offset, buf_size - offset,
++					    ", CAC Remain Time = %d [sec]\n",
++					    remain_time);
++		else
++			offset += scnprintf(buf + offset, buf_size - offset,
++					    "\n");
++	} else if (chan->dfs_state == NL80211_DFS_AVAILABLE) {
++		offset += scnprintf(buf + offset, buf_size - offset,
++				    "	Channel = %d, DFS_state = Available\n",
++				    chan->hw_value);
++	} else {
++		offset += scnprintf(buf + offset, buf_size - offset,
++				    "	Channel = %d, DFS_state = Unknown\n",
++				    chan->hw_value);
++	}
++
++	return offset;
++}
++
++static int dfs_status_read_wdev(struct wiphy *wiphy, struct wireless_dev *wdev, char *buf,
++				unsigned int buf_size, unsigned int offset)
++{
++	struct cfg80211_chan_def *chandef;
++	enum nl80211_band band;
++	struct ieee80211_supported_band *sband;
++	struct ieee80211_channel *chan;
++	unsigned long jiffies_passed;
++	int i, remain_time = 0;
++
++	offset += scnprintf(buf + offset, buf_size - offset, "DFS Channel:\n");
++
++	for (band = 0; band < NUM_NL80211_BANDS; band++) {
++		sband = wiphy->bands[band];
++		if (!sband)
++			continue;
++		for (i = 0; i < sband->n_channels; i++) {
++			chan = &sband->channels[i];
++
++			if (!(chan->flags & IEEE80211_CHAN_RADAR))
++				continue;
++
++			if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
++				jiffies_passed = jiffies - chan->dfs_state_entered;
++				remain_time = (IEEE80211_DFS_MIN_NOP_TIME_MS -
++					       jiffies_to_msecs(jiffies_passed));
++				if (remain_time > IEEE80211_DFS_MIN_NOP_TIME_MS)
++					remain_time = 0;
++			} else if (chan->dfs_state == NL80211_DFS_USABLE) {
++				chandef = &wdev->chandef;
++				if (wdev->cac_started && cfg80211_is_sub_chan(chandef, chan)) {
++					jiffies_passed = jiffies - wdev->cac_start_time;
++					remain_time = (wdev->cac_time_ms -
++							jiffies_to_msecs(jiffies_passed));
++				}
++				if (remain_time > wdev->cac_time_ms)
++					remain_time = 0;
++			}
++			offset = dfs_print_chan(chan, remain_time / 1000, buf, buf_size, offset);
++			remain_time = 0;
++		}
++	}
++
++	return offset;
++}
++
++static ssize_t dfs_status_read(struct file *file, char __user *user_buf,
++			       size_t count, loff_t *ppos)
++{
++	struct wiphy *wiphy = file->private_data;
++	struct wireless_dev *wdev;
++	char *buf;
++	unsigned int offset = 0, buf_size = PAGE_SIZE, r;
++	const char * const iftype_str[] = {
++		[NL80211_IFTYPE_UNSPECIFIED] = "unspecified",
++		[NL80211_IFTYPE_ADHOC] = "adhoc",
++		[NL80211_IFTYPE_STATION] = "station",
++		[NL80211_IFTYPE_AP] = "ap",
++		[NL80211_IFTYPE_AP_VLAN] = "ap vlan",
++		[NL80211_IFTYPE_WDS] = "wds",
++		[NL80211_IFTYPE_MONITOR] = "monitor",
++		[NL80211_IFTYPE_MESH_POINT] = "mesh point",
++		[NL80211_IFTYPE_P2P_CLIENT] = "p2p client",
++		[NL80211_IFTYPE_P2P_GO] = "p2p go",
++		[NL80211_IFTYPE_P2P_DEVICE] = "p2p device",
++		[NL80211_IFTYPE_OCB] = "ocb",
++		[NL80211_IFTYPE_NAN] = "nan",
++	};
++
++	buf = kzalloc(buf_size, GFP_KERNEL);
++	if (!buf)
++		return -ENOMEM;
++
++	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
++		offset += scnprintf(buf + offset, buf_size - offset,
++				    "wdev 0x%x\n"
++				    "interface type %s\n",
++				    wdev->identifier, iftype_str[wdev->iftype]);
++		offset = dfs_status_read_wdev(wiphy, wdev, buf, buf_size, offset);
++	}
++
++	r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
++
++	kfree(buf);
++
++	return r;
++}
++
++static const struct file_operations dfs_status_ops = {
++	.read = dfs_status_read,
++	.open = simple_open,
++	.llseek = default_llseek,
++};
++
++static int
++dfs_nop_skip(void *data, u64 val)
++{
++	struct wiphy *wiphy = data;
++	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++	bool en = !!val;
++	enum nl80211_band band;
++	struct ieee80211_supported_band *sband;
++	struct ieee80211_channel *chan;
++	u32 nop_time = IEEE80211_DFS_MIN_NOP_TIME_MS;
++	int i;
++
++	if (!en)
++		return 0;
++
++	for (band = 0; band < NUM_NL80211_BANDS; band++) {
++		sband = wiphy->bands[band];
++		if (!sband)
++			continue;
++		for (i = 0; i < sband->n_channels; i++) {
++			chan = &sband->channels[i];
++
++			if (!(chan->flags & IEEE80211_CHAN_RADAR))
++				continue;
++
++			if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
++				// Let current jiffies > dfs_state_entered_jiffies + NOP time
++				chan->dfs_state_entered = jiffies -
++						       msecs_to_jiffies(nop_time + 1);
++			}
++		}
++	}
++
++	cfg80211_sched_dfs_chan_update(rdev);
++
++	return 0;
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_nop_ops, NULL,
++			 dfs_nop_skip, "0x%08llx\n");
++
++static int
++dfs_cac_skip(void *data, u64 val)
++{
++	struct wiphy *wiphy = data;
++	struct wireless_dev *wdev;
++	struct cfg80211_chan_def *chandef;
++	bool en = !!val;
++	struct ieee80211_channel *chan;
++
++	if (!en)
++		return 0;
++
++	list_for_each_entry(wdev, &wiphy->wdev_list, list) {
++		chandef = &wdev->chandef;
++		if (chandef->chan) {
++			chan = chandef->chan;
++			if (!(chan->flags & IEEE80211_CHAN_RADAR))
++				continue;
++
++			if (chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started) {
++				// Let current jiffies > dfs_state_entered_jiffies + CAC time
++				wdev->cac_start_time = jiffies -
++						       msecs_to_jiffies(wdev->cac_time_ms + 1);
++				cfg80211_cac_event(wdev->netdev, chandef,
++						   NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
++			}
++		}
++	}
++
++	return 0;
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_cac_ops, NULL,
++			 dfs_cac_skip, "0x%08llx\n");
++
++#define DEBUGFS_ADD(name, chmod)						\
++	debugfs_create_file(#name, chmod, phyd, &rdev->wiphy, &name## _ops)
+ 
+ void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
+ {
+ 	struct dentry *phyd = rdev->wiphy.debugfsdir;
+ 
+-	DEBUGFS_ADD(rts_threshold);
+-	DEBUGFS_ADD(fragmentation_threshold);
+-	DEBUGFS_ADD(short_retry_limit);
+-	DEBUGFS_ADD(long_retry_limit);
+-	DEBUGFS_ADD(ht40allow_map);
++	DEBUGFS_ADD(rts_threshold, 0444);
++	DEBUGFS_ADD(fragmentation_threshold, 0444);
++	DEBUGFS_ADD(short_retry_limit, 0444);
++	DEBUGFS_ADD(long_retry_limit, 0444);
++	DEBUGFS_ADD(ht40allow_map, 0444);
++	DEBUGFS_ADD(dfs_status, 0444);
++	DEBUGFS_ADD(dfs_skip_nop, 0600);
++	DEBUGFS_ADD(dfs_skip_cac, 0600);
+ }
+-- 
+2.18.0
+