1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2022 - 2023 Intel Corporation
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)
11 if (vif->type == NL80211_IFTYPE_AP)
12 cmd->he_ap_support = cpu_to_le16(1);
14 cmd->he_support = cpu_to_le16(1);
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,
22 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
23 struct ieee80211_bss_conf *link_conf;
26 cmd->id_and_color = cpu_to_le32(mvmvif->id);
27 cmd->action = cpu_to_le32(action);
29 cmd->mac_type = cpu_to_le32(iwl_mvm_get_mac_type(vif));
31 memcpy(cmd->local_mld_addr, vif->addr, ETH_ALEN);
36 /* should be set by specific context type handler */
37 cmd->filter_flags = 0;
39 cmd->nic_not_ack_enabled =
40 cpu_to_le32(!iwl_mvm_is_nic_ack_enabled(mvm, vif));
42 if (iwlwifi_mod_params.disable_11ax)
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.
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);
60 for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {
61 link_conf = rcu_dereference(vif->link_conf[link_id]);
65 if (link_conf->he_support)
66 iwl_mvm_mld_set_he_support(mvm, vif, cmd);
68 /* it's not reasonable to have EHT without HE and FW API doesn't
69 * support it. Ignore EHT in this case.
71 if (!link_conf->he_support && link_conf->eht_support)
74 if (link_conf->eht_support) {
75 cmd->eht_support = cpu_to_le32(1);
82 static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
83 struct iwl_mac_config_cmd *cmd)
85 int ret = iwl_mvm_send_cmd_pdu(mvm,
86 WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),
87 0, sizeof(*cmd), cmd);
89 IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n",
90 le32_to_cpu(cmd->action), ret);
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)
98 struct iwl_mac_config_cmd cmd = {};
99 u16 esr_transition_timeout;
101 WARN_ON(vif->type != NL80211_IFTYPE_STATION);
103 /* Fill the common data for all mac context types */
104 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
107 * We always want to hear MCAST frames, if we're not authorized yet,
110 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);
114 iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
116 if (vif->cfg.assoc && !force_assoc_off) {
117 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
119 cmd.client.is_assoc = 1;
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);
128 cmd.client.is_assoc = 0;
130 /* Allow beacons to pass through as long as we are not
131 * associated, or we do not have dtim period information.
133 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
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);
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);
149 if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
150 cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
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));
156 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
159 static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
160 struct ieee80211_vif *vif,
163 struct iwl_mac_config_cmd cmd = {};
165 WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
167 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
169 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC |
170 MAC_FILTER_IN_CONTROL_AND_MGMT |
171 MAC_CFG_FILTER_ACCEPT_BEACON |
172 MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
173 MAC_CFG_FILTER_ACCEPT_GRP);
175 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
178 static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
179 struct ieee80211_vif *vif,
182 struct iwl_mac_config_cmd cmd = {};
184 WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
186 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
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);
192 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
195 static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
196 struct ieee80211_vif *vif,
199 struct iwl_mac_config_cmd cmd = {};
201 WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
203 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
205 cmd.p2p_dev.is_disc_extended =
206 iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);
208 /* Override the filter flags to accept only probe requests */
209 cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
211 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
214 static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
215 struct ieee80211_vif *vif,
218 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
219 struct iwl_mac_config_cmd cmd = {};
221 WARN_ON(vif->type != NL80211_IFTYPE_AP);
223 /* Fill the common data for all mac context types */
224 iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
226 iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
228 MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
229 MAC_CFG_FILTER_ACCEPT_BEACON);
231 return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
234 static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
235 struct ieee80211_vif *vif,
236 u32 action, bool force_assoc_off)
239 case NL80211_IFTYPE_STATION:
240 return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
242 case NL80211_IFTYPE_AP:
243 return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);
244 case NL80211_IFTYPE_MONITOR:
245 return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);
246 case NL80211_IFTYPE_P2P_DEVICE:
247 return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);
248 case NL80211_IFTYPE_ADHOC:
249 return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);
257 int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
259 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
262 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
265 if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
266 vif->addr, ieee80211_vif_type_p2p(vif)))
269 ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
274 /* will only do anything at resume from D3 time */
275 iwl_mvm_set_last_nonqos_seq(mvm, vif);
277 mvmvif->uploaded = true;
281 int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
282 struct ieee80211_vif *vif,
283 bool force_assoc_off)
285 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
287 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
290 if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
291 vif->addr, ieee80211_vif_type_p2p(vif)))
294 return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
298 int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
300 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
301 struct iwl_mac_config_cmd cmd = {
302 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
303 .id_and_color = cpu_to_le32(mvmvif->id),
307 if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
310 if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
311 vif->addr, ieee80211_vif_type_p2p(vif)))
314 ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
318 mvmvif->uploaded = false;