Linux Audio

Check our new training course

Loading...
v6.8
  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}
v6.2
  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}