325 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2022 - 2024 Intel Corporation4 */5#include "mvm.h"6 7static void iwl_mvm_mld_set_he_support(struct iwl_mvm *mvm,8 struct ieee80211_vif *vif,9 struct iwl_mac_config_cmd *cmd)10{11 if (vif->type == NL80211_IFTYPE_AP)12 cmd->he_ap_support = cpu_to_le16(1);13 else14 cmd->he_support = cpu_to_le16(1);15}16 17static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,18 struct ieee80211_vif *vif,19 struct iwl_mac_config_cmd *cmd,20 u32 action)21{22 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);23 struct ieee80211_bss_conf *link_conf;24 unsigned int link_id;25 26 cmd->id_and_color = cpu_to_le32(mvmvif->id);27 cmd->action = cpu_to_le32(action);28 29 cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif));30 31 memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);32 33 cmd->he_support = 0;34 cmd->eht_support = 0;35 36 /* should be set by specific context type handler */37 cmd->filter_flags = 0;38 39 cmd->nic_not_ack_enabled =40 cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif));41 42 if (iwlwifi_mod_params.disable_11ax)43 return;44 45 /* If we have MLO enabled, then the firmware needs to enable46 * address translation for the station(s) we add. That depends47 * on having EHT enabled in firmware, which in turn depends on48 * mac80211 in the code below.49 * However, mac80211 doesn't enable HE/EHT until it has parsed50 * the association response successfully, so just skip all that51 * and enable both when we have MLO.52 */53 if (ieee80211_vif_is_mld(vif)) {54 iwl_mvm_mld_set_he_support(mvm, vif, cmd);55 cmd->eht_support = cpu_to_le32(1);56 return;57 }58 59 rcu_read_lock();60 for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {61 link_conf = rcu_dereference(vif->link_conf[link_id]);62 if (!link_conf)63 continue;64 65 if (link_conf->he_support)66 iwl_mvm_mld_set_he_support(mvm, vif, cmd);67 68 /* it's not reasonable to have EHT without HE and FW API doesn't69 * support it. Ignore EHT in this case.70 */71 if (!link_conf->he_support && link_conf->eht_support)72 continue;73 74 if (link_conf->eht_support) {75 cmd->eht_support = cpu_to_le32(1);76 break;77 }78 }79 rcu_read_unlock();80}81 82static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,83 struct iwl_mac_config_cmd *cmd)84{85 int ret = iwl_mvm_send_cmd_pdu(mvm,86 WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),87 0, sizeof(*cmd), cmd);88 if (ret)89 IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n",90 le32_to_cpu(cmd->action), ret);91 return ret;92}93 94static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,95 struct ieee80211_vif *vif,96 u32 action, bool force_assoc_off)97{98 struct iwl_mac_config_cmd cmd = {};99 u16 esr_transition_timeout;100 101 WARN_ON(vif->type != NL80211_IFTYPE_STATION);102 103 /* Fill the common data for all mac context types */104 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);105 106 /*107 * We always want to hear MCAST frames, if we're not authorized yet,108 * we'll drop them.109 */110 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);111 112 if (vif->p2p)113 cmd.client.ctwin =114 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);115 116 if (vif->cfg.assoc && !force_assoc_off) {117 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);118 119 cmd.client.is_assoc = 1;120 121 if (!mvmvif->authorized &&122 fw_has_capa(&mvm->fw->ucode_capa,123 IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))124 cmd.client.data_policy |=125 cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE);126 127 } else {128 cmd.client.is_assoc = 0;129 130 /* Allow beacons to pass through as long as we are not131 * associated, or we do not have dtim period information.132 */133 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);134 }135 136 cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid);137 if (ieee80211_vif_is_mld(vif)) {138 esr_transition_timeout =139 u16_get_bits(vif->cfg.eml_cap,140 IEEE80211_EML_CAP_TRANSITION_TIMEOUT);141 142 cmd.client.esr_transition_timeout =143 min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU,144 esr_transition_timeout);145 cmd.client.medium_sync_delay =146 cpu_to_le16(vif->cfg.eml_med_sync_delay);147 }148 149 if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)150 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);151 152 if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)153 cmd.client.data_policy |=154 cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif));155 156 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);157}158 159static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,160 struct ieee80211_vif *vif,161 u32 action)162{163 struct iwl_mac_config_cmd cmd = {};164 165 WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);166 167 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);168 169 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC |170 MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT |171 MAC_CFG_FILTER_ACCEPT_BEACON |172 MAC_CFG_FILTER_ACCEPT_PROBE_REQ |173 MAC_CFG_FILTER_ACCEPT_GRP);174 175 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);176}177 178static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,179 struct ieee80211_vif *vif,180 u32 action)181{182 struct iwl_mac_config_cmd cmd = {};183 184 WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);185 186 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);187 188 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON |189 MAC_CFG_FILTER_ACCEPT_PROBE_REQ |190 MAC_CFG_FILTER_ACCEPT_GRP);191 192 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);193}194 195static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,196 struct ieee80211_vif *vif,197 u32 action)198{199 struct iwl_mac_config_cmd cmd = {};200 201 WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);202 203 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);204 205 cmd.p2p_dev.is_disc_extended =206 iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);207 208 /* Override the filter flags to accept all management frames. This is209 * needed to support both P2P device discovery using probe requests and210 * P2P service discovery using action frames211 */212 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);213 214 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);215}216 217static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,218 struct ieee80211_vif *vif,219 u32 action)220{221 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);222 struct iwl_mac_config_cmd cmd = {};223 224 WARN_ON(vif->type != NL80211_IFTYPE_AP);225 226 /* Fill the common data for all mac context types */227 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);228 229 iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,230 &cmd.filter_flags,231 MAC_CFG_FILTER_ACCEPT_PROBE_REQ,232 MAC_CFG_FILTER_ACCEPT_BEACON);233 234 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);235}236 237static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,238 struct ieee80211_vif *vif,239 u32 action, bool force_assoc_off)240{241 switch (vif->type) {242 case NL80211_IFTYPE_STATION:243 return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,244 force_assoc_off);245 case NL80211_IFTYPE_AP:246 return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);247 case NL80211_IFTYPE_MONITOR:248 return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);249 case NL80211_IFTYPE_P2P_DEVICE:250 return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);251 case NL80211_IFTYPE_ADHOC:252 return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);253 default:254 break;255 }256 257 return -EOPNOTSUPP;258}259 260int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)261{262 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);263 int ret;264 265 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))266 return -EOPNOTSUPP;267 268 if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",269 vif->addr, ieee80211_vif_type_p2p(vif)))270 return -EIO;271 272 ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,273 true);274 if (ret)275 return ret;276 277 /* will only do anything at resume from D3 time */278 iwl_mvm_set_last_nonqos_seq(mvm, vif);279 280 mvmvif->uploaded = true;281 return 0;282}283 284int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,285 struct ieee80211_vif *vif,286 bool force_assoc_off)287{288 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);289 290 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))291 return -EOPNOTSUPP;292 293 if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",294 vif->addr, ieee80211_vif_type_p2p(vif)))295 return -EIO;296 297 return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,298 force_assoc_off);299}300 301int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)302{303 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);304 struct iwl_mac_config_cmd cmd = {305 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),306 .id_and_color = cpu_to_le32(mvmvif->id),307 };308 int ret;309 310 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))311 return -EOPNOTSUPP;312 313 if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",314 vif->addr, ieee80211_vif_type_p2p(vif)))315 return -EIO;316 317 ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);318 if (ret)319 return ret;320 321 mvmvif->uploaded = false;322 323 return 0;324}325