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