blob: 1199df90cce977d7877335ff20b31da98c94a63f [file] [log] [blame]
developer6a1998b2022-12-08 18:09:45 +08001From c3fa5e627f8c552852ee25ab366b4035c203aab3 Mon Sep 17 00:00:00 2001
2From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
3Date: Wed, 5 Oct 2022 19:13:43 +0800
4Subject: [PATCH 911/911] mac80211: mtk: fix the issue of AP and STA starting
5 on DFS channel concurrently
6
7Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
8---
9 include/net/cfg80211.h | 21 +++++++++++++++++
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 ++---
14 net/wireless/nl80211.c | 8 +++++++
15 net/wireless/rdev-ops.h | 16 +++++++++++++
16 net/wireless/trace.h | 15 ++++++++++++
17 8 files changed, 109 insertions(+), 5 deletions(-)
18
19diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
20index b97ddbd..c4c0926 100644
21--- a/include/net/cfg80211.h
22+++ b/include/net/cfg80211.h
23@@ -800,6 +800,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@@ -4402,6 +4420,8 @@ struct cfg80211_ops {
49 int (*set_radar_background)(struct wiphy *wiphy,
50 struct cfg80211_chan_def *chandef);
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@@ -5555,6 +5575,7 @@ struct wireless_dev {
58 struct work_struct pmsr_free_wk;
59
60 unsigned long unprot_beacon_reported;
61+ bool start_disabled;
62 };
63
64 static inline u8 *wdev_address(struct wireless_dev *wdev)
65diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
66index e674aa7..ada8288 100644
67--- a/include/uapi/linux/nl80211.h
68+++ b/include/uapi/linux/nl80211.h
69@@ -3129,7 +3129,7 @@ enum nl80211_attrs {
70 NL80211_ATTR_WIPHY_ANTENNA_GAIN,
71
72 /* add attributes here, update the policy in nl80211.c */
73-
74+ NL80211_ATTR_START_DISABLED = 999,
75 __NL80211_ATTR_AFTER_LAST,
76 NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
77 NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
78diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
79index 97c5e5d..d726410 100644
80--- a/net/mac80211/cfg.c
81+++ b/net/mac80211/cfg.c
82@@ -4522,6 +4522,49 @@ ieee80211_skip_cac(struct wireless_dev *wdev)
83 }
84 }
85
86+static void
87+ieee80211_check_cac_skip(struct wiphy *wiphy,
88+ struct cfg80211_chan_def *chandef)
89+{
90+ struct ieee80211_local *local = wiphy_priv(wiphy);
91+ struct ieee80211_sub_if_data *s1;
92+ struct ieee80211_sub_if_data *s2;
93+ struct ieee80211_sub_if_data *sdata_sta;
94+ struct ieee80211_if_managed *ifmgd;
95+ struct ieee80211_channel *chan;
96+ struct wireless_dev *wdev;
97+ unsigned int cac_time_ms;
98+
99+ mutex_lock(&local->mtx);
100+ /* Bypass AP's cac if there is a STA associated to the same DFS channel */
101+ list_for_each_entry(s1, &local->interfaces, list) {
102+ ifmgd = &s1->u.mgd;
103+
104+ if (s1->vif.type == NL80211_IFTYPE_STATION && ifmgd->associated)
105+ sdata_sta = s1;
106+ else
107+ continue;
108+
109+ list_for_each_entry(s2, &local->interfaces, list) {
110+ wdev = &s2->wdev;
111+ chan = wdev->chandef.chan;
112+ if (chan) {
113+ if (!(chan->flags & IEEE80211_CHAN_RADAR))
114+ continue;
115+
116+ if (wdev->identifier != sdata_sta->wdev.identifier &&
117+ chan->dfs_state == NL80211_DFS_USABLE && wdev->cac_started &&
118+ cfg80211_chan_fully_overlap(&sdata_sta->vif.bss_conf.chandef,
119+ &s2->vif.bss_conf.chandef)) {
120+ ieee80211_skip_cac(wdev);
121+ sdata_info(s2, "Skip CAC on the associated STA's chan\n");
122+ }
123+ }
124+ }
125+ }
126+ mutex_unlock(&local->mtx);
127+}
128+
129 const struct cfg80211_ops mac80211_config_ops = {
130 .add_virtual_intf = ieee80211_add_iface,
131 .del_virtual_intf = ieee80211_del_iface,
132@@ -4629,4 +4672,5 @@ const struct cfg80211_ops mac80211_config_ops = {
133 .color_change = ieee80211_color_change,
134 .set_radar_background = ieee80211_set_radar_background,
135 .skip_cac = ieee80211_skip_cac,
136+ .check_cac_skip = ieee80211_check_cac_skip,
137 };
138diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
139index 63e15f5..5e57e4a 100644
140--- a/net/mac80211/chan.c
141+++ b/net/mac80211/chan.c
142@@ -505,7 +505,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
143
144 rcu_read_lock();
145 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
146- if (sdata->radar_required) {
147+ if (sdata->radar_required && sdata->wdev.cac_started) {
148 rcu_read_unlock();
149 return true;
150 }
151diff --git a/net/wireless/chan.c b/net/wireless/chan.c
152index 5f50ac4..067ed79 100644
153--- a/net/wireless/chan.c
154+++ b/net/wireless/chan.c
155@@ -664,13 +664,13 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
156 switch (wdev->iftype) {
157 case NL80211_IFTYPE_AP:
158 case NL80211_IFTYPE_P2P_GO:
159- active = wdev->beacon_interval != 0;
160+ active = wdev->beacon_interval != 0 || wdev->start_disabled;
161 break;
162 case NL80211_IFTYPE_ADHOC:
163- active = wdev->ssid_len != 0;
164+ active = wdev->ssid_len != 0 || wdev->start_disabled;
165 break;
166 case NL80211_IFTYPE_MESH_POINT:
167- active = wdev->mesh_id_len != 0;
168+ active = wdev->mesh_id_len != 0 || wdev->start_disabled;
169 break;
170 case NL80211_IFTYPE_STATION:
171 case NL80211_IFTYPE_OCB:
172diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
173index a20aba5..8dc928d 100644
174--- a/net/wireless/nl80211.c
175+++ b/net/wireless/nl80211.c
176@@ -803,6 +803,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
177 NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
178 [NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
179 [NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
180+ [NL80211_ATTR_START_DISABLED] = { .type = NLA_FLAG },
181 [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
182 };
183
184@@ -5547,6 +5548,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
185
186 memset(&params, 0, sizeof(params));
187
188+ if (info->attrs[NL80211_ATTR_START_DISABLED]) {
189+ wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
190+ err = 0;
191+ goto out;
192+ }
193+
194 /* these are required for START_AP */
195 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
196 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
197@@ -9393,6 +9400,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
198 wdev->cac_started = true;
199 wdev->cac_start_time = jiffies;
200 wdev->cac_time_ms = cac_time_ms;
201+ err = rdev_check_cac_skip(rdev, &wdev->chandef);
202 }
203 unlock:
204 wiphy_unlock(wiphy);
205diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
206index 26f4604..c38aea1 100644
207--- a/net/wireless/rdev-ops.h
208+++ b/net/wireless/rdev-ops.h
209@@ -1412,4 +1412,20 @@ rdev_skip_cac(struct cfg80211_registered_device *rdev,
210 return 0;
211 }
212
213+static inline int
214+rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
215+ struct cfg80211_chan_def *chandef)
216+{
217+ struct wiphy *wiphy = &rdev->wiphy;
218+
219+ if (!rdev->ops->check_cac_skip)
220+ return -EOPNOTSUPP;
221+
222+ trace_rdev_check_cac_skip(wiphy, chandef);
223+ rdev->ops->check_cac_skip(wiphy, chandef);
224+ trace_rdev_return_void(wiphy);
225+
226+ return 0;
227+}
228+
229 #endif /* __CFG80211_RDEV_OPS */
230diff --git a/net/wireless/trace.h b/net/wireless/trace.h
231index eadabfa..a7b0c82 100644
232--- a/net/wireless/trace.h
233+++ b/net/wireless/trace.h
234@@ -3677,6 +3677,21 @@ TRACE_EVENT(rdev_skip_cac,
235 TP_printk(WDEV_PR_FMT, WDEV_PR_ARG)
236 );
237
238+TRACE_EVENT(rdev_check_cac_skip,
239+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
240+
241+ TP_ARGS(wiphy, chandef),
242+
243+ TP_STRUCT__entry(WIPHY_ENTRY
244+ CHAN_DEF_ENTRY),
245+
246+ TP_fast_assign(WIPHY_ASSIGN;
247+ CHAN_DEF_ASSIGN(chandef)),
248+
249+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
250+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
251+);
252+
253 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
254
255 #undef TRACE_INCLUDE_PATH
256--
2572.36.1
258