blob: 6ad3b95e7295a99a7ab60ba94c08b7b70f2afaaf [file] [log] [blame]
From 1c581514b49ffe917cb40d4e073c56b6d1f47416 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 19 Jan 2024 14:35:17 +0800
Subject: [PATCH 43/61] cfg80211: mtk: implement DFS radar detect for MLO
Implement DFS radar detect for MLO
1. Add link id info for radar detection in MLD
2. Note that the radar detection flow requires channel switch, which is not yet
complete in MLO, so postpone it.
(a) cac_started, cac_start_time should be moved into wdev->link, but
channel switch will use it, so wait until channel switch is completed.
(b) ieee80211_dfs_cac_cancel, ieee80211_dfs_radar_detected_work, ...
CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: Ic3004607081ae407dd05095769f9e2855a068dd2
rework radar detected flow for mlo
CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Change-Id: I1c76d0b12db52fdb14e73c410d7da69de65bf115
---
include/net/cfg80211.h | 4 +++-
net/mac80211/cfg.c | 26 +++++++++++++++++++-------
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/main.c | 6 +++---
net/mac80211/pm.c | 9 ++++++++-
net/mac80211/util.c | 26 +++++++++++++++++++-------
net/wireless/core.c | 4 ++--
net/wireless/mlme.c | 4 ++--
net/wireless/nl80211.c | 10 +++++-----
net/wireless/rdev-ops.h | 13 +++++++------
net/wireless/reg.c | 15 +++++++++------
net/wireless/trace.h | 28 ++++++++++++++++++++++------
12 files changed, 100 insertions(+), 47 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index bd516d1..e55309b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -4856,10 +4856,12 @@ struct cfg80211_ops {
int (*start_radar_detection)(struct wiphy *wiphy,
struct net_device *dev,
+ unsigned int link_id,
struct cfg80211_chan_def *chandef,
u32 cac_time_ms);
void (*end_cac)(struct wiphy *wiphy,
- struct net_device *dev);
+ struct net_device *dev,
+ unsigned int link_id);
int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_update_ft_ies_params *ftie);
int (*crit_proto_start)(struct wiphy *wiphy,
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 215b5d2..3233e2a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3443,12 +3443,14 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
static int ieee80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
+ unsigned int link_id,
struct cfg80211_chan_def *chandef,
u32 cac_time_ms)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_chan_req chanreq = { .oper = *chandef };
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_link_data *link;
int err;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -3458,16 +3460,20 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
goto out_unlock;
}
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return -ENOLINK;
+
/* whatever, but channel contexts should not complain about that one */
- sdata->deflink.smps_mode = IEEE80211_SMPS_OFF;
- sdata->deflink.needed_rx_chains = local->rx_chains;
+ link->smps_mode = IEEE80211_SMPS_OFF;
+ link->needed_rx_chains = local->rx_chains;
- err = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
+ err = ieee80211_link_use_channel(link, &chanreq,
IEEE80211_CHANCTX_SHARED);
if (err)
goto out_unlock;
- wiphy_delayed_work_queue(wiphy, &sdata->deflink.dfs_cac_timer_work,
+ wiphy_delayed_work_queue(wiphy, &link->dfs_cac_timer_work,
msecs_to_jiffies(cac_time_ms));
out_unlock:
@@ -3475,23 +3481,29 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
}
static void ieee80211_end_cac(struct wiphy *wiphy,
- struct net_device *dev)
+ struct net_device *dev,
+ unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_link_data *link;
lockdep_assert_wiphy(local->hw.wiphy);
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ return;
+
list_for_each_entry(sdata, &local->interfaces, list) {
/* it might be waiting for the local->mtx, but then
* by the time it gets it, sdata->wdev.cac_started
* will no longer be true
*/
wiphy_delayed_work_cancel(wiphy,
- &sdata->deflink.dfs_cac_timer_work);
+ &link->dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
- ieee80211_link_release_channel(&sdata->deflink);
+ ieee80211_link_release_channel(link);
sdata->wdev.cac_started = false;
}
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index c5781c3..608e442 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2592,7 +2592,7 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
bool ieee80211_is_radar_required(struct ieee80211_local *local);
void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work);
-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local);
+void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, unsigned int link_id);
void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
struct wiphy_work *work);
int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index e9d8581..f6f0509 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1173,8 +1173,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
if (comb->num_different_channels > 1)
return -EINVAL;
}
- } else {
- /* DFS is not supported with multi-channel combinations yet */
+ }/* else {
+ // DFS is not supported with multi-channel combinations yet
for (i = 0; i < local->hw.wiphy->n_iface_combinations; i++) {
const struct ieee80211_iface_combination *comb;
@@ -1184,7 +1184,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
comb->num_different_channels > 1)
return -EINVAL;
}
- }
+ } */
/* Only HW csum features are currently compatible with mac80211 */
if (WARN_ON(hw->netdev_features & ~MAC80211_SUPPORTED_FEATURES))
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index c1fa26e..5a25245 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -22,6 +22,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_chanctx *ctx;
struct sta_info *sta;
if (!local->open_count)
@@ -32,7 +33,13 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
ieee80211_scan_cancel(local);
- ieee80211_dfs_cac_cancel(local);
+ list_for_each_entry(ctx, &local->chanctx_list, list) {
+ struct ieee80211_link_data *link, *tmp;
+
+ list_for_each_entry_safe(link, tmp, &ctx->assigned_links,
+ assigned_chanctx_list)
+ ieee80211_dfs_cac_cancel(local, link->link_id);
+ }
ieee80211_roc_purge(local, NULL);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 55f1566..e5ac902 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3450,9 +3450,10 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
return ts;
}
-void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
+void ieee80211_dfs_cac_cancel(struct ieee80211_local *local, unsigned int link_id)
{
struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_link_data *link;
struct cfg80211_chan_def chandef;
lockdep_assert_wiphy(local->hw.wiphy);
@@ -3462,12 +3463,20 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
* by the time it gets it, sdata->wdev.cac_started
* will no longer be true
*/
+ link = sdata_dereference(sdata->link[link_id], sdata);
+ if (!link)
+ continue;
+
+ if (link->conf->chanreq.oper.chan &&
+ link->conf->chanreq.oper.chan->band != NL80211_BAND_5GHZ)
+ return;
+
wiphy_delayed_work_cancel(local->hw.wiphy,
- &sdata->deflink.dfs_cac_timer_work);
+ &link->dfs_cac_timer_work);
if (sdata->wdev.cac_started) {
- chandef = sdata->vif.bss_conf.chanreq.oper;
- ieee80211_link_release_channel(&sdata->deflink);
+ chandef = link->conf->chanreq.oper;
+ ieee80211_link_release_channel(link);
cfg80211_cac_event(sdata->dev,
&chandef,
NL80211_RADAR_CAC_ABORTED,
@@ -3483,20 +3492,23 @@ void ieee80211_dfs_radar_detected_work(struct wiphy *wiphy,
container_of(work, struct ieee80211_local, radar_detected_work);
struct cfg80211_chan_def chandef = local->hw.conf.chandef;
struct ieee80211_chanctx *ctx;
+ struct ieee80211_link_data *link, *tmp;
int num_chanctx = 0;
lockdep_assert_wiphy(local->hw.wiphy);
list_for_each_entry(ctx, &local->chanctx_list, list) {
- if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER)
+ if (ctx->replace_state == IEEE80211_CHANCTX_REPLACES_OTHER ||
+ !ctx->conf.def.chan || ctx->conf.def.chan->band != NL80211_BAND_5GHZ)
continue;
num_chanctx++;
chandef = ctx->conf.def;
+ list_for_each_entry_safe(link, tmp, &ctx->assigned_links,
+ assigned_chanctx_list)
+ ieee80211_dfs_cac_cancel(local, link->link_id);
}
- ieee80211_dfs_cac_cancel(local);
-
if (num_chanctx > 1)
/* XXX: multi-channel is not supported yet */
WARN_ON(1);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index ac9417e..16f40f3 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -629,10 +629,10 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
if (WARN_ON(!c->num_different_channels))
return -EINVAL;
- /* DFS only works on one channel. */
+ /* DFS only works on one channel.
if (WARN_ON(c->radar_detect_widths &&
(c->num_different_channels > 1)))
- return -EINVAL;
+ return -EINVAL; */
if (WARN_ON(!c->n_limits))
return -EINVAL;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 3da7886..a957989 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -1118,9 +1118,9 @@ void cfg80211_cac_event(struct net_device *netdev,
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
unsigned long timeout;
- /* not yet supported */
+ /* not yet supported
if (wdev->valid_links)
- return;
+ return; */
trace_cfg80211_cac_event(netdev, event);
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 079fedf..2045cdc 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -9964,6 +9964,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
struct cfg80211_chan_def chandef;
enum nl80211_dfs_regions dfs_region;
unsigned int cac_time_ms;
+ unsigned int link_id = nl80211_link_id(info->attrs);
int err = -EINVAL;
flush_delayed_work(&rdev->dfs_update_channels_wk);
@@ -9998,7 +9999,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
goto unlock;
}
- if (netif_carrier_ok(dev)) {
+ if (!wdev->valid_links && netif_carrier_ok(dev)) {
err = -EBUSY;
goto unlock;
}
@@ -10026,9 +10027,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
pr_info("%s: region = %u, center freq1 = %u, center freq2 = %u, cac time ms = %u\n",
__func__, dfs_region, chandef.center_freq1, chandef.center_freq2, cac_time_ms);
- err = rdev_start_radar_detection(rdev, dev, &chandef, cac_time_ms);
+ err = rdev_start_radar_detection(rdev, dev, link_id, &chandef, cac_time_ms);
if (!err) {
- wdev->links[0].ap.chandef = chandef;
+ wdev->links[link_id].ap.chandef = chandef;
wdev->cac_started = true;
wdev->cac_start_time = jiffies;
wdev->cac_time_ms = cac_time_ms;
@@ -17304,8 +17305,7 @@ static const struct genl_small_ops nl80211_small_ops[] = {
.doit = nl80211_start_radar_detection,
.flags = GENL_UNS_ADMIN_PERM,
.internal_flags = IFLAGS(NL80211_FLAG_NEED_NETDEV_UP |
- NL80211_FLAG_NO_WIPHY_MTX |
- NL80211_FLAG_MLO_UNSUPPORTED),
+ NL80211_FLAG_NO_WIPHY_MTX),
},
{
.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
index 2ae7fc5..561637c 100644
--- a/net/wireless/rdev-ops.h
+++ b/net/wireless/rdev-ops.h
@@ -1197,15 +1197,16 @@ rdev_tdls_cancel_channel_switch(struct cfg80211_registered_device *rdev,
static inline int
rdev_start_radar_detection(struct cfg80211_registered_device *rdev,
struct net_device *dev,
+ unsigned int link_id,
struct cfg80211_chan_def *chandef,
u32 cac_time_ms)
{
int ret = -EOPNOTSUPP;
- trace_rdev_start_radar_detection(&rdev->wiphy, dev, chandef,
- cac_time_ms);
+ trace_rdev_start_radar_detection(&rdev->wiphy, dev, link_id,
+ chandef, cac_time_ms);
if (rdev->ops->start_radar_detection)
- ret = rdev->ops->start_radar_detection(&rdev->wiphy, dev,
+ ret = rdev->ops->start_radar_detection(&rdev->wiphy, dev, link_id,
chandef, cac_time_ms);
trace_rdev_return_int(&rdev->wiphy, ret);
return ret;
@@ -1213,11 +1214,11 @@ rdev_start_radar_detection(struct cfg80211_registered_device *rdev,
static inline void
rdev_end_cac(struct cfg80211_registered_device *rdev,
- struct net_device *dev)
+ struct net_device *dev, unsigned int link_id)
{
- trace_rdev_end_cac(&rdev->wiphy, dev);
+ trace_rdev_end_cac(&rdev->wiphy, dev, link_id);
if (rdev->ops->end_cac)
- rdev->ops->end_cac(&rdev->wiphy, dev);
+ rdev->ops->end_cac(&rdev->wiphy, dev, link_id);
trace_rdev_return_void(&rdev->wiphy);
}
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2c0c1f1..6883aa0 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -4246,17 +4246,20 @@ static void cfg80211_check_and_end_cac(struct cfg80211_registered_device *rdev)
*/
list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list) {
struct cfg80211_chan_def *chandef;
+ unsigned int link_id;
if (!wdev->cac_started)
continue;
- /* FIXME: radar detection is tied to link 0 for now */
- chandef = wdev_chandef(wdev, 0);
- if (!chandef)
- continue;
+ for_each_valid_link(wdev, link_id) {
+ chandef = wdev_chandef(wdev, link_id);
+ if (!chandef || !chandef->chan ||
+ chandef->chan->band != NL80211_BAND_5GHZ)
+ continue;
- if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef))
- rdev_end_cac(rdev, wdev->netdev);
+ if (!cfg80211_chandef_dfs_usable(&rdev->wiphy, chandef))
+ rdev_end_cac(rdev, wdev->netdev, link_id);
+ }
}
}
diff --git a/net/wireless/trace.h b/net/wireless/trace.h
index aa3284f..22b1fcc 100644
--- a/net/wireless/trace.h
+++ b/net/wireless/trace.h
@@ -731,9 +731,22 @@ DEFINE_EVENT(wiphy_netdev_evt, rdev_flush_pmksa,
TP_ARGS(wiphy, netdev)
);
-DEFINE_EVENT(wiphy_netdev_evt, rdev_end_cac,
- TP_PROTO(struct wiphy *wiphy, struct net_device *netdev),
- TP_ARGS(wiphy, netdev)
+TRACE_EVENT(rdev_end_cac,
+ TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ unsigned int link_id),
+ TP_ARGS(wiphy, netdev, link_id),
+ TP_STRUCT__entry(
+ WIPHY_ENTRY
+ NETDEV_ENTRY
+ __field(u32, link_id)
+ ),
+ TP_fast_assign(
+ WIPHY_ASSIGN;
+ NETDEV_ASSIGN;
+ __entry->link_id = link_id;
+ ),
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id=%u",
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id)
);
DECLARE_EVENT_CLASS(station_add_change,
@@ -2577,24 +2590,27 @@ TRACE_EVENT(rdev_external_auth,
TRACE_EVENT(rdev_start_radar_detection,
TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+ unsigned int link_id,
struct cfg80211_chan_def *chandef,
u32 cac_time_ms),
- TP_ARGS(wiphy, netdev, chandef, cac_time_ms),
+ TP_ARGS(wiphy, netdev, link_id, chandef, cac_time_ms),
TP_STRUCT__entry(
WIPHY_ENTRY
NETDEV_ENTRY
+ __field(u32, link_id)
CHAN_DEF_ENTRY
__field(u32, cac_time_ms)
),
TP_fast_assign(
WIPHY_ASSIGN;
NETDEV_ASSIGN;
+ __entry->link_id = link_id;
CHAN_DEF_ASSIGN(chandef);
__entry->cac_time_ms = cac_time_ms;
),
- TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT
+ TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", link_id=%u, " CHAN_DEF_PR_FMT
", cac_time_ms=%u",
- WIPHY_PR_ARG, NETDEV_PR_ARG, CHAN_DEF_PR_ARG,
+ WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->link_id, CHAN_DEF_PR_ARG,
__entry->cac_time_ms)
);
--
2.39.2