blob: f5fc0f9f4529864a22c27367ef152b03d9af2cf7 [file] [log] [blame]
developer92929332022-10-08 00:37:23 +08001From a58aa02645052470e6bacb9e6c1eb7adfb9fc0d8 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] mac80211: fix the issue of AP and STA starting on DFS channel
5 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 | 48 ++++++++++++++++++++++++++++++++++++
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, 113 insertions(+), 5 deletions(-)
18
19diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
20index f594914..0af069d 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@@ -4401,6 +4419,8 @@ struct cfg80211_ops {
49 struct cfg80211_color_change_settings *params);
50 int (*set_radar_background)(struct wiphy *wiphy,
51 struct cfg80211_chan_def *chandef);
52+ void (*check_cac_skip)(struct wiphy *wiphy,
53+ struct cfg80211_chan_def *chandef);
54 };
55
56 /*
57@@ -5554,6 +5574,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 bf71594..73fb432 100644
80--- a/net/mac80211/cfg.c
81+++ b/net/mac80211/cfg.c
82@@ -4504,6 +4504,53 @@ ieee80211_set_radar_background(struct wiphy *wiphy,
83 return local->ops->set_radar_background(&local->hw, chandef);
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+ cac_time_ms = wdev->cac_time_ms;
121+ wdev->cac_start_time = jiffies -
122+ msecs_to_jiffies(cac_time_ms + 1);
123+ cfg80211_cac_event(wdev->netdev, &wdev->chandef,
124+ NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
125+ sdata_info(s2, "Skip CAC on the associated STA's chan\n");
126+ }
127+ }
128+ }
129+ }
130+ mutex_unlock(&local->mtx);
131+}
132+
133 const struct cfg80211_ops mac80211_config_ops = {
134 .add_virtual_intf = ieee80211_add_iface,
135 .del_virtual_intf = ieee80211_del_iface,
136@@ -4610,4 +4657,5 @@ const struct cfg80211_ops mac80211_config_ops = {
137 .set_sar_specs = ieee80211_set_sar_specs,
138 .color_change = ieee80211_color_change,
139 .set_radar_background = ieee80211_set_radar_background,
140+ .check_cac_skip = ieee80211_check_cac_skip,
141 };
142diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
143index 63e15f5..5e57e4a 100644
144--- a/net/mac80211/chan.c
145+++ b/net/mac80211/chan.c
146@@ -505,7 +505,7 @@ bool ieee80211_is_radar_required(struct ieee80211_local *local)
147
148 rcu_read_lock();
149 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
150- if (sdata->radar_required) {
151+ if (sdata->radar_required && sdata->wdev.cac_started) {
152 rcu_read_unlock();
153 return true;
154 }
155diff --git a/net/wireless/chan.c b/net/wireless/chan.c
156index 5f50ac4..067ed79 100644
157--- a/net/wireless/chan.c
158+++ b/net/wireless/chan.c
159@@ -664,13 +664,13 @@ bool cfg80211_beaconing_iface_active(struct wireless_dev *wdev)
160 switch (wdev->iftype) {
161 case NL80211_IFTYPE_AP:
162 case NL80211_IFTYPE_P2P_GO:
163- active = wdev->beacon_interval != 0;
164+ active = wdev->beacon_interval != 0 || wdev->start_disabled;
165 break;
166 case NL80211_IFTYPE_ADHOC:
167- active = wdev->ssid_len != 0;
168+ active = wdev->ssid_len != 0 || wdev->start_disabled;
169 break;
170 case NL80211_IFTYPE_MESH_POINT:
171- active = wdev->mesh_id_len != 0;
172+ active = wdev->mesh_id_len != 0 || wdev->start_disabled;
173 break;
174 case NL80211_IFTYPE_STATION:
175 case NL80211_IFTYPE_OCB:
176diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
177index a20aba5..8dc928d 100644
178--- a/net/wireless/nl80211.c
179+++ b/net/wireless/nl80211.c
180@@ -803,6 +803,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_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
186 };
187
188@@ -5547,6 +5548,12 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
189
190 memset(&params, 0, sizeof(params));
191
192+ if (info->attrs[NL80211_ATTR_START_DISABLED]) {
193+ wdev->start_disabled = nla_get_flag(info->attrs[NL80211_ATTR_START_DISABLED]);
194+ err = 0;
195+ goto out;
196+ }
197+
198 /* these are required for START_AP */
199 if (!info->attrs[NL80211_ATTR_BEACON_INTERVAL] ||
200 !info->attrs[NL80211_ATTR_DTIM_PERIOD] ||
201@@ -9393,6 +9400,7 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
202 wdev->cac_started = true;
203 wdev->cac_start_time = jiffies;
204 wdev->cac_time_ms = cac_time_ms;
205+ err = rdev_check_cac_skip(rdev, &wdev->chandef);
206 }
207 unlock:
208 wiphy_unlock(wiphy);
209diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h
210index 8555468..e7d0064 100644
211--- a/net/wireless/rdev-ops.h
212+++ b/net/wireless/rdev-ops.h
213@@ -1398,4 +1398,20 @@ rdev_set_radar_background(struct cfg80211_registered_device *rdev,
214 return ret;
215 }
216
217+static inline int
218+rdev_check_cac_skip(struct cfg80211_registered_device *rdev,
219+ struct cfg80211_chan_def *chandef)
220+{
221+ struct wiphy *wiphy = &rdev->wiphy;
222+
223+ if (!rdev->ops->check_cac_skip)
224+ return -EOPNOTSUPP;
225+
226+ trace_rdev_check_cac_skip(wiphy, chandef);
227+ rdev->ops->check_cac_skip(wiphy, chandef);
228+ trace_rdev_return_void(wiphy);
229+
230+ return 0;
231+}
232+
233 #endif /* __CFG80211_RDEV_OPS */
234diff --git a/net/wireless/trace.h b/net/wireless/trace.h
235index 97a2937..e3f1c79 100644
236--- a/net/wireless/trace.h
237+++ b/net/wireless/trace.h
238@@ -3665,6 +3665,21 @@ TRACE_EVENT(rdev_set_radar_background,
239 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
240 );
241
242+TRACE_EVENT(rdev_check_cac_skip,
243+ TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
244+
245+ TP_ARGS(wiphy, chandef),
246+
247+ TP_STRUCT__entry(WIPHY_ENTRY
248+ CHAN_DEF_ENTRY),
249+
250+ TP_fast_assign(WIPHY_ASSIGN;
251+ CHAN_DEF_ASSIGN(chandef)),
252+
253+ TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
254+ WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
255+);
256+
257 #endif /* !__RDEV_OPS_TRACE || TRACE_HEADER_MULTI_READ */
258
259 #undef TRACE_INCLUDE_PATH
260--
2612.18.0
262