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