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
);