Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
  2/*
  3 * Copyright (C) 2022 - 2023 Intel Corporation
  4 */
  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	else
 14		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 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 (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'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
 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 not
131		 * 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_FILTER_IN_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 only probe requests */
209	cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
210
211	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
212}
213
214static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
215					  struct ieee80211_vif *vif,
216					  u32 action)
217{
218	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
219	struct iwl_mac_config_cmd cmd = {};
220
221	WARN_ON(vif->type != NL80211_IFTYPE_AP);
222
223	/* Fill the common data for all mac context types */
224	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
225
226	iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
227						 &cmd.filter_flags,
228						 MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
229						 MAC_CFG_FILTER_ACCEPT_BEACON);
230
231	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
232}
233
234static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
235				    struct ieee80211_vif *vif,
236				    u32 action, bool force_assoc_off)
237{
238	switch (vif->type) {
239	case NL80211_IFTYPE_STATION:
240		return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
241						    force_assoc_off);
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);
250	default:
251		break;
252	}
253
254	return -EOPNOTSUPP;
255}
256
257int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
258{
259	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
260	int ret;
261
262	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
263		return -EOPNOTSUPP;
264
265	if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
266		      vif->addr, ieee80211_vif_type_p2p(vif)))
267		return -EIO;
268
269	ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
270				       true);
271	if (ret)
272		return ret;
273
274	/* will only do anything at resume from D3 time */
275	iwl_mvm_set_last_nonqos_seq(mvm, vif);
276
277	mvmvif->uploaded = true;
278	return 0;
279}
280
281int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
282				 struct ieee80211_vif *vif,
283				 bool force_assoc_off)
284{
285	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
286
287	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
288		return -EOPNOTSUPP;
289
290	if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
291		      vif->addr, ieee80211_vif_type_p2p(vif)))
292		return -EIO;
293
294	return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
295					force_assoc_off);
296}
297
298int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
299{
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),
304	};
305	int ret;
306
307	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
308		return -EOPNOTSUPP;
309
310	if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
311		      vif->addr, ieee80211_vif_type_p2p(vif)))
312		return -EIO;
313
314	ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
315	if (ret)
316		return ret;
317
318	mvmvif->uploaded = false;
319
320	return 0;
321}