2510cb0dbe95f16869eba01c3b55e2eba1e8dd26
[openwrt/staging/stintel.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Mon, 30 Sep 2024 15:09:45 +0200
3 Subject: [PATCH] wifi: mac80211: add flag to opt out of virtual monitor
4 support
5
6 This is useful for multi-radio devices that are capable of monitoring on
7 multiple channels simultanenously. When this flag is set, each monitor
8 interface is passed to the driver individually and can have a configured
9 channel.
10
11 Signed-off-by: Felix Fietkau <nbd@nbd.name>
12 ---
13
14 --- a/include/net/mac80211.h
15 +++ b/include/net/mac80211.h
16 @@ -2679,6 +2679,11 @@ struct ieee80211_txq {
17 * a virtual monitor interface when monitor interfaces are the only
18 * active interfaces.
19 *
20 + * @IEEE80211_HW_NO_VIRTUAL_MONITOR: The driver would like to be informed
21 + * of any monitor interface, as well as their configured channel.
22 + * This is useful for supporting multiple monitor interfaces on different
23 + * channels.
24 + *
25 * @IEEE80211_HW_NO_AUTO_VIF: The driver would like for no wlanX to
26 * be created. It is expected user-space will create vifs as
27 * desired (and thus have them named as desired).
28 @@ -2838,6 +2843,7 @@ enum ieee80211_hw_flags {
29 IEEE80211_HW_SUPPORTS_DYNAMIC_PS,
30 IEEE80211_HW_MFP_CAPABLE,
31 IEEE80211_HW_WANT_MONITOR_VIF,
32 + IEEE80211_HW_NO_VIRTUAL_MONITOR,
33 IEEE80211_HW_NO_AUTO_VIF,
34 IEEE80211_HW_SW_CRYPTO_CONTROL,
35 IEEE80211_HW_SUPPORT_FAST_XMIT,
36 --- a/net/mac80211/cfg.c
37 +++ b/net/mac80211/cfg.c
38 @@ -105,8 +105,11 @@ static int ieee80211_set_mon_options(str
39 }
40
41 /* also validate MU-MIMO change */
42 - monitor_sdata = wiphy_dereference(local->hw.wiphy,
43 - local->monitor_sdata);
44 + if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
45 + monitor_sdata = sdata;
46 + else
47 + monitor_sdata = wiphy_dereference(local->hw.wiphy,
48 + local->monitor_sdata);
49
50 if (!monitor_sdata &&
51 (params->vht_mumimo_groups || params->vht_mumimo_follow_addr))
52 @@ -114,7 +117,9 @@ static int ieee80211_set_mon_options(str
53
54 /* apply all changes now - no failures allowed */
55
56 - if (monitor_sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
57 + if (monitor_sdata &&
58 + (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) ||
59 + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)))
60 ieee80211_set_mu_mimo_follow(monitor_sdata, params);
61
62 if (params->flags) {
63 @@ -889,22 +894,25 @@ static int ieee80211_set_monitor_channel
64
65 lockdep_assert_wiphy(local->hw.wiphy);
66
67 - if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
68 - &chanreq.oper))
69 - return 0;
70 + sdata = IEEE80211_DEV_TO_SUB_IF(dev);
71 + if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
72 + if (cfg80211_chandef_identical(&local->monitor_chanreq.oper,
73 + &chanreq.oper))
74 + return 0;
75
76 - sdata = wiphy_dereference(local->hw.wiphy,
77 - local->monitor_sdata);
78 - if (!sdata)
79 - goto done;
80 + sdata = wiphy_dereference(wiphy, local->monitor_sdata);
81 + if (!sdata)
82 + goto done;
83 + }
84
85 - if (cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
86 + if (rcu_access_pointer(sdata->deflink.conf->chanctx_conf) &&
87 + cfg80211_chandef_identical(&sdata->vif.bss_conf.chanreq.oper,
88 &chanreq.oper))
89 return 0;
90
91 ieee80211_link_release_channel(&sdata->deflink);
92 ret = ieee80211_link_use_channel(&sdata->deflink, &chanreq,
93 - IEEE80211_CHANCTX_EXCLUSIVE);
94 + IEEE80211_CHANCTX_SHARED);
95 if (ret)
96 return ret;
97 done:
98 @@ -3049,7 +3057,8 @@ static int ieee80211_set_tx_power(struct
99 if (wdev) {
100 sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
101
102 - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
103 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
104 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
105 if (!ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF))
106 return -EOPNOTSUPP;
107
108 @@ -3097,7 +3106,8 @@ static int ieee80211_set_tx_power(struct
109 }
110
111 list_for_each_entry(sdata, &local->interfaces, list) {
112 - if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
113 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
114 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
115 has_monitor = true;
116 continue;
117 }
118 @@ -3107,7 +3117,8 @@ static int ieee80211_set_tx_power(struct
119 sdata->vif.bss_conf.txpower_type = txp_type;
120 }
121 list_for_each_entry(sdata, &local->interfaces, list) {
122 - if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
123 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
124 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
125 continue;
126 ieee80211_recalc_txpower(sdata, update_txp_type);
127 }
128 @@ -4299,7 +4310,8 @@ static int ieee80211_cfg_get_channel(str
129 if (chanctx_conf) {
130 *chandef = link->conf->chanreq.oper;
131 ret = 0;
132 - } else if (local->open_count > 0 &&
133 + } else if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
134 + local->open_count > 0 &&
135 local->open_count == local->monitors &&
136 sdata->vif.type == NL80211_IFTYPE_MONITOR) {
137 *chandef = local->monitor_chanreq.oper;
138 --- a/net/mac80211/chan.c
139 +++ b/net/mac80211/chan.c
140 @@ -337,6 +337,10 @@ ieee80211_get_chanctx_max_required_bw(st
141 case NL80211_IFTYPE_P2P_DEVICE:
142 case NL80211_IFTYPE_NAN:
143 continue;
144 + case NL80211_IFTYPE_MONITOR:
145 + WARN_ON_ONCE(!ieee80211_hw_check(&local->hw,
146 + NO_VIRTUAL_MONITOR));
147 + fallthrough;
148 case NL80211_IFTYPE_ADHOC:
149 case NL80211_IFTYPE_MESH_POINT:
150 case NL80211_IFTYPE_OCB:
151 @@ -345,7 +349,6 @@ ieee80211_get_chanctx_max_required_bw(st
152 case NL80211_IFTYPE_WDS:
153 case NL80211_IFTYPE_UNSPECIFIED:
154 case NUM_NL80211_IFTYPES:
155 - case NL80211_IFTYPE_MONITOR:
156 case NL80211_IFTYPE_P2P_CLIENT:
157 case NL80211_IFTYPE_P2P_GO:
158 WARN_ON_ONCE(1);
159 @@ -954,6 +957,10 @@ void ieee80211_recalc_smps_chanctx(struc
160 if (!link->sdata->u.mgd.associated)
161 continue;
162 break;
163 + case NL80211_IFTYPE_MONITOR:
164 + if (!ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
165 + continue;
166 + break;
167 case NL80211_IFTYPE_AP:
168 case NL80211_IFTYPE_ADHOC:
169 case NL80211_IFTYPE_MESH_POINT:
170 @@ -966,6 +973,11 @@ void ieee80211_recalc_smps_chanctx(struc
171 if (rcu_access_pointer(link->conf->chanctx_conf) != &chanctx->conf)
172 continue;
173
174 + if (link->sdata->vif.type == NL80211_IFTYPE_MONITOR) {
175 + rx_chains_dynamic = rx_chains_static = local->rx_chains;
176 + break;
177 + }
178 +
179 switch (link->smps_mode) {
180 default:
181 WARN_ONCE(1, "Invalid SMPS mode %d\n",
182 --- a/net/mac80211/debugfs.c
183 +++ b/net/mac80211/debugfs.c
184 @@ -465,6 +465,7 @@ static const char *hw_flag_names[] = {
185 FLAG(SUPPORTS_DYNAMIC_PS),
186 FLAG(MFP_CAPABLE),
187 FLAG(WANT_MONITOR_VIF),
188 + FLAG(NO_VIRTUAL_MONITOR),
189 FLAG(NO_AUTO_VIF),
190 FLAG(SW_CRYPTO_CONTROL),
191 FLAG(SUPPORT_FAST_XMIT),
192 --- a/net/mac80211/driver-ops.c
193 +++ b/net/mac80211/driver-ops.c
194 @@ -65,6 +65,7 @@ int drv_add_interface(struct ieee80211_l
195 if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
196 (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
197 !ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF) &&
198 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR) &&
199 !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))))
200 return -EINVAL;
201
202 --- a/net/mac80211/iface.c
203 +++ b/net/mac80211/iface.c
204 @@ -279,8 +279,13 @@ static int _ieee80211_change_mac(struct
205 ret = eth_mac_addr(sdata->dev, sa);
206
207 if (ret == 0) {
208 - memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
209 - ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
210 + if (check_dup) {
211 + memcpy(sdata->vif.addr, sa->sa_data, ETH_ALEN);
212 + ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
213 + } else {
214 + memset(sdata->vif.addr, 0, ETH_ALEN);
215 + memset(sdata->vif.bss_conf.addr, 0, ETH_ALEN);
216 + }
217 }
218
219 /* Regardless of eth_mac_addr() return we still want to add the
220 @@ -699,9 +704,11 @@ static void ieee80211_do_stop(struct iee
221 ieee80211_recalc_idle(local);
222 ieee80211_recalc_offload(local);
223
224 - if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
225 + if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
226 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
227 break;
228
229 + ieee80211_link_release_channel(&sdata->deflink);
230 fallthrough;
231 default:
232 if (!going_down)
233 @@ -1131,7 +1138,8 @@ int ieee80211_add_virtual_monitor(struct
234 ASSERT_RTNL();
235 lockdep_assert_wiphy(local->hw.wiphy);
236
237 - if (local->monitor_sdata)
238 + if (local->monitor_sdata ||
239 + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
240 return 0;
241
242 sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
243 @@ -1193,6 +1201,9 @@ void ieee80211_del_virtual_monitor(struc
244 {
245 struct ieee80211_sub_if_data *sdata;
246
247 + if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
248 + return;
249 +
250 ASSERT_RTNL();
251 lockdep_assert_wiphy(local->hw.wiphy);
252
253 @@ -1328,7 +1339,8 @@ int ieee80211_do_open(struct wireless_de
254 break;
255 }
256
257 - if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
258 + if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
259 + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
260 res = drv_add_interface(local, sdata);
261 if (res)
262 goto err_stop;
263 --- a/net/mac80211/rx.c
264 +++ b/net/mac80211/rx.c
265 @@ -840,6 +840,9 @@ ieee80211_rx_monitor(struct ieee80211_lo
266 bool last_monitor = list_is_last(&sdata->u.mntr.list,
267 &local->mon_list);
268
269 + if (ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
270 + ieee80211_handle_mu_mimo_mon(sdata, origskb, rtap_space);
271 +
272 if (!monskb)
273 monskb = ieee80211_make_monitor_skb(local, &origskb,
274 rate, rtap_space,
275 --- a/net/mac80211/tx.c
276 +++ b/net/mac80211/tx.c
277 @@ -1763,7 +1763,8 @@ static bool __ieee80211_tx(struct ieee80
278
279 switch (sdata->vif.type) {
280 case NL80211_IFTYPE_MONITOR:
281 - if (sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
282 + if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
283 + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
284 vif = &sdata->vif;
285 break;
286 }
287 @@ -3952,7 +3953,8 @@ begin:
288
289 switch (tx.sdata->vif.type) {
290 case NL80211_IFTYPE_MONITOR:
291 - if (tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) {
292 + if ((tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
293 + ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
294 vif = &tx.sdata->vif;
295 break;
296 }
297 --- a/net/mac80211/util.c
298 +++ b/net/mac80211/util.c
299 @@ -754,7 +754,8 @@ static void __iterate_interfaces(struct
300 list_for_each_entry_rcu(sdata, &local->interfaces, list) {
301 switch (sdata->vif.type) {
302 case NL80211_IFTYPE_MONITOR:
303 - if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
304 + if (!(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) &&
305 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
306 continue;
307 break;
308 case NL80211_IFTYPE_AP_VLAN:
309 @@ -1857,8 +1858,10 @@ int ieee80211_reconfig(struct ieee80211_
310 }
311
312 list_for_each_entry(sdata, &local->interfaces, list) {
313 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
314 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
315 + continue;
316 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
317 - sdata->vif.type != NL80211_IFTYPE_MONITOR &&
318 ieee80211_sdata_running(sdata)) {
319 res = drv_add_interface(local, sdata);
320 if (WARN_ON(res))
321 @@ -1871,11 +1874,14 @@ int ieee80211_reconfig(struct ieee80211_
322 */
323 if (res) {
324 list_for_each_entry_continue_reverse(sdata, &local->interfaces,
325 - list)
326 + list) {
327 + if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
328 + !ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
329 + continue;
330 if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
331 - sdata->vif.type != NL80211_IFTYPE_MONITOR &&
332 ieee80211_sdata_running(sdata))
333 drv_remove_interface(local, sdata);
334 + }
335 ieee80211_handle_reconfig_failure(local);
336 return res;
337 }