xref: /linux/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c (revision a34b0e4e21d6be3c3d620aa7f9dfbf0e9550c19e)
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 
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 				       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 
25 static 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 	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, cmd_ver);
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 			if (cmd_ver == 2)
76 				cmd->wifi_gen_v2.eht_support = cpu_to_le32(1);
77 			else
78 				cmd->wifi_gen.eht_support = 1;
79 			break;
80 		}
81 	}
82 	rcu_read_unlock();
83 }
84 
85 static int iwl_mvm_mld_mac_ctxt_send_cmd(struct iwl_mvm *mvm,
86 					 struct iwl_mac_config_cmd *cmd)
87 {
88 	int ret = iwl_mvm_send_cmd_pdu(mvm,
89 				       WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD),
90 				       0, sizeof(*cmd), cmd);
91 	if (ret)
92 		IWL_ERR(mvm, "Failed to send MAC_CONFIG_CMD (action:%d): %d\n",
93 			le32_to_cpu(cmd->action), ret);
94 	return ret;
95 }
96 
97 static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
98 					struct ieee80211_vif *vif,
99 					u32 action, bool force_assoc_off)
100 {
101 	struct iwl_mac_config_cmd cmd = {};
102 
103 	WARN_ON(vif->type != NL80211_IFTYPE_STATION);
104 
105 	/* Fill the common data for all mac context types */
106 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
107 
108 	/*
109 	 * We always want to hear MCAST frames, if we're not authorized yet,
110 	 * we'll drop them.
111 	 */
112 	cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_GRP);
113 
114 	if (vif->p2p)
115 		cmd.client.ctwin =
116 			iwl_mvm_mac_ctxt_cmd_p2p_sta_get_oppps_ctwin(mvm, vif);
117 
118 	if (vif->cfg.assoc && !force_assoc_off) {
119 		struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
120 
121 		cmd.client.is_assoc = 1;
122 
123 		if (!mvmvif->authorized &&
124 		    fw_has_capa(&mvm->fw->ucode_capa,
125 				IWL_UCODE_TLV_CAPA_COEX_HIGH_PRIO))
126 			cmd.client.data_policy |=
127 				cpu_to_le16(COEX_HIGH_PRIORITY_ENABLE);
128 
129 	} else {
130 		cmd.client.is_assoc = 0;
131 
132 		/* Allow beacons to pass through as long as we are not
133 		 * associated, or we do not have dtim period information.
134 		 */
135 		cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON);
136 	}
137 
138 	cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid);
139 
140 	if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
141 		cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
142 
143 	if (vif->bss_conf.he_support && !iwlwifi_mod_params.disable_11ax)
144 		cmd.client.data_policy |=
145 			cpu_to_le16(iwl_mvm_mac_ctxt_cmd_sta_get_twt_policy(mvm, vif));
146 
147 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
148 }
149 
150 static int iwl_mvm_mld_mac_ctxt_cmd_listener(struct iwl_mvm *mvm,
151 					     struct ieee80211_vif *vif,
152 					     u32 action)
153 {
154 	struct iwl_mac_config_cmd cmd = {};
155 
156 	WARN_ON(vif->type != NL80211_IFTYPE_MONITOR);
157 
158 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
159 
160 	cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_PROMISC |
161 				       MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT |
162 				       MAC_CFG_FILTER_ACCEPT_BEACON |
163 				       MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
164 				       MAC_CFG_FILTER_ACCEPT_GRP);
165 
166 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
167 }
168 
169 static int iwl_mvm_mld_mac_ctxt_cmd_ibss(struct iwl_mvm *mvm,
170 					 struct ieee80211_vif *vif,
171 					 u32 action)
172 {
173 	struct iwl_mac_config_cmd cmd = {};
174 
175 	WARN_ON(vif->type != NL80211_IFTYPE_ADHOC);
176 
177 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
178 
179 	cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_BEACON |
180 				       MAC_CFG_FILTER_ACCEPT_PROBE_REQ |
181 				       MAC_CFG_FILTER_ACCEPT_GRP);
182 
183 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
184 }
185 
186 static int iwl_mvm_mld_mac_ctxt_cmd_p2p_device(struct iwl_mvm *mvm,
187 					       struct ieee80211_vif *vif,
188 					       u32 action)
189 {
190 	struct iwl_mac_config_cmd cmd = {};
191 
192 	WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE);
193 
194 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
195 
196 	cmd.p2p_dev.is_disc_extended =
197 		iwl_mac_ctxt_p2p_dev_has_extended_disc(mvm, vif);
198 
199 	/* Override the filter flags to accept all management frames. This is
200 	 * needed to support both P2P device discovery using probe requests and
201 	 * P2P service discovery using action frames
202 	 */
203 	cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);
204 
205 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
206 }
207 
208 static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
209 					  struct ieee80211_vif *vif,
210 					  u32 action)
211 {
212 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
213 	struct iwl_mac_config_cmd cmd = {};
214 
215 	WARN_ON(vif->type != NL80211_IFTYPE_AP);
216 
217 	/* Fill the common data for all mac context types */
218 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
219 
220 	iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
221 						 &cmd.filter_flags,
222 						 MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
223 						 MAC_CFG_FILTER_ACCEPT_BEACON);
224 
225 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
226 }
227 
228 static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
229 				    struct ieee80211_vif *vif,
230 				    u32 action, bool force_assoc_off)
231 {
232 	switch (vif->type) {
233 	case NL80211_IFTYPE_STATION:
234 		return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
235 						    force_assoc_off);
236 	case NL80211_IFTYPE_AP:
237 		return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);
238 	case NL80211_IFTYPE_MONITOR:
239 		return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);
240 	case NL80211_IFTYPE_P2P_DEVICE:
241 		return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);
242 	case NL80211_IFTYPE_ADHOC:
243 		return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);
244 	default:
245 		break;
246 	}
247 
248 	return -EOPNOTSUPP;
249 }
250 
251 int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
252 {
253 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
254 	int ret;
255 
256 	if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
257 		      vif->addr, ieee80211_vif_type_p2p(vif)))
258 		return -EIO;
259 
260 	ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
261 				       true);
262 	if (ret)
263 		return ret;
264 
265 	/* will only do anything at resume from D3 time */
266 	iwl_mvm_set_last_nonqos_seq(mvm, vif);
267 
268 	mvmvif->uploaded = true;
269 	return 0;
270 }
271 
272 int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
273 				 struct ieee80211_vif *vif,
274 				 bool force_assoc_off)
275 {
276 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
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_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