diff --git a/package/kernel/mac80211/patches/subsys/800--cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch b/package/kernel/mac80211/patches/subsys/800--cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad1ff23ef0781c53e33990a8727dfec60085dcfd --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/800--cfg80211-implement-DFS-status-show-cac-and-nop-skip-command.patch @@ -0,0 +1,494 @@ ++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/package/kernel/mac80211/patches/subsys/801-cfg80211-dfs-available.patch b/package/kernel/mac80211/patches/subsys/801-cfg80211-dfs-available.patch new file mode 100644 index 0000000000000000000000000000000000000000..c6be21951b5e462b76f3ddd2e54bea40bb1d02cd --- /dev/null +++ b/package/kernel/mac80211/patches/subsys/801-cfg80211-dfs-available.patch @@ -0,0 +1,60 @@ +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,