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_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 else 14 cmd->he_support = cpu_to_le16(1); 15 } 16 17 static 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 enable 46 * address translation for the station(s) we add. That depends 47 * on having EHT enabled in firmware, which in turn depends on 48 * mac80211 in the code below. 49 * However, mac80211 doesn't enable HE/EHT until it has parsed 50 * the association response successfully, so just skip all that 51 * and enable both when we have MLO. 52 */ 53 if (vif->valid_links) { 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't 69 * 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 82 static 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 94 static 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 100 WARN_ON(vif->type != NL80211_IFTYPE_STATION); 101 102 /* Fill the common data for all mac context types */ 103 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 104 105 /* 106 * We always want to hear MCAST frames, if we're not authorized yet, 107 * we'll drop them. 108 */ 109 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP); 110 111 if (vif->p2p) 112 cmd.client.ctwin = 113 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif); 114 115 if (vif->cfg.assoc && !force_assoc_off) { 116 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 117 118 cmd.client.is_assoc = cpu_to_le32(1); 119 120 if (!mvmvif->authorized && 121 fw_has_capa(&mvm->fw->ucode_capa, 122 IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO)) 123 cmd.client.data_policy |= 124 cpu_to_le32(COEX_HIGH_PRIORITY_ENABLE); 125 126 } else { 127 cmd.client.is_assoc = cpu_to_le32(0); 128 129 /* Allow beacons to pass through as long as we are not 130 * associated, or we do not have dtim period information. 131 */ 132 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON); 133 } 134 135 cmd.client.assoc_id = cpu_to_le32(vif->cfg.aid); 136 137 if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p) 138 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); 139 140 if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax) 141 cmd.client.data_policy |= 142 iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif); 143 144 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 145 } 146 147 static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm, 148 struct ieee80211_vif *vif, 149 u32 action) 150 { 151 struct iwl_mac_config_cmd cmd = {}; 152 153 WARN_ON(vif->type != NL80211_IFTYPE_MONITOR); 154 155 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 156 157 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC | 158 MAC_FILTER_IN_CONTROL_AND_MGMT | 159 MAC_CFG_FILTER_ACCEPT_BEACON | 160 MAC_CFG_FILTER_ACCEPT_PROBE_REQ | 161 MAC_CFG_FILTER_ACCEPT_GRP); 162 163 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 164 } 165 166 static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm, 167 struct ieee80211_vif *vif, 168 u32 action) 169 { 170 struct iwl_mac_config_cmd cmd = {}; 171 172 WARN_ON(vif->type != NL80211_IFTYPE_ADHOC); 173 174 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 175 176 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON | 177 MAC_CFG_FILTER_ACCEPT_PROBE_REQ | 178 MAC_CFG_FILTER_ACCEPT_GRP); 179 180 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 181 } 182 183 static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm, 184 struct ieee80211_vif *vif, 185 u32 action) 186 { 187 struct iwl_mac_config_cmd cmd = {}; 188 189 WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE); 190 191 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 192 193 cmd.p2p_dev.is_disc_extended = 194 iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif); 195 196 /* Override the filter flags to accept only probe requests */ 197 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ); 198 199 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 200 } 201 202 static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm, 203 struct ieee80211_vif *vif, 204 u32 action) 205 { 206 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 207 struct iwl_mac_config_cmd cmd = {}; 208 209 WARN_ON(vif->type != NL80211_IFTYPE_AP); 210 211 /* Fill the common data for all mac context types */ 212 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action); 213 214 iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif, 215 &cmd.filter_flags, 216 MAC_CFG_FILTER_ACCEPT_PROBE_REQ, 217 MAC_CFG_FILTER_ACCEPT_BEACON); 218 219 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 220 } 221 222 static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm, 223 struct ieee80211_vif *vif, 224 u32 action, bool force_assoc_off) 225 { 226 switch (vif->type) { 227 case NL80211_IFTYPE_STATION: 228 return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action, 229 force_assoc_off); 230 case NL80211_IFTYPE_AP: 231 return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action); 232 case NL80211_IFTYPE_MONITOR: 233 return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action); 234 case NL80211_IFTYPE_P2P_DEVICE: 235 return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action); 236 case NL80211_IFTYPE_ADHOC: 237 return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action); 238 default: 239 break; 240 } 241 242 return -EOPNOTSUPP; 243 } 244 245 int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 246 { 247 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 248 int ret; 249 250 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 251 return -EOPNOTSUPP; 252 253 if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", 254 vif->addr, ieee80211_vif_type_p2p(vif))) 255 return -EIO; 256 257 ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD, 258 true); 259 if (ret) 260 return ret; 261 262 /* will only do anything at resume from D3 time */ 263 iwl_mvm_set_last_nonqos_seq(mvm, vif); 264 265 mvmvif->uploaded = true; 266 return 0; 267 } 268 269 int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, 270 struct ieee80211_vif *vif, 271 bool force_assoc_off) 272 { 273 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 274 275 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 276 return -EOPNOTSUPP; 277 278 if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", 279 vif->addr, ieee80211_vif_type_p2p(vif))) 280 return -EIO; 281 282 return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY, 283 force_assoc_off); 284 } 285 286 int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) 287 { 288 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 289 struct iwl_mac_config_cmd cmd = { 290 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), 291 .id_and_color = cpu_to_le32(mvmvif->id), 292 }; 293 int ret; 294 295 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) 296 return -EOPNOTSUPP; 297 298 if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", 299 vif->addr, ieee80211_vif_type_p2p(vif))) 300 return -EIO; 301 302 ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd); 303 if (ret) 304 return ret; 305 306 mvmvif->uploaded = false; 307 308 return 0; 309 } 310