1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright (C) 2022 - 2024 Intel Corporation
5 #include <linux/kernel.h>
6 #include <net/mac80211.h>
8 #include "fw/api/context.h"
9 #include "fw/api/datapath.h"
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)
16 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
17 struct iwl_mvm_vif_link_info *link_info = &mvmvif->deflink;
19 lockdep_assert_held(&mvm->mutex);
21 if (keyconf->link_id >= 0) {
22 link_info = mvmvif->link[keyconf->link_id];
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);
37 /* for client mode use the AP STA also for group keys */
38 if (!sta && vif->type == NL80211_IFTYPE_STATION)
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.
50 if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif)))
51 return BIT(link_info->ap_sta_id);
53 /* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */
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);
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)
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;
69 lockdep_assert_held(&mvm->mutex);
72 flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
74 switch (keyconf->cipher) {
75 case WLAN_CIPHER_SUITE_WEP104:
76 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
78 case WLAN_CIPHER_SUITE_WEP40:
79 flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
81 case WLAN_CIPHER_SUITE_TKIP:
82 flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
84 case WLAN_CIPHER_SUITE_AES_CMAC:
85 case WLAN_CIPHER_SUITE_CCMP:
86 flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
88 case WLAN_CIPHER_SUITE_GCMP_256:
89 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
90 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
92 case WLAN_CIPHER_SUITE_GCMP:
93 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
94 flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
98 if (!sta && vif->type == NL80211_IFTYPE_STATION)
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.
108 if ((!IS_ERR_OR_NULL(sta) && sta->mfp && pairwise) || igtk)
109 flags |= IWL_SEC_KEY_FLAG_MFP;
111 if (keyconf->flags & IEEE80211_KEY_FLAG_SPP_AMSDU)
112 flags |= IWL_SEC_KEY_FLAG_SPP_AMSDU;
117 struct iwl_mvm_sta_key_update_data {
118 struct ieee80211_sta *sta;
124 static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
125 struct ieee80211_vif *vif,
126 struct ieee80211_sta *sta,
127 struct ieee80211_key_conf *key,
130 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
131 struct iwl_mvm_sta_key_update_data *data = _data;
132 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
133 struct iwl_sec_key_cmd cmd = {
134 .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
135 .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
136 .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
137 .u.modify.key_id = cpu_to_le32(key->keyidx),
138 .u.modify.key_flags =
139 cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)),
143 /* only need to do this for pairwise keys (link_id == -1) */
144 if (sta != data->sta || key->link_id >= 0)
147 err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
153 int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
154 struct ieee80211_vif *vif,
155 struct ieee80211_sta *sta,
159 struct iwl_mvm_sta_key_update_data data = {
161 .old_sta_mask = old_sta_mask,
162 .new_sta_mask = new_sta_mask,
165 ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
170 static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
171 u32 key_flags, u32 keyidx, u32 flags)
173 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
174 struct iwl_sec_key_cmd cmd = {
175 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
176 .u.remove.sta_mask = cpu_to_le32(sta_mask),
177 .u.remove.key_id = cpu_to_le32(keyidx),
178 .u.remove.key_flags = cpu_to_le32(key_flags),
181 return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
184 int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
185 struct ieee80211_key_conf *keyconf)
187 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
188 struct iwl_sec_key_cmd cmd = {
189 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
190 .u.add.sta_mask = cpu_to_le32(sta_mask),
191 .u.add.key_id = cpu_to_le32(keyconf->keyidx),
192 .u.add.key_flags = cpu_to_le32(key_flags),
193 .u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
195 int max_key_len = sizeof(cmd.u.add.key);
198 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
199 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
200 max_key_len -= IWL_SEC_WEP_KEY_OFFSET;
202 if (WARN_ON(keyconf->keylen > max_key_len))
205 if (WARN_ON(!sta_mask))
208 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
209 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
210 memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
213 memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
215 if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
216 memcpy(cmd.u.add.tkip_mic_rx_key,
217 keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
219 memcpy(cmd.u.add.tkip_mic_tx_key,
220 keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
224 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
229 * For WEP, the same key is used for multicast and unicast so need to
230 * upload it again. If this fails, remove the original as well.
232 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
233 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
234 cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
235 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
237 __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
244 int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
245 struct ieee80211_vif *vif,
246 struct ieee80211_sta *sta,
247 struct ieee80211_key_conf *keyconf)
249 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
250 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
251 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
252 struct iwl_mvm_vif_link_info *mvm_link = NULL;
255 if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
256 unsigned int link_id = 0;
258 /* set to -1 for non-MLO right now */
259 if (keyconf->link_id >= 0)
260 link_id = keyconf->link_id;
262 mvm_link = mvmvif->link[link_id];
263 if (WARN_ON(!mvm_link))
266 if (mvm_link->igtk) {
267 IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n",
268 mvm_link->igtk->keyidx);
269 ret = iwl_mvm_sec_key_del(mvm, vif, sta,
273 "failed to remove old IGTK (ret=%d)\n",
277 WARN_ON(mvm_link->igtk);
280 ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
285 mvm_link->igtk = keyconf;
287 /* We don't really need this, but need it to be not invalid,
288 * and if we switch links multiple times it might go to be
289 * invalid when removed.
291 keyconf->hw_key_idx = 0;
296 static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
297 struct ieee80211_vif *vif,
298 struct ieee80211_sta *sta,
299 struct ieee80211_key_conf *keyconf,
302 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
303 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
304 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
307 if (WARN_ON(!sta_mask))
310 if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
311 struct iwl_mvm_vif_link_info *mvm_link;
312 unsigned int link_id = 0;
314 /* set to -1 for non-MLO right now */
315 if (keyconf->link_id >= 0)
316 link_id = keyconf->link_id;
318 mvm_link = mvmvif->link[link_id];
319 if (WARN_ON(!mvm_link))
322 if (mvm_link->igtk == keyconf) {
323 /* no longer in HW - mark for later */
324 mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
325 mvm_link->igtk = NULL;
329 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
334 /* For WEP, delete the key again as unicast */
335 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
336 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
337 key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
338 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
339 keyconf->keyidx, flags);
345 int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm,
346 struct ieee80211_vif *vif,
348 struct ieee80211_key_conf *keyconf)
350 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) |
351 IWL_SEC_KEY_FLAG_MFP;
353 if (WARN_ON(!sta_mask))
356 return __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
360 int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
361 struct ieee80211_vif *vif,
362 struct ieee80211_sta *sta,
363 struct ieee80211_key_conf *keyconf)
365 return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
368 static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
369 struct ieee80211_vif *vif,
370 struct ieee80211_sta *sta,
371 struct ieee80211_key_conf *key,
374 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
375 unsigned int link_id = (uintptr_t)data;
377 if (key->hw_key_idx == STA_KEY_IDX_INVALID)
383 if (key->link_id >= 0 && key->link_id != link_id)
386 _iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
387 key->hw_key_idx = STA_KEY_IDX_INVALID;
390 void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
391 struct ieee80211_vif *vif,
392 struct iwl_mvm_vif_link_info *link,
393 unsigned int link_id)
395 u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
396 u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
398 if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
399 link->ap_sta_id == IWL_INVALID_STA))
405 ieee80211_iter_keys(mvm->hw, vif,
406 iwl_mvm_sec_key_remove_ap_iter,
407 (void *)(uintptr_t)link_id);