blob: 2aaf1144593502bc6be3f4cf0a6ffb59c3ac6767 [file] [log] [blame]
developer202889a2022-09-23 12:11:58 +08001From eca521242b94855825f085d1bca67a5958420baa Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Thu, 22 Sep 2022 14:27:41 +0800
4Subject: [PATCH] cfg80211: implement DFS status show, cac and nop skip command
5 via debugfs
6
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
9 net/wireless/debugfs.c | 228 +++++++++++++++++++++++++++++++++++++++--
10 1 file changed, 221 insertions(+), 7 deletions(-)
11
12diff --git a/net/wireless/debugfs.c b/net/wireless/debugfs.c
13index aab4346..19c3091 100644
14--- a/net/wireless/debugfs.c
15+++ b/net/wireless/debugfs.c
16@@ -95,16 +95,230 @@ static const struct file_operations ht40allow_map_ops = {
17 .llseek = default_llseek,
18 };
19
20-#define DEBUGFS_ADD(name) \
21- debugfs_create_file(#name, 0444, phyd, &rdev->wiphy, &name## _ops)
22+static int dfs_print_chan(struct ieee80211_channel *chan, int remain_time,
23+ char *buf, int buf_size, int offset)
24+{
25+ if (WARN_ON(offset > buf_size))
26+ return 0;
27+
28+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
29+ offset += scnprintf(buf + offset, buf_size - offset,
30+ " Channel = %d, DFS_state = Unavailable",
31+ chan->hw_value);
32+ if (remain_time > 0)
33+ offset += scnprintf(buf + offset, buf_size - offset,
34+ ", Non-occupancy Remain Time = %d [sec]\n",
35+ remain_time);
36+ else
37+ offset += scnprintf(buf + offset, buf_size - offset,
38+ ", Changing state...\n");
39+ } else if (chan->dfs_state == NL80211_DFS_USABLE) {
40+ offset += scnprintf(buf + offset, buf_size - offset,
41+ " Channel = %d, DFS_state = Usable",
42+ chan->hw_value);
43+ if (remain_time > 0)
44+ offset += scnprintf(buf + offset, buf_size - offset,
45+ ", CAC Remain Time = %d [sec]\n",
46+ remain_time);
47+ else
48+ offset += scnprintf(buf + offset, buf_size - offset,
49+ "\n");
50+ } else if (chan->dfs_state == NL80211_DFS_AVAILABLE) {
51+ offset += scnprintf(buf + offset, buf_size - offset,
52+ " Channel = %d, DFS_state = Available\n",
53+ chan->hw_value);
54+ } else {
55+ offset += scnprintf(buf + offset, buf_size - offset,
56+ " Channel = %d, DFS_state = Unknown\n",
57+ chan->hw_value);
58+ }
59+
60+ return offset;
61+}
62+
63+static int dfs_status_read_wdev(struct wiphy *wiphy, struct wireless_dev *wdev, char *buf,
64+ unsigned int buf_size, unsigned int offset)
65+{
66+ struct cfg80211_chan_def *chandef;
67+ enum nl80211_band band;
68+ struct ieee80211_supported_band *sband;
69+ struct ieee80211_channel *chan;
70+ unsigned long jiffies_passed;
71+ int i, remain_time = 0;
72+
73+ offset += scnprintf(buf + offset, buf_size - offset, "DFS Channel:\n");
74+
75+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
76+ sband = wiphy->bands[band];
77+ if (!sband)
78+ continue;
79+ for (i = 0; i < sband->n_channels; i++) {
80+ chan = &sband->channels[i];
81+
82+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
83+ continue;
84+
85+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
86+ jiffies_passed = jiffies - chan->dfs_state_entered;
87+ remain_time = (IEEE80211_DFS_MIN_NOP_TIME_MS -
88+ jiffies_to_msecs(jiffies_passed));
89+ if (remain_time > IEEE80211_DFS_MIN_NOP_TIME_MS)
90+ remain_time = 0;
91+ } else if (chan->dfs_state == NL80211_DFS_USABLE) {
92+ chandef = &wdev->chandef;
93+ if (wdev->cac_started && cfg80211_is_sub_chan(chandef, chan)) {
94+ jiffies_passed = jiffies - wdev->cac_start_time;
95+ remain_time = (wdev->cac_time_ms -
96+ jiffies_to_msecs(jiffies_passed));
97+ }
98+ if (remain_time > wdev->cac_time_ms)
99+ remain_time = 0;
100+ }
101+ offset = dfs_print_chan(chan, remain_time / 1000, buf, buf_size, offset);
102+ remain_time = 0;
103+ }
104+ }
105+
106+ return offset;
107+}
108+
109+static ssize_t dfs_status_read(struct file *file, char __user *user_buf,
110+ size_t count, loff_t *ppos)
111+{
112+ struct wiphy *wiphy = file->private_data;
113+ struct wireless_dev *wdev;
114+ char *buf;
115+ unsigned int offset = 0, buf_size = PAGE_SIZE, r;
116+ const char * const iftype_str[] = {
117+ [NL80211_IFTYPE_UNSPECIFIED] = "unspecified",
118+ [NL80211_IFTYPE_ADHOC] = "adhoc",
119+ [NL80211_IFTYPE_STATION] = "station",
120+ [NL80211_IFTYPE_AP] = "ap",
121+ [NL80211_IFTYPE_AP_VLAN] = "ap vlan",
122+ [NL80211_IFTYPE_WDS] = "wds",
123+ [NL80211_IFTYPE_MONITOR] = "monitor",
124+ [NL80211_IFTYPE_MESH_POINT] = "mesh point",
125+ [NL80211_IFTYPE_P2P_CLIENT] = "p2p client",
126+ [NL80211_IFTYPE_P2P_GO] = "p2p go",
127+ [NL80211_IFTYPE_P2P_DEVICE] = "p2p device",
128+ [NL80211_IFTYPE_OCB] = "ocb",
129+ [NL80211_IFTYPE_NAN] = "nan",
130+ };
131+
132+ buf = kzalloc(buf_size, GFP_KERNEL);
133+ if (!buf)
134+ return -ENOMEM;
135+
136+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
137+ offset += scnprintf(buf + offset, buf_size - offset,
138+ "wdev 0x%x\n"
139+ "interface type %s\n",
140+ wdev->identifier, iftype_str[wdev->iftype]);
141+ offset = dfs_status_read_wdev(wiphy, wdev, buf, buf_size, offset);
142+ }
143+
144+ r = simple_read_from_buffer(user_buf, count, ppos, buf, offset);
145+
146+ kfree(buf);
147+
148+ return r;
149+}
150+
151+static const struct file_operations dfs_status_ops = {
152+ .read = dfs_status_read,
153+ .open = simple_open,
154+ .llseek = default_llseek,
155+};
156+
157+static int
158+dfs_nop_skip(void *data, u64 val)
159+{
160+ struct wiphy *wiphy = data;
161+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
162+ bool en = !!val;
163+ enum nl80211_band band;
164+ struct ieee80211_supported_band *sband;
165+ struct ieee80211_channel *chan;
166+ u32 nop_time = IEEE80211_DFS_MIN_NOP_TIME_MS;
167+ int i;
168+
169+ if (!en)
170+ return 0;
171+
172+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
173+ sband = wiphy->bands[band];
174+ if (!sband)
175+ continue;
176+ for (i = 0; i < sband->n_channels; i++) {
177+ chan = &sband->channels[i];
178+
179+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
180+ continue;
181+
182+ if (chan->dfs_state == NL80211_DFS_UNAVAILABLE) {
183+ // Let current jiffies > dfs_state_entered_jiffies + NOP time
184+ chan->dfs_state_entered = jiffies -
185+ msecs_to_jiffies(nop_time + 1);
186+ }
187+ }
188+ }
189+
190+ cfg80211_sched_dfs_chan_update(rdev);
191+
192+ return 0;
193+}
194+
195+DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_nop_ops, NULL,
196+ dfs_nop_skip, "0x%08llx\n");
197+
198+static int
199+dfs_cac_skip(void *data, u64 val)
200+{
201+ struct wiphy *wiphy = data;
202+ struct wireless_dev *wdev;
203+ struct cfg80211_chan_def *chandef;
204+ bool en = !!val;
205+ struct ieee80211_channel *chan;
206+
207+ if (!en)
208+ return 0;
209+
210+ list_for_each_entry(wdev, &wiphy->wdev_list, list) {
211+ chandef = &wdev->chandef;
212+ if (chandef->chan) {
213+ chan = chandef->chan;
214+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
215+ continue;
216+
217+ if (chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started) {
218+ // Let current jiffies > dfs_state_entered_jiffies + CAC time
219+ wdev->cac_start_time = jiffies -
220+ msecs_to_jiffies(wdev->cac_time_ms + 1);
221+ cfg80211_cac_event(wdev->netdev, chandef,
222+ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
223+ }
224+ }
225+ }
226+
227+ return 0;
228+}
229+
230+DEFINE_DEBUGFS_ATTRIBUTE(dfs_skip_cac_ops, NULL,
231+ dfs_cac_skip, "0x%08llx\n");
232+
233+#define DEBUGFS_ADD(name, chmod) \
234+ debugfs_create_file(#name, chmod, phyd, &rdev->wiphy, &name## _ops)
235
236 void cfg80211_debugfs_rdev_add(struct cfg80211_registered_device *rdev)
237 {
238 struct dentry *phyd = rdev->wiphy.debugfsdir;
239
240- DEBUGFS_ADD(rts_threshold);
241- DEBUGFS_ADD(fragmentation_threshold);
242- DEBUGFS_ADD(short_retry_limit);
243- DEBUGFS_ADD(long_retry_limit);
244- DEBUGFS_ADD(ht40allow_map);
245+ DEBUGFS_ADD(rts_threshold, 0444);
246+ DEBUGFS_ADD(fragmentation_threshold, 0444);
247+ DEBUGFS_ADD(short_retry_limit, 0444);
248+ DEBUGFS_ADD(long_retry_limit, 0444);
249+ DEBUGFS_ADD(ht40allow_map, 0444);
250+ DEBUGFS_ADD(dfs_status, 0444);
251+ DEBUGFS_ADD(dfs_skip_nop, 0600);
252+ DEBUGFS_ADD(dfs_skip_cac, 0600);
253 }
254--
2552.18.0
256