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