19be162a7SMiri Korenblit // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 29be162a7SMiri Korenblit /* 3*59214747SIlan Peer * Copyright (C) 2022 - 2024 Intel Corporation 49be162a7SMiri Korenblit */ 59be162a7SMiri Korenblit #include "mvm.h" 69be162a7SMiri Korenblit 7bb7fcb37SJohannes Berg static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm, 8bb7fcb37SJohannes Berg struct ieee80211_vif *vif, 9bb7fcb37SJohannes Berg struct iwl_mac_config_cmd *cmd) 10bb7fcb37SJohannes Berg { 11bb7fcb37SJohannes Berg if (vif->type == NL80211_IFTYPE_AP) 12bb7fcb37SJohannes Berg cmd->he_ap_support = cpu_to_le16(1); 13bb7fcb37SJohannes Berg else 14bb7fcb37SJohannes Berg cmd->he_support = cpu_to_le16(1); 15bb7fcb37SJohannes Berg } 16bb7fcb37SJohannes Berg 179be162a7SMiri Korenblit static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm, 189be162a7SMiri Korenblit struct ieee80211_vif *vif, 199be162a7SMiri Korenblit struct iwl_mac_config_cmd *cmd, 209be162a7SMiri Korenblit u32 action) 219be162a7SMiri Korenblit { 229be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2336cf5377SGregory Greenman struct ieee80211_bss_conf *link_conf; 2436cf5377SGregory Greenman unsigned int link_id; 259be162a7SMiri Korenblit 269be162a7SMiri Korenblit cmd->id_and_color = cpu_to_le32(mvmvif->id); 279be162a7SMiri Korenblit cmd->action = cpu_to_le32(action); 289be162a7SMiri Korenblit 299be162a7SMiri Korenblit cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif)); 309be162a7SMiri Korenblit 319be162a7SMiri Korenblit memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN); 329be162a7SMiri Korenblit 3336cf5377SGregory Greenman cmd->he_support = 0; 3436cf5377SGregory Greenman cmd->eht_support = 0; 3536cf5377SGregory Greenman 3636cf5377SGregory Greenman /* should be set by specific context type handler */ 3736cf5377SGregory Greenman cmd->filter_flags = 0; 389be162a7SMiri Korenblit 399be162a7SMiri Korenblit cmd->nic_not_ack_enabled = 409be162a7SMiri Korenblit cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif)); 419be162a7SMiri Korenblit 429be162a7SMiri Korenblit if (iwlwifi_mod_params.disable_11ax) 439be162a7SMiri Korenblit return; 449be162a7SMiri Korenblit 4536cf5377SGregory Greenman /* If we have MLO enabled, then the firmware needs to enable 4636cf5377SGregory Greenman * address translation for the station(s) we add. That depends 4736cf5377SGregory Greenman * on having EHT enabled in firmware, which in turn depends on 4836cf5377SGregory Greenman * mac80211 in the code below. 4936cf5377SGregory Greenman * However, mac80211 doesn't enable HE/EHT until it has parsed 5036cf5377SGregory Greenman * the association response successfully, so just skip all that 5136cf5377SGregory Greenman * and enable both when we have MLO. 5236cf5377SGregory Greenman */ 5398d8a003SIlan Peer if (ieee80211_vif_is_mld(vif)) { 54bb7fcb37SJohannes Berg iwl_mvm_mld_set_he_support(mvm, vif, cmd); 5536cf5377SGregory Greenman cmd->eht_support = cpu_to_le32(1); 5636cf5377SGregory Greenman return; 5736cf5377SGregory Greenman } 5836cf5377SGregory Greenman 5936cf5377SGregory Greenman rcu_read_lock(); 6036cf5377SGregory Greenman for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) { 6136cf5377SGregory Greenman link_conf = rcu_dereference(vif->link_conf[link_id]); 6236cf5377SGregory Greenman if (!link_conf) 6336cf5377SGregory Greenman continue; 6436cf5377SGregory Greenman 6536cf5377SGregory Greenman if (link_conf->he_support) 66bb7fcb37SJohannes Berg iwl_mvm_mld_set_he_support(mvm, vif, cmd); 6736cf5377SGregory Greenman 6836cf5377SGregory Greenman /* it's not reasonable to have EHT without HE and FW API doesn't 6936cf5377SGregory Greenman * support it. Ignore EHT in this case. 7036cf5377SGregory Greenman */ 7136cf5377SGregory Greenman if (!link_conf->he_support && link_conf->eht_support) 7236cf5377SGregory Greenman continue; 7336cf5377SGregory Greenman 7436cf5377SGregory Greenman if (link_conf->eht_support) { 7536cf5377SGregory Greenman cmd->eht_support = cpu_to_le32(1); 7636cf5377SGregory Greenman break; 7736cf5377SGregory Greenman } 7836cf5377SGregory Greenman } 7936cf5377SGregory Greenman rcu_read_unlock(); 809be162a7SMiri Korenblit } 819be162a7SMiri Korenblit 829be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm, 839be162a7SMiri Korenblit struct iwl_mac_config_cmd *cmd) 849be162a7SMiri Korenblit { 859be162a7SMiri Korenblit int ret = iwl_mvm_send_cmd_pdu(mvm, 869be162a7SMiri Korenblit WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), 879be162a7SMiri Korenblit 0, sizeof(*cmd), cmd); 889be162a7SMiri Korenblit if (ret) 899be162a7SMiri Korenblit IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n", 909be162a7SMiri Korenblit le32_to_cpu(cmd->action), ret); 919be162a7SMiri Korenblit return ret; 929be162a7SMiri Korenblit } 939be162a7SMiri Korenblit 949be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm, 959be162a7SMiri Korenblit struct ieee80211_vif *vif, 969be162a7SMiri Korenblit u32 action, bool force_assoc_off) 979be162a7SMiri Korenblit { 989be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = {}; 996107f300SEmmanuel Grumbach u16 esr_transition_timeout; 1009be162a7SMiri Korenblit 1019be162a7SMiri Korenblit WARN_ON(vif->type != NL80211_IFTYPE_STATION); 1029be162a7SMiri Korenblit 1039be162a7SMiri Korenblit /* Fill the common data for all mac context types */ 1049be162a7SMiri Korenblit iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 1059be162a7SMiri Korenblit 1069be162a7SMiri Korenblit /* 1079be162a7SMiri Korenblit * We always want to hear MCAST frames, if we're not authorized yet, 1089be162a7SMiri Korenblit * we'll drop them. 1099be162a7SMiri Korenblit */ 1109be162a7SMiri Korenblit cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP); 1119be162a7SMiri Korenblit 1129be162a7SMiri Korenblit if (vif->p2p) 1139be162a7SMiri Korenblit cmd.client.ctwin = 1149be162a7SMiri Korenblit iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif); 1159be162a7SMiri Korenblit 116ac251da9SJohannes Berg if (vif->cfg.assoc && !force_assoc_off) { 1179be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 1189be162a7SMiri Korenblit 1193f302269SEmmanuel Grumbach cmd.client.is_assoc = 1; 1209be162a7SMiri Korenblit 1219be162a7SMiri Korenblit if (!mvmvif->authorized && 1229be162a7SMiri Korenblit fw_has_capa(&mvm->fw->ucode_capa, 1239be162a7SMiri Korenblit IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO)) 1249be162a7SMiri Korenblit cmd.client.data_policy |= 1253f302269SEmmanuel Grumbach cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE); 1269be162a7SMiri Korenblit 1279be162a7SMiri Korenblit } else { 1283f302269SEmmanuel Grumbach cmd.client.is_assoc = 0; 1299be162a7SMiri Korenblit 1309be162a7SMiri Korenblit /* Allow beacons to pass through as long as we are not 1319be162a7SMiri Korenblit * associated, or we do not have dtim period information. 1329be162a7SMiri Korenblit */ 1339be162a7SMiri Korenblit cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON); 1349be162a7SMiri Korenblit } 1359be162a7SMiri Korenblit 1363f302269SEmmanuel Grumbach cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid); 1376107f300SEmmanuel Grumbach if (ieee80211_vif_is_mld(vif)) { 1386107f300SEmmanuel Grumbach esr_transition_timeout = 1396107f300SEmmanuel Grumbach u16_get_bits(vif->cfg.eml_cap, 1406107f300SEmmanuel Grumbach IEEE80211_EML_CAP_TRANSITION_TIMEOUT); 1416107f300SEmmanuel Grumbach 1426107f300SEmmanuel Grumbach cmd.client.esr_transition_timeout = 1436107f300SEmmanuel Grumbach min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU, 1446107f300SEmmanuel Grumbach esr_transition_timeout); 1456107f300SEmmanuel Grumbach cmd.client.medium_sync_delay = 1466107f300SEmmanuel Grumbach cpu_to_le16(vif->cfg.eml_med_sync_delay); 1476107f300SEmmanuel Grumbach } 1489be162a7SMiri Korenblit 1499be162a7SMiri Korenblit if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) 1509be162a7SMiri Korenblit cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); 1519be162a7SMiri Korenblit 1529be162a7SMiri Korenblit if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) 1539be162a7SMiri Korenblit cmd.client.data_policy |= 1543f302269SEmmanuel Grumbach cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif)); 1559be162a7SMiri Korenblit 1569be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 1579be162a7SMiri Korenblit } 1589be162a7SMiri Korenblit 1599be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, 1609be162a7SMiri Korenblit struct ieee80211_vif *vif, 1619be162a7SMiri Korenblit u32 action) 1629be162a7SMiri Korenblit { 1639be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = {}; 1649be162a7SMiri Korenblit 1659be162a7SMiri Korenblit WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); 1669be162a7SMiri Korenblit 1679be162a7SMiri Korenblit iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 1689be162a7SMiri Korenblit 1699be162a7SMiri Korenblit cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC | 1709be162a7SMiri Korenblit MAC_FILTER_IN_CONTROL_AND_MGMT | 1719be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_BEACON | 1729be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_PROBE_REQ | 1739be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_GRP); 1749be162a7SMiri Korenblit 1759be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 1769be162a7SMiri Korenblit } 1779be162a7SMiri Korenblit 1789be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, 1799be162a7SMiri Korenblit struct ieee80211_vif *vif, 1809be162a7SMiri Korenblit u32 action) 1819be162a7SMiri Korenblit { 1829be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = {}; 1839be162a7SMiri Korenblit 1849be162a7SMiri Korenblit WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); 1859be162a7SMiri Korenblit 1869be162a7SMiri Korenblit iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 1879be162a7SMiri Korenblit 1889be162a7SMiri Korenblit cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON | 1899be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_PROBE_REQ | 1909be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_GRP); 1919be162a7SMiri Korenblit 1929be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 1939be162a7SMiri Korenblit } 1949be162a7SMiri Korenblit 1959be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, 1969be162a7SMiri Korenblit struct ieee80211_vif *vif, 1979be162a7SMiri Korenblit u32 action) 1989be162a7SMiri Korenblit { 1999be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = {}; 2009be162a7SMiri Korenblit 2019be162a7SMiri Korenblit WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); 2029be162a7SMiri Korenblit 2039be162a7SMiri Korenblit iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 2049be162a7SMiri Korenblit 2059be162a7SMiri Korenblit cmd.p2p_dev.is_disc_extended = 2069be162a7SMiri Korenblit iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif); 2079be162a7SMiri Korenblit 208*59214747SIlan Peer /* Override the filter flags to accept all management frames. This is 209*59214747SIlan Peer * needed to support both P2P device discovery using probe requests and 210*59214747SIlan Peer * P2P service discovery using action frames 211*59214747SIlan Peer */ 212*59214747SIlan Peer cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT); 2139be162a7SMiri Korenblit 2149be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 2159be162a7SMiri Korenblit } 2169be162a7SMiri Korenblit 2179be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm, 2189be162a7SMiri Korenblit struct ieee80211_vif *vif, 2199be162a7SMiri Korenblit u32 action) 2209be162a7SMiri Korenblit { 2219be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2229be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = {}; 2239be162a7SMiri Korenblit 2249be162a7SMiri Korenblit WARN_ON(vif->type != NL80211_IFTYPE_AP); 2259be162a7SMiri Korenblit 2269be162a7SMiri Korenblit /* Fill the common data for all mac context types */ 2279be162a7SMiri Korenblit iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 2289be162a7SMiri Korenblit 2299be162a7SMiri Korenblit iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif, 2309be162a7SMiri Korenblit &cmd.filter_flags, 2319be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_PROBE_REQ, 2329be162a7SMiri Korenblit MAC_CFG_FILTER_ACCEPT_BEACON); 2339be162a7SMiri Korenblit 2349be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 2359be162a7SMiri Korenblit } 2369be162a7SMiri Korenblit 2379be162a7SMiri Korenblit static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm, 2389be162a7SMiri Korenblit struct ieee80211_vif *vif, 2399be162a7SMiri Korenblit u32 action, bool force_assoc_off) 2409be162a7SMiri Korenblit { 2419be162a7SMiri Korenblit switch (vif->type) { 2429be162a7SMiri Korenblit case NL80211_IFTYPE_STATION: 2439be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action, 2449be162a7SMiri Korenblit force_assoc_off); 2459be162a7SMiri Korenblit case NL80211_IFTYPE_AP: 2469be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action); 2479be162a7SMiri Korenblit case NL80211_IFTYPE_MONITOR: 2489be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action); 2499be162a7SMiri Korenblit case NL80211_IFTYPE_P2P_DEVICE: 2509be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action); 2519be162a7SMiri Korenblit case NL80211_IFTYPE_ADHOC: 2529be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action); 2539be162a7SMiri Korenblit default: 2549be162a7SMiri Korenblit break; 2559be162a7SMiri Korenblit } 2569be162a7SMiri Korenblit 2579be162a7SMiri Korenblit return -EOPNOTSUPP; 2589be162a7SMiri Korenblit } 2599be162a7SMiri Korenblit 2609be162a7SMiri Korenblit int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 2619be162a7SMiri Korenblit { 2629be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2639be162a7SMiri Korenblit int ret; 2649be162a7SMiri Korenblit 2659be162a7SMiri Korenblit if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 2669be162a7SMiri Korenblit return -EOPNOTSUPP; 2679be162a7SMiri Korenblit 2689be162a7SMiri Korenblit if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", 2699be162a7SMiri Korenblit vif->addr, ieee80211_vif_type_p2p(vif))) 2709be162a7SMiri Korenblit return -EIO; 2719be162a7SMiri Korenblit 2729be162a7SMiri Korenblit ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD, 2739be162a7SMiri Korenblit true); 2749be162a7SMiri Korenblit if (ret) 2759be162a7SMiri Korenblit return ret; 2769be162a7SMiri Korenblit 2779be162a7SMiri Korenblit /* will only do anything at resume from D3 time */ 2789be162a7SMiri Korenblit iwl_mvm_set_last_nonqos_seq(mvm, vif); 2799be162a7SMiri Korenblit 2809be162a7SMiri Korenblit mvmvif->uploaded = true; 2819be162a7SMiri Korenblit return 0; 2829be162a7SMiri Korenblit } 2839be162a7SMiri Korenblit 2849be162a7SMiri Korenblit int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, 2859be162a7SMiri Korenblit struct ieee80211_vif *vif, 2869be162a7SMiri Korenblit bool force_assoc_off) 2879be162a7SMiri Korenblit { 2889be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 2899be162a7SMiri Korenblit 2909be162a7SMiri Korenblit if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 2919be162a7SMiri Korenblit return -EOPNOTSUPP; 2929be162a7SMiri Korenblit 2939be162a7SMiri Korenblit if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", 2949be162a7SMiri Korenblit vif->addr, ieee80211_vif_type_p2p(vif))) 2959be162a7SMiri Korenblit return -EIO; 2969be162a7SMiri Korenblit 2979be162a7SMiri Korenblit return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY, 2989be162a7SMiri Korenblit force_assoc_off); 2999be162a7SMiri Korenblit } 3009be162a7SMiri Korenblit 3019be162a7SMiri Korenblit int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 3029be162a7SMiri Korenblit { 3039be162a7SMiri Korenblit struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 3049be162a7SMiri Korenblit struct iwl_mac_config_cmd cmd = { 3059be162a7SMiri Korenblit .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), 3069be162a7SMiri Korenblit .id_and_color = cpu_to_le32(mvmvif->id), 3079be162a7SMiri Korenblit }; 3089be162a7SMiri Korenblit int ret; 3099be162a7SMiri Korenblit 3109be162a7SMiri Korenblit if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 3119be162a7SMiri Korenblit return -EOPNOTSUPP; 3129be162a7SMiri Korenblit 3139be162a7SMiri Korenblit if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", 3149be162a7SMiri Korenblit vif->addr, ieee80211_vif_type_p2p(vif))) 3159be162a7SMiri Korenblit return -EIO; 3169be162a7SMiri Korenblit 3179be162a7SMiri Korenblit ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 3189be162a7SMiri Korenblit if (ret) 3199be162a7SMiri Korenblit return ret; 3209be162a7SMiri Korenblit 3219be162a7SMiri Korenblit mvmvif->uploaded = false; 3229be162a7SMiri Korenblit 3239be162a7SMiri Korenblit return 0; 3249be162a7SMiri Korenblit } 325