Skip to content
Snippets Groups Projects
Commit a45c690f authored by Janusz Dziedzic's avatar Janusz Dziedzic
Browse files

cac derive work

parent 43ce02b9
No related tags found
1 merge request!310Draft: cac derive work
+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);
+ }
--- a/net/wireless/debugfs.c
+++ b/net/wireless/debugfs.c
@@ -95,16 +95,231 @@ static const struct file_operations ht40
.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);
}
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ab83553..040b0ec 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -7639,6 +7639,16 @@ void cfg80211_cac_event(struct net_device *netdev,
const struct cfg80211_chan_def *chandef,
enum nl80211_radar_event event, gfp_t gfp);
+/**
+ * cfg80211_set_available - Set DFS channel available
+ * @netdev: network device
+ * @chandef: chandef for the current channel
+ *
+ * Put comments here
+ */
+void cfg80211_set_available(struct net_device *netdev,
+ const struct cfg80211_chan_def *chandef);
+
/**
* cfg80211_background_cac_abort - Channel Availability Check offchan abort event
* @wiphy: the wiphy
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index cc6d38a..a1270f6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3800,6 +3800,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
cfg80211_rx_assoc_resp(sdata->dev, cbss, (u8 *)mgmt, len, uapsd_queues,
ifmgd->assoc_req_ies, ifmgd->assoc_req_ies_len);
+
+ cfg80211_set_available(sdata->dev, &sdata->vif.bss_conf.chandef);
notify_driver:
drv_mgd_complete_tx(sdata->local, sdata, &info);
kfree(elems);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 00370ca..2e3c037 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -974,6 +974,21 @@ void cfg80211_cac_event(struct net_device *netdev,
}
EXPORT_SYMBOL(cfg80211_cac_event);
+void cfg80211_set_available(struct net_device *netdev,
+ const struct cfg80211_chan_def *chandef)
+{
+ struct wireless_dev *wdev = netdev->ieee80211_ptr;
+ struct wiphy *wiphy = wdev->wiphy;
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+
+ cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_AVAILABLE);
+ memcpy(&rdev->cac_done_chandef, chandef,
+ sizeof(struct cfg80211_chan_def));
+ queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
+ cfg80211_sched_dfs_chan_update(rdev);
+}
+EXPORT_SYMBOL(cfg80211_set_available);
+
static void
__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment