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