FILE
mld-mac80211.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2/* 3 * Copyright (C) 2022-2025 Intel Corporation 4 */ 5#include "mvm.h" 6 7static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw, 8 struct ieee80211_vif *vif) 9{ 10 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 11 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 12 int ret; 13 int i; 14 15 guard(mvm)(mvm); 16 17 iwl_mvm_mac_init_mvmvif(mvm, mvmvif); 18 19 mvmvif->mvm = mvm; 20 21 vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; 22 23 /* Not much to do here. The stack will not allow interface 24 * types or combinations that we didn't advertise, so we 25 * don't really have to check the types. 26 */ 27 28 /* make sure that beacon statistics don't go backwards with FW reset */ 29 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 30 for_each_mvm_vif_valid_link(mvmvif, i) 31 mvmvif->link[i]->beacon_stats.accu_num_beacons += 32 mvmvif->link[i]->beacon_stats.num_beacons; 33 34 /* Allocate resources for the MAC context, and add it to the fw */ 35 ret = iwl_mvm_mac_ctxt_init(mvm, vif); 36 if (ret) 37 return ret; 38 39 rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); 40 41 mvmvif->features |= hw->netdev_features; 42 43 /* reset deflink MLO parameters */ 44 mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; 45 mvmvif->deflink.active = 0; 46 47 ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif); 48 if (ret) 49 return ret; 50 51 /* beacon filtering */ 52 ret = iwl_mvm_disable_beacon_filter(mvm, vif); 53 if (ret) 54 goto out_remove_mac; 55 56 if (!mvm->bf_allowed_vif && 57 vif->type == NL80211_IFTYPE_STATION && !vif->p2p) { 58 mvm->bf_allowed_vif = mvmvif; 59 vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | 60 IEEE80211_VIF_SUPPORTS_CQM_RSSI; 61 } 62 63 /* We want link[0] to point to the default link, unless we have MLO and 64 * in this case this will be modified later by .change_vif_links() 65 * If we are in the restart flow with an MLD connection, we will wait 66 * to .change_vif_links() to setup the links. 67 */ 68 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || 69 !ieee80211_vif_is_mld(vif)) { 70 mvmvif->link[0] = &mvmvif->deflink; 71 72 ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); 73 if (ret) 74 goto out_free_bf; 75 } 76 77 /* Save a pointer to p2p device vif, so it can later be used to 78 * update the p2p device MAC when a GO is started/stopped 79 */ 80 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) 81 mvm->p2p_device_vif = vif; 82 83 ret = iwl_mvm_power_update_mac(mvm); 84 if (ret) 85 goto out_free_bf; 86 87 iwl_mvm_tcm_add_vif(mvm, vif); 88 89 if (vif->type == NL80211_IFTYPE_MONITOR) { 90 mvm->monitor_on = true; 91 ieee80211_hw_set(mvm->hw, RX_INCLUDES_FCS); 92 } 93 94 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 95 iwl_mvm_vif_dbgfs_add_link(mvm, vif); 96 97 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && 98 vif->type == NL80211_IFTYPE_STATION && !vif->p2p && 99 !mvm->csme_vif && mvm->mei_registered) { 100 iwl_mei_set_nic_info(vif->addr, mvm->nvm_data->hw_addr); 101 iwl_mei_set_netdev(ieee80211_vif_to_wdev(vif)->netdev); 102 mvm->csme_vif = vif; 103 } 104 105 return 0; 106 107 out_free_bf: 108 if (mvm->bf_allowed_vif == mvmvif) { 109 mvm->bf_allowed_vif = NULL; 110 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | 111 IEEE80211_VIF_SUPPORTS_CQM_RSSI); 112 } 113 out_remove_mac: 114 mvmvif->link[0] = NULL; 115 iwl_mvm_mld_mac_ctxt_remove(mvm, vif); 116 return ret; 117} 118 119static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw, 120 struct ieee80211_vif *vif) 121{ 122 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 123 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 124 struct iwl_probe_resp_data *probe_data; 125 126 iwl_mvm_prepare_mac_removal(mvm, vif); 127 128 if (!(vif->type == NL80211_IFTYPE_AP || 129 vif->type == NL80211_IFTYPE_ADHOC)) 130 iwl_mvm_tcm_rm_vif(mvm, vif); 131 132 guard(mvm)(mvm); 133 134 if (vif == mvm->csme_vif) { 135 iwl_mei_set_netdev(NULL); 136 mvm->csme_vif = NULL; 137 } 138 139 if (mvm->bf_allowed_vif == mvmvif) { 140 mvm->bf_allowed_vif = NULL; 141 vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER | 142 IEEE80211_VIF_SUPPORTS_CQM_RSSI); 143 } 144 145 if (vif->bss_conf.ftm_responder) 146 memset(&mvm->ftm_resp_stats, 0, sizeof(mvm->ftm_resp_stats)); 147 148 iwl_mvm_vif_dbgfs_rm_link(mvm, vif); 149 150 iwl_mvm_power_update_mac(mvm); 151 152 /* Before the interface removal, mac80211 would cancel the ROC, and the 153 * ROC worker would be scheduled if needed. The worker would be flushed 154 * in iwl_mvm_prepare_mac_removal() and thus at this point the link is 155 * not active. So need only to remove the link. 156 */ 157 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { 158 if (mvmvif->deflink.phy_ctxt) { 159 iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt); 160 mvmvif->deflink.phy_ctxt = NULL; 161 } 162 mvm->p2p_device_vif = NULL; 163 iwl_mvm_remove_link(mvm, vif, &vif->bss_conf); 164 } else { 165 iwl_mvm_disable_link(mvm, vif, &vif->bss_conf); 166 } 167 168 iwl_mvm_mld_mac_ctxt_remove(mvm, vif); 169 170 RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL); 171 172 probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data, 173 lockdep_is_held(&mvm->mutex)); 174 RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL); 175 if (probe_data) 176 kfree_rcu(probe_data, rcu_head); 177 178 if (vif->type == NL80211_IFTYPE_MONITOR) { 179 mvm->monitor_on = false; 180 __clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags); 181 } 182} 183 184static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif) 185{ 186 unsigned int n_active = 0; 187 int i; 188 189 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { 190 if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt) 191 n_active++; 192 } 193 194 return n_active; 195} 196 197static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm, 198 struct ieee80211_vif *vif) 199{ 200 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 201 int link_id, ret = 0; 202 203 mvmvif->esr_active = true; 204 205 /* Indicate to mac80211 that EML is enabled */ 206 vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; 207 208 iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, 209 IEEE80211_SMPS_OFF); 210 211 for_each_mvm_vif_valid_link(mvmvif, link_id) { 212 struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; 213 214 if (!link->phy_ctxt) 215 continue; 216 217 ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2); 218 if (ret) 219 break; 220 221 link->phy_ctxt->rlc_disabled = true; 222 } 223 224 if (vif->active_links == mvmvif->link_selection_res && 225 !WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary)))) 226 mvmvif->primary_link = mvmvif->link_selection_primary; 227 else 228 mvmvif->primary_link = __ffs(vif->active_links); 229 230 iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP, 231 NULL); 232 233 return ret; 234} 235 236static int 237__iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm, 238 struct ieee80211_vif *vif, 239 struct ieee80211_bss_conf *link_conf, 240 struct ieee80211_chanctx_conf *ctx, 241 bool switching_chanctx) 242{ 243 u16 *phy_ctxt_id = (u16 *)ctx->drv_priv; 244 struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; 245 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 246 unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); 247 unsigned int link_id = link_conf->link_id; 248 int ret; 249 250 if (WARN_ON_ONCE(!mvmvif->link[link_id])) 251 return -EINVAL; 252 253 /* if the assigned one was not counted yet, count it now */ 254 if (!mvmvif->link[link_id]->phy_ctxt) 255 n_active++; 256 257 /* mac parameters such as HE support can change at this stage 258 * For sta, need first to configure correct state from drv_sta_state 259 * and only after that update mac config. 260 */ 261 if (vif->type == NL80211_IFTYPE_AP) { 262 ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false); 263 if (ret) { 264 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); 265 return -EINVAL; 266 } 267 } 268 269 mvmvif->link[link_id]->phy_ctxt = phy_ctxt; 270 271 if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { 272 mvmvif->link[link_id]->listen_lmac = true; 273 ret = iwl_mvm_esr_mode_active(mvm, vif); 274 if (ret) { 275 IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret); 276 goto out; 277 } 278 } 279 280 if (switching_chanctx) { 281 /* reactivate if we turned this off during channel switch */ 282 if (vif->type == NL80211_IFTYPE_AP) 283 mvmvif->ap_ibss_active = true; 284 } 285 286 /* send it first with phy context ID */ 287 ret = iwl_mvm_link_changed(mvm, vif, link_conf, 0, false); 288 if (ret) 289 goto out; 290 291 /* 292 * if link switching (link not active yet) we'll activate it in 293 * firmware later on link-info change, which mac80211 guarantees 294 * for link switch after the stations are set up 295 */ 296 if (ieee80211_vif_link_active(vif, link_conf->link_id)) { 297 ret = iwl_mvm_link_changed(mvm, vif, link_conf, 298 LINK_CONTEXT_MODIFY_ACTIVE | 299 LINK_CONTEXT_MODIFY_RATES_INFO, 300 true); 301 if (ret) 302 goto out; 303 } 304 305 if (vif->type == NL80211_IFTYPE_STATION) 306 iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, 307 link_conf, 308 false); 309 310 /* 311 * Power state must be updated before quotas, 312 * otherwise fw will complain. 313 */ 314 iwl_mvm_power_update_mac(mvm); 315 316 if (vif->type == NL80211_IFTYPE_MONITOR) { 317 ret = iwl_mvm_mld_add_snif_sta(mvm, vif, link_conf); 318 if (ret) 319 goto deactivate; 320 } 321 322 return 0; 323 324deactivate: 325 iwl_mvm_link_changed(mvm, vif, link_conf, LINK_CONTEXT_MODIFY_ACTIVE, 326 false); 327out: 328 mvmvif->link[link_id]->phy_ctxt = NULL; 329 iwl_mvm_power_update_mac(mvm); 330 return ret; 331} 332 333static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, 334 struct ieee80211_vif *vif, 335 struct ieee80211_bss_conf *link_conf, 336 struct ieee80211_chanctx_conf *ctx) 337{ 338 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 339 340 guard(mvm)(mvm); 341 return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false); 342} 343 344static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm, 345 struct ieee80211_vif *vif) 346{ 347 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 348 struct ieee80211_bss_conf *link_conf; 349 int link_id, ret = 0; 350 351 mvmvif->esr_active = false; 352 353 vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE; 354 355 iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW, 356 IEEE80211_SMPS_AUTOMATIC); 357 358 for_each_vif_active_link(vif, link_conf, link_id) { 359 struct ieee80211_chanctx_conf *chanctx_conf; 360 struct iwl_mvm_phy_ctxt *phy_ctxt; 361 u8 static_chains, dynamic_chains; 362 363 mvmvif->link[link_id]->listen_lmac = false; 364 365 rcu_read_lock(); 366 367 chanctx_conf = rcu_dereference(link_conf->chanctx_conf); 368 phy_ctxt = mvmvif->link[link_id]->phy_ctxt; 369 370 if (!chanctx_conf || !phy_ctxt) { 371 rcu_read_unlock(); 372 continue; 373 } 374 375 phy_ctxt->rlc_disabled = false; 376 static_chains = chanctx_conf->rx_chains_static; 377 dynamic_chains = chanctx_conf->rx_chains_dynamic; 378 379 rcu_read_unlock(); 380 381 ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains, 382 dynamic_chains); 383 if (ret) 384 break; 385 } 386 387 iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN, 388 NULL); 389 390 return ret; 391} 392 393static void 394__iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm, 395 struct ieee80211_vif *vif, 396 struct ieee80211_bss_conf *link_conf, 397 struct ieee80211_chanctx_conf *ctx, 398 bool switching_chanctx) 399 400{ 401 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 402 unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif); 403 unsigned int link_id = link_conf->link_id; 404 405 /* shouldn't happen, but verify link_id is valid before accessing */ 406 if (WARN_ON_ONCE(!mvmvif->link[link_id])) 407 return; 408 409 if (vif->type == NL80211_IFTYPE_AP && switching_chanctx) { 410 mvmvif->csa_countdown = false; 411 412 /* Set CS bit on all the stations */ 413 iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); 414 415 /* Save blocked iface, the timeout is set on the next beacon */ 416 rcu_assign_pointer(mvm->csa_tx_blocked_vif, vif); 417 418 mvmvif->ap_ibss_active = false; 419 } 420 421 iwl_mvm_link_changed(mvm, vif, link_conf, 422 LINK_CONTEXT_MODIFY_ACTIVE, false); 423 424 if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) { 425 int ret = iwl_mvm_esr_mode_inactive(mvm, vif); 426 427 if (ret) 428 IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n", 429 ret); 430 } 431 432 if (vif->type == NL80211_IFTYPE_MONITOR) 433 iwl_mvm_mld_rm_snif_sta(mvm, vif); 434 435 if (switching_chanctx) 436 return; 437 mvmvif->link[link_id]->phy_ctxt = NULL; 438 iwl_mvm_power_update_mac(mvm); 439} 440 441static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, 442 struct ieee80211_vif *vif, 443 struct ieee80211_bss_conf *link_conf, 444 struct ieee80211_chanctx_conf *ctx) 445{ 446 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 447 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 448 449 mutex_lock(&mvm->mutex); 450 __iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false); 451 /* in the non-MLD case, remove/re-add the link to clean up FW state */ 452 if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta && 453 !WARN_ON_ONCE(vif->cfg.assoc)) { 454 iwl_mvm_remove_link(mvm, vif, link_conf); 455 iwl_mvm_add_link(mvm, vif, link_conf); 456 } 457 mutex_unlock(&mvm->mutex); 458} 459 460static void 461iwl_mvm_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd, 462 const struct ieee80211_bss_conf *bss_info) 463{ 464 u8 i; 465 466 /* 467 * NOTE: the 0 here is IEEE80211_TPE_CAT_6GHZ_DEFAULT, 468 * we fully ignore IEEE80211_TPE_CAT_6GHZ_SUBORDINATE 469 */ 470 471 BUILD_BUG_ON(ARRAY_SIZE(cmd->psd_pwr) != 472 ARRAY_SIZE(bss_info->tpe.psd_local[0].power)); 473 474 /* if not valid, mac80211 puts default (max value) */ 475 for (i = 0; i < ARRAY_SIZE(cmd->psd_pwr); i++) 476 cmd->psd_pwr[i] = min(bss_info->tpe.psd_local[0].power[i], 477 bss_info->tpe.psd_reg_client[0].power[i]); 478 479 BUILD_BUG_ON(ARRAY_SIZE(cmd->eirp_pwr) != 480 ARRAY_SIZE(bss_info->tpe.max_local[0].power)); 481 482 for (i = 0; i < ARRAY_SIZE(cmd->eirp_pwr); i++) 483 cmd->eirp_pwr[i] = min(bss_info->tpe.max_local[0].power[i], 484 bss_info->tpe.max_reg_client[0].power[i]); 485} 486 487void 488iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, 489 struct ieee80211_vif *vif, 490 struct ieee80211_bss_conf *bss_conf, 491 bool is_ap) 492{ 493 struct iwl_txpower_constraints_cmd cmd = {}; 494 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 495 struct iwl_mvm_vif_link_info *link_info = 496 mvmvif->link[bss_conf->link_id]; 497 u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, AP_TX_POWER_CONSTRAINTS_CMD); 498 u32 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 499 IWL_FW_CMD_VER_UNKNOWN); 500 int ret; 501 502 lockdep_assert_held(&mvm->mutex); 503 504 if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) 505 return; 506 507 if (!link_info->active || 508 link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) 509 return; 510 511 if (bss_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ) 512 return; 513 514 cmd.link_id = cpu_to_le16(link_info->fw_link_id); 515 memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr)); 516 memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr)); 517 518 if (is_ap) { 519 cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP); 520 } else if (bss_conf->power_type == IEEE80211_REG_UNSET_AP) { 521 return; 522 } else { 523 cmd.ap_type = cpu_to_le16(bss_conf->power_type - 1); 524 iwl_mvm_tpe_sta_cmd_data(&cmd, bss_conf); 525 } 526 527 ret = iwl_mvm_send_cmd_pdu(mvm, 528 WIDE_ID(PHY_OPS_GROUP, 529 AP_TX_POWER_CONSTRAINTS_CMD), 530 0, sizeof(cmd), &cmd); 531 if (ret) 532 IWL_ERR(mvm, 533 "failed to send AP_TX_POWER_CONSTRAINTS_CMD (%d)\n", 534 ret); 535} 536 537static int iwl_mvm_mld_start_ap_ibss(struct ieee80211_hw *hw, 538 struct ieee80211_vif *vif, 539 struct ieee80211_bss_conf *link_conf) 540{ 541 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 542 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 543 int ret; 544 545 guard(mvm)(mvm); 546 547 if (vif->type == NL80211_IFTYPE_AP) 548 iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif, 549 link_conf, true); 550 551 /* Send the beacon template */ 552 ret = iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf); 553 if (ret) 554 return ret; 555 556 /* the link should be already activated when assigning chan context */ 557 ret = iwl_mvm_link_changed(mvm, vif, link_conf, 558 LINK_CONTEXT_MODIFY_ALL & 559 ~LINK_CONTEXT_MODIFY_ACTIVE, 560 true); 561 if (ret) 562 return ret; 563 564 ret = iwl_mvm_mld_add_mcast_sta(mvm, vif, link_conf); 565 if (ret) 566 return ret; 567 568 /* Send the bcast station. At this stage the TBTT and DTIM time 569 * events are added and applied to the scheduler 570 */ 571 ret = iwl_mvm_mld_add_bcast_sta(mvm, vif, link_conf); 572 if (ret) 573 goto out_rm_mcast; 574 575 if (iwl_mvm_start_ap_ibss_common(hw, vif, &ret)) 576 goto out_failed; 577 578 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ 579 if (vif->p2p && mvm->p2p_device_vif) 580 iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); 581 582 iwl_mvm_bt_coex_vif_change(mvm); 583 584 /* we don't support TDLS during DCM */ 585 if (iwl_mvm_phy_ctx_count(mvm) > 1) 586 iwl_mvm_teardown_tdls_peers(mvm); 587 588 iwl_mvm_ftm_restart_responder(mvm, vif, link_conf); 589 590 return 0; 591 592out_failed: 593 iwl_mvm_power_update_mac(mvm); 594 mvmvif->ap_ibss_active = false; 595 iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf); 596out_rm_mcast: 597 iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf); 598 return ret; 599} 600 601static int iwl_mvm_mld_start_ap(struct ieee80211_hw *hw, 602 struct ieee80211_vif *vif, 603 struct ieee80211_bss_conf *link_conf) 604{ 605 return iwl_mvm_mld_start_ap_ibss(hw, vif, link_conf); 606} 607 608static int iwl_mvm_mld_start_ibss(struct ieee80211_hw *hw, 609 struct ieee80211_vif *vif) 610{ 611 return iwl_mvm_mld_start_ap_ibss(hw, vif, &vif->bss_conf); 612} 613 614static void iwl_mvm_mld_stop_ap_ibss(struct ieee80211_hw *hw, 615 struct ieee80211_vif *vif, 616 struct ieee80211_bss_conf *link_conf) 617{ 618 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 619 620 guard(mvm)(mvm); 621 622 iwl_mvm_stop_ap_ibss_common(mvm, vif); 623 624 /* Need to update the P2P Device MAC (only GO, IBSS is single vif) */ 625 if (vif->p2p && mvm->p2p_device_vif) 626 iwl_mvm_mld_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false); 627 628 iwl_mvm_ftm_responder_clear(mvm, vif); 629 630 iwl_mvm_mld_rm_bcast_sta(mvm, vif, link_conf); 631 iwl_mvm_mld_rm_mcast_sta(mvm, vif, link_conf); 632 633 iwl_mvm_power_update_mac(mvm); 634} 635 636static void iwl_mvm_mld_stop_ap(struct ieee80211_hw *hw, 637 struct ieee80211_vif *vif, 638 struct ieee80211_bss_conf *link_conf) 639{ 640 iwl_mvm_mld_stop_ap_ibss(hw, vif, link_conf); 641} 642 643static void iwl_mvm_mld_stop_ibss(struct ieee80211_hw *hw, 644 struct ieee80211_vif *vif) 645{ 646 iwl_mvm_mld_stop_ap_ibss(hw, vif, &vif->bss_conf); 647} 648 649static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, 650 struct ieee80211_vif *vif, 651 struct ieee80211_sta *sta, 652 enum ieee80211_sta_state old_state, 653 enum ieee80211_sta_state new_state) 654{ 655 static const struct iwl_mvm_sta_state_ops callbacks = { 656 .add_sta = iwl_mvm_mld_add_sta, 657 .update_sta = iwl_mvm_mld_update_sta, 658 .rm_sta = iwl_mvm_mld_rm_sta, 659 .mac_ctxt_changed = iwl_mvm_mld_mac_ctxt_changed, 660 }; 661 662 return iwl_mvm_mac_sta_state_common(hw, vif, sta, old_state, new_state, 663 &callbacks); 664} 665 666static void 667iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, 668 struct ieee80211_vif *vif, 669 struct ieee80211_bss_conf *link_conf, 670 u64 changes) 671{ 672 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 673 bool has_he, has_eht; 674 u32 link_changes = 0; 675 int ret; 676 677 if (WARN_ON_ONCE(!mvmvif->link[link_conf->link_id])) 678 return; 679 680 /* not yet marked active in vif means during link switch */ 681 if (!ieee80211_vif_link_active(vif, link_conf->link_id) && 682 vif->cfg.assoc && mvmvif->link[link_conf->link_id]->phy_ctxt) 683 link_changes |= LINK_CONTEXT_MODIFY_ACTIVE; 684 685 has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax; 686 has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be; 687 688 /* Update EDCA params */ 689 if (changes & BSS_CHANGED_QOS && vif->cfg.assoc && link_conf->qos) 690 link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS; 691 692 if (changes & BSS_CHANGED_ERP_SLOT) 693 link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO; 694 695 if (vif->cfg.assoc && (has_he || has_eht)) { 696 IWL_DEBUG_MAC80211(mvm, "Associated in HE mode\n"); 697 link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; 698 } 699 700 /* if associated, maybe puncturing changed - we'll check later */ 701 if (vif->cfg.assoc) 702 link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS; 703 704 if (link_changes) { 705 ret = iwl_mvm_link_changed(mvm, vif, link_conf, link_changes, 706 true); 707 if (ret) 708 IWL_ERR(mvm, "failed to update link\n"); 709 } 710 711 ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false); 712 if (ret) 713 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); 714 715 memcpy(mvmvif->link[link_conf->link_id]->bssid, link_conf->bssid, 716 ETH_ALEN); 717 718 iwl_mvm_bss_info_changed_station_common(mvm, vif, link_conf, changes); 719} 720 721static bool iwl_mvm_mld_vif_have_valid_ap_sta(struct iwl_mvm_vif *mvmvif) 722{ 723 int i; 724 725 for_each_mvm_vif_valid_link(mvmvif, i) { 726 if (mvmvif->link[i]->ap_sta_id != IWL_INVALID_STA) 727 return true; 728 } 729 730 return false; 731} 732 733static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, 734 struct ieee80211_vif *vif, 735 u64 changes) 736{ 737 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 738 struct ieee80211_bss_conf *link_conf; 739 bool protect = false; 740 unsigned int i; 741 int ret; 742 743 /* This might get called without active links during the 744 * chanctx switch, but we don't care about it anyway. 745 */ 746 if (changes == BSS_CHANGED_IDLE) 747 return; 748 749 ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false); 750 if (ret) 751 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); 752 753 mvmvif->associated = vif->cfg.assoc; 754 755 if (changes & BSS_CHANGED_ASSOC) { 756 if (vif->cfg.assoc) { 757 mvmvif->session_prot_connection_loss = false; 758 759 /* 760 * Clear statistics to get clean beacon counter, and ask for 761 * periodic statistics, as they are needed for link 762 * selection and RX OMI decisions. 763 */ 764 iwl_mvm_request_statistics(mvm, true); 765 iwl_mvm_request_periodic_system_statistics(mvm, true); 766 iwl_mvm_sf_update(mvm, vif, false); 767 iwl_mvm_power_vif_assoc(mvm, vif); 768 769 for_each_mvm_vif_valid_link(mvmvif, i) { 770 memset(&mvmvif->link[i]->beacon_stats, 0, 771 sizeof(mvmvif->link[i]->beacon_stats)); 772 773 if (vif->p2p) { 774 iwl_mvm_update_smps(mvm, vif, 775 IWL_MVM_SMPS_REQ_PROT, 776 IEEE80211_SMPS_DYNAMIC, i); 777 } 778 779 rcu_read_lock(); 780 link_conf = rcu_dereference(vif->link_conf[i]); 781 if (link_conf && !link_conf->dtim_period) 782 protect = true; 783 rcu_read_unlock(); 784 } 785 786 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && 787 protect) { 788 /* We are in assoc so only one link is active- 789 * The association link 790 */ 791 unsigned int link_id = 792 ffs(vif->active_links) - 1; 793 794 /* If we're not restarting and still haven't 795 * heard a beacon (dtim period unknown) then 796 * make sure we still have enough minimum time 797 * remaining in the time event, since the auth 798 * might actually have taken quite a while 799 * (especially for SAE) and so the remaining 800 * time could be small without us having heard 801 * a beacon yet. 802 */ 803 iwl_mvm_protect_assoc(mvm, vif, 0, link_id); 804 } 805 806 iwl_mvm_sf_update(mvm, vif, false); 807 808 /* FIXME: need to decide about misbehaving AP handling */ 809 iwl_mvm_power_vif_assoc(mvm, vif); 810 } else if (iwl_mvm_mld_vif_have_valid_ap_sta(mvmvif)) { 811 iwl_mvm_mei_host_disassociated(mvm); 812 813 iwl_mvm_request_periodic_system_statistics(mvm, false); 814 815 /* If update fails - SF might be running in associated 816 * mode while disassociated - which is forbidden. 817 */ 818 ret = iwl_mvm_sf_update(mvm, vif, false); 819 WARN_ONCE(ret && 820 !test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, 821 &mvm->status), 822 "Failed to update SF upon disassociation\n"); 823 } 824 825 iwl_mvm_bss_info_changed_station_assoc(mvm, vif, changes); 826 } 827 828 if (changes & BSS_CHANGED_PS) { 829 iwl_mvm_smps_workaround(mvm, vif, false); 830 ret = iwl_mvm_power_update_mac(mvm); 831 if (ret) 832 IWL_ERR(mvm, "failed to update power mode\n"); 833 } 834} 835 836static void 837iwl_mvm_mld_link_info_changed_ap_ibss(struct iwl_mvm *mvm, 838 struct ieee80211_vif *vif, 839 struct ieee80211_bss_conf *link_conf, 840 u64 changes) 841{ 842 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 843 u32 link_changes = LINK_CONTEXT_MODIFY_PROTECT_FLAGS | 844 LINK_CONTEXT_MODIFY_QOS_PARAMS; 845 846 /* Changes will be applied when the AP/IBSS is started */ 847 if (!mvmvif->ap_ibss_active) 848 return; 849 850 if (link_conf->he_support) 851 link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; 852 853 if (changes & BSS_CHANGED_ERP_SLOT) 854 link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO; 855 856 if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_SLOT | 857 BSS_CHANGED_HT | 858 BSS_CHANGED_BANDWIDTH | BSS_CHANGED_QOS | 859 BSS_CHANGED_HE_BSS_COLOR) && 860 iwl_mvm_link_changed(mvm, vif, link_conf, 861 link_changes, true)) 862 IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); 863 864 /* Need to send a new beacon template to the FW */ 865 if (changes & BSS_CHANGED_BEACON && 866 iwl_mvm_mac_ctxt_beacon_changed(mvm, vif, link_conf)) 867 IWL_WARN(mvm, "Failed updating beacon data\n"); 868 869 /* FIXME: need to decide if we need FTM responder per link */ 870 if (changes & BSS_CHANGED_FTM_RESPONDER) { 871 int ret = iwl_mvm_ftm_start_responder(mvm, vif, link_conf); 872 873 if (ret) 874 IWL_WARN(mvm, "Failed to enable FTM responder (%d)\n", 875 ret); 876 } 877} 878 879static void iwl_mvm_mld_link_info_changed(struct ieee80211_hw *hw, 880 struct ieee80211_vif *vif, 881 struct ieee80211_bss_conf *link_conf, 882 u64 changes) 883{ 884 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 885 886 guard(mvm)(mvm); 887 888 switch (vif->type) { 889 case NL80211_IFTYPE_STATION: 890 iwl_mvm_mld_link_info_changed_station(mvm, vif, link_conf, 891 changes); 892 break; 893 case NL80211_IFTYPE_AP: 894 case NL80211_IFTYPE_ADHOC: 895 iwl_mvm_mld_link_info_changed_ap_ibss(mvm, vif, link_conf, 896 changes); 897 break; 898 case NL80211_IFTYPE_MONITOR: 899 if (changes & BSS_CHANGED_MU_GROUPS) 900 iwl_mvm_update_mu_groups(mvm, vif); 901 break; 902 default: 903 /* shouldn't happen */ 904 WARN_ON_ONCE(1); 905 } 906 907 if (changes & BSS_CHANGED_TXPOWER) { 908 IWL_DEBUG_CALIB(mvm, "Changing TX Power to %d dBm\n", 909 link_conf->txpower); 910 iwl_mvm_set_tx_power(mvm, link_conf, link_conf->txpower); 911 } 912} 913 914static void iwl_mvm_mld_vif_cfg_changed(struct ieee80211_hw *hw, 915 struct ieee80211_vif *vif, 916 u64 changes) 917{ 918 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 919 920 guard(mvm)(mvm); 921 922 if (changes & BSS_CHANGED_IDLE && !vif->cfg.idle) 923 iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_SCHED, true); 924 925 if (vif->type == NL80211_IFTYPE_STATION) 926 iwl_mvm_mld_vif_cfg_changed_station(mvm, vif, changes); 927} 928 929static int 930iwl_mvm_mld_switch_vif_chanctx(struct ieee80211_hw *hw, 931 struct ieee80211_vif_chanctx_switch *vifs, 932 int n_vifs, 933 enum ieee80211_chanctx_switch_mode mode) 934{ 935 static const struct iwl_mvm_switch_vif_chanctx_ops ops = { 936 .__assign_vif_chanctx = __iwl_mvm_mld_assign_vif_chanctx, 937 .__unassign_vif_chanctx = __iwl_mvm_mld_unassign_vif_chanctx, 938 }; 939 940 return iwl_mvm_switch_vif_chanctx_common(hw, vifs, n_vifs, mode, &ops); 941} 942 943static void iwl_mvm_mld_config_iface_filter(struct ieee80211_hw *hw, 944 struct ieee80211_vif *vif, 945 unsigned int filter_flags, 946 unsigned int changed_flags) 947{ 948 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 949 950 /* We support only filter for probe requests */ 951 if (!(changed_flags & FIF_PROBE_REQ)) 952 return; 953 954 /* Supported only for p2p client interfaces */ 955 if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc || 956 !vif->p2p) 957 return; 958 959 guard(mvm)(mvm); 960 iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false); 961} 962 963static int 964iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw, 965 struct ieee80211_vif *vif, 966 unsigned int link_id, u16 ac, 967 const struct ieee80211_tx_queue_params *params) 968{ 969 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 970 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 971 struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; 972 973 if (!mvm_link) 974 return -EINVAL; 975 976 mvm_link->queue_params[ac] = *params; 977 978 /* No need to update right away, we'll get BSS_CHANGED_QOS 979 * The exception is P2P_DEVICE interface which needs immediate update. 980 */ 981 if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { 982 guard(mvm)(mvm); 983 return iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 984 LINK_CONTEXT_MODIFY_QOS_PARAMS, 985 true); 986 } 987 return 0; 988} 989 990static int iwl_mvm_mld_roc_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 991{ 992 int ret; 993 994 lockdep_assert_held(&mvm->mutex); 995 996 /* The PHY context ID might have changed so need to set it */ 997 ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 0, false); 998 if (WARN(ret, "Failed to set PHY context ID\n")) 999 return ret; 1000 1001 ret = iwl_mvm_link_changed(mvm, vif, &vif->bss_conf, 1002 LINK_CONTEXT_MODIFY_ACTIVE | 1003 LINK_CONTEXT_MODIFY_RATES_INFO, 1004 true); 1005 1006 if (WARN(ret, "Failed linking P2P_DEVICE\n")) 1007 return ret; 1008 1009 /* The station and queue allocation must be done only after the linking 1010 * is done, as otherwise the FW might incorrectly configure its state. 1011 */ 1012 return iwl_mvm_mld_add_bcast_sta(mvm, vif, &vif->bss_conf); 1013} 1014 1015static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1016 struct ieee80211_channel *channel, int duration, 1017 enum ieee80211_roc_type type) 1018{ 1019 static const struct iwl_mvm_roc_ops ops = { 1020 .add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta, 1021 .link = iwl_mvm_mld_roc_link, 1022 }; 1023 1024 return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops); 1025} 1026 1027static int 1028iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw, 1029 struct ieee80211_vif *vif, 1030 u16 old_links, u16 new_links, 1031 struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS]) 1032{ 1033 struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {}; 1034 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1035 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1036 u16 removed = old_links & ~new_links; 1037 u16 added = new_links & ~old_links; 1038 int err, i; 1039 1040 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { 1041 if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) 1042 break; 1043 1044 if (!(added & BIT(i))) 1045 continue; 1046 new_link[i] = kzalloc(sizeof(*new_link[i]), GFP_KERNEL); 1047 if (!new_link[i]) { 1048 err = -ENOMEM; 1049 goto free; 1050 } 1051 1052 new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; 1053 iwl_mvm_init_link(new_link[i]); 1054 } 1055 1056 mutex_lock(&mvm->mutex); 1057 1058 /* If we're in RESTART flow, the default link wasn't added in 1059 * drv_add_interface(), and link[0] doesn't point to it. 1060 */ 1061 if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, 1062 &mvm->status)) { 1063 err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf); 1064 if (err) 1065 goto out_err; 1066 mvmvif->link[0] = NULL; 1067 } 1068 1069 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) { 1070 if (removed & BIT(i)) { 1071 struct ieee80211_bss_conf *link_conf = old[i]; 1072 1073 err = iwl_mvm_disable_link(mvm, vif, link_conf); 1074 if (err) 1075 goto out_err; 1076 kfree(mvmvif->link[i]); 1077 mvmvif->link[i] = NULL; 1078 } else if (added & BIT(i)) { 1079 struct ieee80211_bss_conf *link_conf; 1080 1081 link_conf = link_conf_dereference_protected(vif, i); 1082 if (WARN_ON(!link_conf)) 1083 continue; 1084 1085 if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, 1086 &mvm->status)) 1087 mvmvif->link[i] = new_link[i]; 1088 new_link[i] = NULL; 1089 err = iwl_mvm_add_link(mvm, vif, link_conf); 1090 if (err) 1091 goto out_err; 1092 } 1093 } 1094 1095 err = 0; 1096 if (new_links == 0) { 1097 mvmvif->link[0] = &mvmvif->deflink; 1098 err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf); 1099 if (err == 0) 1100 mvmvif->primary_link = 0; 1101 } else if (!(new_links & BIT(mvmvif->primary_link))) { 1102 /* 1103 * Ensure we always have a valid primary_link, the real 1104 * decision happens later when PHY is activated. 1105 */ 1106 mvmvif->primary_link = __ffs(new_links); 1107 } 1108 1109out_err: 1110 /* we really don't have a good way to roll back here ... */ 1111 mutex_unlock(&mvm->mutex); 1112 1113free: 1114 for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) 1115 kfree(new_link[i]); 1116 return err; 1117} 1118 1119static int 1120iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw, 1121 struct ieee80211_vif *vif, 1122 struct ieee80211_sta *sta, 1123 u16 old_links, u16 new_links) 1124{ 1125 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1126 1127 guard(mvm)(mvm); 1128 return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links); 1129} 1130 1131bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 1132{ 1133 const struct wiphy_iftype_ext_capab *ext_capa; 1134 1135 lockdep_assert_held(&mvm->mutex); 1136 1137 if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc || 1138 hweight16(ieee80211_vif_usable_links(vif)) == 1) 1139 return false; 1140 1141 if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP)) 1142 return false; 1143 1144 ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy, 1145 ieee80211_vif_type_p2p(vif)); 1146 return (ext_capa && 1147 (ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP)); 1148} 1149 1150static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw, 1151 struct ieee80211_vif *vif, 1152 u16 desired_links) 1153{ 1154 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 1155 int n_links = hweight16(desired_links); 1156 1157 if (n_links <= 1) 1158 return true; 1159 1160 guard(mvm)(mvm); 1161 1162 /* Check if HW supports the wanted number of links */ 1163 if (n_links > iwl_mvm_max_active_links(mvm, vif)) 1164 return false; 1165 1166 /* If it is an eSR device, check that we can enter eSR */ 1167 return iwl_mvm_is_esr_supported(mvm->fwrt.trans) && 1168 iwl_mvm_vif_has_esr_cap(mvm, vif); 1169} 1170 1171static enum ieee80211_neg_ttlm_res 1172iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 1173 struct ieee80211_neg_ttlm *neg_ttlm) 1174{ 1175 u16 map; 1176 u8 i; 1177 1178 /* Verify all TIDs are mapped to the same links set */ 1179 map = neg_ttlm->downlink[0]; 1180 for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { 1181 if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] || 1182 neg_ttlm->uplink[i] != map) 1183 return NEG_TTLM_RES_REJECT; 1184 } 1185 1186 return NEG_TTLM_RES_ACCEPT; 1187} 1188 1189const struct ieee80211_ops iwl_mvm_mld_hw_ops = { 1190 .tx = iwl_mvm_mac_tx, 1191 .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, 1192 .ampdu_action = iwl_mvm_mac_ampdu_action, 1193 .get_antenna = iwl_mvm_op_get_antenna, 1194 .set_antenna = iwl_mvm_op_set_antenna, 1195 .start = iwl_mvm_mac_start, 1196 .reconfig_complete = iwl_mvm_mac_reconfig_complete, 1197 .stop = iwl_mvm_mac_stop, 1198 .add_interface = iwl_mvm_mld_mac_add_interface, 1199 .remove_interface = iwl_mvm_mld_mac_remove_interface, 1200 .config = iwl_mvm_mac_config, 1201 .prepare_multicast = iwl_mvm_prepare_multicast, 1202 .configure_filter = iwl_mvm_configure_filter, 1203 .config_iface_filter = iwl_mvm_mld_config_iface_filter, 1204 .link_info_changed = iwl_mvm_mld_link_info_changed, 1205 .vif_cfg_changed = iwl_mvm_mld_vif_cfg_changed, 1206 .hw_scan = iwl_mvm_mac_hw_scan, 1207 .cancel_hw_scan = iwl_mvm_mac_cancel_hw_scan, 1208 .sta_pre_rcu_remove = iwl_mvm_sta_pre_rcu_remove, 1209 .sta_state = iwl_mvm_mld_mac_sta_state, 1210 .sta_notify = iwl_mvm_mac_sta_notify, 1211 .allow_buffered_frames = iwl_mvm_mac_allow_buffered_frames, 1212 .release_buffered_frames = iwl_mvm_mac_release_buffered_frames, 1213 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, 1214 .link_sta_rc_update = iwl_mvm_sta_rc_update, 1215 .conf_tx = iwl_mvm_mld_mac_conf_tx, 1216 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, 1217 .mgd_complete_tx = iwl_mvm_mac_mgd_complete_tx, 1218 .mgd_protect_tdls_discover = iwl_mvm_mac_mgd_protect_tdls_discover, 1219 .flush = iwl_mvm_mac_flush, 1220 .flush_sta = iwl_mvm_mac_flush_sta, 1221 .sched_scan_start = iwl_mvm_mac_sched_scan_start, 1222 .sched_scan_stop = iwl_mvm_mac_sched_scan_stop, 1223 .set_key = iwl_mvm_mac_set_key, 1224 .update_tkip_key = iwl_mvm_mac_update_tkip_key, 1225 .remain_on_channel = iwl_mvm_mld_roc, 1226 .cancel_remain_on_channel = iwl_mvm_cancel_roc, 1227 .add_chanctx = iwl_mvm_add_chanctx, 1228 .remove_chanctx = iwl_mvm_remove_chanctx, 1229 .change_chanctx = iwl_mvm_change_chanctx, 1230 .assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx, 1231 .unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx, 1232 .switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx, 1233 1234 .start_ap = iwl_mvm_mld_start_ap, 1235 .stop_ap = iwl_mvm_mld_stop_ap, 1236 .join_ibss = iwl_mvm_mld_start_ibss, 1237 .leave_ibss = iwl_mvm_mld_stop_ibss, 1238 1239 .tx_last_beacon = iwl_mvm_tx_last_beacon, 1240 1241 .channel_switch = iwl_mvm_channel_switch, 1242 .pre_channel_switch = iwl_mvm_mac_pre_channel_switch, 1243 .post_channel_switch = iwl_mvm_post_channel_switch, 1244 .abort_channel_switch = iwl_mvm_abort_channel_switch, 1245 .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon, 1246 1247 .tdls_channel_switch = iwl_mvm_tdls_channel_switch, 1248 .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, 1249 .tdls_recv_channel_switch = iwl_mvm_tdls_recv_channel_switch, 1250 1251 .event_callback = iwl_mvm_mac_event_callback, 1252 1253 .sync_rx_queues = iwl_mvm_sync_rx_queues, 1254 1255#ifdef CONFIG_PM_SLEEP 1256 /* look at d3.c */ 1257 .suspend = iwl_mvm_suspend, 1258 .resume = iwl_mvm_resume, 1259 .set_wakeup = iwl_mvm_set_wakeup, 1260 .set_rekey_data = iwl_mvm_set_rekey_data, 1261#if IS_ENABLED(CONFIG_IPV6) 1262 .ipv6_addr_change = iwl_mvm_ipv6_addr_change, 1263#endif 1264 .set_default_unicast_key = iwl_mvm_set_default_unicast_key, 1265#endif 1266 .get_survey = iwl_mvm_mac_get_survey, 1267 .sta_statistics = iwl_mvm_mac_sta_statistics, 1268 .get_ftm_responder_stats = iwl_mvm_mac_get_ftm_responder_stats, 1269 .start_pmsr = iwl_mvm_start_pmsr, 1270 .abort_pmsr = iwl_mvm_abort_pmsr, 1271 1272#ifdef CONFIG_IWLWIFI_DEBUGFS 1273 .vif_add_debugfs = iwl_mvm_vif_add_debugfs, 1274 .link_add_debugfs = iwl_mvm_link_add_debugfs, 1275 .link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs, 1276#endif 1277 .set_hw_timestamp = iwl_mvm_set_hw_timestamp, 1278 1279 .change_vif_links = iwl_mvm_mld_change_vif_links, 1280 .change_sta_links = iwl_mvm_mld_change_sta_links, 1281 .can_activate_links = iwl_mvm_mld_can_activate_links, 1282 .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, 1283};
~/
Read-only file preview.