[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250527-mlo-dfs-acs-v2-2-92c2f37c81d9@quicinc.com>
Date: Tue, 27 May 2025 14:11:44 +0530
From: Raj Kumar Bhagat <quic_rajkbhag@...cinc.com>
To: Johannes Berg <johannes@...solutions.net>
CC: <linux-wireless@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
"Aditya
Kumar Singh" <aditya.kumar.singh@....qualcomm.com>,
Raj Kumar Bhagat
<quic_rajkbhag@...cinc.com>
Subject: [PATCH wireless-next v2 2/3] wifi: mac80211: Allow DFS/CSA on a
radio if scan is ongoing on another radio
From: Aditya Kumar Singh <aditya.kumar.singh@....qualcomm.com>
Currently, in multi-radio wiphy cases, if a scan is ongoing on one radio,
-EBUSY is returned when DFS or a channel switch is initiated on another
radio. Because of this, an MLD AP with one radio (link) in an ongoing scan
cannot initiate DFS or a channel switch on another radio (link).
In multi-radio wiphy cases, multiple radios are grouped under a single
wiphy. Hence, if a scan is ongoing on one underlying radio and DFS or a
channel switch is requested on a different underlying radio of the same
wiphy, these operations can be allowed simultaneously.
Add logic to check the underlying radio used for the ongoing scan. If the
radio on which DFS or a channel switch is requested is not being used for
the scan, allow the operation; otherwise, return -EBUSY.
Signed-off-by: Aditya Kumar Singh <aditya.kumar.singh@....qualcomm.com>
Co-developed-by: Raj Kumar Bhagat <quic_rajkbhag@...cinc.com>
Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@...cinc.com>
---
net/mac80211/cfg.c | 54 ++++++++++++++++++++++++++++++++++++++++++++--
net/mac80211/ieee80211_i.h | 3 +++
net/mac80211/util.c | 27 +++++++++++++++++++++++
3 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index d9d88f2f283120ba366401d3ac546e59d8c61c21..55a8fbd255148b3a40d9239f5bfd4c7e6619c0c7 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3549,6 +3549,56 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
return 0;
}
+static bool ieee80211_is_scan_ongoing(struct wiphy *wiphy,
+ struct ieee80211_local *local,
+ struct cfg80211_chan_def *chandef)
+{
+ struct cfg80211_scan_request *scan_req;
+ int chan_radio_idx, req_radio_idx;
+ struct ieee80211_roc_work *roc;
+
+ if (list_empty(&local->roc_list) && !local->scanning)
+ return false;
+
+ if (wiphy->n_radio < 2)
+ return true;
+
+ req_radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chandef->chan);
+ if (req_radio_idx < 0)
+ return true;
+
+ if (local->scanning) {
+ scan_req = wiphy_dereference(wiphy, local->scan_req);
+ /*
+ * Scan is going on but info is not there. Should not happen
+ * but if it does, let's not take risk and assume we can't use
+ * the hw hence return true
+ */
+ if (WARN_ON_ONCE(!scan_req))
+ return true;
+
+ return ieee80211_is_radio_idx_in_scan_req(wiphy, scan_req,
+ req_radio_idx);
+ }
+
+ list_for_each_entry(roc, &local->roc_list, list) {
+ chan_radio_idx = cfg80211_get_radio_idx_by_chan(wiphy,
+ roc->chan);
+ /*
+ * The roc work is added but chan_radio_idx is invalid.
+ * Should not happen but if it does, let's not take
+ * risk and return true.
+ */
+ if (chan_radio_idx < 0)
+ return true;
+
+ if (chan_radio_idx == req_radio_idx)
+ return true;
+ }
+
+ return false;
+}
+
static int ieee80211_start_radar_detection(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef,
@@ -3562,7 +3612,7 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
lockdep_assert_wiphy(local->hw.wiphy);
- if (!list_empty(&local->roc_list) || local->scanning)
+ if (ieee80211_is_scan_ongoing(wiphy, local, chandef))
return -EBUSY;
link_data = sdata_dereference(sdata->link[link_id], sdata);
@@ -4054,7 +4104,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
lockdep_assert_wiphy(local->hw.wiphy);
- if (!list_empty(&local->roc_list) || local->scanning)
+ if (ieee80211_is_scan_ongoing(wiphy, local, ¶ms->chandef))
return -EBUSY;
if (sdata->wdev.links[link_id].cac_started)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 30809f0b35f73e77b05a6f802011a64900e1532f..7719d6c307fed5f44c9a5e35b8250c31daa6f523 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2713,6 +2713,9 @@ void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
struct ieee80211_link_data *rsvd_for,
bool check_reserved);
bool ieee80211_is_radar_required(struct ieee80211_local *local);
+bool ieee80211_is_radio_idx_in_scan_req(struct wiphy *wiphy,
+ struct cfg80211_scan_request *scan_req,
+ int radio_idx);
void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work);
void ieee80211_dfs_cac_cancel(struct ieee80211_local *local,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 27d414efa3fd4bda40d2a37b14da6a4aa6bf0a02..ea73a38fb8665ec7179289771f44e8ba3abef5f7 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -3953,6 +3953,33 @@ static u8 ieee80211_chanctx_radar_detect(struct ieee80211_local *local,
return radar_detect;
}
+bool ieee80211_is_radio_idx_in_scan_req(struct wiphy *wiphy,
+ struct cfg80211_scan_request *scan_req,
+ int radio_idx)
+{
+ struct ieee80211_channel *chan;
+ int i, chan_radio_idx;
+
+ for (i = 0; i < scan_req->n_channels; i++) {
+ chan = scan_req->channels[i];
+ chan_radio_idx = cfg80211_get_radio_idx_by_chan(wiphy, chan);
+ /*
+ * The chan_radio_idx should be valid since it's taken from a
+ * valid scan request.
+ * However, if chan_radio_idx is unexpectedly invalid (negative),
+ * we take a conservative approach and assume the scan request
+ * might use the specified radio_idx. Hence, return true.
+ */
+ if (WARN_ON(chan_radio_idx < 0))
+ return true;
+
+ if (chan_radio_idx == radio_idx)
+ return true;
+ }
+
+ return false;
+}
+
static u32
__ieee80211_get_radio_mask(struct ieee80211_sub_if_data *sdata)
{
--
2.34.1
Powered by blists - more mailing lists