xref: /freebsd/sys/contrib/dev/iwlwifi/mld/iface.c (revision b2bd08185e4984c70179c195f712cef5a136d21b)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2024-2025 Intel Corporation
4  */
5 #include <net/cfg80211.h>
6 
7 #include "iface.h"
8 #include "hcmd.h"
9 #include "key.h"
10 #include "mlo.h"
11 #include "mac80211.h"
12 
13 #include "fw/api/context.h"
14 #include "fw/api/mac.h"
15 #include "fw/api/time-event.h"
16 #include "fw/api/datapath.h"
17 
18 /* Cleanup function for struct iwl_mld_vif, will be called in restart */
iwl_mld_cleanup_vif(void * data,u8 * mac,struct ieee80211_vif * vif)19 void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
20 {
21 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
22 	struct iwl_mld *mld = mld_vif->mld;
23 	struct iwl_mld_link *link;
24 
25 	mld_vif->emlsr.blocked_reasons &= ~IWL_MLD_EMLSR_BLOCKED_ROC;
26 
27 	if (mld_vif->aux_sta.sta_id != IWL_INVALID_STA)
28 		iwl_mld_free_internal_sta(mld, &mld_vif->aux_sta);
29 
30 	/* EMLSR is turned back on during recovery */
31 	vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;
32 
33 	if (mld_vif->roc_activity != ROC_NUM_ACTIVITIES)
34 		ieee80211_remain_on_channel_expired(mld->hw);
35 
36 	mld_vif->roc_activity = ROC_NUM_ACTIVITIES;
37 
38 	for_each_mld_vif_valid_link(mld_vif, link) {
39 		iwl_mld_cleanup_link(mld_vif->mld, link);
40 
41 		/* Correctly allocated primary link in non-MLO mode */
42 		if (!ieee80211_vif_is_mld(vif) &&
43 		    link_id == 0 && link == &mld_vif->deflink)
44 			continue;
45 
46 		if (vif->active_links & BIT(link_id))
47 			continue;
48 
49 		/* Should not happen as link removal should always succeed */
50 		WARN_ON(1);
51 		if (link != &mld_vif->deflink)
52 			kfree_rcu(link, rcu_head);
53 		RCU_INIT_POINTER(mld_vif->link[link_id], NULL);
54 	}
55 
56 	ieee80211_iter_keys(mld->hw, vif, iwl_mld_cleanup_keys_iter, NULL);
57 
58 	CLEANUP_STRUCT(mld_vif);
59 }
60 
iwl_mld_send_mac_cmd(struct iwl_mld * mld,struct iwl_mac_config_cmd * cmd)61 static int iwl_mld_send_mac_cmd(struct iwl_mld *mld,
62 				struct iwl_mac_config_cmd *cmd)
63 {
64 	int ret;
65 
66 	lockdep_assert_wiphy(mld->wiphy);
67 
68 	ret = iwl_mld_send_cmd_pdu(mld,
69 				   WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),
70 				   cmd);
71 	if (ret)
72 		IWL_ERR(mld, "Failed to send MAC_CONFIG_CMD ret = %d\n", ret);
73 
74 	return ret;
75 }
76 
iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif * vif)77 int iwl_mld_mac80211_iftype_to_fw(const struct ieee80211_vif *vif)
78 {
79 	switch (vif->type) {
80 	case NL80211_IFTYPE_STATION:
81 		return vif->p2p ? FW_MAC_TYPE_P2P_STA : FW_MAC_TYPE_BSS_STA;
82 	case NL80211_IFTYPE_AP:
83 		return FW_MAC_TYPE_GO;
84 	case NL80211_IFTYPE_MONITOR:
85 		return FW_MAC_TYPE_LISTENER;
86 	case NL80211_IFTYPE_P2P_DEVICE:
87 		return FW_MAC_TYPE_P2P_DEVICE;
88 	case NL80211_IFTYPE_ADHOC:
89 		return FW_MAC_TYPE_IBSS;
90 	default:
91 		WARN_ON_ONCE(1);
92 	}
93 	return FW_MAC_TYPE_BSS_STA;
94 }
95 
iwl_mld_is_nic_ack_enabled(struct iwl_mld * mld,struct ieee80211_vif * vif)96 static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
97 				       struct ieee80211_vif *vif)
98 {
99 	const struct ieee80211_supported_band *sband;
100 	const struct ieee80211_sta_he_cap *own_he_cap;
101 
102 	lockdep_assert_wiphy(mld->wiphy);
103 
104 	/* This capability is the same for all bands,
105 	 * so take it from one of them.
106 	 */
107 	sband = mld->hw->wiphy->bands[NL80211_BAND_2GHZ];
108 	own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
109 
110 	return own_he_cap && (own_he_cap->he_cap_elem.mac_cap_info[2] &
111 			       IEEE80211_HE_MAC_CAP2_ACK_EN);
112 }
113 
114 struct iwl_mld_mac_wifi_gen_sta_iter_data {
115 	struct ieee80211_vif *vif;
116 	struct iwl_mac_wifi_gen_support *support;
117 };
118 
iwl_mld_mac_wifi_gen_sta_iter(void * _data,struct ieee80211_sta * sta)119 static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
120 					  struct ieee80211_sta *sta)
121 {
122 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
123 	struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
124 	struct ieee80211_link_sta *link_sta;
125 	unsigned int link_id;
126 
127 	if (mld_sta->vif != data->vif)
128 		return;
129 
130 	for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
131 		if (link_sta->he_cap.has_he)
132 			data->support->he_support = 1;
133 		if (link_sta->eht_cap.has_eht)
134 			data->support->eht_support = 1;
135 	}
136 }
137 
iwl_mld_set_wifi_gen(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mac_wifi_gen_support * support)138 static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
139 				 struct ieee80211_vif *vif,
140 				 struct iwl_mac_wifi_gen_support *support)
141 {
142 	struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
143 		.vif = vif,
144 		.support = support,
145 	};
146 	struct ieee80211_bss_conf *link_conf;
147 	unsigned int link_id;
148 
149 	switch (vif->type) {
150 	case NL80211_IFTYPE_MONITOR:
151 		/* for sniffer, set to HW capabilities */
152 		support->he_support = 1;
153 		support->eht_support = mld->trans->cfg->eht_supported;
154 		break;
155 	case NL80211_IFTYPE_AP:
156 		/* for AP set according to the link configs */
157 		for_each_vif_active_link(vif, link_conf, link_id) {
158 			support->he_ap_support |= link_conf->he_support;
159 			support->eht_support |= link_conf->eht_support;
160 		}
161 		break;
162 	default:
163 		/*
164 		 * If we have MLO enabled, then the firmware needs to enable
165 		 * address translation for the station(s) we add. That depends
166 		 * on having EHT enabled in firmware, which in turn depends on
167 		 * mac80211 in the iteration below.
168 		 * However, mac80211 doesn't enable capabilities on the AP STA
169 		 * until it has parsed the association response successfully,
170 		 * so set EHT (and HE as a pre-requisite for EHT) when the vif
171 		 * is an MLD.
172 		 */
173 		if (ieee80211_vif_is_mld(vif)) {
174 			support->he_support = 1;
175 			support->eht_support = 1;
176 		}
177 
178 		ieee80211_iterate_stations_mtx(mld->hw,
179 					       iwl_mld_mac_wifi_gen_sta_iter,
180 					       &sta_iter_data);
181 		break;
182 	}
183 }
184 
185 /* fill the common part for all interface types */
iwl_mld_mac_cmd_fill_common(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mac_config_cmd * cmd,u32 action)186 static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
187 					struct ieee80211_vif *vif,
188 					struct iwl_mac_config_cmd *cmd,
189 					u32 action)
190 {
191 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
192 
193 	lockdep_assert_wiphy(mld->wiphy);
194 
195 	cmd->id_and_color = cpu_to_le32(mld_vif->fw_id);
196 	cmd->action = cpu_to_le32(action);
197 
198 	cmd->mac_type =
199 		cpu_to_le32(iwl_mld_mac80211_iftype_to_fw(vif));
200 
201 	memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);
202 
203 	if (iwlwifi_mod_params.disable_11ax)
204 		return;
205 
206 	cmd->nic_not_ack_enabled =
207 		cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
208 
209 	iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
210 }
211 
iwl_mld_fill_mac_cmd_sta(struct iwl_mld * mld,struct ieee80211_vif * vif,u32 action,struct iwl_mac_config_cmd * cmd)212 static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
213 				     struct ieee80211_vif *vif, u32 action,
214 				     struct iwl_mac_config_cmd *cmd)
215 {
216 	struct ieee80211_bss_conf *link;
217 	u32 twt_policy = 0;
218 	int link_id;
219 
220 	lockdep_assert_wiphy(mld->wiphy);
221 
222 	WARN_ON(vif->type != NL80211_IFTYPE_STATION);
223 
224 	/* We always want to hear MCAST frames, if we're not authorized yet,
225 	 * we'll drop them.
226 	 */
227 	cmd->filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);
228 
229 	/* Adding a MAC ctxt with is_assoc set is not allowed in fw
230 	 * (and shouldn't happen)
231 	 */
232 	if (vif->cfg.assoc && action != FW_CTXT_ACTION_ADD) {
233 		cmd->client.is_assoc = 1;
234 
235 		if (!iwl_mld_vif_from_mac80211(vif)->authorized)
236 			cmd->client.data_policy |=
237 				cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE);
238 	} else {
239 		/* Allow beacons to pass through as long as we are not
240 		 * associated
241 		 */
242 		cmd->filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
243 	}
244 
245 	cmd->client.assoc_id = cpu_to_le16(vif->cfg.aid);
246 
247 	if (ieee80211_vif_is_mld(vif)) {
248 		u16 esr_transition_timeout =
249 			u16_get_bits(vif->cfg.eml_cap,
250 				     IEEE80211_EML_CAP_TRANSITION_TIMEOUT);
251 
252 		cmd->client.esr_transition_timeout =
253 			min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU,
254 			      esr_transition_timeout);
255 		cmd->client.medium_sync_delay =
256 			cpu_to_le16(vif->cfg.eml_med_sync_delay);
257 	}
258 
259 	for_each_vif_active_link(vif, link, link_id) {
260 		if (!link->he_support)
261 			continue;
262 
263 		if (link->twt_requester)
264 			twt_policy |= TWT_SUPPORTED;
265 		if (link->twt_protected)
266 			twt_policy |= PROTECTED_TWT_SUPPORTED;
267 		if (link->twt_broadcast)
268 			twt_policy |= BROADCAST_TWT_SUPPORTED;
269 	}
270 
271 	if (!iwlwifi_mod_params.disable_11ax)
272 		cmd->client.data_policy |= cpu_to_le16(twt_policy);
273 
274 	if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
275 		cmd->filter_flags |=
276 			cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
277 }
278 
iwl_mld_fill_mac_cmd_ap(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mac_config_cmd * cmd)279 static void iwl_mld_fill_mac_cmd_ap(struct iwl_mld *mld,
280 				    struct ieee80211_vif *vif,
281 				    struct iwl_mac_config_cmd *cmd)
282 {
283 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
284 
285 	lockdep_assert_wiphy(mld->wiphy);
286 
287 	WARN_ON(vif->type != NL80211_IFTYPE_AP);
288 
289 	cmd->filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
290 
291 	/* in AP mode, pass beacons from other APs (needed for ht protection).
292 	 * When there're no any associated station, which means that we are not
293 	 * TXing anyway, don't ask FW to pass beacons to prevent unnecessary
294 	 * wake-ups.
295 	 */
296 	if (mld_vif->num_associated_stas)
297 		cmd->filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
298 }
299 
iwl_mld_go_iterator(void * _data,u8 * mac,struct ieee80211_vif * vif)300 static void iwl_mld_go_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif)
301 {
302 	bool *go_active = _data;
303 
304 	if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_P2P_GO &&
305 	    iwl_mld_vif_from_mac80211(vif)->ap_ibss_active)
306 		*go_active = true;
307 }
308 
iwl_mld_p2p_dev_has_extended_disc(struct iwl_mld * mld)309 static bool iwl_mld_p2p_dev_has_extended_disc(struct iwl_mld *mld)
310 {
311 	bool go_active = false;
312 
313 	/* This flag should be set to true when the P2P Device is
314 	 * discoverable and there is at least a P2P GO. Setting
315 	 * this flag will allow the P2P Device to be discoverable on other
316 	 * channels in addition to its listen channel.
317 	 * Note that this flag should not be set in other cases as it opens the
318 	 * Rx filters on all MAC and increases the number of interrupts.
319 	 */
320 	ieee80211_iterate_active_interfaces(mld->hw,
321 					    IEEE80211_IFACE_ITER_RESUME_ALL,
322 					    iwl_mld_go_iterator, &go_active);
323 
324 	return go_active;
325 }
326 
iwl_mld_fill_mac_cmd_p2p_dev(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mac_config_cmd * cmd)327 static void iwl_mld_fill_mac_cmd_p2p_dev(struct iwl_mld *mld,
328 					 struct ieee80211_vif *vif,
329 					 struct iwl_mac_config_cmd *cmd)
330 {
331 	bool ext_disc = iwl_mld_p2p_dev_has_extended_disc(mld);
332 
333 	lockdep_assert_wiphy(mld->wiphy);
334 
335 	/* Override the filter flags to accept all management frames. This is
336 	 * needed to support both P2P device discovery using probe requests and
337 	 * P2P service discovery using action frames
338 	 */
339 	cmd->filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);
340 
341 	if (ext_disc)
342 		cmd->p2p_dev.is_disc_extended = cpu_to_le32(1);
343 }
344 
iwl_mld_fill_mac_cmd_ibss(struct iwl_mld * mld,struct ieee80211_vif * vif,struct iwl_mac_config_cmd * cmd)345 static void iwl_mld_fill_mac_cmd_ibss(struct iwl_mld *mld,
346 				      struct ieee80211_vif *vif,
347 				      struct iwl_mac_config_cmd *cmd)
348 {
349 	lockdep_assert_wiphy(mld->wiphy);
350 
351 	WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
352 
353 	cmd->filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON |
354 					 MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
355 					 MAC_CFG_FILTER_ACCEPT_GRP);
356 }
357 
358 static int
iwl_mld_rm_mac_from_fw(struct iwl_mld * mld,struct ieee80211_vif * vif)359 iwl_mld_rm_mac_from_fw(struct iwl_mld *mld, struct ieee80211_vif *vif)
360 {
361 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
362 	struct iwl_mac_config_cmd cmd = {
363 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
364 		.id_and_color = cpu_to_le32(mld_vif->fw_id),
365 	};
366 
367 	return iwl_mld_send_mac_cmd(mld, &cmd);
368 }
369 
iwl_mld_mac_fw_action(struct iwl_mld * mld,struct ieee80211_vif * vif,u32 action)370 int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
371 			  u32 action)
372 {
373 	struct iwl_mac_config_cmd cmd = {};
374 
375 	lockdep_assert_wiphy(mld->wiphy);
376 
377 	/* NAN interface type is not known to FW */
378 	if (vif->type == NL80211_IFTYPE_NAN)
379 		return 0;
380 
381 	if (action == FW_CTXT_ACTION_REMOVE)
382 		return iwl_mld_rm_mac_from_fw(mld, vif);
383 
384 	iwl_mld_mac_cmd_fill_common(mld, vif, &cmd, action);
385 
386 	switch (vif->type) {
387 	case NL80211_IFTYPE_STATION:
388 		iwl_mld_fill_mac_cmd_sta(mld, vif, action, &cmd);
389 		break;
390 	case NL80211_IFTYPE_AP:
391 		iwl_mld_fill_mac_cmd_ap(mld, vif, &cmd);
392 		break;
393 	case NL80211_IFTYPE_MONITOR:
394 		cmd.filter_flags =
395 			cpu_to_le32(MAC_CFG_FILTER_PROMISC |
396 				    MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT |
397 				    MAC_CFG_FILTER_ACCEPT_BEACON |
398 				    MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
399 				    MAC_CFG_FILTER_ACCEPT_GRP);
400 		break;
401 	case NL80211_IFTYPE_P2P_DEVICE:
402 		iwl_mld_fill_mac_cmd_p2p_dev(mld, vif, &cmd);
403 		break;
404 	case NL80211_IFTYPE_ADHOC:
405 		iwl_mld_fill_mac_cmd_ibss(mld, vif, &cmd);
406 		break;
407 	default:
408 		WARN(1, "not supported yet\n");
409 		return -EOPNOTSUPP;
410 	}
411 
412 	return iwl_mld_send_mac_cmd(mld, &cmd);
413 }
414 
iwl_mld_mlo_scan_start_wk(struct wiphy * wiphy,struct wiphy_work * wk)415 static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy,
416 				      struct wiphy_work *wk)
417 {
418 	struct iwl_mld_vif *mld_vif = container_of(wk, struct iwl_mld_vif,
419 						   mlo_scan_start_wk.work);
420 	struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
421 	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
422 
423 	iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif));
424 }
425 
IWL_MLD_ALLOC_FN(vif,vif)426 IWL_MLD_ALLOC_FN(vif, vif)
427 
428 /* Constructor function for struct iwl_mld_vif */
429 static void
430 iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
431 {
432 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
433 
434 	lockdep_assert_wiphy(mld->wiphy);
435 
436 	mld_vif->mld = mld;
437 	mld_vif->roc_activity = ROC_NUM_ACTIVITIES;
438 
439 	if (!mld->fw_status.in_hw_restart) {
440 		wiphy_work_init(&mld_vif->emlsr.unblock_tpt_wk,
441 				iwl_mld_emlsr_unblock_tpt_wk);
442 		wiphy_delayed_work_init(&mld_vif->emlsr.check_tpt_wk,
443 					iwl_mld_emlsr_check_tpt);
444 		wiphy_delayed_work_init(&mld_vif->emlsr.prevent_done_wk,
445 					iwl_mld_emlsr_prevent_done_wk);
446 		wiphy_delayed_work_init(&mld_vif->emlsr.tmp_non_bss_done_wk,
447 					iwl_mld_emlsr_tmp_non_bss_done_wk);
448 		wiphy_delayed_work_init(&mld_vif->mlo_scan_start_wk,
449 					iwl_mld_mlo_scan_start_wk);
450 	}
451 	iwl_mld_init_internal_sta(&mld_vif->aux_sta);
452 }
453 
iwl_mld_add_vif(struct iwl_mld * mld,struct ieee80211_vif * vif)454 int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
455 {
456 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
457 	int ret;
458 
459 	lockdep_assert_wiphy(mld->wiphy);
460 
461 	iwl_mld_init_vif(mld, vif);
462 
463 	/* NAN interface type is not known to FW */
464 	if (vif->type == NL80211_IFTYPE_NAN)
465 		return 0;
466 
467 	ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif);
468 	if (ret)
469 		return ret;
470 
471 	ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_ADD);
472 	if (ret)
473 		RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL);
474 
475 	return ret;
476 }
477 
iwl_mld_rm_vif(struct iwl_mld * mld,struct ieee80211_vif * vif)478 void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
479 {
480 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
481 
482 	lockdep_assert_wiphy(mld->wiphy);
483 
484 	iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE);
485 
486 	if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif)))
487 		return;
488 
489 	RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL);
490 
491 	iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_VIF,
492 					       mld_vif->fw_id);
493 }
494 
iwl_mld_set_vif_associated(struct iwl_mld * mld,struct ieee80211_vif * vif)495 void iwl_mld_set_vif_associated(struct iwl_mld *mld,
496 				struct ieee80211_vif *vif)
497 {
498 	struct ieee80211_bss_conf *link;
499 	unsigned int link_id;
500 
501 	for_each_vif_active_link(vif, link, link_id) {
502 		if (iwl_mld_link_set_associated(mld, vif, link))
503 			IWL_ERR(mld, "failed to update link %d\n", link_id);
504 	}
505 
506 	iwl_mld_recalc_multicast_filter(mld);
507 }
508 
iwl_mld_get_fw_id_bss_bitmap_iter(void * _data,u8 * mac,struct ieee80211_vif * vif)509 static void iwl_mld_get_fw_id_bss_bitmap_iter(void *_data, u8 *mac,
510 					      struct ieee80211_vif *vif)
511 {
512 	u8 *fw_id_bitmap = _data;
513 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
514 
515 	if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)
516 		return;
517 
518 	*fw_id_bitmap |= BIT(mld_vif->fw_id);
519 }
520 
iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld * mld)521 u8 iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld *mld)
522 {
523 	u8 fw_id_bitmap = 0;
524 
525 	ieee80211_iterate_active_interfaces_mtx(mld->hw,
526 						IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER,
527 						iwl_mld_get_fw_id_bss_bitmap_iter,
528 						&fw_id_bitmap);
529 
530 	return fw_id_bitmap;
531 }
532 
iwl_mld_handle_probe_resp_data_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)533 void iwl_mld_handle_probe_resp_data_notif(struct iwl_mld *mld,
534 					  struct iwl_rx_packet *pkt)
535 {
536 	const struct iwl_probe_resp_data_notif *notif = (void *)pkt->data;
537 	struct iwl_probe_resp_data *old_data, *new_data;
538 	struct ieee80211_vif *vif;
539 	struct iwl_mld_link *mld_link;
540 
541 	IWL_DEBUG_INFO(mld, "Probe response data notif: noa %d, csa %d\n",
542 		       notif->noa_active, notif->csa_counter);
543 
544 	if (IWL_FW_CHECK(mld, le32_to_cpu(notif->mac_id) >=
545 			 ARRAY_SIZE(mld->fw_id_to_vif),
546 			 "mac id is invalid: %d\n",
547 			 le32_to_cpu(notif->mac_id)))
548 		return;
549 
550 	vif = wiphy_dereference(mld->wiphy,
551 				mld->fw_id_to_vif[le32_to_cpu(notif->mac_id)]);
552 
553 	/* the firmware gives us the mac_id (and not the link_id), mac80211
554 	 * gets a vif and not a link, bottom line, this flow is not MLD ready
555 	 * yet.
556 	 */
557 	if (WARN_ON(!vif) || ieee80211_vif_is_mld(vif))
558 		return;
559 
560 	if (notif->csa_counter != IWL_PROBE_RESP_DATA_NO_CSA &&
561 	    notif->csa_counter >= 1)
562 		ieee80211_beacon_set_cntdwn(vif, notif->csa_counter);
563 
564 	if (!vif->p2p)
565 		return;
566 
567 	mld_link = &iwl_mld_vif_from_mac80211(vif)->deflink;
568 
569 	/* len_low should be 2 + n*13 (where n is the number of descriptors.
570 	 * 13 is the size of a NoA descriptor). We can have either one or two
571 	 * descriptors.
572 	 */
573 	if (IWL_FW_CHECK(mld, notif->noa_active &&
574 			 notif->noa_attr.len_low != 2 +
575 			 sizeof(struct ieee80211_p2p_noa_desc) &&
576 			 notif->noa_attr.len_low != 2 +
577 			 sizeof(struct ieee80211_p2p_noa_desc) * 2,
578 			 "Invalid noa_attr.len_low (%d)\n",
579 			 notif->noa_attr.len_low))
580 		return;
581 
582 	new_data = kzalloc_obj(*new_data);
583 	if (!new_data)
584 		return;
585 
586 	memcpy(&new_data->notif, notif, sizeof(new_data->notif));
587 
588 	/* noa_attr contains 1 reserved byte, need to substruct it */
589 	new_data->noa_len = sizeof(struct ieee80211_vendor_ie) +
590 			    sizeof(new_data->notif.noa_attr) - 1;
591 
592 	/*
593 	 * If it's a one time NoA, only one descriptor is needed,
594 	 * adjust the length according to len_low.
595 	 */
596 	if (new_data->notif.noa_attr.len_low ==
597 	    sizeof(struct ieee80211_p2p_noa_desc) + 2)
598 		new_data->noa_len -= sizeof(struct ieee80211_p2p_noa_desc);
599 
600 	old_data = wiphy_dereference(mld->wiphy, mld_link->probe_resp_data);
601 	rcu_assign_pointer(mld_link->probe_resp_data, new_data);
602 
603 	if (old_data)
604 		kfree_rcu(old_data, rcu_head);
605 }
606 
iwl_mld_handle_uapsd_misbehaving_ap_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)607 void iwl_mld_handle_uapsd_misbehaving_ap_notif(struct iwl_mld *mld,
608 					       struct iwl_rx_packet *pkt)
609 {
610 	struct iwl_uapsd_misbehaving_ap_notif *notif = (void *)pkt->data;
611 	struct ieee80211_vif *vif;
612 
613 	if (IWL_FW_CHECK(mld, notif->mac_id >= ARRAY_SIZE(mld->fw_id_to_vif),
614 			 "mac id is invalid: %d\n", notif->mac_id))
615 		return;
616 
617 	vif = wiphy_dereference(mld->wiphy, mld->fw_id_to_vif[notif->mac_id]);
618 
619 	if (WARN_ON(!vif) || ieee80211_vif_is_mld(vif))
620 		return;
621 
622 	IWL_WARN(mld, "uapsd misbehaving AP: %pM\n", vif->bss_conf.bssid);
623 }
624 
iwl_mld_handle_datapath_monitor_notif(struct iwl_mld * mld,struct iwl_rx_packet * pkt)625 void iwl_mld_handle_datapath_monitor_notif(struct iwl_mld *mld,
626 					   struct iwl_rx_packet *pkt)
627 {
628 	struct iwl_datapath_monitor_notif *notif = (void *)pkt->data;
629 	struct ieee80211_bss_conf *link;
630 	struct ieee80211_supported_band *sband;
631 	const struct ieee80211_sta_he_cap *he_cap;
632 	struct ieee80211_vif *vif;
633 	struct iwl_mld_vif *mld_vif;
634 
635 	if (notif->type != cpu_to_le32(IWL_DP_MON_NOTIF_TYPE_EXT_CCA))
636 		return;
637 
638 	link = iwl_mld_fw_id_to_link_conf(mld, notif->link_id);
639 	if (WARN_ON(!link))
640 		return;
641 
642 	vif = link->vif;
643 	if (WARN_ON(!vif) || vif->type != NL80211_IFTYPE_STATION ||
644 	    !vif->cfg.assoc)
645 		return;
646 
647 	if (!link->chanreq.oper.chan ||
648 	    link->chanreq.oper.chan->band != NL80211_BAND_2GHZ ||
649 	    link->chanreq.oper.width < NL80211_CHAN_WIDTH_40)
650 		return;
651 
652 	mld_vif = iwl_mld_vif_from_mac80211(vif);
653 
654 	/* this shouldn't happen *again*, ignore it */
655 	if (mld_vif->cca_40mhz_workaround != CCA_40_MHZ_WA_NONE)
656 		return;
657 
658 	mld_vif->cca_40mhz_workaround = CCA_40_MHZ_WA_RECONNECT;
659 
660 	/*
661 	 * This capability manipulation isn't really ideal, but it's the
662 	 * easiest choice - otherwise we'd have to do some major changes
663 	 * in mac80211 to support this, which isn't worth it. This does
664 	 * mean that userspace may have outdated information, but that's
665 	 * actually not an issue at all.
666 	 */
667 	sband = mld->wiphy->bands[NL80211_BAND_2GHZ];
668 
669 	WARN_ON(!sband->ht_cap.ht_supported);
670 	WARN_ON(!(sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40));
671 	sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
672 
673 	he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
674 
675 	if (he_cap) {
676 		/* we know that ours is writable */
677 		struct ieee80211_sta_he_cap *he = (void *)(uintptr_t)he_cap;
678 
679 		WARN_ON(!he->has_he);
680 		WARN_ON(!(he->he_cap_elem.phy_cap_info[0] &
681 			  IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G));
682 		he->he_cap_elem.phy_cap_info[0] &=
683 			~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
684 	}
685 
686 	ieee80211_disconnect(vif, true);
687 }
688 
iwl_mld_reset_cca_40mhz_workaround(struct iwl_mld * mld,struct ieee80211_vif * vif)689 void iwl_mld_reset_cca_40mhz_workaround(struct iwl_mld *mld,
690 					struct ieee80211_vif *vif)
691 {
692 	struct ieee80211_supported_band *sband;
693 	const struct ieee80211_sta_he_cap *he_cap;
694 	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
695 
696 	if (vif->type != NL80211_IFTYPE_STATION)
697 		return;
698 
699 	if (mld_vif->cca_40mhz_workaround == CCA_40_MHZ_WA_NONE)
700 		return;
701 
702 	/* Now we are just reconnecting with the new capabilities,
703 	 * but remember to reset the capabilities when we disconnect for real
704 	 */
705 	if (mld_vif->cca_40mhz_workaround == CCA_40_MHZ_WA_RECONNECT) {
706 		mld_vif->cca_40mhz_workaround = CCA_40_MHZ_WA_RESET;
707 		return;
708 	}
709 
710 	/* Now cca_40mhz_workaround == CCA_40_MHZ_WA_RESET */
711 
712 	sband = mld->wiphy->bands[NL80211_BAND_2GHZ];
713 
714 	sband->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
715 
716 	he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
717 
718 	if (he_cap) {
719 		/* we know that ours is writable */
720 		struct ieee80211_sta_he_cap *he = (void *)(uintptr_t)he_cap;
721 
722 		he->he_cap_elem.phy_cap_info[0] |=
723 			IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
724 	}
725 
726 	mld_vif->cca_40mhz_workaround = CCA_40_MHZ_WA_NONE;
727 }
728 
iwl_mld_get_bss_vif(struct iwl_mld * mld)729 struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld)
730 {
731 	unsigned long fw_id_bitmap = iwl_mld_get_fw_bss_vifs_ids(mld);
732 	int fw_id;
733 
734 	if (hweight8(fw_id_bitmap) != 1)
735 		return NULL;
736 
737 	fw_id = __ffs(fw_id_bitmap);
738 
739 	return wiphy_dereference(mld->wiphy,
740 				 mld->fw_id_to_vif[fw_id]);
741 }
742