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