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