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