blob: 39e8817533a5474a0d4279bf77d285ea6eef2b38 [file] [log] [blame]
developer05f3b2b2024-08-19 19:17:34 +08001From 16ec7de7b7f4d09a4b84ea2d85fb287a579626b2 Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Tue, 6 Feb 2024 17:46:10 +0800
4Subject: [PATCH 72/89] mtk: mac80211: add DFS CAC countdown in CSA flow
5
6Add DFS channel CAC countdown mechanism in CSA flow
7
8Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
9---
10 include/net/cfg80211.h | 38 ++++++++++++++++-
11 net/mac80211/cfg.c | 85 ++++++++++++++++++++++++++++++++++++--
12 net/mac80211/ieee80211_i.h | 1 +
13 net/mac80211/mlme.c | 6 ++-
14 net/mac80211/util.c | 7 +++-
15 net/wireless/chan.c | 74 +++++++++++++++++++++++++++++++++
16 net/wireless/nl80211.c | 5 ++-
17 net/wireless/rdev-ops.h | 18 ++++++++
18 net/wireless/reg.c | 8 +++-
19 9 files changed, 232 insertions(+), 10 deletions(-)
20
21diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
22index 5de1d1c..bedf711 100644
23--- a/include/net/cfg80211.h
24+++ b/include/net/cfg80211.h
25@@ -4481,6 +4481,8 @@ struct mgmt_frame_regs {
26 *
27 * @start_radar_detection: Start radar detection in the driver.
28 *
29+ * @start_radar_detection_post_csa: Start radar detection during post CSA.
30+ *
31 * @end_cac: End running CAC, probably because a related CAC
32 * was finished on another phy.
33 *
34@@ -4853,9 +4855,13 @@ struct cfg80211_ops {
35
36 int (*start_radar_detection)(struct wiphy *wiphy,
37 struct net_device *dev,
38- unsigned int link_id,
39 struct cfg80211_chan_def *chandef,
40 u32 cac_time_ms, int link_id);
41+ int (*start_radar_detection_post_csa)(struct wiphy *wiphy,
42+ struct net_device *dev,
43+ unsigned int link_id,
44+ struct cfg80211_chan_def *chandef,
45+ u32 cac_time_ms);
46 void (*end_cac)(struct wiphy *wiphy,
47 struct net_device *dev, unsigned int link_id);
48 int (*update_ft_ies)(struct wiphy *wiphy, struct net_device *dev,
49@@ -9018,6 +9024,36 @@ cfg80211_reg_can_beacon_relax(struct wiphy *wiphy,
50 }
51
52 /**
53+ * cfg80211_reg_can_beacon_dfs_relax - check if beaconing is allowed with DFS & IR-relaxation
54+ * @wiphy: the wiphy
55+ * @chandef: the channel definition
56+ * @iftype: interface type
57+ *
58+ * Return: %true if there is no secondary channel or the secondary channel(s)
59+ * can be used for beaconing. This version bypasses radar channel check, allowing
60+ * channel switch to a USABLE DFS channel and performing CAC after the channel switch.
61+ * It also checks if IR-relaxation conditions apply, to allow beaconing under more
62+ * permissive conditions.
63+ *
64+ * Requires the wiphy mutex to be held.
65+ */
66+bool cfg80211_reg_can_beacon_dfs_relax(struct wiphy *wiphy,
67+ struct cfg80211_chan_def *chandef,
68+ enum nl80211_iftype iftype);
69+
70+/**
71+ * cfg80211_start_radar_detection_post_csa - start radar detection after CSA
72+ * @wiphy: the wiphy
73+ * @wdev: the wireless device
74+ * @link_id: the link ID for MLO, must be 0 for non-MLO
75+ * @chandef: the channel definition to start radar detection on
76+ */
77+int cfg80211_start_radar_detection_post_csa(struct wiphy *wiphy,
78+ struct wireless_dev *wdev,
79+ unsigned int link_id,
80+ struct cfg80211_chan_def *chandef);
81+
82+/*
83 * cfg80211_ch_switch_notify - update wdev channel and notify userspace
84 * @dev: the device which switched channels
85 * @chandef: the new channel definition
86diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
87index c52cde0..36c898c 100644
88--- a/net/mac80211/cfg.c
89+++ b/net/mac80211/cfg.c
90@@ -1576,7 +1576,7 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
91 return 0;
92 }
93
94-static void ieee80211_free_next_beacon(struct ieee80211_link_data *link)
95+void ieee80211_free_next_beacon(struct ieee80211_link_data *link)
96 {
97 if (!link->u.ap.next_beacon)
98 return;
99@@ -3725,6 +3725,72 @@ static int ieee80211_set_after_csa_beacon(struct ieee80211_link_data *link_data,
100 return 0;
101 }
102
103+static int ieee80211_start_radar_detection_post_csa(struct wiphy *wiphy,
104+ struct net_device *dev,
105+ unsigned int link_id,
106+ struct cfg80211_chan_def *chandef,
107+ u32 cac_time_ms)
108+{
109+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
110+ struct ieee80211_local *local = sdata->local;
111+ struct ieee80211_link_data *link;
112+
113+ if (!list_empty(&local->roc_list) || local->scanning)
114+ return -EBUSY;
115+
116+ link = sdata_dereference(sdata->link[link_id], sdata);
117+ if (!link)
118+ return -ENOLINK;
119+
120+ /* whatever, but channel contexts should not complain about that one */
121+ link->smps_mode = IEEE80211_SMPS_OFF;
122+ link->needed_rx_chains = local->rx_chains;
123+
124+ if (hweight16(sdata->vif.valid_links) <= 1)
125+ sta_info_flush(sdata, -1);
126+
127+ wiphy_delayed_work_queue(wiphy, &link->dfs_cac_timer_work,
128+ msecs_to_jiffies(cac_time_ms));
129+
130+ return 1;
131+}
132+
133+static void ieee80211_csa_send_deauth(struct ieee80211_link_data *link_data)
134+{
135+ struct ieee80211_sub_if_data *sdata = link_data->sdata;
136+ struct ieee80211_local *local = sdata->local;
137+ struct ieee80211_bss_conf *link_conf = link_data->conf;
138+ u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
139+ u8 broadcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
140+ bool send_deauth;
141+
142+ send_deauth = !cfg80211_chandef_identical(&link_conf->chanreq.oper,
143+ &link_data->csa.chanreq.oper) &&
144+ !cfg80211_reg_can_beacon_relax(local->hw.wiphy,
145+ &link_data->csa.chanreq.oper,
146+ sdata->wdev.iftype) &&
147+ hweight16(sdata->vif.valid_links) <= 1;
148+ /* broadcast deauth frame if CAC is required for non MLD or single link MLD AP */
149+ if (!send_deauth)
150+ return;
151+
152+ if (sdata->csa_blocked_queues) {
153+ ieee80211_wake_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA);
154+ ieee80211_send_deauth_disassoc(sdata, broadcast,
155+ link_conf->bssid,
156+ IEEE80211_STYPE_DEAUTH,
157+ WLAN_REASON_DEAUTH_LEAVING,
158+ send_deauth, frame_buf);
159+ ieee80211_stop_vif_queues(local, sdata, IEEE80211_QUEUE_STOP_REASON_CSA);
160+ return;
161+ }
162+
163+ ieee80211_send_deauth_disassoc(sdata, broadcast,
164+ link_conf->bssid, IEEE80211_STYPE_DEAUTH,
165+ WLAN_REASON_DEAUTH_LEAVING,
166+ send_deauth, frame_buf);
167+}
168+
169 static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
170 {
171 struct ieee80211_sub_if_data *sdata = link_data->sdata;
172@@ -3735,6 +3801,8 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
173
174 lockdep_assert_wiphy(local->hw.wiphy);
175
176+ ieee80211_csa_send_deauth(link_data);
177+
178 /*
179 * using reservation isn't immediate as it may be deferred until later
180 * with multi-vif. once reservation is complete it will re-schedule the
181@@ -3758,6 +3826,12 @@ static int __ieee80211_csa_finalize(struct ieee80211_link_data *link_data)
182 &link_data->csa.chanreq.oper))
183 return -EINVAL;
184
185+ err = cfg80211_start_radar_detection_post_csa(local->hw.wiphy, &sdata->wdev,
186+ link_data->link_id,
187+ &link_conf->chanreq.oper);
188+ if (err)
189+ return err > 0 ? 0 : err;
190+
191 link_conf->csa_active = false;
192
193 err = ieee80211_set_after_csa_beacon(link_data, &changed);
194@@ -5140,8 +5214,12 @@ ieee80211_skip_cac(struct wireless_dev *wdev, unsigned int link_id)
195
196 wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
197 &link->dfs_cac_timer_work);
198- if (wdev->cac_links & BIT(link_id)) {
199- ieee80211_link_release_channel(link);
200+ if (wdev->links[link_id].cac_started) {
201+ if (link->conf->csa_active)
202+ wiphy_work_queue(sdata->local->hw.wiphy,
203+ &link->csa.finalize_work);
204+ else
205+ ieee80211_link_release_channel(link);
206 cac_time_ms = wdev->links[link_id].cac_time_ms;
207 wdev->links[link_id].cac_start_time = jiffies -
208 msecs_to_jiffies(cac_time_ms + 1);
209@@ -5233,6 +5311,7 @@ const struct cfg80211_ops mac80211_config_ops = {
210 #endif
211 .get_channel = ieee80211_cfg_get_channel,
212 .start_radar_detection = ieee80211_start_radar_detection,
213+ .start_radar_detection_post_csa = ieee80211_start_radar_detection_post_csa,
214 .end_cac = ieee80211_end_cac,
215 .channel_switch = ieee80211_channel_switch,
216 .set_qos_map = ieee80211_set_qos_map,
217diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
218index a5c0d6c..2cb80c3 100644
219--- a/net/mac80211/ieee80211_i.h
220+++ b/net/mac80211/ieee80211_i.h
221@@ -2015,6 +2015,7 @@ int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
222 void ieee80211_csa_finalize_work(struct wiphy *wiphy, struct wiphy_work *work);
223 int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
224 struct cfg80211_csa_settings *params);
225+void ieee80211_free_next_beacon(struct ieee80211_link_data *link);
226
227 /* color change handling */
228 void ieee80211_color_change_finalize_work(struct wiphy *wiphy,
229diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
230index 1b19583..b684fed 100644
231--- a/net/mac80211/mlme.c
232+++ b/net/mac80211/mlme.c
233@@ -3051,7 +3051,11 @@ void ieee80211_dfs_cac_timer_work(struct wiphy *wiphy, struct wiphy_work *work)
234 lockdep_assert_wiphy(sdata->local->hw.wiphy);
235
236 if (sdata->wdev.links[link->link_id].cac_started) {
237- ieee80211_link_release_channel(link);
238+ if (link->conf->csa_active)
239+ wiphy_work_queue(sdata->local->hw.wiphy,
240+ &link->csa.finalize_work);
241+ else
242+ ieee80211_link_release_channel(link);
243 cfg80211_cac_event(sdata->dev, &chandef,
244 NL80211_RADAR_CAC_FINISHED,
245 GFP_KERNEL, link->link_id);
246diff --git a/net/mac80211/util.c b/net/mac80211/util.c
247index 2d2b871..df4fa1a 100644
248--- a/net/mac80211/util.c
249+++ b/net/mac80211/util.c
250@@ -3494,7 +3494,12 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
251 continue;
252
253 chandef = link_conf->chanreq.oper;
254- ieee80211_link_release_channel(link_data);
255+ if (link_conf->csa_active) {
256+ link_conf->csa_active = false;
257+ ieee80211_free_next_beacon(link_data);
258+ } else {
259+ ieee80211_link_release_channel(link_data);
260+ }
261 cfg80211_cac_event(sdata->dev,
262 &chandef,
263 NL80211_RADAR_CAC_ABORTED,
264diff --git a/net/wireless/chan.c b/net/wireless/chan.c
265index 38e8432..03747bb 100644
266--- a/net/wireless/chan.c
267+++ b/net/wireless/chan.c
268@@ -1680,6 +1680,80 @@ bool cfg80211_reg_check_beaconing(struct wiphy *wiphy,
269 }
270 EXPORT_SYMBOL(cfg80211_reg_check_beaconing);
271
272+bool cfg80211_reg_can_beacon_dfs_relax(struct wiphy *wiphy,
273+ struct cfg80211_chan_def *chandef,
274+ enum nl80211_iftype iftype)
275+{
276+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
277+ u32 prohibited_flags = IEEE80211_CHAN_DISABLED |
278+ IEEE80211_CHAN_RADAR;
279+
280+ lockdep_assert_held(&rdev->wiphy.mtx);
281+
282+ /* Bypass available and usable dfs channel */
283+ if (cfg80211_chandef_dfs_required(wiphy, chandef, iftype) > 0 &&
284+ (cfg80211_chandef_dfs_usable(wiphy, chandef) ||
285+ cfg80211_chandef_dfs_available(wiphy, chandef)))
286+ prohibited_flags = IEEE80211_CHAN_DISABLED;
287+
288+ /*
289+ * Under certain conditions suggested by some regulatory bodies a
290+ * GO/STA can IR on channels marked with IEEE80211_NO_IR. Set this flag
291+ * only if such relaxations are not enabled and the conditions are not
292+ * met.
293+ */
294+ if (!cfg80211_ir_permissive_chan(wiphy, iftype, chandef->chan))
295+ prohibited_flags |= IEEE80211_CHAN_NO_IR;
296+
297+ return cfg80211_chandef_usable(wiphy, chandef, prohibited_flags);
298+}
299+EXPORT_SYMBOL(cfg80211_reg_can_beacon_dfs_relax);
300+
301+int cfg80211_start_radar_detection_post_csa(struct wiphy *wiphy,
302+ struct wireless_dev *wdev,
303+ unsigned int link_id,
304+ struct cfg80211_chan_def *chandef)
305+{
306+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
307+ u32 cac_time_ms;
308+ enum nl80211_dfs_regions dfs_region;
309+ int ret = 0;
310+
311+ if (cfg80211_chandef_dfs_available(wiphy, chandef))
312+ goto out;
313+
314+ /* Update DFS channel state especially when original channel include DFS channel */
315+ cfg80211_sched_dfs_chan_update(rdev);
316+
317+ dfs_region = reg_get_dfs_region(wiphy);
318+ if (dfs_region == NL80211_DFS_UNSET)
319+ goto out;
320+
321+ cac_time_ms = cfg80211_chandef_dfs_cac_time(wiphy, chandef);
322+ if (WARN_ON(!cac_time_ms))
323+ cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
324+
325+ pr_info("%s: region = %u, center freq1 = %u, center freq2 = %u, cac time ms = %u\n",
326+ __func__, dfs_region, chandef->center_freq1, chandef->center_freq2, cac_time_ms);
327+
328+ ret = rdev_start_radar_detection_post_csa(rdev, wdev->netdev, link_id,
329+ chandef, cac_time_ms);
330+ if (ret > 0) {
331+ wdev->links[link_id].ap.chandef = *chandef;
332+ wdev->links[link_id].cac_start_time = jiffies;
333+ wdev->links[link_id].cac_time_ms = cac_time_ms;
334+ if (rdev->background_cac_started &&
335+ cfg80211_is_sub_chan(chandef, rdev->background_radar_chandef.chan, false))
336+ cfg80211_stop_background_radar_detection(rdev->background_radar_wdev);
337+ cfg80211_cac_event(wdev->netdev, chandef,
338+ NL80211_RADAR_CAC_STARTED, GFP_KERNEL, link_id);
339+ }
340+
341+out:
342+ return ret;
343+}
344+EXPORT_SYMBOL(cfg80211_start_radar_detection_post_csa);
345+
346 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
347 struct cfg80211_chan_def *chandef)
348 {
349diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
350index ba1190d..756a29a 100644
351--- a/net/wireless/nl80211.c
352+++ b/net/wireless/nl80211.c
353@@ -10462,8 +10462,9 @@ skip_beacons:
354 cfg80211_set_dfs_state(&rdev->wiphy, &params.chandef, NL80211_DFS_AVAILABLE);
355 }
356
357- if (!cfg80211_reg_can_beacon_relax(&rdev->wiphy, &params.chandef,
358- wdev->iftype)) {
359+ /* handle DFS CAC after CSA is sent */
360+ if (!cfg80211_reg_can_beacon_dfs_relax(&rdev->wiphy, &params.chandef,
361+ wdev->iftype)) {
362 err = -EINVAL;
363 goto free;
364 }
365diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
366index e4a77a8..5b3c94f 100644
367--- a/net/wireless/rdev-ops.h
368+++ b/net/wireless/rdev-ops.h
369@@ -1214,6 +1214,24 @@ rdev_start_radar_detection(struct cfg80211_registered_device *rdev,
370 return ret;
371 }
372
373+static inline int
374+rdev_start_radar_detection_post_csa(struct cfg80211_registered_device *rdev,
375+ struct net_device *dev,
376+ unsigned int link_id,
377+ struct cfg80211_chan_def *chandef,
378+ u32 cac_time_ms)
379+{
380+ int ret = -EOPNOTSUPP;
381+
382+ trace_rdev_start_radar_detection(&rdev->wiphy, dev, chandef,
383+ cac_time_ms, link_id);
384+ if (rdev->ops->start_radar_detection_post_csa)
385+ ret = rdev->ops->start_radar_detection_post_csa(&rdev->wiphy, dev, link_id,
386+ chandef, cac_time_ms);
387+ trace_rdev_return_int(&rdev->wiphy, ret);
388+ return ret;
389+}
390+
391 static inline void
392 rdev_end_cac(struct cfg80211_registered_device *rdev,
393 struct net_device *dev, unsigned int link_id)
394diff --git a/net/wireless/reg.c b/net/wireless/reg.c
395index 2a13721..651f286 100644
396--- a/net/wireless/reg.c
397+++ b/net/wireless/reg.c
398@@ -2441,8 +2441,12 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
399 case NL80211_IFTYPE_P2P_GO:
400 case NL80211_IFTYPE_ADHOC:
401 case NL80211_IFTYPE_MESH_POINT:
402- ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef,
403- iftype);
404+ if (wdev->links[link].cac_started)
405+ ret = cfg80211_reg_can_beacon_dfs_relax(wiphy, &chandef,
406+ iftype);
407+ else
408+ ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef,
409+ iftype);
410 if (!ret)
411 return ret;
412 break;
413--
4142.18.0
415