blob: c42a00fe92e6bf9aa66a525a2be3b2569c78a93e [file] [log] [blame]
developer1413c882023-02-15 00:01:06 +08001From 7dd3aacd15e5678a617001dc329cf942ed7f4298 Mon Sep 17 00:00:00 2001
developer4a339e82022-12-12 19:00:30 +08002From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Wed, 5 Oct 2022 19:13:43 +0800
developer1413c882023-02-15 00:01:06 +08004Subject: [PATCH 11/16] mac80211: mtk: fix the issue of AP and STA starting on
5 DFS channel concurrently
developer4a339e82022-12-12 19:00:30 +08006
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
9 include/net/cfg80211.h | 22 ++++++++++++++++++
10 include/uapi/linux/nl80211.h | 2 +-
11 net/mac80211/cfg.c | 44 ++++++++++++++++++++++++++++++++++++
12 net/mac80211/chan.c | 2 +-
13 net/wireless/chan.c | 6 ++---
developer3783b072023-02-01 16:07:11 +080014 net/wireless/nl80211.c | 7 ++++++
developer4a339e82022-12-12 19:00:30 +080015 net/wireless/rdev-ops.h | 16 +++++++++++++
16 net/wireless/trace.h | 15 ++++++++++++
developer3783b072023-02-01 16:07:11 +080017 8 files changed, 109 insertions(+), 5 deletions(-)
developer4a339e82022-12-12 19:00:30 +080018
19diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
20index f9c2cc3..84e769b 100644
21--- a/include/net/cfg80211.h
22+++ b/include/net/cfg80211.h
23@@ -888,6 +888,24 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
24 chandef1->center_freq2 == chandef2->center_freq2);
25 }
26
27+/**
28+ * cfg80211_chan_fully_overlap - check if two channel are fully overlapped
29+ * @chandef1: first channel definition
30+ * @chandef2: second channel definition
31+ *
32+ * Return: %true if the channels are valid and fully overlapped, %false otherwise.
33+ */
34+static inline bool
35+cfg80211_chan_fully_overlap(const struct cfg80211_chan_def *chandef1,
36+ const struct cfg80211_chan_def *chandef2)
37+{
38+ return (chandef1->center_freq1 != 0 &&
39+ chandef1->center_freq1 == chandef2->center_freq1 &&
40+ chandef1->width == chandef2->width &&
41+ chandef1->freq1_offset == chandef2->freq1_offset &&
42+ chandef1->center_freq2 == chandef2->center_freq2);
43+}
44+
45 /**
46 * cfg80211_chandef_is_edmg - check if chandef represents an EDMG channel
47 *
48@@ -4642,6 +4660,8 @@ struct cfg80211_ops {
49 int (*del_link_station)(struct wiphy *wiphy, struct net_device *dev,
50 struct link_station_del_parameters *params);
51 void (*skip_cac)(struct wireless_dev *wdev);
52+ void (*check_cac_skip)(struct wiphy *wiphy,
53+ struct cfg80211_chan_def *chandef);
54 };
55
56 /*
57@@ -5847,6 +5867,8 @@ struct wireless_dev {
58 };
59 } links[IEEE80211_MLD_MAX_NUM_LINKS];
60 u16 valid_links;
61+
62+ bool start_disabled;
63 };
64
65 static inline const u8 *wdev_address(struct wireless_dev *wdev)
66diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
67index 1293d30..db9d0a8 100644
68--- a/include/uapi/linux/nl80211.h
69+++ b/include/uapi/linux/nl80211.h
70@@ -3283,7 +3283,7 @@ enum nl80211_attrs {
71 NL80211_ATTR_WIPHY_ANTENNA_GAIN,
72
73 /* add attributes here, update the policy in nl80211.c */
74-
75+ NL80211_ATTR_START_DISABLED = 999,
76 __NL80211_ATTR_AFTER_LAST,
77 NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
78 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
79diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
80index 5718c56..9da02d9 100644
81--- a/net/mac80211/cfg.c
82+++ b/net/mac80211/cfg.c
83@@ -4889,6 +4889,49 @@ ieee80211_skip_cac(struct wireless_dev *wdev)
84 }
85 }
86
87+static void
88+ieee80211_check_cac_skip(struct wiphy *wiphy,
89+ struct cfg80211_chan_def *chandef)
90+{
91+ struct ieee80211_local *local = wiphy_priv(wiphy);
92+ struct ieee80211_sub_if_data *s1;
93+ struct ieee80211_sub_if_data *s2;
94+ struct ieee80211_sub_if_data *sdata_sta;
95+ struct ieee80211_if_managed *ifmgd;
96+ struct ieee80211_channel *chan;
97+ struct wireless_dev *wdev;
98+ unsigned int cac_time_ms;
99+
100+ mutex_lock(&local->mtx);
101+ /* Bypass AP's cac if there is a STA associated to the same DFS channel */
102+ list_for_each_entry(s1, &local->interfaces, list) {
103+ ifmgd = &s1->u.mgd;
104+
105+ if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated)
106+ sdata_sta = s1;
107+ else
108+ continue;
109+
110+ list_for_each_entry(s2, &local->interfaces, list) {
111+ wdev = &s2->wdev;
112+ chan = wdev->links[0].ap.chandef.chan;
113+ if (chan) {
114+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
115+ continue;
116+
117+ if (wdev->identifier != sdata_sta->wdev.identifier &&
118+ chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started &&
119+ cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef,
120+ &s2->vif.bss_conf.chandef)) {
121+ ieee80211_skip_cac(wdev);
122+ sdata_info(s2, "Skip CAC on the associated STA's chan\n");
123+ }
124+ }
125+ }
126+ }
127+ mutex_unlock(&local->mtx);
128+}
129+
130 const struct cfg80211_ops mac80211_config_ops = {
131 .add_virtual_intf = ieee80211_add_iface,
132 .del_virtual_intf = ieee80211_del_iface,
133@@ -5001,4 +5044,5 @@ const struct cfg80211_ops mac80211_config_ops = {
134 .mod_link_station = ieee80211_mod_link_station,
135 .del_link_station = ieee80211_del_link_station,
136 .skip_cac = ieee80211_skip_cac,
137+ .check_cac_skip = ieee80211_check_cac_skip,
138 };
139diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
140index e72cf07..94496d7 100644
141--- a/net/mac80211/chan.c
142+++ b/net/mac80211/chan.c
143@@ -567,7 +567,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
144
145 link = rcu_dereference(sdata->link[link_id]);
146
147- if (link && link->radar_required) {
148+ if (link && link->radar_required && sdata->wdev.cac_started) {
149 rcu_read_unlock();
150 return true;
151 }
152diff --git a/net/wireless/chan.c b/net/wireless/chan.c
153index 29b5c2f..bf21f99 100644
154--- a/net/wireless/chan.c
155+++ b/net/wireless/chan.c
156@@ -719,16 +719,16 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
157 case NL80211_IFTYPE_AP:
158 case NL80211_IFTYPE_P2P_GO:
159 for_each_valid_link(wdev, link) {
160- if (wdev->links[link].ap.beacon_interval)
161+ if (wdev->links[link].ap.beacon_interval || wdev->start_disabled)
162 return true;
163 }
164 break;
165 case NL80211_IFTYPE_ADHOC:
166- if (wdev->u.ibss.ssid_len)
167+ if (wdev->u.ibss.ssid_len || wdev->start_disabled)
168 return true;
169 break;
170 case NL80211_IFTYPE_MESH_POINT:
171- if (wdev->u.mesh.id_len)
172+ if (wdev->u.mesh.id_len || wdev->start_disabled)
173 return true;
174 break;
175 case NL80211_IFTYPE_STATION:
176diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
developer3783b072023-02-01 16:07:11 +0800177index 202f802..cc8d4b2 100644
developer4a339e82022-12-12 19:00:30 +0800178--- a/net/wireless/nl80211.c
179+++ b/net/wireless/nl80211.c
180@@ -789,6 +789,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
181 NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
182 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
183 [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
184+ [NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG },
185 [NL80211_ATTR_AP_SETTINGS_FLAGS] = { .type = NLA_U32 },
186 [NL80211_ATTR_EHT_CAPABILITY] =
187 NLA_POLICY_BINARY_RANGE(NL80211_EHT_MIN_CAPABILITY_LEN, NL80211_EHT_MAX_CAPABILITY_LEN),
developer3783b072023-02-01 16:07:11 +0800188@@ -5803,6 +5804,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
developer4a339e82022-12-12 19:00:30 +0800189 if (wdev->links[link_id].ap.beacon_interval)
190 return -EALREADY;
191
192+ if (info->attrs[NL80211_ATTR_START_DISABLED]) {
193+ wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
developer3783b072023-02-01 16:07:11 +0800194+ return 0;
developer4a339e82022-12-12 19:00:30 +0800195+ }
196+
197 /* these are required for START_AP */
198 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
199 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
developer3783b072023-02-01 16:07:11 +0800200@@ -9846,6 +9852,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
developer4a339e82022-12-12 19:00:30 +0800201 wdev->cac_started = true;
202 wdev->cac_start_time = jiffies;
203 wdev->cac_time_ms = cac_time_ms;
204+ err = rdev_check_cac_skip(rdev, &wdev->links[0].ap.chandef);
205 }
206 unlock:
207 wiphy_unlock(wiphy);
208diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
209index ce83152..ffa504a 100644
210--- a/net/wireless/rdev-ops.h
211+++ b/net/wireless/rdev-ops.h
212@@ -1508,4 +1508,20 @@ rdev_skip_cac(struct cfg80211_registered_device *rdev,
213 return 0;
214 }
215
216+static inline int
217+rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
218+ struct cfg80211_chan_def *chandef)
219+{
220+ struct wiphy *wiphy = &rdev->wiphy;
221+
222+ if (!rdev->ops->check_cac_skip)
223+ return -EOPNOTSUPP;
224+
225+ trace_rdev_check_cac_skip(wiphy, chandef);
226+ rdev->ops->check_cac_skip(wiphy, chandef);
227+ trace_rdev_return_void(wiphy);
228+
229+ return 0;
230+}
231+
232 #endif /* __CFG80211_RDEV_OPS */
233diff --git a/net/wireless/trace.h b/net/wireless/trace.h
234index d3a98e8..72c8f0e 100644
235--- a/net/wireless/trace.h
236+++ b/net/wireless/trace.h
237@@ -3913,6 +3913,21 @@ TRACE_EVENT(rdev_skip_cac,
238 TP_printk(WDEV_PR_FMT, WDEV_PR_ARG)
239 );
240
241+TRACE_EVENT(rdev_check_cac_skip,
242+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
243+
244+ TP_ARGS(wiphy, chandef),
245+
246+ TP_STRUCT__entry(WIPHY_ENTRY
247+ CHAN_DEF_ENTRY),
248+
249+ TP_fast_assign(WIPHY_ASSIGN;
250+ CHAN_DEF_ASSIGN(chandef)),
251+
252+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
253+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
254+);
255+
256 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
257
258 #undef TRACE_INCLUDE_PATH
259--
developer1413c882023-02-15 00:01:06 +08002602.25.1
developer4a339e82022-12-12 19:00:30 +0800261