Loading...
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
11static 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
59u32 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
110struct 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
117static 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
146int 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
163static 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
177int 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
237int 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
289static 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
338int 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
346static 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
368void 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}
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2/*
3 * Copyright (C) 2022 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
11static 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
18 if (vif->type == NL80211_IFTYPE_AP &&
19 !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
20 return BIT(mvmvif->mcast_sta.sta_id);
21
22 if (sta) {
23 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
24
25 return BIT(mvmsta->sta_id);
26 }
27
28 if (vif->type == NL80211_IFTYPE_STATION &&
29 mvmvif->ap_sta_id != IWL_MVM_INVALID_STA)
30 return BIT(mvmvif->ap_sta_id);
31
32 /* invalid */
33 return 0;
34}
35
36static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
37 struct ieee80211_vif *vif,
38 struct ieee80211_sta *sta,
39 struct ieee80211_key_conf *keyconf)
40{
41 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
42 u32 flags = 0;
43
44 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE))
45 flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
46
47 switch (keyconf->cipher) {
48 case WLAN_CIPHER_SUITE_WEP104:
49 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
50 fallthrough;
51 case WLAN_CIPHER_SUITE_WEP40:
52 flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
53 break;
54 case WLAN_CIPHER_SUITE_TKIP:
55 flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
56 break;
57 case WLAN_CIPHER_SUITE_AES_CMAC:
58 case WLAN_CIPHER_SUITE_CCMP:
59 flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
60 break;
61 case WLAN_CIPHER_SUITE_GCMP_256:
62 case WLAN_CIPHER_SUITE_BIP_GMAC_256:
63 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
64 fallthrough;
65 case WLAN_CIPHER_SUITE_GCMP:
66 case WLAN_CIPHER_SUITE_BIP_GMAC_128:
67 flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
68 break;
69 }
70
71 rcu_read_lock();
72 if (!sta && vif->type == NL80211_IFTYPE_STATION &&
73 mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) {
74 u8 sta_id = mvmvif->ap_sta_id;
75
76 sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
77 lockdep_is_held(&mvm->mutex));
78 }
79
80 if (!IS_ERR_OR_NULL(sta) && sta->mfp)
81 flags |= IWL_SEC_KEY_FLAG_MFP;
82 rcu_read_unlock();
83
84 return flags;
85}
86
87static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
88 u32 key_flags, u32 keyidx, u32 flags)
89{
90 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
91 struct iwl_sec_key_cmd cmd = {
92 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
93 .u.remove.sta_mask = cpu_to_le32(sta_mask),
94 .u.remove.key_id = cpu_to_le32(keyidx),
95 .u.remove.key_flags = cpu_to_le32(key_flags),
96 };
97
98 return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
99}
100
101int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
102 struct ieee80211_vif *vif,
103 struct ieee80211_sta *sta,
104 struct ieee80211_key_conf *keyconf)
105{
106 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
107 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
108 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
109 struct iwl_sec_key_cmd cmd = {
110 .action = cpu_to_le32(FW_CTXT_ACTION_ADD),
111 .u.add.sta_mask = cpu_to_le32(sta_mask),
112 .u.add.key_id = cpu_to_le32(keyconf->keyidx),
113 .u.add.key_flags = cpu_to_le32(key_flags),
114 .u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
115 };
116 int ret;
117
118 if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key)))
119 return -EINVAL;
120
121 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
122 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
123 memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
124 keyconf->keylen);
125 else
126 memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
127
128 if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
129 memcpy(cmd.u.add.tkip_mic_rx_key,
130 keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
131 8);
132 memcpy(cmd.u.add.tkip_mic_tx_key,
133 keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
134 8);
135 }
136
137 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
138 if (ret)
139 return ret;
140
141 /*
142 * For WEP, the same key is used for multicast and unicast so need to
143 * upload it again. If this fails, remove the original as well.
144 */
145 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
146 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
147 cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
148 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
149 if (ret)
150 __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
151 keyconf->keyidx, 0);
152 }
153
154 return ret;
155}
156
157static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
158 struct ieee80211_vif *vif,
159 struct ieee80211_sta *sta,
160 struct ieee80211_key_conf *keyconf,
161 u32 flags)
162{
163 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
164 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
165 int ret;
166
167 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
168 flags);
169 if (ret)
170 return ret;
171
172 /* For WEP, delete the key again as unicast */
173 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
174 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
175 key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
176 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
177 keyconf->keyidx, flags);
178 }
179
180 return ret;
181}
182
183int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
184 struct ieee80211_vif *vif,
185 struct ieee80211_sta *sta,
186 struct ieee80211_key_conf *keyconf)
187{
188 return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
189}
190
191static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
192 struct ieee80211_vif *vif,
193 struct ieee80211_sta *sta,
194 struct ieee80211_key_conf *key,
195 void *data)
196{
197 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
198
199 if (key->hw_key_idx == STA_KEY_IDX_INVALID)
200 return;
201
202 if (sta)
203 return;
204
205 _iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
206 key->hw_key_idx = STA_KEY_IDX_INVALID;
207}
208
209void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
210 struct ieee80211_vif *vif)
211{
212 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
213 u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
214 u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
215
216 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
217 mvmvif->ap_sta_id == IWL_MVM_INVALID_STA))
218 return;
219
220 if (!sec_key_ver)
221 return;
222
223 ieee80211_iter_keys_rcu(mvm->hw, vif,
224 iwl_mvm_sec_key_remove_ap_iter,
225 NULL);
226}