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