File Index
Files and directories
Sign in
FILE

mld-mac.c

File preview with syntax highlighting.

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