• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright (C) 2022 - 2024 Intel Corporation
4  */
5 #include <linux/kernel.h>
6 #include <net/mac80211.h>
7 #include "mvm.h"
8 #include "fw/api/context.h"
9 #include "fw/api/datapath.h"
10 
iwl_mvm_get_sec_sta_mask(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)11 static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
12 				    struct ieee80211_vif *vif,
13 				    struct ieee80211_sta *sta,
14 				    struct ieee80211_key_conf *keyconf)
15 {
16 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
17 	struct iwl_mvm_vif_link_info *link_info = &mvmvif->deflink;
18 
19 	lockdep_assert_held(&mvm->mutex);
20 
21 	if (keyconf->link_id >= 0) {
22 		link_info = mvmvif->link[keyconf->link_id];
23 		if (!link_info)
24 			return 0;
25 	}
26 
27 	/* AP group keys are per link and should be on the mcast/bcast STA */
28 	if (vif->type == NL80211_IFTYPE_AP &&
29 	    !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
30 		/* IGTK/BIGTK to bcast STA */
31 		if (keyconf->keyidx >= 4)
32 			return BIT(link_info->bcast_sta.sta_id);
33 		/* GTK for data to mcast STA */
34 		return BIT(link_info->mcast_sta.sta_id);
35 	}
36 
37 	/* for client mode use the AP STA also for group keys */
38 	if (!sta && vif->type == NL80211_IFTYPE_STATION)
39 		sta = mvmvif->ap_sta;
40 
41 	/* During remove the STA was removed and the group keys come later
42 	 * (which sounds like a bad sequence, but remember that to mac80211 the
43 	 * group keys have no sta pointer), so we don't have a STA now.
44 	 * Since this happens for group keys only, just use the link_info as
45 	 * the group keys are per link; make sure that is the case by checking
46 	 * we do have a link_id or are not doing MLO.
47 	 * Of course the same can be done during add as well, but we must do
48 	 * it during remove, since we don't have the mvmvif->ap_sta pointer.
49 	 */
50 	if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif)))
51 		return BIT(link_info->ap_sta_id);
52 
53 	/* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */
54 
55 	/* pass link_id to filter by it if not -1 (GTK on client) */
56 	return iwl_mvm_sta_fw_id_mask(mvm, sta, keyconf->link_id);
57 }
58 
iwl_mvm_get_sec_flags(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)59 u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
60 			  struct ieee80211_vif *vif,
61 			  struct ieee80211_sta *sta,
62 			  struct ieee80211_key_conf *keyconf)
63 {
64 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
65 	bool pairwise = keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE;
66 	bool igtk = keyconf->keyidx == 4 || keyconf->keyidx == 5;
67 	u32 flags = 0;
68 
69 	lockdep_assert_held(&mvm->mutex);
70 
71 	if (!pairwise)
72 		flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
73 
74 	switch (keyconf->cipher) {
75 	case WLAN_CIPHER_SUITE_WEP104:
76 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
77 		fallthrough;
78 	case WLAN_CIPHER_SUITE_WEP40:
79 		flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
80 		break;
81 	case WLAN_CIPHER_SUITE_TKIP:
82 		flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
83 		break;
84 	case WLAN_CIPHER_SUITE_AES_CMAC:
85 	case WLAN_CIPHER_SUITE_CCMP:
86 		flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
87 		break;
88 	case WLAN_CIPHER_SUITE_GCMP_256:
89 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
90 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
91 		fallthrough;
92 	case WLAN_CIPHER_SUITE_GCMP:
93 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
94 		flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
95 		break;
96 	}
97 
98 	if (!sta && vif->type == NL80211_IFTYPE_STATION)
99 		sta = mvmvif->ap_sta;
100 
101 	/*
102 	 * If we are installing an iGTK (in AP or STA mode), we need to tell
103 	 * the firmware this key will en/decrypt MGMT frames.
104 	 * Same goes if we are installing a pairwise key for an MFP station.
105 	 * In case we're installing a groupwise key (which is not an iGTK),
106 	 * then, we will not use this key for MGMT frames.
107 	 */
108 	if ((!IS_ERR_OR_NULL(sta) && sta->mfp && pairwise) || igtk)
109 		flags |= IWL_SEC_KEY_FLAG_MFP;
110 
111 	return flags;
112 }
113 
114 struct iwl_mvm_sta_key_update_data {
115 	struct ieee80211_sta *sta;
116 	u32 old_sta_mask;
117 	u32 new_sta_mask;
118 	int err;
119 };
120 
iwl_mvm_mld_update_sta_key(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key,void * _data)121 static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
122 				       struct ieee80211_vif *vif,
123 				       struct ieee80211_sta *sta,
124 				       struct ieee80211_key_conf *key,
125 				       void *_data)
126 {
127 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
128 	struct iwl_mvm_sta_key_update_data *data = _data;
129 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
130 	struct iwl_sec_key_cmd cmd = {
131 		.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
132 		.u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
133 		.u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
134 		.u.modify.key_id = cpu_to_le32(key->keyidx),
135 		.u.modify.key_flags =
136 			cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)),
137 	};
138 	int err;
139 
140 	/* only need to do this for pairwise keys (link_id == -1) */
141 	if (sta != data->sta || key->link_id >= 0)
142 		return;
143 
144 	err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cmd), &cmd);
145 
146 	if (err)
147 		data->err = err;
148 }
149 
iwl_mvm_mld_update_sta_keys(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u32 old_sta_mask,u32 new_sta_mask)150 int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
151 				struct ieee80211_vif *vif,
152 				struct ieee80211_sta *sta,
153 				u32 old_sta_mask,
154 				u32 new_sta_mask)
155 {
156 	struct iwl_mvm_sta_key_update_data data = {
157 		.sta = sta,
158 		.old_sta_mask = old_sta_mask,
159 		.new_sta_mask = new_sta_mask,
160 	};
161 
162 	ieee80211_iter_keys_rcu(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
163 				&data);
164 	return data.err;
165 }
166 
__iwl_mvm_sec_key_del(struct iwl_mvm * mvm,u32 sta_mask,u32 key_flags,u32 keyidx,u32 flags)167 static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
168 				 u32 key_flags, u32 keyidx, u32 flags)
169 {
170 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
171 	struct iwl_sec_key_cmd cmd = {
172 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
173 		.u.remove.sta_mask = cpu_to_le32(sta_mask),
174 		.u.remove.key_id = cpu_to_le32(keyidx),
175 		.u.remove.key_flags = cpu_to_le32(key_flags),
176 	};
177 
178 	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
179 }
180 
iwl_mvm_mld_send_key(struct iwl_mvm * mvm,u32 sta_mask,u32 key_flags,struct ieee80211_key_conf * keyconf)181 int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
182 			 struct ieee80211_key_conf *keyconf)
183 {
184 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
185 	struct iwl_sec_key_cmd cmd = {
186 		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
187 		.u.add.sta_mask = cpu_to_le32(sta_mask),
188 		.u.add.key_id = cpu_to_le32(keyconf->keyidx),
189 		.u.add.key_flags = cpu_to_le32(key_flags),
190 		.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
191 	};
192 	int max_key_len = sizeof(cmd.u.add.key);
193 	int ret;
194 
195 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
196 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
197 		max_key_len -= IWL_SEC_WEP_KEY_OFFSET;
198 
199 	if (WARN_ON(keyconf->keylen > max_key_len))
200 		return -EINVAL;
201 
202 	if (WARN_ON(!sta_mask))
203 		return -EINVAL;
204 
205 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
206 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
207 		memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
208 		       keyconf->keylen);
209 	else
210 		memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
211 
212 	if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
213 		memcpy(cmd.u.add.tkip_mic_rx_key,
214 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
215 		       8);
216 		memcpy(cmd.u.add.tkip_mic_tx_key,
217 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
218 		       8);
219 	}
220 
221 	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
222 	if (ret)
223 		return ret;
224 
225 	/*
226 	 * For WEP, the same key is used for multicast and unicast so need to
227 	 * upload it again. If this fails, remove the original as well.
228 	 */
229 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
230 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
231 		cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
232 		ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
233 		if (ret)
234 			__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
235 					      keyconf->keyidx, 0);
236 	}
237 
238 	return ret;
239 }
240 
iwl_mvm_sec_key_add(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)241 int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
242 			struct ieee80211_vif *vif,
243 			struct ieee80211_sta *sta,
244 			struct ieee80211_key_conf *keyconf)
245 {
246 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
247 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
248 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
249 	struct iwl_mvm_vif_link_info *mvm_link = NULL;
250 	int ret;
251 
252 	if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
253 		unsigned int link_id = 0;
254 
255 		/* set to -1 for non-MLO right now */
256 		if (keyconf->link_id >= 0)
257 			link_id = keyconf->link_id;
258 
259 		mvm_link = mvmvif->link[link_id];
260 		if (WARN_ON(!mvm_link))
261 			return -EINVAL;
262 
263 		if (mvm_link->igtk) {
264 			IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n",
265 					   mvm_link->igtk->keyidx);
266 			ret = iwl_mvm_sec_key_del(mvm, vif, sta,
267 						  mvm_link->igtk);
268 			if (ret)
269 				IWL_ERR(mvm,
270 					"failed to remove old IGTK (ret=%d)\n",
271 					ret);
272 		}
273 
274 		WARN_ON(mvm_link->igtk);
275 	}
276 
277 	ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
278 	if (ret)
279 		return ret;
280 
281 	if (mvm_link)
282 		mvm_link->igtk = keyconf;
283 
284 	/* We don't really need this, but need it to be not invalid,
285 	 * and if we switch links multiple times it might go to be
286 	 * invalid when removed.
287 	 */
288 	keyconf->hw_key_idx = 0;
289 
290 	return 0;
291 }
292 
_iwl_mvm_sec_key_del(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf,u32 flags)293 static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
294 				struct ieee80211_vif *vif,
295 				struct ieee80211_sta *sta,
296 				struct ieee80211_key_conf *keyconf,
297 				u32 flags)
298 {
299 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
300 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
301 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
302 	int ret;
303 
304 	if (WARN_ON(!sta_mask))
305 		return -EINVAL;
306 
307 	if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
308 		struct iwl_mvm_vif_link_info *mvm_link;
309 		unsigned int link_id = 0;
310 
311 		/* set to -1 for non-MLO right now */
312 		if (keyconf->link_id >= 0)
313 			link_id = keyconf->link_id;
314 
315 		mvm_link = mvmvif->link[link_id];
316 		if (WARN_ON(!mvm_link))
317 			return -EINVAL;
318 
319 		if (mvm_link->igtk == keyconf) {
320 			/* no longer in HW - mark for later */
321 			mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
322 			mvm_link->igtk = NULL;
323 		}
324 	}
325 
326 	ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
327 				    flags);
328 	if (ret)
329 		return ret;
330 
331 	/* For WEP, delete the key again as unicast */
332 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
333 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
334 		key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
335 		ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
336 					    keyconf->keyidx, flags);
337 	}
338 
339 	return ret;
340 }
341 
iwl_mvm_sec_key_del(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * keyconf)342 int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
343 			struct ieee80211_vif *vif,
344 			struct ieee80211_sta *sta,
345 			struct ieee80211_key_conf *keyconf)
346 {
347 	return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
348 }
349 
iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key,void * data)350 static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
351 					   struct ieee80211_vif *vif,
352 					   struct ieee80211_sta *sta,
353 					   struct ieee80211_key_conf *key,
354 					   void *data)
355 {
356 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
357 	unsigned int link_id = (uintptr_t)data;
358 
359 	if (key->hw_key_idx == STA_KEY_IDX_INVALID)
360 		return;
361 
362 	if (sta)
363 		return;
364 
365 	if (key->link_id >= 0 && key->link_id != link_id)
366 		return;
367 
368 	_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
369 	key->hw_key_idx = STA_KEY_IDX_INVALID;
370 }
371 
iwl_mvm_sec_key_remove_ap(struct iwl_mvm * mvm,struct ieee80211_vif * vif,struct iwl_mvm_vif_link_info * link,unsigned int link_id)372 void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
373 			       struct ieee80211_vif *vif,
374 			       struct iwl_mvm_vif_link_info *link,
375 			       unsigned int link_id)
376 {
377 	u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
378 	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
379 
380 	if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
381 			 link->ap_sta_id == IWL_MVM_INVALID_STA))
382 		return;
383 
384 	if (!sec_key_ver)
385 		return;
386 
387 	ieee80211_iter_keys_rcu(mvm->hw, vif,
388 				iwl_mvm_sec_key_remove_ap_iter,
389 				(void *)(uintptr_t)link_id);
390 }
391