]> Git Repo - J-linux.git/blob - drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / net / wireless / intel / iwlwifi / mvm / mld-key.c
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
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
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         if (keyconf->flags & IEEE80211_KEY_FLAG_SPP_AMSDU)
112                 flags |= IWL_SEC_KEY_FLAG_SPP_AMSDU;
113
114         return flags;
115 }
116
117 struct iwl_mvm_sta_key_update_data {
118         struct ieee80211_sta *sta;
119         u32 old_sta_mask;
120         u32 new_sta_mask;
121         int err;
122 };
123
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,
128                                        void *_data)
129 {
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)),
140         };
141         int err;
142
143         /* only need to do this for pairwise keys (link_id == -1) */
144         if (sta != data->sta || key->link_id >= 0)
145                 return;
146
147         err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
148
149         if (err)
150                 data->err = err;
151 }
152
153 int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
154                                 struct ieee80211_vif *vif,
155                                 struct ieee80211_sta *sta,
156                                 u32 old_sta_mask,
157                                 u32 new_sta_mask)
158 {
159         struct iwl_mvm_sta_key_update_data data = {
160                 .sta = sta,
161                 .old_sta_mask = old_sta_mask,
162                 .new_sta_mask = new_sta_mask,
163         };
164
165         ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
166                             &data);
167         return data.err;
168 }
169
170 static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
171                                  u32 key_flags, u32 keyidx, u32 flags)
172 {
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),
179         };
180
181         return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
182 }
183
184 int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
185                          struct ieee80211_key_conf *keyconf)
186 {
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)),
194         };
195         int max_key_len = sizeof(cmd.u.add.key);
196         int ret;
197
198         if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
199             keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
200                 max_key_len -= IWL_SEC_WEP_KEY_OFFSET;
201
202         if (WARN_ON(keyconf->keylen > max_key_len))
203                 return -EINVAL;
204
205         if (WARN_ON(!sta_mask))
206                 return -EINVAL;
207
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,
211                        keyconf->keylen);
212         else
213                 memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
214
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,
218                        8);
219                 memcpy(cmd.u.add.tkip_mic_tx_key,
220                        keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
221                        8);
222         }
223
224         ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
225         if (ret)
226                 return ret;
227
228         /*
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.
231          */
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);
236                 if (ret)
237                         __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
238                                               keyconf->keyidx, 0);
239         }
240
241         return ret;
242 }
243
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)
248 {
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;
253         int ret;
254
255         if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
256                 unsigned int link_id = 0;
257
258                 /* set to -1 for non-MLO right now */
259                 if (keyconf->link_id >= 0)
260                         link_id = keyconf->link_id;
261
262                 mvm_link = mvmvif->link[link_id];
263                 if (WARN_ON(!mvm_link))
264                         return -EINVAL;
265
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,
270                                                   mvm_link->igtk);
271                         if (ret)
272                                 IWL_ERR(mvm,
273                                         "failed to remove old IGTK (ret=%d)\n",
274                                         ret);
275                 }
276
277                 WARN_ON(mvm_link->igtk);
278         }
279
280         ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
281         if (ret)
282                 return ret;
283
284         if (mvm_link)
285                 mvm_link->igtk = keyconf;
286
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.
290          */
291         keyconf->hw_key_idx = 0;
292
293         return 0;
294 }
295
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,
300                                 u32 flags)
301 {
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);
305         int ret;
306
307         if (WARN_ON(!sta_mask))
308                 return -EINVAL;
309
310         if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
311                 struct iwl_mvm_vif_link_info *mvm_link;
312                 unsigned int link_id = 0;
313
314                 /* set to -1 for non-MLO right now */
315                 if (keyconf->link_id >= 0)
316                         link_id = keyconf->link_id;
317
318                 mvm_link = mvmvif->link[link_id];
319                 if (WARN_ON(!mvm_link))
320                         return -EINVAL;
321
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;
326                 }
327         }
328
329         ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
330                                     flags);
331         if (ret)
332                 return ret;
333
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);
340         }
341
342         return ret;
343 }
344
345 int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm,
346                              struct ieee80211_vif *vif,
347                              u32 sta_mask,
348                              struct ieee80211_key_conf *keyconf)
349 {
350         u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) |
351                 IWL_SEC_KEY_FLAG_MFP;
352
353         if (WARN_ON(!sta_mask))
354                 return -EINVAL;
355
356         return  __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
357                                       0);
358 }
359
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)
364 {
365         return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
366 }
367
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,
372                                            void *data)
373 {
374         struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
375         unsigned int link_id = (uintptr_t)data;
376
377         if (key->hw_key_idx == STA_KEY_IDX_INVALID)
378                 return;
379
380         if (sta)
381                 return;
382
383         if (key->link_id >= 0 && key->link_id != link_id)
384                 return;
385
386         _iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
387         key->hw_key_idx = STA_KEY_IDX_INVALID;
388 }
389
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)
394 {
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);
397
398         if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
399                          link->ap_sta_id == IWL_INVALID_STA))
400                 return;
401
402         if (!sec_key_ver)
403                 return;
404
405         ieee80211_iter_keys(mvm->hw, vif,
406                             iwl_mvm_sec_key_remove_ap_iter,
407                             (void *)(uintptr_t)link_id);
408 }
This page took 0.050521 seconds and 4 git commands to generate.