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