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 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 */ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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