Path: blob/main/sys/contrib/dev/iwlwifi/mld/mac80211.c
48285 views
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause1/*2* Copyright (C) 2024-2025 Intel Corporation3*/45#include <net/mac80211.h>6#include <linux/fips.h>7#include <linux/ip.h>89#include "mld.h"10#include "mac80211.h"11#include "phy.h"12#include "iface.h"13#include "power.h"14#include "sta.h"15#include "agg.h"16#include "scan.h"17#include "d3.h"18#include "tlc.h"19#include "key.h"20#include "ap.h"21#include "tx.h"22#include "roc.h"23#include "mlo.h"24#include "stats.h"25#include "ftm-initiator.h"26#include "low_latency.h"27#include "fw/api/scan.h"28#include "fw/api/context.h"29#include "fw/api/filter.h"30#include "fw/api/sta.h"31#include "fw/api/tdls.h"32#ifdef CONFIG_PM_SLEEP33#include "fw/api/d3.h"34#endif /* CONFIG_PM_SLEEP */35#include "iwl-trans.h"3637#define IWL_MLD_LIMITS(ap) \38{ \39.max = 2, \40.types = BIT(NL80211_IFTYPE_STATION), \41}, \42{ \43.max = 1, \44.types = ap | \45BIT(NL80211_IFTYPE_P2P_CLIENT) | \46BIT(NL80211_IFTYPE_P2P_GO), \47}, \48{ \49.max = 1, \50.types = BIT(NL80211_IFTYPE_P2P_DEVICE), \51}5253static const struct ieee80211_iface_limit iwl_mld_limits[] = {54IWL_MLD_LIMITS(0)55};5657static const struct ieee80211_iface_limit iwl_mld_limits_ap[] = {58IWL_MLD_LIMITS(BIT(NL80211_IFTYPE_AP))59};6061static const struct ieee80211_iface_combination62iwl_mld_iface_combinations[] = {63{64.num_different_channels = 2,65.max_interfaces = 4,66.limits = iwl_mld_limits,67.n_limits = ARRAY_SIZE(iwl_mld_limits),68},69{70.num_different_channels = 1,71.max_interfaces = 4,72.limits = iwl_mld_limits_ap,73.n_limits = ARRAY_SIZE(iwl_mld_limits_ap),74},75};7677static const u8 if_types_ext_capa_sta[] = {78[0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,79[2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,80[7] = WLAN_EXT_CAPA8_OPMODE_NOTIF |81WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB,82[8] = WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB,83[9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,84};8586#define IWL_MLD_EMLSR_CAPA (IEEE80211_EML_CAP_EMLSR_SUPP | \87IEEE80211_EML_CAP_EMLSR_PADDING_DELAY_32US << \88__bf_shf(IEEE80211_EML_CAP_EMLSR_PADDING_DELAY) | \89IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY_64US << \90__bf_shf(IEEE80211_EML_CAP_EMLSR_TRANSITION_DELAY))91#define IWL_MLD_CAPA_OPS (FIELD_PREP_CONST( \92IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP, \93IEEE80211_MLD_CAP_OP_TID_TO_LINK_MAP_NEG_SUPP_SAME) | \94IEEE80211_MLD_CAP_OP_LINK_RECONF_SUPPORT)9596static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = {97{98.iftype = NL80211_IFTYPE_STATION,99.extended_capabilities = if_types_ext_capa_sta,100.extended_capabilities_mask = if_types_ext_capa_sta,101.extended_capabilities_len = sizeof(if_types_ext_capa_sta),102/* relevant only if EHT is supported */103.eml_capabilities = IWL_MLD_EMLSR_CAPA,104.mld_capa_and_ops = IWL_MLD_CAPA_OPS,105},106};107108static void iwl_mld_hw_set_addresses(struct iwl_mld *mld)109{110struct wiphy *wiphy = mld->wiphy;111int num_addrs = 1;112113/* Extract MAC address */114memcpy(mld->addresses[0].addr, mld->nvm_data->hw_addr, ETH_ALEN);115wiphy->addresses = mld->addresses;116wiphy->n_addresses = 1;117118/* Extract additional MAC addresses if available */119if (mld->nvm_data->n_hw_addrs > 1)120num_addrs = min(mld->nvm_data->n_hw_addrs,121IWL_MLD_MAX_ADDRESSES);122123for (int i = 1; i < num_addrs; i++) {124memcpy(mld->addresses[i].addr,125mld->addresses[i - 1].addr,126ETH_ALEN);127mld->addresses[i].addr[ETH_ALEN - 1]++;128wiphy->n_addresses++;129}130}131132static void iwl_mld_hw_set_channels(struct iwl_mld *mld)133{134struct wiphy *wiphy = mld->wiphy;135struct ieee80211_supported_band *bands = mld->nvm_data->bands;136137wiphy->bands[NL80211_BAND_2GHZ] = &bands[NL80211_BAND_2GHZ];138wiphy->bands[NL80211_BAND_5GHZ] = &bands[NL80211_BAND_5GHZ];139140if (bands[NL80211_BAND_6GHZ].n_channels)141wiphy->bands[NL80211_BAND_6GHZ] = &bands[NL80211_BAND_6GHZ];142}143144static void iwl_mld_hw_set_security(struct iwl_mld *mld)145{146struct ieee80211_hw *hw = mld->hw;147static const u32 mld_ciphers[] = {148WLAN_CIPHER_SUITE_WEP40,149WLAN_CIPHER_SUITE_WEP104,150WLAN_CIPHER_SUITE_TKIP,151WLAN_CIPHER_SUITE_CCMP,152WLAN_CIPHER_SUITE_GCMP,153WLAN_CIPHER_SUITE_GCMP_256,154WLAN_CIPHER_SUITE_AES_CMAC,155WLAN_CIPHER_SUITE_BIP_GMAC_128,156WLAN_CIPHER_SUITE_BIP_GMAC_256157};158159if (fips_enabled)160return;161162hw->wiphy->n_cipher_suites = ARRAY_SIZE(mld_ciphers);163hw->wiphy->cipher_suites = mld_ciphers;164165ieee80211_hw_set(hw, MFP_CAPABLE);166wiphy_ext_feature_set(hw->wiphy,167NL80211_EXT_FEATURE_BEACON_PROTECTION);168}169170static void iwl_mld_hw_set_antennas(struct iwl_mld *mld)171{172struct wiphy *wiphy = mld->wiphy;173174wiphy->available_antennas_tx = iwl_mld_get_valid_tx_ant(mld);175wiphy->available_antennas_rx = iwl_mld_get_valid_rx_ant(mld);176}177178static void iwl_mld_hw_set_pm(struct iwl_mld *mld)179{180#ifdef CONFIG_PM_SLEEP181struct wiphy *wiphy = mld->wiphy;182183if (!device_can_wakeup(mld->trans->dev))184return;185186if (fips_enabled)187return;188189mld->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |190WIPHY_WOWLAN_DISCONNECT |191WIPHY_WOWLAN_EAP_IDENTITY_REQ |192WIPHY_WOWLAN_RFKILL_RELEASE |193WIPHY_WOWLAN_NET_DETECT |194WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |195WIPHY_WOWLAN_GTK_REKEY_FAILURE |196WIPHY_WOWLAN_4WAY_HANDSHAKE;197198mld->wowlan.n_patterns = IWL_WOWLAN_MAX_PATTERNS;199mld->wowlan.pattern_min_len = IWL_WOWLAN_MIN_PATTERN_LEN;200mld->wowlan.pattern_max_len = IWL_WOWLAN_MAX_PATTERN_LEN;201mld->wowlan.max_nd_match_sets = IWL_SCAN_MAX_PROFILES_V2;202203wiphy->wowlan = &mld->wowlan;204#endif /* CONFIG_PM_SLEEP */205}206207static void iwl_mac_hw_set_radiotap(struct iwl_mld *mld)208{209struct ieee80211_hw *hw = mld->hw;210211hw->radiotap_mcs_details |= IEEE80211_RADIOTAP_MCS_HAVE_FEC |212IEEE80211_RADIOTAP_MCS_HAVE_STBC;213214hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |215IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;216217hw->radiotap_timestamp.units_pos =218IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US |219IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ;220221/* this is the case for CCK frames, it's better (only 8) for OFDM */222hw->radiotap_timestamp.accuracy = 22;223}224225static void iwl_mac_hw_set_flags(struct iwl_mld *mld)226{227struct ieee80211_hw *hw = mld->hw;228229ieee80211_hw_set(hw, USES_RSS);230ieee80211_hw_set(hw, HANDLES_QUIET_CSA);231ieee80211_hw_set(hw, AP_LINK_PS);232ieee80211_hw_set(hw, SIGNAL_DBM);233ieee80211_hw_set(hw, SPECTRUM_MGMT);234ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS);235ieee80211_hw_set(hw, WANT_MONITOR_VIF);236ieee80211_hw_set(hw, SUPPORTS_PS);237ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);238ieee80211_hw_set(hw, AMPDU_AGGREGATION);239ieee80211_hw_set(hw, CONNECTION_MONITOR);240ieee80211_hw_set(hw, CHANCTX_STA_CSA);241ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);242ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);243ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);244ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);245ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);246ieee80211_hw_set(hw, STA_MMPDU_TXQ);247ieee80211_hw_set(hw, TX_AMSDU);248ieee80211_hw_set(hw, TX_FRAG_LIST);249ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);250ieee80211_hw_set(hw, HAS_RATE_CONTROL);251ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);252ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);253ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);254ieee80211_hw_set(hw, TDLS_WIDER_BW);255}256257static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld)258{259struct ieee80211_hw *hw = mld->hw;260struct wiphy *wiphy = hw->wiphy;261const struct iwl_ucode_capabilities *ucode_capa = &mld->fw->ucode_capa;262263snprintf(wiphy->fw_version,264sizeof(wiphy->fw_version),265"%.31s", mld->fw->fw_version);266267wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |268BIT(NL80211_IFTYPE_P2P_CLIENT) |269BIT(NL80211_IFTYPE_AP) |270BIT(NL80211_IFTYPE_P2P_GO) |271BIT(NL80211_IFTYPE_P2P_DEVICE) |272BIT(NL80211_IFTYPE_ADHOC);273274wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |275NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |276NL80211_FEATURE_ND_RANDOM_MAC_ADDR |277NL80211_FEATURE_HT_IBSS |278NL80211_FEATURE_P2P_GO_CTWIN |279NL80211_FEATURE_LOW_PRIORITY_SCAN |280NL80211_FEATURE_P2P_GO_OPPPS |281NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |282NL80211_FEATURE_SUPPORTS_WMM_ADMISSION |283NL80211_FEATURE_TX_POWER_INSERTION |284NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES;285286wiphy->flags |= WIPHY_FLAG_IBSS_RSN |287WIPHY_FLAG_AP_UAPSD |288WIPHY_FLAG_HAS_CHANNEL_SWITCH |289WIPHY_FLAG_SPLIT_SCAN_6GHZ |290WIPHY_FLAG_SUPPORTS_TDLS |291WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK;292293/* For fips_enabled, don't support WiFi7 due to WPA3/MFP requirements */294if (mld->nvm_data->sku_cap_11be_enable &&295!iwlwifi_mod_params.disable_11ax &&296!iwlwifi_mod_params.disable_11be &&297!fips_enabled)298wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;299300/* the firmware uses u8 for num of iterations, but 0xff is saved for301* infinite loop, so the maximum number of iterations is actually 254.302*/303wiphy->max_sched_scan_plan_iterations = 254;304wiphy->max_sched_scan_ie_len = iwl_mld_scan_max_template_size();305wiphy->max_scan_ie_len = iwl_mld_scan_max_template_size();306wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;307wiphy->max_scan_ssids = PROBE_OPTION_MAX;308wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;309wiphy->max_sched_scan_reqs = 1;310wiphy->max_sched_scan_plan_interval = U16_MAX;311wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES_V2;312313wiphy->max_remain_on_channel_duration = 10000;314315wiphy->hw_version = mld->trans->info.hw_id;316317wiphy->hw_timestamp_max_peers = 1;318319wiphy->iface_combinations = iwl_mld_iface_combinations;320wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mld_iface_combinations);321322wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);323wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_CONCURRENT);324wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY);325wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SCAN_START_TIME);326wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_PARENT_TSF);327wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT);328wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP);329wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME);330wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE);331wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);332wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);333334if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT))335wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PROTECTED_TWT);336337wiphy->iftype_ext_capab = NULL;338wiphy->num_iftype_ext_capab = 0;339340if (!iwlwifi_mod_params.disable_11ax) {341wiphy->iftype_ext_capab = iftypes_ext_capa;342wiphy->num_iftype_ext_capab = ARRAY_SIZE(iftypes_ext_capa);343344ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);345ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID);346}347348if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)349wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;350else351wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;352}353354static void iwl_mac_hw_set_misc(struct iwl_mld *mld)355{356struct ieee80211_hw *hw = mld->hw;357358hw->queues = IEEE80211_NUM_ACS;359360hw->netdev_features = NETIF_F_HIGHDMA | NETIF_F_SG;361hw->netdev_features |= mld->trans->mac_cfg->base->features;362363hw->max_tx_fragments = mld->trans->info.max_skb_frags;364hw->max_listen_interval = IWL_MLD_CONN_LISTEN_INTERVAL;365366hw->uapsd_max_sp_len = IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL;367hw->uapsd_queues = IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |368IEEE80211_WMM_IE_STA_QOSINFO_AC_VI |369IEEE80211_WMM_IE_STA_QOSINFO_AC_BK |370IEEE80211_WMM_IE_STA_QOSINFO_AC_BE;371372hw->chanctx_data_size = sizeof(struct iwl_mld_phy);373hw->vif_data_size = sizeof(struct iwl_mld_vif);374hw->sta_data_size = sizeof(struct iwl_mld_sta);375hw->txq_data_size = sizeof(struct iwl_mld_txq);376377/* TODO: Remove this division when IEEE80211_MAX_AMPDU_BUF_EHT size378* is supported.379* Note: ensure that IWL_DEFAULT_QUEUE_SIZE_EHT is updated accordingly.380*/381hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT / 2;382}383384static int iwl_mld_hw_verify_preconditions(struct iwl_mld *mld)385{386int ratecheck;387388/* check for rates version 3 */389ratecheck =390(iwl_fw_lookup_cmd_ver(mld->fw, TX_CMD, 0) >= 11) +391(iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP,392TLC_MNG_UPDATE_NOTIF, 0) >= 4) +393(iwl_fw_lookup_notif_ver(mld->fw, LEGACY_GROUP,394REPLY_RX_MPDU_CMD, 0) >= 6) +395(iwl_fw_lookup_notif_ver(mld->fw, DATA_PATH_GROUP,396RX_NO_DATA_NOTIF, 0) >= 4) +397(iwl_fw_lookup_notif_ver(mld->fw, LONG_GROUP, TX_CMD, 0) >= 9);398399if (ratecheck != 0 && ratecheck != 5) {400IWL_ERR(mld, "Firmware has inconsistent rates\n");401return -EINVAL;402}403404/* 11ax is expected to be enabled for all supported devices */405if (WARN_ON(!mld->nvm_data->sku_cap_11ax_enable))406return -EINVAL;407408/* LAR is expected to be enabled for all supported devices */409if (WARN_ON(!mld->nvm_data->lar_enabled))410return -EINVAL;411412/* All supported devices are currently using version 3 of the cmd.413* Since version 3, IWL_SCAN_MAX_PROFILES_V2 shall be used where414* necessary.415*/416if (WARN_ON(iwl_fw_lookup_cmd_ver(mld->fw,417SCAN_OFFLOAD_UPDATE_PROFILES_CMD,418IWL_FW_CMD_VER_UNKNOWN) != 3))419return -EINVAL;420421return 0;422}423424int iwl_mld_register_hw(struct iwl_mld *mld)425{426/* verify once essential preconditions required for setting427* the hw capabilities428*/429if (iwl_mld_hw_verify_preconditions(mld))430return -EINVAL;431432iwl_mld_hw_set_addresses(mld);433iwl_mld_hw_set_channels(mld);434iwl_mld_hw_set_security(mld);435iwl_mld_hw_set_pm(mld);436iwl_mld_hw_set_antennas(mld);437iwl_mac_hw_set_radiotap(mld);438iwl_mac_hw_set_flags(mld);439iwl_mac_hw_set_wiphy(mld);440iwl_mac_hw_set_misc(mld);441442SET_IEEE80211_DEV(mld->hw, mld->trans->dev);443444return ieee80211_register_hw(mld->hw);445}446447static void448iwl_mld_mac80211_tx(struct ieee80211_hw *hw,449struct ieee80211_tx_control *control, struct sk_buff *skb)450{451struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);452struct ieee80211_sta *sta = control->sta;453struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);454struct ieee80211_hdr *hdr = (void *)skb->data;455u32 link_id = u32_get_bits(info->control.flags,456IEEE80211_TX_CTRL_MLO_LINK);457458/* In AP mode, mgmt frames are sent on the bcast station,459* so the FW can't translate the MLD addr to the link addr. Do it here460*/461if (ieee80211_is_mgmt(hdr->frame_control) && sta &&462link_id != IEEE80211_LINK_UNSPECIFIED &&463!ieee80211_is_probe_resp(hdr->frame_control)) {464/* translate MLD addresses to LINK addresses */465struct ieee80211_link_sta *link_sta =466rcu_dereference(sta->link[link_id]);467struct ieee80211_bss_conf *link_conf =468rcu_dereference(info->control.vif->link_conf[link_id]);469struct ieee80211_mgmt *mgmt;470471if (WARN_ON(!link_sta || !link_conf)) {472ieee80211_free_txskb(hw, skb);473return;474}475476mgmt = (void *)hdr;477memcpy(mgmt->da, link_sta->addr, ETH_ALEN);478memcpy(mgmt->sa, link_conf->addr, ETH_ALEN);479memcpy(mgmt->bssid, link_conf->bssid, ETH_ALEN);480}481482iwl_mld_tx_skb(mld, skb, NULL);483}484485static void486iwl_mld_restart_cleanup(struct iwl_mld *mld)487{488iwl_cleanup_mld(mld);489490ieee80211_iterate_interfaces(mld->hw, IEEE80211_IFACE_ITER_ACTIVE,491iwl_mld_cleanup_vif, NULL);492493ieee80211_iterate_stations_atomic(mld->hw,494iwl_mld_cleanup_sta, NULL);495496iwl_mld_ftm_restart_cleanup(mld);497}498499static500int iwl_mld_mac80211_start(struct ieee80211_hw *hw)501{502struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);503bool in_d3 = false;504int ret = 0;505506lockdep_assert_wiphy(mld->wiphy);507508#ifdef CONFIG_PM_SLEEP509/* Unless the host goes into hibernate the FW always stays on and510* the d3_resume flow is used. When wowlan is configured, mac80211511* would call it's resume callback and the wowlan_resume flow512* would be used.513*/514515in_d3 = mld->fw_status.in_d3;516if (in_d3) {517/* mac80211 already cleaned up the state, no need for cleanup */518ret = iwl_mld_no_wowlan_resume(mld);519if (ret) {520iwl_mld_stop_fw(mld);521/* We're not really restarting in the sense of522* in_hw_restart even if we got an error during523* this. We'll just start again below and have524* nothing to recover, mac80211 will do anyway.525*/526mld->fw_status.in_hw_restart = false;527}528}529#endif /* CONFIG_PM_SLEEP */530531if (mld->fw_status.in_hw_restart) {532iwl_mld_stop_fw(mld);533iwl_mld_restart_cleanup(mld);534}535536if (!in_d3 || ret) {537ret = iwl_mld_start_fw(mld);538if (ret)539goto error;540}541542mld->scan.last_start_time_jiffies = jiffies;543544iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_POST_INIT,545NULL);546iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_PERIODIC,547NULL);548549return 0;550551error:552/* If we failed to restart the hw, there is nothing useful553* we can do but indicate we are no longer in restart.554*/555mld->fw_status.in_hw_restart = false;556557return ret;558}559560static561void iwl_mld_mac80211_stop(struct ieee80211_hw *hw, bool suspend)562{563struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);564565lockdep_assert_wiphy(mld->wiphy);566567wiphy_work_cancel(mld->wiphy, &mld->add_txqs_wk);568569/* if the suspend flow fails the fw is in error. Stop it here, and it570* will be started upon wakeup571*/572if (!suspend ||573(IS_ENABLED(CONFIG_PM_SLEEP) && iwl_mld_no_wowlan_suspend(mld)))574iwl_mld_stop_fw(mld);575576/* Clear in_hw_restart flag when stopping the hw, as mac80211 won't577* execute the restart.578*/579mld->fw_status.in_hw_restart = false;580581/* We shouldn't have any UIDs still set. Loop over all the UIDs to582* make sure there's nothing left there and warn if any is found.583*/584for (int i = 0; i < ARRAY_SIZE(mld->scan.uid_status); i++)585if (WARN_ONCE(mld->scan.uid_status[i],586"UMAC scan UID %d status was not cleaned (0x%x 0x%x)\n",587i, mld->scan.uid_status[i], mld->scan.status))588mld->scan.uid_status[i] = 0;589}590591static592int iwl_mld_mac80211_config(struct ieee80211_hw *hw, int radio_idx,593u32 changed)594{595return 0;596}597598static599int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,600struct ieee80211_vif *vif)601{602struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);603int ret;604605lockdep_assert_wiphy(mld->wiphy);606607/* Construct mld_vif, add it to fw, and map its ID to ieee80211_vif */608ret = iwl_mld_add_vif(mld, vif);609if (ret)610return ret;611612/*613* Add the default link, but not if this is an MLD vif as that implies614* the HW is restarting and it will be configured by change_vif_links.615*/616if (!ieee80211_vif_is_mld(vif))617ret = iwl_mld_add_link(mld, &vif->bss_conf);618if (ret)619goto err;620621if (vif->type == NL80211_IFTYPE_STATION) {622vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC;623if (!vif->p2p)624vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |625IEEE80211_VIF_SUPPORTS_CQM_RSSI;626}627628if (vif->p2p || iwl_fw_lookup_cmd_ver(mld->fw, PHY_CONTEXT_CMD, 0) < 5)629vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW;630631/*632* For an MLD vif (in restart) we may not have a link; delay the call633* the initial change_vif_links.634*/635if (vif->type == NL80211_IFTYPE_STATION &&636!ieee80211_vif_is_mld(vif))637iwl_mld_update_mac_power(mld, vif, false);638639if (vif->type == NL80211_IFTYPE_MONITOR) {640mld->monitor.on = true;641ieee80211_hw_set(mld->hw, RX_INCLUDES_FCS);642}643644if (vif->type == NL80211_IFTYPE_P2P_DEVICE)645mld->p2p_device_vif = vif;646647return 0;648649err:650iwl_mld_rm_vif(mld, vif);651return ret;652}653654static655void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw,656struct ieee80211_vif *vif)657{658struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);659660lockdep_assert_wiphy(mld->wiphy);661662if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION)663vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |664IEEE80211_VIF_SUPPORTS_CQM_RSSI);665666if (vif->type == NL80211_IFTYPE_MONITOR) {667__clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mld->hw->flags);668mld->monitor.on = false;669}670671if (vif->type == NL80211_IFTYPE_P2P_DEVICE)672mld->p2p_device_vif = NULL;673674iwl_mld_remove_link(mld, &vif->bss_conf);675676#ifdef CONFIG_IWLWIFI_DEBUGFS677debugfs_remove(iwl_mld_vif_from_mac80211(vif)->dbgfs_slink);678iwl_mld_vif_from_mac80211(vif)->dbgfs_slink = NULL;679#endif680681iwl_mld_rm_vif(mld, vif);682}683684struct iwl_mld_mc_iter_data {685struct iwl_mld *mld;686int port_id;687};688689static void iwl_mld_mc_iface_iterator(void *data, u8 *mac,690struct ieee80211_vif *vif)691{692struct iwl_mld_mc_iter_data *mc_data = data;693struct iwl_mld *mld = mc_data->mld;694struct iwl_mcast_filter_cmd *cmd = mld->mcast_filter_cmd;695struct iwl_host_cmd hcmd = {696.id = MCAST_FILTER_CMD,697.dataflags[0] = IWL_HCMD_DFL_NOCOPY,698};699int ret, len;700701/* If we don't have free ports, mcast frames will be dropped */702if (WARN_ON_ONCE(mc_data->port_id >= MAX_PORT_ID_NUM))703return;704705if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)706return;707708cmd->port_id = mc_data->port_id++;709ether_addr_copy(cmd->bssid, vif->bss_conf.bssid);710len = roundup(sizeof(*cmd) + cmd->count * ETH_ALEN, 4);711712hcmd.len[0] = len;713hcmd.data[0] = cmd;714715ret = iwl_mld_send_cmd(mld, &hcmd);716if (ret)717IWL_ERR(mld, "mcast filter cmd error. ret=%d\n", ret);718}719720void iwl_mld_recalc_multicast_filter(struct iwl_mld *mld)721{722struct iwl_mld_mc_iter_data iter_data = {723.mld = mld,724};725726if (WARN_ON_ONCE(!mld->mcast_filter_cmd))727return;728729ieee80211_iterate_active_interfaces(mld->hw,730IEEE80211_IFACE_ITER_NORMAL,731iwl_mld_mc_iface_iterator,732&iter_data);733}734735static u64736iwl_mld_mac80211_prepare_multicast(struct ieee80211_hw *hw,737struct netdev_hw_addr_list *mc_list)738{739struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);740struct iwl_mcast_filter_cmd *cmd;741struct netdev_hw_addr *addr;742int addr_count = netdev_hw_addr_list_count(mc_list);743bool pass_all = addr_count > MAX_MCAST_FILTERING_ADDRESSES;744int len;745746if (pass_all)747addr_count = 0;748749/* len must be a multiple of 4 */750len = roundup(sizeof(*cmd) + addr_count * ETH_ALEN, 4);751cmd = kzalloc(len, GFP_ATOMIC);752if (!cmd)753return 0;754755if (pass_all) {756cmd->pass_all = 1;757goto out;758}759760netdev_hw_addr_list_for_each(addr, mc_list) {761IWL_DEBUG_MAC80211(mld, "mcast addr (%d): %pM\n",762cmd->count, addr->addr);763ether_addr_copy(&cmd->addr_list[cmd->count * ETH_ALEN],764addr->addr);765cmd->count++;766}767768out:769return (u64)(unsigned long)cmd;770}771772static773void iwl_mld_mac80211_configure_filter(struct ieee80211_hw *hw,774unsigned int changed_flags,775unsigned int *total_flags,776u64 multicast)777{778struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);779struct iwl_mcast_filter_cmd *cmd = (void *)(unsigned long)multicast;780781/* Replace previous configuration */782kfree(mld->mcast_filter_cmd);783mld->mcast_filter_cmd = cmd;784785if (!cmd)786goto out;787788if (changed_flags & FIF_ALLMULTI)789cmd->pass_all = !!(*total_flags & FIF_ALLMULTI);790791if (cmd->pass_all)792cmd->count = 0;793794iwl_mld_recalc_multicast_filter(mld);795out:796*total_flags = 0;797}798799static800void iwl_mld_mac80211_wake_tx_queue(struct ieee80211_hw *hw,801struct ieee80211_txq *txq)802{803struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);804struct iwl_mld_txq *mld_txq = iwl_mld_txq_from_mac80211(txq);805806if (likely(mld_txq->status.allocated) || !txq->sta) {807iwl_mld_tx_from_txq(mld, txq);808return;809}810811/* We don't support TSPEC tids. %IEEE80211_NUM_TIDS is for mgmt */812if (txq->tid != IEEE80211_NUM_TIDS && txq->tid >= IWL_MAX_TID_COUNT) {813IWL_DEBUG_MAC80211(mld, "TID %d is not supported\n", txq->tid);814return;815}816817/* The worker will handle any packets we leave on the txq now */818819spin_lock_bh(&mld->add_txqs_lock);820/* The list is being deleted only after the queue is fully allocated. */821if (list_empty(&mld_txq->list) &&822/* recheck under lock, otherwise it can be added twice */823!mld_txq->status.allocated) {824list_add_tail(&mld_txq->list, &mld->txqs_to_add);825wiphy_work_queue(mld->wiphy, &mld->add_txqs_wk);826}827spin_unlock_bh(&mld->add_txqs_lock);828}829830static void iwl_mld_teardown_tdls_peers(struct iwl_mld *mld)831{832lockdep_assert_wiphy(mld->wiphy);833834for (int i = 0; i < mld->fw->ucode_capa.num_stations; i++) {835struct ieee80211_link_sta *link_sta;836struct iwl_mld_sta *mld_sta;837838link_sta = wiphy_dereference(mld->wiphy,839mld->fw_id_to_link_sta[i]);840if (IS_ERR_OR_NULL(link_sta))841continue;842843if (!link_sta->sta->tdls)844continue;845846mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);847848ieee80211_tdls_oper_request(mld_sta->vif, link_sta->addr,849NL80211_TDLS_TEARDOWN,850WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED,851GFP_KERNEL);852}853}854855static856int iwl_mld_add_chanctx(struct ieee80211_hw *hw,857struct ieee80211_chanctx_conf *ctx)858{859struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);860struct iwl_mld_phy *phy = iwl_mld_phy_from_mac80211(ctx);861int fw_id = iwl_mld_allocate_fw_phy_id(mld);862int ret;863864if (fw_id < 0)865return fw_id;866867phy->mld = mld;868phy->fw_id = fw_id;869phy->chandef = *iwl_mld_get_chandef_from_chanctx(mld, ctx);870871ret = iwl_mld_phy_fw_action(mld, ctx, FW_CTXT_ACTION_ADD);872if (ret) {873mld->used_phy_ids &= ~BIT(phy->fw_id);874return ret;875}876877if (hweight8(mld->used_phy_ids) > 1)878iwl_mld_teardown_tdls_peers(mld);879880return 0;881}882883static884void iwl_mld_remove_chanctx(struct ieee80211_hw *hw,885struct ieee80211_chanctx_conf *ctx)886{887struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);888struct iwl_mld_phy *phy = iwl_mld_phy_from_mac80211(ctx);889890iwl_mld_phy_fw_action(mld, ctx, FW_CTXT_ACTION_REMOVE);891mld->used_phy_ids &= ~BIT(phy->fw_id);892}893894static895void iwl_mld_change_chanctx(struct ieee80211_hw *hw,896struct ieee80211_chanctx_conf *ctx, u32 changed)897{898struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);899struct iwl_mld_phy *phy = iwl_mld_phy_from_mac80211(ctx);900struct cfg80211_chan_def *chandef =901iwl_mld_get_chandef_from_chanctx(mld, ctx);902903/* We don't care about these */904if (!(changed & ~(IEEE80211_CHANCTX_CHANGE_RX_CHAINS |905IEEE80211_CHANCTX_CHANGE_RADAR |906IEEE80211_CHANCTX_CHANGE_CHANNEL)))907return;908909/* Check if a FW update is required */910911if (changed & IEEE80211_CHANCTX_CHANGE_AP)912goto update;913914if (chandef->chan == phy->chandef.chan &&915chandef->center_freq1 == phy->chandef.center_freq1 &&916chandef->punctured == phy->chandef.punctured) {917/* Check if we are toggling between HT and non-HT, no-op */918if (phy->chandef.width == chandef->width ||919(phy->chandef.width <= NL80211_CHAN_WIDTH_20 &&920chandef->width <= NL80211_CHAN_WIDTH_20))921return;922}923update:924925iwl_mld_update_phy_chandef(mld, ctx);926}927928static u8929iwl_mld_chandef_get_primary_80(struct cfg80211_chan_def *chandef)930{931int data_start;932int control_start;933int bw;934935if (chandef->width == NL80211_CHAN_WIDTH_320)936bw = 320;937else if (chandef->width == NL80211_CHAN_WIDTH_160)938bw = 160;939else940return 0;941942/* data is bw wide so the start is half the width */943data_start = chandef->center_freq1 - bw / 2;944/* control is 20Mhz width */945control_start = chandef->chan->center_freq - 10;946947return (control_start - data_start) / 80;948}949950static bool iwl_mld_can_activate_link(struct iwl_mld *mld,951struct ieee80211_vif *vif,952struct ieee80211_bss_conf *link)953{954struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);955struct iwl_mld_sta *mld_sta;956struct iwl_mld_link_sta *link_sta;957958/* In association, we activate the assoc link before adding the STA. */959if (!mld_vif->ap_sta || !vif->cfg.assoc)960return true;961962mld_sta = iwl_mld_sta_from_mac80211(mld_vif->ap_sta);963964/* When switching links, we need to wait with the activation until the965* STA was added to the FW. It'll be activated in966* iwl_mld_update_link_stas967*/968link_sta = wiphy_dereference(mld->wiphy, mld_sta->link[link->link_id]);969970/* In restart we can have a link_sta that doesn't exist in FW yet */971return link_sta && link_sta->in_fw;972}973974static975int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,976struct ieee80211_vif *vif,977struct ieee80211_bss_conf *link,978struct ieee80211_chanctx_conf *ctx)979{980struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);981struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);982unsigned int n_active = iwl_mld_count_active_links(mld, vif);983int ret;984985lockdep_assert_wiphy(mld->wiphy);986987if (WARN_ON(!mld_link))988return -EINVAL;989990/* if the assigned one was not counted yet, count it now */991if (!rcu_access_pointer(mld_link->chan_ctx)) {992n_active++;993994/* Track addition of non-BSS link */995if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {996ret = iwl_mld_emlsr_check_non_bss_block(mld, 1);997if (ret)998return ret;999}1000}10011002/* for AP, mac parameters such as HE support are updated at this stage. */1003if (vif->type == NL80211_IFTYPE_AP) {1004ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);10051006if (ret) {1007IWL_ERR(mld, "failed to update MAC %pM\n", vif->addr);1008return -EINVAL;1009}1010}10111012rcu_assign_pointer(mld_link->chan_ctx, ctx);10131014if (n_active > 1) {1015struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);10161017/* Indicate to mac80211 that EML is enabled */1018vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;1019mld_vif->emlsr.last_entry_ts = jiffies;10201021if (vif->active_links & BIT(mld_vif->emlsr.selected_links))1022mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary;1023else1024mld_vif->emlsr.primary = __ffs(vif->active_links);10251026iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,1027NULL);1028}10291030/* First send the link command with the phy context ID.1031* Now that we have the phy, we know the band so also the rates1032*/1033ret = iwl_mld_change_link_in_fw(mld, link,1034LINK_CONTEXT_MODIFY_RATES_INFO);1035if (ret)1036goto err;10371038/* TODO: Initialize rate control for the AP station, since we might be1039* doing a link switch here - we cannot initialize it before since1040* this needs the phy context assigned (and in FW?), and we cannot1041* do it later because it needs to be initialized as soon as we're1042* able to TX on the link, i.e. when active. (task=link-switch)1043*/10441045/* Now activate the link */1046if (iwl_mld_can_activate_link(mld, vif, link)) {1047ret = iwl_mld_activate_link(mld, link);1048if (ret)1049goto err;1050}10511052if (vif->type == NL80211_IFTYPE_STATION)1053iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link);10541055if (vif->type == NL80211_IFTYPE_MONITOR) {1056ret = iwl_mld_add_mon_sta(mld, vif, link);1057if (ret)1058goto deactivate_link;10591060mld->monitor.p80 =1061iwl_mld_chandef_get_primary_80(&vif->bss_conf.chanreq.oper);1062}10631064return 0;10651066deactivate_link:1067if (mld_link->active)1068iwl_mld_deactivate_link(mld, link);1069err:1070RCU_INIT_POINTER(mld_link->chan_ctx, NULL);1071return ret;1072}10731074static1075void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,1076struct ieee80211_vif *vif,1077struct ieee80211_bss_conf *link,1078struct ieee80211_chanctx_conf *ctx)1079{1080struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1081struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1082struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);1083unsigned int n_active = iwl_mld_count_active_links(mld, vif);10841085if (WARN_ON(!mld_link))1086return;10871088/* Track removal of non-BSS link */1089if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION)1090iwl_mld_emlsr_check_non_bss_block(mld, -1);10911092iwl_mld_deactivate_link(mld, link);10931094if (vif->type == NL80211_IFTYPE_MONITOR)1095iwl_mld_remove_mon_sta(mld, vif, link);10961097if (n_active > 1) {1098/* Indicate to mac80211 that EML is disabled */1099vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;11001101iwl_dbg_tlv_time_point(&mld->fwrt,1102IWL_FW_INI_TIME_ESR_LINK_DOWN,1103NULL);1104}11051106RCU_INIT_POINTER(mld_link->chan_ctx, NULL);11071108/* in the non-MLO case, remove/re-add the link to clean up FW state.1109* In MLO, it'll be done in drv_change_vif_link1110*/1111if (!ieee80211_vif_is_mld(vif) && !mld_vif->ap_sta &&1112!WARN_ON_ONCE(vif->cfg.assoc) &&1113vif->type != NL80211_IFTYPE_AP && !mld->fw_status.in_hw_restart) {1114iwl_mld_remove_link(mld, link);1115iwl_mld_add_link(mld, link);1116}1117}11181119static1120int iwl_mld_mac80211_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,1121u32 value)1122{1123return 0;1124}11251126static void1127iwl_mld_link_info_changed_ap_ibss(struct iwl_mld *mld,1128struct ieee80211_vif *vif,1129struct ieee80211_bss_conf *link,1130u64 changes)1131{1132u32 link_changes = 0;11331134if (changes & BSS_CHANGED_ERP_SLOT)1135link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;11361137if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))1138link_changes |= LINK_CONTEXT_MODIFY_PROTECT_FLAGS;11391140if (changes & (BSS_CHANGED_QOS | BSS_CHANGED_BANDWIDTH))1141link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;11421143if (changes & BSS_CHANGED_HE_BSS_COLOR)1144link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;11451146if (link_changes)1147iwl_mld_change_link_in_fw(mld, link, link_changes);11481149if (changes & BSS_CHANGED_BEACON)1150iwl_mld_update_beacon_template(mld, vif, link);1151}11521153static1154u32 iwl_mld_link_changed_mapping(struct iwl_mld *mld,1155struct ieee80211_vif *vif,1156struct ieee80211_bss_conf *link_conf,1157u64 changes)1158{1159u32 link_changes = 0;1160bool has_he, has_eht;11611162if (changes & BSS_CHANGED_QOS && vif->cfg.assoc && link_conf->qos)1163link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;11641165if (changes & (BSS_CHANGED_ERP_PREAMBLE | BSS_CHANGED_BASIC_RATES |1166BSS_CHANGED_ERP_SLOT))1167link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;11681169if (changes & (BSS_CHANGED_HT | BSS_CHANGED_ERP_CTS_PROT))1170link_changes |= LINK_CONTEXT_MODIFY_PROTECT_FLAGS;11711172/* TODO: task=MLO check mac80211's HE flags and if command is needed1173* every time there's a link change. Currently used flags are1174* BSS_CHANGED_HE_OBSS_PD and BSS_CHANGED_HE_BSS_COLOR.1175*/1176has_he = link_conf->he_support && !iwlwifi_mod_params.disable_11ax;1177has_eht = link_conf->eht_support && !iwlwifi_mod_params.disable_11be;11781179if (vif->cfg.assoc && (has_he || has_eht)) {1180IWL_DEBUG_MAC80211(mld, "Associated in HE mode\n");1181link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;1182}11831184return link_changes;1185}11861187static void1188iwl_mld_mac80211_link_info_changed_sta(struct iwl_mld *mld,1189struct ieee80211_vif *vif,1190struct ieee80211_bss_conf *link_conf,1191u64 changes)1192{1193u32 link_changes = iwl_mld_link_changed_mapping(mld, vif, link_conf,1194changes);11951196if (link_changes)1197iwl_mld_change_link_in_fw(mld, link_conf, link_changes);11981199if (changes & BSS_CHANGED_TPE)1200iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link_conf);12011202if (changes & BSS_CHANGED_BEACON_INFO)1203iwl_mld_update_mac_power(mld, vif, false);12041205/* The firmware will wait quite a while after association before it1206* starts filtering the beacons. We can safely enable beacon filtering1207* upon CQM configuration, even if we didn't get a beacon yet.1208*/1209if (changes & (BSS_CHANGED_CQM | BSS_CHANGED_BEACON_INFO))1210iwl_mld_enable_beacon_filter(mld, link_conf, false);12111212if (changes & BSS_CHANGED_BANDWIDTH)1213iwl_mld_retry_emlsr(mld, vif);1214}12151216static int iwl_mld_update_mu_groups(struct iwl_mld *mld,1217struct ieee80211_bss_conf *link_conf)1218{1219struct iwl_mu_group_mgmt_cmd cmd = {};12201221BUILD_BUG_ON(sizeof(cmd.membership_status) !=1222sizeof(link_conf->mu_group.membership));1223BUILD_BUG_ON(sizeof(cmd.user_position) !=1224sizeof(link_conf->mu_group.position));12251226memcpy(cmd.membership_status, link_conf->mu_group.membership,1227WLAN_MEMBERSHIP_LEN);1228memcpy(cmd.user_position, link_conf->mu_group.position,1229WLAN_USER_POSITION_LEN);12301231return iwl_mld_send_cmd_pdu(mld,1232WIDE_ID(DATA_PATH_GROUP,1233UPDATE_MU_GROUPS_CMD),1234&cmd);1235}12361237static void1238iwl_mld_mac80211_link_info_changed(struct ieee80211_hw *hw,1239struct ieee80211_vif *vif,1240struct ieee80211_bss_conf *link_conf,1241u64 changes)1242{1243struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);12441245switch (vif->type) {1246case NL80211_IFTYPE_STATION:1247iwl_mld_mac80211_link_info_changed_sta(mld, vif, link_conf,1248changes);1249break;1250case NL80211_IFTYPE_AP:1251case NL80211_IFTYPE_ADHOC:1252iwl_mld_link_info_changed_ap_ibss(mld, vif, link_conf,1253changes);1254break;1255case NL80211_IFTYPE_MONITOR:1256/* The firmware tracks this on its own in STATION mode, but1257* obviously not in sniffer mode.1258*/1259if (changes & BSS_CHANGED_MU_GROUPS)1260iwl_mld_update_mu_groups(mld, link_conf);1261break;1262default:1263/* shouldn't happen */1264WARN_ON_ONCE(1);1265}12661267/* We now know our BSSID, we can configure the MAC context with1268* eht_support if needed.1269*/1270if (changes & BSS_CHANGED_BSSID)1271iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);12721273if (changes & BSS_CHANGED_TXPOWER)1274iwl_mld_set_tx_power(mld, link_conf, link_conf->txpower);1275}12761277static void1278iwl_mld_smps_workaround(struct iwl_mld *mld, struct ieee80211_vif *vif, bool enable)1279{1280struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1281bool workaround_required =1282iwl_fw_lookup_cmd_ver(mld->fw, MAC_PM_POWER_TABLE, 0) < 2;12831284if (!workaround_required)1285return;12861287/* Send the device-level power commands since the1288* firmware checks the POWER_TABLE_CMD's POWER_SAVE_EN bit to1289* determine SMPS mode.1290*/1291if (mld_vif->ps_disabled == !enable)1292return;12931294mld_vif->ps_disabled = !enable;12951296iwl_mld_update_device_power(mld, false);1297}12981299static1300void iwl_mld_mac80211_vif_cfg_changed(struct ieee80211_hw *hw,1301struct ieee80211_vif *vif,1302u64 changes)1303{1304struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1305int ret;13061307lockdep_assert_wiphy(mld->wiphy);13081309if (vif->type != NL80211_IFTYPE_STATION)1310return;13111312if (changes & BSS_CHANGED_ASSOC) {1313ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);1314if (ret)1315IWL_ERR(mld, "failed to update context\n");13161317if (vif->cfg.assoc) {1318/* Clear statistics to get clean beacon counter, and1319* ask for periodic statistics, as they are needed for1320* link selection and RX OMI decisions.1321*/1322iwl_mld_clear_stats_in_fw(mld);1323iwl_mld_request_periodic_fw_stats(mld, true);13241325iwl_mld_set_vif_associated(mld, vif);1326} else {1327iwl_mld_request_periodic_fw_stats(mld, false);1328}1329}13301331if (changes & BSS_CHANGED_PS) {1332iwl_mld_smps_workaround(mld, vif, vif->cfg.ps);1333iwl_mld_update_mac_power(mld, vif, false);1334}13351336/* TODO: task=MLO BSS_CHANGED_MLD_VALID_LINKS/CHANGED_MLD_TTLM */1337}13381339static int1340iwl_mld_mac80211_hw_scan(struct ieee80211_hw *hw,1341struct ieee80211_vif *vif,1342struct ieee80211_scan_request *hw_req)1343{1344struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1345int ret;13461347if (WARN_ON(!hw_req->req.n_channels ||1348hw_req->req.n_channels >1349mld->fw->ucode_capa.n_scan_channels))1350return -EINVAL;13511352ret = iwl_mld_regular_scan_start(mld, vif, &hw_req->req, &hw_req->ies);1353if (!ret) {1354/* We will be busy with scanning, so the counters may not reflect the1355* reality. Stop checking the counters until the scan ends1356*/1357iwl_mld_start_ignoring_tpt_updates(mld);1358}13591360return ret;1361}13621363static void1364iwl_mld_mac80211_cancel_hw_scan(struct ieee80211_hw *hw,1365struct ieee80211_vif *vif)1366{1367struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);13681369/* Due to a race condition, it's possible that mac80211 asks1370* us to stop a hw_scan when it's already stopped. This can1371* happen, for instance, if we stopped the scan ourselves,1372* called ieee80211_scan_completed() and the userspace called1373* cancel scan before ieee80211_scan_work() could run.1374* To handle that, simply return if the scan is not running.1375*/1376if (mld->scan.status & IWL_MLD_SCAN_REGULAR) {1377iwl_mld_scan_stop(mld, IWL_MLD_SCAN_REGULAR, true);1378/* Scan is over, we can check again the tpt counters */1379iwl_mld_stop_ignoring_tpt_updates(mld);1380}1381}13821383static int1384iwl_mld_mac80211_sched_scan_start(struct ieee80211_hw *hw,1385struct ieee80211_vif *vif,1386struct cfg80211_sched_scan_request *req,1387struct ieee80211_scan_ies *ies)1388{1389struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);13901391return iwl_mld_sched_scan_start(mld, vif, req, ies, IWL_MLD_SCAN_SCHED);1392}13931394static int1395iwl_mld_mac80211_sched_scan_stop(struct ieee80211_hw *hw,1396struct ieee80211_vif *vif)1397{1398struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);13991400/* Due to a race condition, it's possible that mac80211 asks1401* us to stop a sched_scan when it's already stopped. This1402* can happen, for instance, if we stopped the scan ourselves,1403* called ieee80211_sched_scan_stopped() and the userspace called1404* stop sched scan before ieee80211_sched_scan_stopped_work()1405* could run. To handle this, simply return if the scan is1406* not running.1407*/1408if (!(mld->scan.status & IWL_MLD_SCAN_SCHED))1409return 0;14101411return iwl_mld_scan_stop(mld, IWL_MLD_SCAN_SCHED, false);1412}14131414static void1415iwl_mld_mac80211_reconfig_complete(struct ieee80211_hw *hw,1416enum ieee80211_reconfig_type reconfig_type)1417{1418struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);14191420switch (reconfig_type) {1421case IEEE80211_RECONFIG_TYPE_RESTART:1422mld->fw_status.in_hw_restart = false;1423iwl_mld_send_recovery_cmd(mld, ERROR_RECOVERY_END_OF_RECOVERY);1424iwl_trans_finish_sw_reset(mld->trans);1425/* no need to lock, adding in parallel would schedule too */1426if (!list_empty(&mld->txqs_to_add))1427wiphy_work_queue(mld->wiphy, &mld->add_txqs_wk);14281429IWL_INFO(mld, "restart completed\n");1430break;1431case IEEE80211_RECONFIG_TYPE_SUSPEND:1432break;1433}1434}14351436static1437void iwl_mld_mac80211_mgd_prepare_tx(struct ieee80211_hw *hw,1438struct ieee80211_vif *vif,1439struct ieee80211_prep_tx_info *info)1440{1441struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1442u32 duration = IWL_MLD_SESSION_PROTECTION_ASSOC_TIME_MS;14431444/* After a successful association the connection is established1445* and we can rely on the quota to send the disassociation frame.1446*/1447if (info->was_assoc)1448return;14491450if (info->duration > duration)1451duration = info->duration;14521453iwl_mld_schedule_session_protection(mld, vif, duration,1454IWL_MLD_SESSION_PROTECTION_MIN_TIME_MS,1455info->link_id);1456}14571458static1459void iwl_mld_mac_mgd_complete_tx(struct ieee80211_hw *hw,1460struct ieee80211_vif *vif,1461struct ieee80211_prep_tx_info *info)1462{1463struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);14641465/* Successful authentication is the only case that requires to let1466* the session protection go. We'll need it for the upcoming1467* association. For all the other cases, we need to cancel the session1468* protection.1469* After successful association the connection is established and1470* further mgd tx can rely on the quota.1471*/1472if (info->success && info->subtype == IEEE80211_STYPE_AUTH)1473return;14741475/* The firmware will be on medium after we configure the vif as1476* associated. Removing the session protection allows the firmware1477* to stop being on medium. In order to ensure the continuity of our1478* presence on medium, we need first to configure the vif as associated1479* and only then, remove the session protection.1480* Currently, mac80211 calls vif_cfg_changed() first and then,1481* drv_mgd_complete_tx(). Ensure that this assumption stays true by1482* a warning.1483*/1484WARN_ON(info->success &&1485(info->subtype == IEEE80211_STYPE_ASSOC_REQ ||1486info->subtype == IEEE80211_STYPE_REASSOC_REQ) &&1487!vif->cfg.assoc);14881489iwl_mld_cancel_session_protection(mld, vif, info->link_id);1490}14911492static int1493iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw,1494struct ieee80211_vif *vif,1495unsigned int link_id, u16 ac,1496const struct ieee80211_tx_queue_params *params)1497{1498struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1499struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1500struct iwl_mld_link *link;15011502lockdep_assert_wiphy(mld->wiphy);15031504link = iwl_mld_link_dereference_check(mld_vif, link_id);1505if (!link)1506return -EINVAL;15071508link->queue_params[ac] = *params;15091510/* No need to update right away, we'll get BSS_CHANGED_QOS1511* The exception is P2P_DEVICE interface which needs immediate update.1512*/1513if (vif->type == NL80211_IFTYPE_P2P_DEVICE)1514iwl_mld_change_link_in_fw(mld, &vif->bss_conf,1515LINK_CONTEXT_MODIFY_QOS_PARAMS);15161517return 0;1518}15191520static void iwl_mld_set_uapsd(struct iwl_mld *mld, struct ieee80211_vif *vif)1521{1522vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;15231524if (vif->type != NL80211_IFTYPE_STATION)1525return;15261527if (vif->p2p &&1528!(iwlwifi_mod_params.uapsd_disable & IWL_DISABLE_UAPSD_P2P_CLIENT))1529vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;15301531if (!vif->p2p &&1532!(iwlwifi_mod_params.uapsd_disable & IWL_DISABLE_UAPSD_BSS))1533vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;1534}15351536int iwl_mld_tdls_sta_count(struct iwl_mld *mld)1537{1538int count = 0;15391540lockdep_assert_wiphy(mld->wiphy);15411542for (int i = 0; i < mld->fw->ucode_capa.num_stations; i++) {1543struct ieee80211_link_sta *link_sta;15441545link_sta = wiphy_dereference(mld->wiphy,1546mld->fw_id_to_link_sta[i]);1547if (IS_ERR_OR_NULL(link_sta))1548continue;15491550if (!link_sta->sta->tdls)1551continue;15521553count++;1554}15551556return count;1557}15581559static void iwl_mld_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,1560struct cfg80211_bss *bss,1561void *_data)1562{1563bool *tolerated = _data;1564const struct cfg80211_bss_ies *ies;1565const struct element *elem;15661567rcu_read_lock();1568ies = rcu_dereference(bss->ies);1569elem = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, ies->data,1570ies->len);15711572if (!elem || elem->datalen < 10 ||1573!(elem->data[10] &1574WLAN_EXT_CAPA10_OBSS_NARROW_BW_RU_TOLERANCE_SUPPORT)) {1575*tolerated = false;1576}1577rcu_read_unlock();1578}15791580static void1581iwl_mld_check_he_obss_narrow_bw_ru(struct iwl_mld *mld,1582struct iwl_mld_link *mld_link,1583struct ieee80211_bss_conf *link_conf)1584{1585bool tolerated = true;15861587if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan))1588return;15891590if (!(link_conf->chanreq.oper.chan->flags & IEEE80211_CHAN_RADAR)) {1591mld_link->he_ru_2mhz_block = false;1592return;1593}15941595cfg80211_bss_iter(mld->wiphy, &link_conf->chanreq.oper,1596iwl_mld_check_he_obss_narrow_bw_ru_iter, &tolerated);15971598/* If there is at least one AP on radar channel that cannot1599* tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.1600*/1601mld_link->he_ru_2mhz_block = !tolerated;1602}16031604static void iwl_mld_link_set_2mhz_block(struct iwl_mld *mld,1605struct ieee80211_vif *vif,1606struct ieee80211_sta *sta)1607{1608struct ieee80211_link_sta *link_sta;1609unsigned int link_id;16101611for_each_sta_active_link(vif, sta, link_sta, link_id) {1612struct ieee80211_bss_conf *link_conf =1613link_conf_dereference_protected(vif, link_id);1614struct iwl_mld_link *mld_link =1615iwl_mld_link_from_mac80211(link_conf);16161617if (WARN_ON(!link_conf || !mld_link))1618continue;16191620if (link_sta->he_cap.has_he)1621iwl_mld_check_he_obss_narrow_bw_ru(mld, mld_link,1622link_conf);1623}1624}16251626static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,1627struct ieee80211_vif *vif,1628struct ieee80211_sta *sta,1629enum ieee80211_sta_state old_state,1630enum ieee80211_sta_state new_state)1631{1632struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);1633int tdls_count = 0;1634int ret;16351636if (old_state == IEEE80211_STA_NOTEXIST &&1637new_state == IEEE80211_STA_NONE) {1638if (sta->tdls) {1639if (vif->p2p || hweight8(mld->used_phy_ids) != 1)1640return -EBUSY;16411642tdls_count = iwl_mld_tdls_sta_count(mld);1643if (tdls_count >= IWL_TDLS_STA_COUNT)1644return -EBUSY;1645}16461647ret = iwl_mld_add_sta(mld, sta, vif, STATION_TYPE_PEER);1648if (ret)1649return ret;16501651/* just added first TDLS STA, so disable PM */1652if (sta->tdls && tdls_count == 0)1653iwl_mld_update_mac_power(mld, vif, false);16541655if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)1656mld_vif->ap_sta = sta;16571658/* Initialize TLC here already - this really tells1659* the firmware only what the supported legacy rates are1660* (may be) since it's initialized already from what the1661* AP advertised in the beacon/probe response. This will1662* allow the firmware to send auth/assoc frames with one1663* of the supported rates already, rather than having to1664* use a mandatory rate.1665* If we're the AP, we'll just assume mandatory rates at1666* this point, but we know nothing about the STA anyway.1667*/1668iwl_mld_config_tlc(mld, vif, sta);16691670return ret;1671} else if (old_state == IEEE80211_STA_NONE &&1672new_state == IEEE80211_STA_AUTH) {1673iwl_mld_set_uapsd(mld, vif);1674return 0;1675} else if (old_state == IEEE80211_STA_AUTH &&1676new_state == IEEE80211_STA_ASSOC) {1677ret = iwl_mld_update_all_link_stations(mld, sta);16781679if (vif->type == NL80211_IFTYPE_STATION)1680iwl_mld_link_set_2mhz_block(mld, vif, sta);1681/* Now the link_sta's capabilities are set, update the FW */1682iwl_mld_config_tlc(mld, vif, sta);16831684if (vif->type == NL80211_IFTYPE_AP) {1685/* Update MAC_CFG_FILTER_ACCEPT_BEACON if at least1686* one sta is associated1687*/1688if (++mld_vif->num_associated_stas == 1)1689ret = iwl_mld_mac_fw_action(mld, vif,1690FW_CTXT_ACTION_MODIFY);1691}16921693return ret;1694} else if (old_state == IEEE80211_STA_ASSOC &&1695new_state == IEEE80211_STA_AUTHORIZED) {1696ret = 0;16971698if (!sta->tdls) {1699mld_vif->authorized = true;17001701/* Ensure any block due to a non-BSS link is synced */1702iwl_mld_emlsr_check_non_bss_block(mld, 0);17031704/* Block EMLSR until a certain throughput it reached */1705if (!mld->fw_status.in_hw_restart &&1706IWL_MLD_ENTER_EMLSR_TPT_THRESH > 0)1707iwl_mld_block_emlsr(mld_vif->mld, vif,1708IWL_MLD_EMLSR_BLOCKED_TPT,17090);17101711/* clear COEX_HIGH_PRIORITY_ENABLE */1712ret = iwl_mld_mac_fw_action(mld, vif,1713FW_CTXT_ACTION_MODIFY);1714if (ret)1715return ret;1716iwl_mld_smps_workaround(mld, vif, vif->cfg.ps);1717}17181719/* MFP is set by default before the station is authorized.1720* Clear it here in case it's not used.1721*/1722if (!sta->mfp)1723ret = iwl_mld_update_all_link_stations(mld, sta);17241725/* We can use wide bandwidth now, not only 20 MHz */1726iwl_mld_config_tlc(mld, vif, sta);17271728return ret;1729} else {1730return -EINVAL;1731}1732}17331734static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,1735struct ieee80211_vif *vif,1736struct ieee80211_sta *sta,1737enum ieee80211_sta_state old_state,1738enum ieee80211_sta_state new_state)1739{1740struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);17411742if (old_state == IEEE80211_STA_AUTHORIZED &&1743new_state == IEEE80211_STA_ASSOC) {1744if (!sta->tdls) {1745mld_vif->authorized = false;17461747memset(&mld_vif->emlsr.zeroed_on_not_authorized, 0,1748sizeof(mld_vif->emlsr.zeroed_on_not_authorized));17491750wiphy_delayed_work_cancel(mld->wiphy,1751&mld_vif->emlsr.prevent_done_wk);1752wiphy_delayed_work_cancel(mld->wiphy,1753&mld_vif->emlsr.tmp_non_bss_done_wk);1754wiphy_work_cancel(mld->wiphy, &mld_vif->emlsr.unblock_tpt_wk);1755wiphy_delayed_work_cancel(mld->wiphy,1756&mld_vif->emlsr.check_tpt_wk);17571758iwl_mld_reset_cca_40mhz_workaround(mld, vif);1759iwl_mld_smps_workaround(mld, vif, true);1760}17611762/* once we move into assoc state, need to update the FW to1763* stop using wide bandwidth1764*/1765iwl_mld_config_tlc(mld, vif, sta);1766} else if (old_state == IEEE80211_STA_ASSOC &&1767new_state == IEEE80211_STA_AUTH) {1768if (vif->type == NL80211_IFTYPE_AP &&1769!WARN_ON(!mld_vif->num_associated_stas)) {1770/* Update MAC_CFG_FILTER_ACCEPT_BEACON if the last sta1771* is disassociating1772*/1773if (--mld_vif->num_associated_stas == 0)1774iwl_mld_mac_fw_action(mld, vif,1775FW_CTXT_ACTION_MODIFY);1776}1777} else if (old_state == IEEE80211_STA_AUTH &&1778new_state == IEEE80211_STA_NONE) {1779/* nothing */1780} else if (old_state == IEEE80211_STA_NONE &&1781new_state == IEEE80211_STA_NOTEXIST) {1782iwl_mld_remove_sta(mld, sta);17831784if (sta->tdls && iwl_mld_tdls_sta_count(mld) == 0) {1785/* just removed last TDLS STA, so enable PM */1786iwl_mld_update_mac_power(mld, vif, false);1787}1788} else {1789return -EINVAL;1790}1791return 0;1792}17931794static int iwl_mld_mac80211_sta_state(struct ieee80211_hw *hw,1795struct ieee80211_vif *vif,1796struct ieee80211_sta *sta,1797enum ieee80211_sta_state old_state,1798enum ieee80211_sta_state new_state)1799{1800struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1801struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);18021803IWL_DEBUG_MAC80211(mld, "station %pM state change %d->%d\n",1804sta->addr, old_state, new_state);18051806mld_sta->sta_state = new_state;18071808if (old_state < new_state)1809return iwl_mld_move_sta_state_up(mld, vif, sta, old_state,1810new_state);1811else1812return iwl_mld_move_sta_state_down(mld, vif, sta, old_state,1813new_state);1814}18151816static void iwl_mld_mac80211_flush(struct ieee80211_hw *hw,1817struct ieee80211_vif *vif,1818u32 queues, bool drop)1819{1820struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);18211822/* Make sure we're done with the deferred traffic before flushing */1823iwl_mld_add_txq_list(mld);18241825for (int i = 0; i < mld->fw->ucode_capa.num_stations; i++) {1826struct ieee80211_link_sta *link_sta =1827wiphy_dereference(mld->wiphy,1828mld->fw_id_to_link_sta[i]);18291830if (IS_ERR_OR_NULL(link_sta))1831continue;18321833/* Check that the sta belongs to the given vif */1834if (vif && vif != iwl_mld_sta_from_mac80211(link_sta->sta)->vif)1835continue;18361837if (drop)1838iwl_mld_flush_sta_txqs(mld, link_sta->sta);1839else1840iwl_mld_wait_sta_txqs_empty(mld, link_sta->sta);1841}1842}18431844static void iwl_mld_mac80211_flush_sta(struct ieee80211_hw *hw,1845struct ieee80211_vif *vif,1846struct ieee80211_sta *sta)1847{1848struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);18491850iwl_mld_flush_sta_txqs(mld, sta);1851}18521853static int1854iwl_mld_mac80211_ampdu_action(struct ieee80211_hw *hw,1855struct ieee80211_vif *vif,1856struct ieee80211_ampdu_params *params)1857{1858struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1859struct ieee80211_sta *sta = params->sta;1860enum ieee80211_ampdu_mlme_action action = params->action;1861u16 tid = params->tid;1862u16 ssn = params->ssn;1863u16 buf_size = params->buf_size;1864u16 timeout = params->timeout;1865int ret;18661867IWL_DEBUG_HT(mld, "A-MPDU action on addr %pM tid: %d action: %d\n",1868sta->addr, tid, action);18691870switch (action) {1871case IEEE80211_AMPDU_RX_START:1872if (!iwl_enable_rx_ampdu()) {1873ret = -EINVAL;1874break;1875}1876ret = iwl_mld_ampdu_rx_start(mld, sta, tid, ssn, buf_size,1877timeout);1878break;1879case IEEE80211_AMPDU_RX_STOP:1880ret = iwl_mld_ampdu_rx_stop(mld, sta, tid);1881break;1882default:1883/* The mac80211 TX_AMPDU_SETUP_IN_HW flag is set for all1884* devices, since all support TX A-MPDU offload in hardware.1885* Therefore, no TX action should be requested here.1886*/1887WARN_ON_ONCE(1);1888return -EINVAL;1889}18901891return ret;1892}18931894static bool iwl_mld_can_hw_csum(struct sk_buff *skb)1895{1896u8 protocol = ip_hdr(skb)->protocol;18971898return protocol == IPPROTO_TCP || protocol == IPPROTO_UDP;1899}19001901static bool iwl_mld_mac80211_can_aggregate(struct ieee80211_hw *hw,1902struct sk_buff *head,1903struct sk_buff *skb)1904{1905if (!IS_ENABLED(CONFIG_INET))1906return false;19071908/* For now don't aggregate IPv6 in AMSDU */1909if (skb->protocol != htons(ETH_P_IP))1910return false;19111912/* Allow aggregation only if both frames have the same HW csum offload1913* capability, ensuring consistent HW or SW csum handling in A-MSDU.1914*/1915return iwl_mld_can_hw_csum(skb) == iwl_mld_can_hw_csum(head);1916}19171918static void iwl_mld_mac80211_sync_rx_queues(struct ieee80211_hw *hw)1919{1920struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);19211922iwl_mld_sync_rx_queues(mld, IWL_MLD_RXQ_EMPTY, NULL, 0);1923}19241925static void iwl_mld_sta_rc_update(struct ieee80211_hw *hw,1926struct ieee80211_vif *vif,1927struct ieee80211_link_sta *link_sta,1928u32 changed)1929{1930struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);19311932if (changed & (IEEE80211_RC_BW_CHANGED |1933IEEE80211_RC_SUPP_RATES_CHANGED |1934IEEE80211_RC_NSS_CHANGED)) {1935struct ieee80211_bss_conf *link =1936link_conf_dereference_check(vif, link_sta->link_id);19371938if (WARN_ON(!link))1939return;19401941iwl_mld_config_tlc_link(mld, vif, link, link_sta);1942}1943}19441945#ifdef CONFIG_PM_SLEEP1946static void iwl_mld_set_wakeup(struct ieee80211_hw *hw, bool enabled)1947{1948struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);19491950device_set_wakeup_enable(mld->trans->dev, enabled);1951}19521953/* Returns 0 on success. 1 if failed to suspend with wowlan:1954* If the circumstances didn't satisfy the conditions for suspension1955* with wowlan, mac80211 would use the no_wowlan flow.1956* If an error had occurred we update the trans status and state here1957* and the result will be stopping the FW.1958*/1959static int1960iwl_mld_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)1961{1962struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1963int ret;19641965iwl_fw_runtime_suspend(&mld->fwrt);19661967ret = iwl_mld_wowlan_suspend(mld, wowlan);1968if (ret) {1969if (ret < 0) {1970mld->trans->state = IWL_TRANS_NO_FW;1971set_bit(STATUS_FW_ERROR, &mld->trans->status);1972}1973return 1;1974}19751976if (iwl_mld_no_wowlan_suspend(mld))1977return 1;19781979return 0;1980}19811982static int iwl_mld_resume(struct ieee80211_hw *hw)1983{1984struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);1985int ret;19861987ret = iwl_mld_wowlan_resume(mld);1988if (ret)1989return ret;19901991iwl_fw_runtime_resume(&mld->fwrt);19921993iwl_mld_low_latency_restart(mld);19941995return 0;1996}1997#endif19981999static int iwl_mld_alloc_ptk_pn(struct iwl_mld *mld,2000struct iwl_mld_sta *mld_sta,2001struct ieee80211_key_conf *key,2002struct iwl_mld_ptk_pn **ptk_pn)2003{2004u8 num_rx_queues = mld->trans->info.num_rxqs;2005int keyidx = key->keyidx;2006struct ieee80211_key_seq seq;20072008if (WARN_ON(keyidx >= ARRAY_SIZE(mld_sta->ptk_pn)))2009return -EINVAL;20102011WARN_ON(rcu_access_pointer(mld_sta->ptk_pn[keyidx]));2012*ptk_pn = kzalloc(struct_size(*ptk_pn, q, num_rx_queues),2013GFP_KERNEL);2014if (!*ptk_pn)2015return -ENOMEM;20162017for (u8 tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {2018ieee80211_get_key_rx_seq(key, tid, &seq);2019for (u8 q = 0; q < num_rx_queues; q++)2020memcpy((*ptk_pn)->q[q].pn[tid], seq.ccmp.pn,2021IEEE80211_CCMP_PN_LEN);2022}20232024rcu_assign_pointer(mld_sta->ptk_pn[keyidx], *ptk_pn);20252026return 0;2027}20282029static int iwl_mld_set_key_add(struct iwl_mld *mld,2030struct ieee80211_vif *vif,2031struct ieee80211_sta *sta,2032struct ieee80211_key_conf *key)2033{2034struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);2035struct iwl_mld_sta *mld_sta =2036sta ? iwl_mld_sta_from_mac80211(sta) : NULL;2037struct iwl_mld_ptk_pn *ptk_pn = NULL;2038int keyidx = key->keyidx;2039int ret;20402041/* Will be set to 0 if added successfully */2042key->hw_key_idx = STA_KEY_IDX_INVALID;20432044switch (key->cipher) {2045case WLAN_CIPHER_SUITE_WEP40:2046case WLAN_CIPHER_SUITE_WEP104:2047IWL_DEBUG_MAC80211(mld, "Use SW encryption for WEP\n");2048return -EOPNOTSUPP;2049case WLAN_CIPHER_SUITE_TKIP:2050if (vif->type == NL80211_IFTYPE_STATION) {2051key->flags |= IEEE80211_KEY_FLAG_PUT_MIC_SPACE;2052break;2053}2054IWL_DEBUG_MAC80211(mld, "Use SW encryption for TKIP\n");2055return -EOPNOTSUPP;2056case WLAN_CIPHER_SUITE_CCMP:2057case WLAN_CIPHER_SUITE_GCMP:2058case WLAN_CIPHER_SUITE_GCMP_256:2059case WLAN_CIPHER_SUITE_AES_CMAC:2060case WLAN_CIPHER_SUITE_BIP_GMAC_128:2061case WLAN_CIPHER_SUITE_BIP_GMAC_256:2062break;2063default:2064return -EOPNOTSUPP;2065}20662067if (vif->type == NL80211_IFTYPE_STATION &&2068(keyidx == 6 || keyidx == 7))2069rcu_assign_pointer(mld_vif->bigtks[keyidx - 6], key);20702071/* After exiting from RFKILL, hostapd configures GTK/ITGK before the2072* AP is started, but those keys can't be sent to the FW before the2073* MCAST/BCAST STAs are added to it (which happens upon AP start).2074* Store it here to be sent later when the AP is started.2075*/2076if ((vif->type == NL80211_IFTYPE_ADHOC ||2077vif->type == NL80211_IFTYPE_AP) && !sta &&2078!mld_vif->ap_ibss_active)2079return iwl_mld_store_ap_early_key(mld, key, mld_vif);20802081if (!mld->fw_status.in_hw_restart && mld_sta &&2082key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&2083(key->cipher == WLAN_CIPHER_SUITE_CCMP ||2084key->cipher == WLAN_CIPHER_SUITE_GCMP ||2085key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {2086ret = iwl_mld_alloc_ptk_pn(mld, mld_sta, key, &ptk_pn);2087if (ret)2088return ret;2089}20902091IWL_DEBUG_MAC80211(mld, "set hwcrypto key (sta:%pM, id:%d)\n",2092sta ? sta->addr : NULL, keyidx);20932094ret = iwl_mld_add_key(mld, vif, sta, key);2095if (ret) {2096IWL_WARN(mld, "set key failed (%d)\n", ret);2097if (ptk_pn) {2098RCU_INIT_POINTER(mld_sta->ptk_pn[keyidx], NULL);2099kfree(ptk_pn);2100}21012102return -EOPNOTSUPP;2103}21042105return 0;2106}21072108static void iwl_mld_set_key_remove(struct iwl_mld *mld,2109struct ieee80211_vif *vif,2110struct ieee80211_sta *sta,2111struct ieee80211_key_conf *key)2112{2113struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);2114struct iwl_mld_sta *mld_sta =2115sta ? iwl_mld_sta_from_mac80211(sta) : NULL;2116int keyidx = key->keyidx;21172118if (vif->type == NL80211_IFTYPE_STATION &&2119(keyidx == 6 || keyidx == 7))2120RCU_INIT_POINTER(mld_vif->bigtks[keyidx - 6], NULL);21212122if (mld_sta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE &&2123(key->cipher == WLAN_CIPHER_SUITE_CCMP ||2124key->cipher == WLAN_CIPHER_SUITE_GCMP ||2125key->cipher == WLAN_CIPHER_SUITE_GCMP_256)) {2126struct iwl_mld_ptk_pn *ptk_pn;21272128if (WARN_ON(keyidx >= ARRAY_SIZE(mld_sta->ptk_pn)))2129return;21302131ptk_pn = wiphy_dereference(mld->wiphy,2132mld_sta->ptk_pn[keyidx]);2133RCU_INIT_POINTER(mld_sta->ptk_pn[keyidx], NULL);2134if (!WARN_ON(!ptk_pn))2135kfree_rcu(ptk_pn, rcu_head);2136}21372138/* if this key was stored to be added later to the FW - free it here */2139if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))2140iwl_mld_free_ap_early_key(mld, key, mld_vif);21412142/* We already removed it */2143if (key->hw_key_idx == STA_KEY_IDX_INVALID)2144return;21452146IWL_DEBUG_MAC80211(mld, "disable hwcrypto key\n");21472148iwl_mld_remove_key(mld, vif, sta, key);2149}21502151static int iwl_mld_mac80211_set_key(struct ieee80211_hw *hw,2152enum set_key_cmd cmd,2153struct ieee80211_vif *vif,2154struct ieee80211_sta *sta,2155struct ieee80211_key_conf *key)2156{2157struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2158int ret;21592160switch (cmd) {2161case SET_KEY:2162ret = iwl_mld_set_key_add(mld, vif, sta, key);2163if (ret)2164ret = -EOPNOTSUPP;2165break;2166case DISABLE_KEY:2167iwl_mld_set_key_remove(mld, vif, sta, key);2168ret = 0;2169break;2170default:2171ret = -EINVAL;2172break;2173}21742175return ret;2176}21772178static int2179iwl_mld_pre_channel_switch(struct ieee80211_hw *hw,2180struct ieee80211_vif *vif,2181struct ieee80211_channel_switch *chsw)2182{2183struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2184struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);2185struct iwl_mld_link *mld_link =2186iwl_mld_link_dereference_check(mld_vif, chsw->link_id);2187u8 primary;2188int selected;21892190lockdep_assert_wiphy(mld->wiphy);21912192if (WARN_ON(!mld_link))2193return -EINVAL;21942195IWL_DEBUG_MAC80211(mld, "pre CSA to freq %d\n",2196chsw->chandef.center_freq1);21972198if (!iwl_mld_emlsr_active(vif))2199return 0;22002201primary = iwl_mld_get_primary_link(vif);22022203/* stay on the primary link unless it is undergoing a CSA with quiet */2204if (chsw->link_id == primary && chsw->block_tx)2205selected = iwl_mld_get_other_link(vif, primary);2206else2207selected = primary;22082209/* Remember to tell the firmware that this link can't tx2210* Note that this logic seems to be unrelated to emlsr, but it2211* really is needed only when emlsr is active. When we have a2212* single link, the firmware will handle all this on its own.2213* In multi-link scenarios, we can learn about the CSA from2214* another link and this logic is too complex for the firmware2215* to track.2216* Since we want to de-activate the link that got a CSA with mode=1,2217* we need to tell the firmware not to send any frame on that link2218* as the firmware may not be aware that link is under a CSA2219* with mode=1 (no Tx allowed).2220*/2221mld_link->silent_deactivation = chsw->block_tx;2222iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_CSA, selected);22232224return 0;2225}22262227static void2228iwl_mld_channel_switch(struct ieee80211_hw *hw,2229struct ieee80211_vif *vif,2230struct ieee80211_channel_switch *chsw)2231{2232struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);22332234/* By implementing this operation, we prevent mac80211 from2235* starting its own channel switch timer, so that we can call2236* ieee80211_chswitch_done() ourselves at the right time2237* (Upon receiving the channel_switch_start notification from the fw)2238*/2239IWL_DEBUG_MAC80211(mld,2240"dummy channel switch op\n");2241}22422243static int2244iwl_mld_post_channel_switch(struct ieee80211_hw *hw,2245struct ieee80211_vif *vif,2246struct ieee80211_bss_conf *link_conf)2247{2248struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2249struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);22502251lockdep_assert_wiphy(mld->wiphy);22522253WARN_ON(mld_link->silent_deactivation);22542255return 0;2256}22572258static void2259iwl_mld_abort_channel_switch(struct ieee80211_hw *hw,2260struct ieee80211_vif *vif,2261struct ieee80211_bss_conf *link_conf)2262{2263struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2264struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);22652266IWL_DEBUG_MAC80211(mld,2267"abort channel switch op\n");2268mld_link->silent_deactivation = false;2269}22702271static int2272iwl_mld_switch_vif_chanctx_swap(struct ieee80211_hw *hw,2273struct ieee80211_vif_chanctx_switch *vifs)2274{2275struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2276int ret;22772278iwl_mld_unassign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2279vifs[0].old_ctx);2280iwl_mld_remove_chanctx(hw, vifs[0].old_ctx);22812282ret = iwl_mld_add_chanctx(hw, vifs[0].new_ctx);2283if (ret) {2284IWL_ERR(mld, "failed to add new_ctx during channel switch\n");2285goto out_reassign;2286}22872288ret = iwl_mld_assign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2289vifs[0].new_ctx);2290if (ret) {2291IWL_ERR(mld,2292"failed to assign new_ctx during channel switch\n");2293goto out_remove;2294}22952296return 0;22972298out_remove:2299iwl_mld_remove_chanctx(hw, vifs[0].new_ctx);2300out_reassign:2301if (iwl_mld_add_chanctx(hw, vifs[0].old_ctx)) {2302IWL_ERR(mld, "failed to add old_ctx after failure\n");2303return ret;2304}23052306if (iwl_mld_assign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2307vifs[0].old_ctx))2308IWL_ERR(mld, "failed to reassign old_ctx after failure\n");23092310return ret;2311}23122313static int2314iwl_mld_switch_vif_chanctx_reassign(struct ieee80211_hw *hw,2315struct ieee80211_vif_chanctx_switch *vifs)2316{2317struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2318int ret;23192320iwl_mld_unassign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2321vifs[0].old_ctx);2322ret = iwl_mld_assign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2323vifs[0].new_ctx);2324if (ret) {2325IWL_ERR(mld,2326"failed to assign new_ctx during channel switch\n");2327goto out_reassign;2328}23292330return 0;23312332out_reassign:2333if (iwl_mld_assign_vif_chanctx(hw, vifs[0].vif, vifs[0].link_conf,2334vifs[0].old_ctx))2335IWL_ERR(mld, "failed to reassign old_ctx after failure\n");23362337return ret;2338}23392340static int2341iwl_mld_switch_vif_chanctx(struct ieee80211_hw *hw,2342struct ieee80211_vif_chanctx_switch *vifs,2343int n_vifs,2344enum ieee80211_chanctx_switch_mode mode)2345{2346int ret;23472348/* we only support a single-vif right now */2349if (n_vifs > 1)2350return -EOPNOTSUPP;23512352switch (mode) {2353case CHANCTX_SWMODE_SWAP_CONTEXTS:2354ret = iwl_mld_switch_vif_chanctx_swap(hw, vifs);2355break;2356case CHANCTX_SWMODE_REASSIGN_VIF:2357ret = iwl_mld_switch_vif_chanctx_reassign(hw, vifs);2358break;2359default:2360ret = -EOPNOTSUPP;2361break;2362}23632364return ret;2365}23662367static void iwl_mld_sta_pre_rcu_remove(struct ieee80211_hw *hw,2368struct ieee80211_vif *vif,2369struct ieee80211_sta *sta)2370{2371struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2372struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);2373struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);2374struct iwl_mld_link_sta *mld_link_sta;2375u8 link_id;23762377lockdep_assert_wiphy(mld->wiphy);23782379/* This is called before mac80211 does RCU synchronisation,2380* so here we already invalidate our internal RCU-protected2381* station pointer. The rest of the code will thus no longer2382* be able to find the station this way, and we don't rely2383* on further RCU synchronisation after the sta_state()2384* callback deleted the station.2385*/2386for_each_mld_link_sta(mld_sta, mld_link_sta, link_id)2387RCU_INIT_POINTER(mld->fw_id_to_link_sta[mld_link_sta->fw_id],2388NULL);23892390if (sta == mld_vif->ap_sta)2391mld_vif->ap_sta = NULL;2392}23932394static void2395iwl_mld_mac80211_mgd_protect_tdls_discover(struct ieee80211_hw *hw,2396struct ieee80211_vif *vif,2397unsigned int link_id)2398{2399struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2400struct ieee80211_bss_conf *link_conf;2401u32 duration;2402int ret;24032404link_conf = wiphy_dereference(hw->wiphy, vif->link_conf[link_id]);2405if (WARN_ON_ONCE(!link_conf))2406return;24072408/* Protect the session to hear the TDLS setup response on the channel */24092410duration = 2 * link_conf->dtim_period * link_conf->beacon_int;24112412ret = iwl_mld_start_session_protection(mld, vif, duration, duration,2413link_id, HZ / 5);2414if (ret)2415IWL_ERR(mld,2416"Failed to start session protection for TDLS: %d\n",2417ret);2418}24192420static bool iwl_mld_can_activate_links(struct ieee80211_hw *hw,2421struct ieee80211_vif *vif,2422u16 desired_links)2423{2424struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2425int n_links = hweight16(desired_links);24262427/* Check if HW supports the wanted number of links */2428return n_links <= iwl_mld_max_active_links(mld, vif);2429}24302431static int2432iwl_mld_change_vif_links(struct ieee80211_hw *hw,2433struct ieee80211_vif *vif,2434u16 old_links, u16 new_links,2435struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])2436{2437struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);2438struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2439struct ieee80211_bss_conf *link_conf;2440u16 removed = old_links & ~new_links;2441u16 added = new_links & ~old_links;2442int err;24432444lockdep_assert_wiphy(mld->wiphy);24452446/*2447* No bits designate non-MLO mode. We can handle MLO exit/enter by2448* simply mapping that to link ID zero internally.2449* Note that mac80211 does such a non-MLO to MLO switch during restart2450* if it was in MLO before. In that case, we do not have a link to2451* remove.2452*/2453if (old_links == 0 && !mld->fw_status.in_hw_restart)2454removed |= BIT(0);24552456if (new_links == 0)2457added |= BIT(0);24582459for (int i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {2460if (removed & BIT(i) && !WARN_ON(!old[i]))2461iwl_mld_remove_link(mld, old[i]);2462}24632464for (int i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {2465if (added & BIT(i)) {2466link_conf = link_conf_dereference_protected(vif, i);2467if (!link_conf) {2468err = -EINVAL;2469goto remove_added_links;2470}24712472err = iwl_mld_add_link(mld, link_conf);2473if (err)2474goto remove_added_links;2475}2476}24772478/*2479* Ensure we always have a valid primary_link. When using multiple2480* links the proper value is set in assign_vif_chanctx.2481*/2482mld_vif->emlsr.primary = new_links ? __ffs(new_links) : 0;24832484/*2485* Special MLO restart case. We did not have a link when the interface2486* was added, so do the power configuration now.2487*/2488if (old_links == 0 && mld->fw_status.in_hw_restart)2489iwl_mld_update_mac_power(mld, vif, false);24902491return 0;24922493remove_added_links:2494for (int i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {2495if (!(added & BIT(i)))2496continue;24972498link_conf = link_conf_dereference_protected(vif, i);2499if (!link_conf || !iwl_mld_link_from_mac80211(link_conf))2500continue;25012502iwl_mld_remove_link(mld, link_conf);2503}25042505if (WARN_ON(!iwl_mld_error_before_recovery(mld)))2506return err;25072508/* reconfig will fix us anyway */2509return 0;2510}25112512static int iwl_mld_change_sta_links(struct ieee80211_hw *hw,2513struct ieee80211_vif *vif,2514struct ieee80211_sta *sta,2515u16 old_links, u16 new_links)2516{2517struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);25182519return iwl_mld_update_link_stas(mld, vif, sta, old_links, new_links);2520}25212522static int iwl_mld_mac80211_join_ibss(struct ieee80211_hw *hw,2523struct ieee80211_vif *vif)2524{2525return iwl_mld_start_ap_ibss(hw, vif, &vif->bss_conf);2526}25272528static void iwl_mld_mac80211_leave_ibss(struct ieee80211_hw *hw,2529struct ieee80211_vif *vif)2530{2531return iwl_mld_stop_ap_ibss(hw, vif, &vif->bss_conf);2532}25332534static int iwl_mld_mac80211_tx_last_beacon(struct ieee80211_hw *hw)2535{2536struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);25372538return mld->ibss_manager;2539}25402541static void iwl_mld_prep_add_interface(struct ieee80211_hw *hw,2542enum nl80211_iftype type)2543{2544struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);25452546IWL_DEBUG_MAC80211(mld, "prep_add_interface: type=%u\n", type);25472548if (!(type == NL80211_IFTYPE_AP ||2549type == NL80211_IFTYPE_P2P_GO ||2550type == NL80211_IFTYPE_P2P_CLIENT))2551return;25522553iwl_mld_emlsr_block_tmp_non_bss(mld);2554}25552556static int iwl_mld_set_hw_timestamp(struct ieee80211_hw *hw,2557struct ieee80211_vif *vif,2558struct cfg80211_set_hw_timestamp *hwts)2559{2560struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);2561u32 protocols = 0;25622563/* HW timestamping is only supported for a specific station */2564if (!hwts->macaddr)2565return -EOPNOTSUPP;25662567if (hwts->enable)2568protocols =2569IWL_TIME_SYNC_PROTOCOL_TM | IWL_TIME_SYNC_PROTOCOL_FTM;25702571return iwl_mld_time_sync_config(mld, hwts->macaddr, protocols);2572}25732574static int iwl_mld_start_pmsr(struct ieee80211_hw *hw,2575struct ieee80211_vif *vif,2576struct cfg80211_pmsr_request *request)2577{2578struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);25792580return iwl_mld_ftm_start(mld, vif, request);2581}25822583static enum ieee80211_neg_ttlm_res2584iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,2585struct ieee80211_neg_ttlm *neg_ttlm)2586{2587u16 map;25882589/* Verify all TIDs are mapped to the same links set */2590map = neg_ttlm->downlink[0];2591for (int i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {2592if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||2593neg_ttlm->uplink[i] != map)2594return NEG_TTLM_RES_REJECT;2595}25962597return NEG_TTLM_RES_ACCEPT;2598}25992600const struct ieee80211_ops iwl_mld_hw_ops = {2601.tx = iwl_mld_mac80211_tx,2602.start = iwl_mld_mac80211_start,2603.stop = iwl_mld_mac80211_stop,2604.config = iwl_mld_mac80211_config,2605.add_interface = iwl_mld_mac80211_add_interface,2606.remove_interface = iwl_mld_mac80211_remove_interface,2607.conf_tx = iwl_mld_mac80211_conf_tx,2608.prepare_multicast = iwl_mld_mac80211_prepare_multicast,2609.configure_filter = iwl_mld_mac80211_configure_filter,2610.reconfig_complete = iwl_mld_mac80211_reconfig_complete,2611.wake_tx_queue = iwl_mld_mac80211_wake_tx_queue,2612.add_chanctx = iwl_mld_add_chanctx,2613.remove_chanctx = iwl_mld_remove_chanctx,2614.change_chanctx = iwl_mld_change_chanctx,2615.assign_vif_chanctx = iwl_mld_assign_vif_chanctx,2616.unassign_vif_chanctx = iwl_mld_unassign_vif_chanctx,2617.set_rts_threshold = iwl_mld_mac80211_set_rts_threshold,2618.link_info_changed = iwl_mld_mac80211_link_info_changed,2619.vif_cfg_changed = iwl_mld_mac80211_vif_cfg_changed,2620.set_key = iwl_mld_mac80211_set_key,2621.hw_scan = iwl_mld_mac80211_hw_scan,2622.cancel_hw_scan = iwl_mld_mac80211_cancel_hw_scan,2623.sched_scan_start = iwl_mld_mac80211_sched_scan_start,2624.sched_scan_stop = iwl_mld_mac80211_sched_scan_stop,2625.mgd_prepare_tx = iwl_mld_mac80211_mgd_prepare_tx,2626.mgd_complete_tx = iwl_mld_mac_mgd_complete_tx,2627.sta_state = iwl_mld_mac80211_sta_state,2628.sta_statistics = iwl_mld_mac80211_sta_statistics,2629.get_survey = iwl_mld_mac80211_get_survey,2630.flush = iwl_mld_mac80211_flush,2631.flush_sta = iwl_mld_mac80211_flush_sta,2632.ampdu_action = iwl_mld_mac80211_ampdu_action,2633.can_aggregate_in_amsdu = iwl_mld_mac80211_can_aggregate,2634.sync_rx_queues = iwl_mld_mac80211_sync_rx_queues,2635.link_sta_rc_update = iwl_mld_sta_rc_update,2636.start_ap = iwl_mld_start_ap_ibss,2637.stop_ap = iwl_mld_stop_ap_ibss,2638.pre_channel_switch = iwl_mld_pre_channel_switch,2639.channel_switch = iwl_mld_channel_switch,2640.post_channel_switch = iwl_mld_post_channel_switch,2641.abort_channel_switch = iwl_mld_abort_channel_switch,2642.switch_vif_chanctx = iwl_mld_switch_vif_chanctx,2643.sta_pre_rcu_remove = iwl_mld_sta_pre_rcu_remove,2644.remain_on_channel = iwl_mld_start_roc,2645.cancel_remain_on_channel = iwl_mld_cancel_roc,2646.can_activate_links = iwl_mld_can_activate_links,2647.change_vif_links = iwl_mld_change_vif_links,2648.change_sta_links = iwl_mld_change_sta_links,2649#ifdef CONFIG_PM_SLEEP2650.suspend = iwl_mld_suspend,2651.resume = iwl_mld_resume,2652.set_wakeup = iwl_mld_set_wakeup,2653.set_rekey_data = iwl_mld_set_rekey_data,2654#if IS_ENABLED(CONFIG_IPV6)2655.ipv6_addr_change = iwl_mld_ipv6_addr_change,2656#endif /* IS_ENABLED(CONFIG_IPV6) */2657#endif /* CONFIG_PM_SLEEP */2658#ifdef CONFIG_IWLWIFI_DEBUGFS2659.vif_add_debugfs = iwl_mld_add_vif_debugfs,2660.link_add_debugfs = iwl_mld_add_link_debugfs,2661.link_sta_add_debugfs = iwl_mld_add_link_sta_debugfs,2662#endif2663.mgd_protect_tdls_discover = iwl_mld_mac80211_mgd_protect_tdls_discover,2664.join_ibss = iwl_mld_mac80211_join_ibss,2665.leave_ibss = iwl_mld_mac80211_leave_ibss,2666.tx_last_beacon = iwl_mld_mac80211_tx_last_beacon,2667.prep_add_interface = iwl_mld_prep_add_interface,2668.set_hw_timestamp = iwl_mld_set_hw_timestamp,2669.start_pmsr = iwl_mld_start_pmsr,2670.can_neg_ttlm = iwl_mld_can_neg_ttlm,2671};267226732674