xref: /linux/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c (revision ae22a94997b8a03dcb3c922857c203246711f9d4)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2022 - 2024 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 (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 
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 	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 
159 static 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_CFG_FILTER_ACCEPT_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 
178 static 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 
195 static 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 all management frames. This is
209 	 * needed to support both P2P device discovery using probe requests and
210 	 * P2P service discovery using action frames
211 	 */
212 	cmd.filter_flags = cpu_to_le32(MAC_CFG_FILTER_ACCEPT_CONTROL_AND_MGMT);
213 
214 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
215 }
216 
217 static int iwl_mvm_mld_mac_ctxt_cmd_ap_go(struct iwl_mvm *mvm,
218 					  struct ieee80211_vif *vif,
219 					  u32 action)
220 {
221 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
222 	struct iwl_mac_config_cmd cmd = {};
223 
224 	WARN_ON(vif->type != NL80211_IFTYPE_AP);
225 
226 	/* Fill the common data for all mac context types */
227 	iwl_mvm_mld_mac_ctxt_cmd_common(mvm, vif, &cmd, action);
228 
229 	iwl_mvm_mac_ctxt_cmd_ap_set_filter_flags(mvm, mvmvif,
230 						 &cmd.filter_flags,
231 						 MAC_CFG_FILTER_ACCEPT_PROBE_REQ,
232 						 MAC_CFG_FILTER_ACCEPT_BEACON);
233 
234 	return iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
235 }
236 
237 static int iwl_mvm_mld_mac_ctx_send(struct iwl_mvm *mvm,
238 				    struct ieee80211_vif *vif,
239 				    u32 action, bool force_assoc_off)
240 {
241 	switch (vif->type) {
242 	case NL80211_IFTYPE_STATION:
243 		return iwl_mvm_mld_mac_ctxt_cmd_sta(mvm, vif, action,
244 						    force_assoc_off);
245 	case NL80211_IFTYPE_AP:
246 		return iwl_mvm_mld_mac_ctxt_cmd_ap_go(mvm, vif, action);
247 	case NL80211_IFTYPE_MONITOR:
248 		return iwl_mvm_mld_mac_ctxt_cmd_listener(mvm, vif, action);
249 	case NL80211_IFTYPE_P2P_DEVICE:
250 		return iwl_mvm_mld_mac_ctxt_cmd_p2p_device(mvm, vif, action);
251 	case NL80211_IFTYPE_ADHOC:
252 		return iwl_mvm_mld_mac_ctxt_cmd_ibss(mvm, vif, action);
253 	default:
254 		break;
255 	}
256 
257 	return -EOPNOTSUPP;
258 }
259 
260 int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
261 {
262 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
263 	int ret;
264 
265 	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
266 		return -EOPNOTSUPP;
267 
268 	if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n",
269 		      vif->addr, ieee80211_vif_type_p2p(vif)))
270 		return -EIO;
271 
272 	ret = iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_ADD,
273 				       true);
274 	if (ret)
275 		return ret;
276 
277 	/* will only do anything at resume from D3 time */
278 	iwl_mvm_set_last_nonqos_seq(mvm, vif);
279 
280 	mvmvif->uploaded = true;
281 	return 0;
282 }
283 
284 int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm,
285 				 struct ieee80211_vif *vif,
286 				 bool force_assoc_off)
287 {
288 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
289 
290 	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
291 		return -EOPNOTSUPP;
292 
293 	if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n",
294 		      vif->addr, ieee80211_vif_type_p2p(vif)))
295 		return -EIO;
296 
297 	return iwl_mvm_mld_mac_ctx_send(mvm, vif, FW_CTXT_ACTION_MODIFY,
298 					force_assoc_off);
299 }
300 
301 int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
302 {
303 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
304 	struct iwl_mac_config_cmd cmd = {
305 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
306 		.id_and_color = cpu_to_le32(mvmvif->id),
307 	};
308 	int ret;
309 
310 	if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN))
311 		return -EOPNOTSUPP;
312 
313 	if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n",
314 		      vif->addr, ieee80211_vif_type_p2p(vif)))
315 		return -EIO;
316 
317 	ret = iwl_mvm_mld_mac_ctxt_send_cmd(mvm, &cmd);
318 	if (ret)
319 		return ret;
320 
321 	mvmvif->uploaded = false;
322 
323 	return 0;
324 }
325