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