1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3 * Copyright (C) 2024 Intel Corporation
4 */
5 #include "key.h"
6 #include "iface.h"
7 #include "sta.h"
8 #include "fw/api/datapath.h"
9
iwl_mld_get_key_flags(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)10 static u32 iwl_mld_get_key_flags(struct iwl_mld *mld,
11 struct ieee80211_vif *vif,
12 struct ieee80211_sta *sta,
13 struct ieee80211_key_conf *key)
14 {
15 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
16 bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
17 bool igtk = key->keyidx == 4 || key->keyidx == 5;
18 u32 flags = 0;
19
20 if (!pairwise)
21 flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
22
23 switch (key->cipher) {
24 case WLAN_CIPHER_SUITE_TKIP:
25 flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
26 break;
27 case WLAN_CIPHER_SUITE_AES_CMAC:
28 case WLAN_CIPHER_SUITE_CCMP:
29 flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
30 break;
31 case WLAN_CIPHER_SUITE_GCMP_256:
32 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
33 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
34 fallthrough;
35 case WLAN_CIPHER_SUITE_GCMP:
36 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
37 flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
38 break;
39 }
40
41 if (!sta && vif->type == NL80211_IFTYPE_STATION)
42 sta = mld_vif->ap_sta;
43
44 /* If we are installing an iGTK (in AP or STA mode), we need to tell
45 * the firmware this key will en/decrypt MGMT frames.
46 * Same goes if we are installing a pairwise key for an MFP station.
47 * In case we're installing a groupwise key (which is not an iGTK),
48 * then, we will not use this key for MGMT frames.
49 */
50 if ((sta && sta->mfp && pairwise) || igtk)
51 flags |= IWL_SEC_KEY_FLAG_MFP;
52
53 if (key->flags & IEEE80211_KEY_FLAG_SPP_AMSDU)
54 flags |= IWL_SEC_KEY_FLAG_SPP_AMSDU;
55
56 return flags;
57 }
58
iwl_mld_get_key_sta_mask(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)59 static u32 iwl_mld_get_key_sta_mask(struct iwl_mld *mld,
60 struct ieee80211_vif *vif,
61 struct ieee80211_sta *sta,
62 struct ieee80211_key_conf *key)
63 {
64 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
65 struct ieee80211_link_sta *link_sta;
66 int sta_id;
67
68 lockdep_assert_wiphy(mld->wiphy);
69
70 /* AP group keys are per link and should be on the mcast/bcast STA */
71 if (vif->type == NL80211_IFTYPE_AP &&
72 !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
73 struct iwl_mld_link *link = NULL;
74
75 if (key->link_id >= 0)
76 link = iwl_mld_link_dereference_check(mld_vif,
77 key->link_id);
78
79 if (WARN_ON(!link))
80 return 0;
81
82 /* In this stage we should have both the bcast and mcast STAs */
83 if (WARN_ON(link->bcast_sta.sta_id == IWL_INVALID_STA ||
84 link->mcast_sta.sta_id == IWL_INVALID_STA))
85 return 0;
86
87 /* IGTK/BIGTK to bcast STA */
88 if (key->keyidx >= 4)
89 return BIT(link->bcast_sta.sta_id);
90
91 /* GTK for data to mcast STA */
92 return BIT(link->mcast_sta.sta_id);
93 }
94
95 /* for client mode use the AP STA also for group keys */
96 if (!sta && vif->type == NL80211_IFTYPE_STATION)
97 sta = mld_vif->ap_sta;
98
99 /* STA should be non-NULL now */
100 if (WARN_ON(!sta))
101 return 0;
102
103 /* Key is not per-link, get the full sta mask */
104 if (key->link_id < 0)
105 return iwl_mld_fw_sta_id_mask(mld, sta);
106
107 /* The link_sta shouldn't be NULL now, but this is checked in
108 * iwl_mld_fw_sta_id_mask
109 */
110 link_sta = link_sta_dereference_check(sta, key->link_id);
111
112 sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
113 if (sta_id < 0)
114 return 0;
115
116 return BIT(sta_id);
117 }
118
iwl_mld_add_key_to_fw(struct iwl_mld * mld,u32 sta_mask,u32 key_flags,struct ieee80211_key_conf * key)119 static int iwl_mld_add_key_to_fw(struct iwl_mld *mld, u32 sta_mask,
120 u32 key_flags, struct ieee80211_key_conf *key)
121 {
122 struct iwl_sec_key_cmd cmd = {
123 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
124 .u.add.sta_mask = cpu_to_le32(sta_mask),
125 .u.add.key_id = cpu_to_le32(key->keyidx),
126 .u.add.key_flags = cpu_to_le32(key_flags),
127 .u.add.tx_seq = cpu_to_le64(atomic64_read(&key->tx_pn)),
128 };
129 bool tkip = key->cipher == WLAN_CIPHER_SUITE_TKIP;
130 int max_key_len = sizeof(cmd.u.add.key);
131
132 #ifdef CONFIG_PM_SLEEP
133 /* If there was a rekey in wowlan, FW already has the key */
134 if (mld->fw_status.resuming)
135 return 0;
136 #endif
137
138 if (WARN_ON(!sta_mask))
139 return -EINVAL;
140
141 if (WARN_ON(key->keylen > max_key_len))
142 return -EINVAL;
143
144 memcpy(cmd.u.add.key, key->key, key->keylen);
145
146 if (tkip) {
147 memcpy(cmd.u.add.tkip_mic_rx_key,
148 key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
149 8);
150 memcpy(cmd.u.add.tkip_mic_tx_key,
151 key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
152 8);
153 }
154
155 return iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD),
156 &cmd);
157 }
158
iwl_mld_remove_key_from_fw(struct iwl_mld * mld,u32 sta_mask,u32 key_flags,u32 keyidx)159 static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask,
160 u32 key_flags, u32 keyidx)
161 {
162 struct iwl_sec_key_cmd cmd = {
163 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
164 .u.remove.sta_mask = cpu_to_le32(sta_mask),
165 .u.remove.key_id = cpu_to_le32(keyidx),
166 .u.remove.key_flags = cpu_to_le32(key_flags),
167 };
168
169 #ifdef CONFIG_PM_SLEEP
170 /* If there was a rekey in wowlan, FW already removed the key */
171 if (mld->fw_status.resuming)
172 return;
173 #endif
174
175 if (WARN_ON(!sta_mask))
176 return;
177
178 iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), &cmd);
179 }
180
iwl_mld_remove_key(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)181 void iwl_mld_remove_key(struct iwl_mld *mld, struct ieee80211_vif *vif,
182 struct ieee80211_sta *sta,
183 struct ieee80211_key_conf *key)
184 {
185 u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
186 u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
187 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
188
189 lockdep_assert_wiphy(mld->wiphy);
190
191 if (!sta_mask)
192 return;
193
194 if (key->keyidx == 4 || key->keyidx == 5) {
195 struct iwl_mld_link *mld_link;
196 unsigned int link_id = 0;
197
198 /* set to -1 for non-MLO right now */
199 if (key->link_id >= 0)
200 link_id = key->link_id;
201
202 mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
203 if (WARN_ON(!mld_link))
204 return;
205
206 if (mld_link->igtk == key)
207 mld_link->igtk = NULL;
208
209 mld->num_igtks--;
210 }
211
212 iwl_mld_remove_key_from_fw(mld, sta_mask, key_flags, key->keyidx);
213
214 /* no longer in HW */
215 key->hw_key_idx = STA_KEY_IDX_INVALID;
216 }
217
iwl_mld_add_key(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key)218 int iwl_mld_add_key(struct iwl_mld *mld,
219 struct ieee80211_vif *vif,
220 struct ieee80211_sta *sta,
221 struct ieee80211_key_conf *key)
222 {
223 u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
224 u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
225 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
226 struct iwl_mld_link *mld_link = NULL;
227 bool igtk = key->keyidx == 4 || key->keyidx == 5;
228 int ret;
229
230 lockdep_assert_wiphy(mld->wiphy);
231
232 if (!sta_mask)
233 return -EINVAL;
234
235 if (igtk) {
236 if (mld->num_igtks == IWL_MAX_NUM_IGTKS)
237 return -EOPNOTSUPP;
238
239 u8 link_id = 0;
240
241 /* set to -1 for non-MLO right now */
242 if (key->link_id >= 0)
243 link_id = key->link_id;
244
245 mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
246
247 if (WARN_ON(!mld_link))
248 return -EINVAL;
249
250 if (mld_link->igtk) {
251 IWL_DEBUG_MAC80211(mld, "remove old IGTK %d\n",
252 mld_link->igtk->keyidx);
253 iwl_mld_remove_key(mld, vif, sta, mld_link->igtk);
254 }
255
256 WARN_ON(mld_link->igtk);
257 }
258
259 ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key);
260 if (ret)
261 return ret;
262
263 if (mld_link) {
264 mld_link->igtk = key;
265 mld->num_igtks++;
266 }
267
268 /* We don't really need this, but need it to be not invalid,
269 * so we will know if the key is in fw.
270 */
271 key->hw_key_idx = 0;
272
273 return 0;
274 }
275
276 struct remove_ap_keys_iter_data {
277 u8 link_id;
278 struct ieee80211_sta *sta;
279 };
280
iwl_mld_remove_ap_keys_iter(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key,void * _data)281 static void iwl_mld_remove_ap_keys_iter(struct ieee80211_hw *hw,
282 struct ieee80211_vif *vif,
283 struct ieee80211_sta *sta,
284 struct ieee80211_key_conf *key,
285 void *_data)
286 {
287 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
288 struct remove_ap_keys_iter_data *data = _data;
289
290 if (key->hw_key_idx == STA_KEY_IDX_INVALID)
291 return;
292
293 /* All the pairwise keys should have been removed by now */
294 if (WARN_ON(sta))
295 return;
296
297 if (key->link_id >= 0 && key->link_id != data->link_id)
298 return;
299
300 iwl_mld_remove_key(mld, vif, data->sta, key);
301 }
302
iwl_mld_remove_ap_keys(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,unsigned int link_id)303 void iwl_mld_remove_ap_keys(struct iwl_mld *mld, struct ieee80211_vif *vif,
304 struct ieee80211_sta *sta, unsigned int link_id)
305 {
306 struct remove_ap_keys_iter_data iter_data = {
307 .link_id = link_id,
308 .sta = sta,
309 };
310
311 if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION))
312 return;
313
314 ieee80211_iter_keys(mld->hw, vif,
315 iwl_mld_remove_ap_keys_iter,
316 &iter_data);
317 }
318
319 struct iwl_mvm_sta_key_update_data {
320 struct ieee80211_sta *sta;
321 u32 old_sta_mask;
322 u32 new_sta_mask;
323 int err;
324 };
325
iwl_mld_update_sta_key_iter(struct ieee80211_hw * hw,struct ieee80211_vif * vif,struct ieee80211_sta * sta,struct ieee80211_key_conf * key,void * _data)326 static void iwl_mld_update_sta_key_iter(struct ieee80211_hw *hw,
327 struct ieee80211_vif *vif,
328 struct ieee80211_sta *sta,
329 struct ieee80211_key_conf *key,
330 void *_data)
331 {
332 struct iwl_mvm_sta_key_update_data *data = _data;
333 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
334 struct iwl_sec_key_cmd cmd = {
335 .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
336 .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
337 .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
338 .u.modify.key_id = cpu_to_le32(key->keyidx),
339 .u.modify.key_flags =
340 cpu_to_le32(iwl_mld_get_key_flags(mld, vif, sta, key)),
341 };
342 int err;
343
344 /* only need to do this for pairwise keys (link_id == -1) */
345 if (sta != data->sta || key->link_id >= 0)
346 return;
347
348 err = iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD),
349 &cmd);
350
351 if (err)
352 data->err = err;
353 }
354
iwl_mld_update_sta_keys(struct iwl_mld * mld,struct ieee80211_vif * vif,struct ieee80211_sta * sta,u32 old_sta_mask,u32 new_sta_mask)355 int iwl_mld_update_sta_keys(struct iwl_mld *mld,
356 struct ieee80211_vif *vif,
357 struct ieee80211_sta *sta,
358 u32 old_sta_mask,
359 u32 new_sta_mask)
360 {
361 struct iwl_mvm_sta_key_update_data data = {
362 .sta = sta,
363 .old_sta_mask = old_sta_mask,
364 .new_sta_mask = new_sta_mask,
365 };
366
367 ieee80211_iter_keys(mld->hw, vif, iwl_mld_update_sta_key_iter,
368 &data);
369 return data.err;
370 }
371