xref: /freebsd/sys/contrib/dev/iwlwifi/mvm/mld-key.c (revision a4128aad8503277614f2d214011ef60a19447b83)
19af1bba4SBjoern A. Zeeb // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
29af1bba4SBjoern A. Zeeb /*
3*a4128aadSBjoern A. Zeeb  * Copyright (C) 2022 - 2024 Intel Corporation
49af1bba4SBjoern A. Zeeb  */
59af1bba4SBjoern A. Zeeb #include <linux/kernel.h>
69af1bba4SBjoern A. Zeeb #include <net/mac80211.h>
79af1bba4SBjoern A. Zeeb #include "mvm.h"
89af1bba4SBjoern A. Zeeb #include "fw/api/context.h"
99af1bba4SBjoern A. Zeeb #include "fw/api/datapath.h"
109af1bba4SBjoern A. Zeeb 
119af1bba4SBjoern A. Zeeb static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
129af1bba4SBjoern A. Zeeb 				    struct ieee80211_vif *vif,
139af1bba4SBjoern A. Zeeb 				    struct ieee80211_sta *sta,
149af1bba4SBjoern A. Zeeb 				    struct ieee80211_key_conf *keyconf)
159af1bba4SBjoern A. Zeeb {
169af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
179af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif_link_info *link_info = &mvmvif->deflink;
189af1bba4SBjoern A. Zeeb 
199af1bba4SBjoern A. Zeeb 	lockdep_assert_held(&mvm->mutex);
209af1bba4SBjoern A. Zeeb 
219af1bba4SBjoern A. Zeeb 	if (keyconf->link_id >= 0) {
229af1bba4SBjoern A. Zeeb 		link_info = mvmvif->link[keyconf->link_id];
239af1bba4SBjoern A. Zeeb 		if (!link_info)
249af1bba4SBjoern A. Zeeb 			return 0;
259af1bba4SBjoern A. Zeeb 	}
269af1bba4SBjoern A. Zeeb 
27*a4128aadSBjoern A. Zeeb 	/* AP group keys are per link and should be on the mcast/bcast STA */
289af1bba4SBjoern A. Zeeb 	if (vif->type == NL80211_IFTYPE_AP &&
29*a4128aadSBjoern A. Zeeb 	    !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
30*a4128aadSBjoern A. Zeeb 		/* IGTK/BIGTK to bcast STA */
31*a4128aadSBjoern A. Zeeb 		if (keyconf->keyidx >= 4)
32*a4128aadSBjoern A. Zeeb 			return BIT(link_info->bcast_sta.sta_id);
33*a4128aadSBjoern A. Zeeb 		/* GTK for data to mcast STA */
349af1bba4SBjoern A. Zeeb 		return BIT(link_info->mcast_sta.sta_id);
35*a4128aadSBjoern A. Zeeb 	}
369af1bba4SBjoern A. Zeeb 
379af1bba4SBjoern A. Zeeb 	/* for client mode use the AP STA also for group keys */
389af1bba4SBjoern A. Zeeb 	if (!sta && vif->type == NL80211_IFTYPE_STATION)
399af1bba4SBjoern A. Zeeb 		sta = mvmvif->ap_sta;
409af1bba4SBjoern A. Zeeb 
419af1bba4SBjoern A. Zeeb 	/* During remove the STA was removed and the group keys come later
429af1bba4SBjoern A. Zeeb 	 * (which sounds like a bad sequence, but remember that to mac80211 the
439af1bba4SBjoern A. Zeeb 	 * group keys have no sta pointer), so we don't have a STA now.
449af1bba4SBjoern A. Zeeb 	 * Since this happens for group keys only, just use the link_info as
459af1bba4SBjoern A. Zeeb 	 * the group keys are per link; make sure that is the case by checking
469af1bba4SBjoern A. Zeeb 	 * we do have a link_id or are not doing MLO.
479af1bba4SBjoern A. Zeeb 	 * Of course the same can be done during add as well, but we must do
489af1bba4SBjoern A. Zeeb 	 * it during remove, since we don't have the mvmvif->ap_sta pointer.
499af1bba4SBjoern A. Zeeb 	 */
509af1bba4SBjoern A. Zeeb 	if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif)))
519af1bba4SBjoern A. Zeeb 		return BIT(link_info->ap_sta_id);
529af1bba4SBjoern A. Zeeb 
539af1bba4SBjoern A. Zeeb 	/* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */
549af1bba4SBjoern A. Zeeb 
559af1bba4SBjoern A. Zeeb 	/* pass link_id to filter by it if not -1 (GTK on client) */
569af1bba4SBjoern A. Zeeb 	return iwl_mvm_sta_fw_id_mask(mvm, sta, keyconf->link_id);
579af1bba4SBjoern A. Zeeb }
589af1bba4SBjoern A. Zeeb 
599af1bba4SBjoern A. Zeeb u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
609af1bba4SBjoern A. Zeeb 			  struct ieee80211_vif *vif,
619af1bba4SBjoern A. Zeeb 			  struct ieee80211_sta *sta,
629af1bba4SBjoern A. Zeeb 			  struct ieee80211_key_conf *keyconf)
639af1bba4SBjoern A. Zeeb {
649af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
65*a4128aadSBjoern A. Zeeb 	bool pairwise = keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE;
66*a4128aadSBjoern A. Zeeb 	bool igtk = keyconf->keyidx == 4 || keyconf->keyidx == 5;
679af1bba4SBjoern A. Zeeb 	u32 flags = 0;
689af1bba4SBjoern A. Zeeb 
699af1bba4SBjoern A. Zeeb 	lockdep_assert_held(&mvm->mutex);
709af1bba4SBjoern A. Zeeb 
71*a4128aadSBjoern A. Zeeb 	if (!pairwise)
729af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_MCAST_KEY;
739af1bba4SBjoern A. Zeeb 
749af1bba4SBjoern A. Zeeb 	switch (keyconf->cipher) {
759af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_WEP104:
769af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
779af1bba4SBjoern A. Zeeb 		fallthrough;
789af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_WEP40:
799af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP;
809af1bba4SBjoern A. Zeeb 		break;
819af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_TKIP:
829af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP;
839af1bba4SBjoern A. Zeeb 		break;
849af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_AES_CMAC:
859af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_CCMP:
869af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP;
879af1bba4SBjoern A. Zeeb 		break;
889af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_GCMP_256:
899af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
909af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_KEY_SIZE;
919af1bba4SBjoern A. Zeeb 		fallthrough;
929af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_GCMP:
939af1bba4SBjoern A. Zeeb 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
949af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP;
959af1bba4SBjoern A. Zeeb 		break;
969af1bba4SBjoern A. Zeeb 	}
979af1bba4SBjoern A. Zeeb 
989af1bba4SBjoern A. Zeeb 	if (!sta && vif->type == NL80211_IFTYPE_STATION)
999af1bba4SBjoern A. Zeeb 		sta = mvmvif->ap_sta;
1009af1bba4SBjoern A. Zeeb 
101*a4128aadSBjoern A. Zeeb 	/*
102*a4128aadSBjoern A. Zeeb 	 * If we are installing an iGTK (in AP or STA mode), we need to tell
103*a4128aadSBjoern A. Zeeb 	 * the firmware this key will en/decrypt MGMT frames.
104*a4128aadSBjoern A. Zeeb 	 * Same goes if we are installing a pairwise key for an MFP station.
105*a4128aadSBjoern A. Zeeb 	 * In case we're installing a groupwise key (which is not an iGTK),
106*a4128aadSBjoern A. Zeeb 	 * then, we will not use this key for MGMT frames.
107*a4128aadSBjoern A. Zeeb 	 */
108*a4128aadSBjoern A. Zeeb 	if ((!IS_ERR_OR_NULL(sta) && sta->mfp && pairwise) || igtk)
1099af1bba4SBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_MFP;
1109af1bba4SBjoern A. Zeeb 
111*a4128aadSBjoern A. Zeeb 	if (keyconf->flags & IEEE80211_KEY_FLAG_SPP_AMSDU)
112*a4128aadSBjoern A. Zeeb 		flags |= IWL_SEC_KEY_FLAG_SPP_AMSDU;
113*a4128aadSBjoern A. Zeeb 
1149af1bba4SBjoern A. Zeeb 	return flags;
1159af1bba4SBjoern A. Zeeb }
1169af1bba4SBjoern A. Zeeb 
1179af1bba4SBjoern A. Zeeb struct iwl_mvm_sta_key_update_data {
1189af1bba4SBjoern A. Zeeb 	struct ieee80211_sta *sta;
1199af1bba4SBjoern A. Zeeb 	u32 old_sta_mask;
1209af1bba4SBjoern A. Zeeb 	u32 new_sta_mask;
1219af1bba4SBjoern A. Zeeb 	int err;
1229af1bba4SBjoern A. Zeeb };
1239af1bba4SBjoern A. Zeeb 
1249af1bba4SBjoern A. Zeeb static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
1259af1bba4SBjoern A. Zeeb 				       struct ieee80211_vif *vif,
1269af1bba4SBjoern A. Zeeb 				       struct ieee80211_sta *sta,
1279af1bba4SBjoern A. Zeeb 				       struct ieee80211_key_conf *key,
1289af1bba4SBjoern A. Zeeb 				       void *_data)
1299af1bba4SBjoern A. Zeeb {
1309af1bba4SBjoern A. Zeeb 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
1319af1bba4SBjoern A. Zeeb 	struct iwl_mvm_sta_key_update_data *data = _data;
1329af1bba4SBjoern A. Zeeb 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1339af1bba4SBjoern A. Zeeb 	struct iwl_sec_key_cmd cmd = {
1349af1bba4SBjoern A. Zeeb 		.action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
1359af1bba4SBjoern A. Zeeb 		.u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
1369af1bba4SBjoern A. Zeeb 		.u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
1379af1bba4SBjoern A. Zeeb 		.u.modify.key_id = cpu_to_le32(key->keyidx),
1389af1bba4SBjoern A. Zeeb 		.u.modify.key_flags =
1399af1bba4SBjoern A. Zeeb 			cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)),
1409af1bba4SBjoern A. Zeeb 	};
1419af1bba4SBjoern A. Zeeb 	int err;
1429af1bba4SBjoern A. Zeeb 
1439af1bba4SBjoern A. Zeeb 	/* only need to do this for pairwise keys (link_id == -1) */
1449af1bba4SBjoern A. Zeeb 	if (sta != data->sta || key->link_id >= 0)
1459af1bba4SBjoern A. Zeeb 		return;
1469af1bba4SBjoern A. Zeeb 
1479af1bba4SBjoern A. Zeeb 	err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_ASYNC, sizeof(cmd), &cmd);
1489af1bba4SBjoern A. Zeeb 
1499af1bba4SBjoern A. Zeeb 	if (err)
1509af1bba4SBjoern A. Zeeb 		data->err = err;
1519af1bba4SBjoern A. Zeeb }
1529af1bba4SBjoern A. Zeeb 
1539af1bba4SBjoern A. Zeeb int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
1549af1bba4SBjoern A. Zeeb 				struct ieee80211_vif *vif,
1559af1bba4SBjoern A. Zeeb 				struct ieee80211_sta *sta,
1569af1bba4SBjoern A. Zeeb 				u32 old_sta_mask,
1579af1bba4SBjoern A. Zeeb 				u32 new_sta_mask)
1589af1bba4SBjoern A. Zeeb {
1599af1bba4SBjoern A. Zeeb 	struct iwl_mvm_sta_key_update_data data = {
1609af1bba4SBjoern A. Zeeb 		.sta = sta,
1619af1bba4SBjoern A. Zeeb 		.old_sta_mask = old_sta_mask,
1629af1bba4SBjoern A. Zeeb 		.new_sta_mask = new_sta_mask,
1639af1bba4SBjoern A. Zeeb 	};
1649af1bba4SBjoern A. Zeeb 
1659af1bba4SBjoern A. Zeeb 	ieee80211_iter_keys_rcu(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
1669af1bba4SBjoern A. Zeeb 				&data);
1679af1bba4SBjoern A. Zeeb 	return data.err;
1689af1bba4SBjoern A. Zeeb }
1699af1bba4SBjoern A. Zeeb 
1709af1bba4SBjoern A. Zeeb static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
1719af1bba4SBjoern A. Zeeb 				 u32 key_flags, u32 keyidx, u32 flags)
1729af1bba4SBjoern A. Zeeb {
1739af1bba4SBjoern A. Zeeb 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
1749af1bba4SBjoern A. Zeeb 	struct iwl_sec_key_cmd cmd = {
1759af1bba4SBjoern A. Zeeb 		.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
1769af1bba4SBjoern A. Zeeb 		.u.remove.sta_mask = cpu_to_le32(sta_mask),
1779af1bba4SBjoern A. Zeeb 		.u.remove.key_id = cpu_to_le32(keyidx),
1789af1bba4SBjoern A. Zeeb 		.u.remove.key_flags = cpu_to_le32(key_flags),
1799af1bba4SBjoern A. Zeeb 	};
1809af1bba4SBjoern A. Zeeb 
1819af1bba4SBjoern A. Zeeb 	return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd);
1829af1bba4SBjoern A. Zeeb }
1839af1bba4SBjoern A. Zeeb 
1849af1bba4SBjoern A. Zeeb int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
1859af1bba4SBjoern A. Zeeb 			 struct ieee80211_key_conf *keyconf)
1869af1bba4SBjoern A. Zeeb {
1879af1bba4SBjoern A. Zeeb 	u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
1889af1bba4SBjoern A. Zeeb 	struct iwl_sec_key_cmd cmd = {
1899af1bba4SBjoern A. Zeeb 		.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
1909af1bba4SBjoern A. Zeeb 		.u.add.sta_mask = cpu_to_le32(sta_mask),
1919af1bba4SBjoern A. Zeeb 		.u.add.key_id = cpu_to_le32(keyconf->keyidx),
1929af1bba4SBjoern A. Zeeb 		.u.add.key_flags = cpu_to_le32(key_flags),
1939af1bba4SBjoern A. Zeeb 		.u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)),
1949af1bba4SBjoern A. Zeeb 	};
1959af1bba4SBjoern A. Zeeb 	int max_key_len = sizeof(cmd.u.add.key);
1969af1bba4SBjoern A. Zeeb 	int ret;
1979af1bba4SBjoern A. Zeeb 
1989af1bba4SBjoern A. Zeeb 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
1999af1bba4SBjoern A. Zeeb 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
2009af1bba4SBjoern A. Zeeb 		max_key_len -= IWL_SEC_WEP_KEY_OFFSET;
2019af1bba4SBjoern A. Zeeb 
2029af1bba4SBjoern A. Zeeb 	if (WARN_ON(keyconf->keylen > max_key_len))
2039af1bba4SBjoern A. Zeeb 		return -EINVAL;
2049af1bba4SBjoern A. Zeeb 
2059af1bba4SBjoern A. Zeeb 	if (WARN_ON(!sta_mask))
2069af1bba4SBjoern A. Zeeb 		return -EINVAL;
2079af1bba4SBjoern A. Zeeb 
2089af1bba4SBjoern A. Zeeb 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
2099af1bba4SBjoern A. Zeeb 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104)
2109af1bba4SBjoern A. Zeeb 		memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key,
2119af1bba4SBjoern A. Zeeb 		       keyconf->keylen);
2129af1bba4SBjoern A. Zeeb 	else
2139af1bba4SBjoern A. Zeeb 		memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen);
2149af1bba4SBjoern A. Zeeb 
2159af1bba4SBjoern A. Zeeb 	if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) {
2169af1bba4SBjoern A. Zeeb 		memcpy(cmd.u.add.tkip_mic_rx_key,
2179af1bba4SBjoern A. Zeeb 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
2189af1bba4SBjoern A. Zeeb 		       8);
2199af1bba4SBjoern A. Zeeb 		memcpy(cmd.u.add.tkip_mic_tx_key,
2209af1bba4SBjoern A. Zeeb 		       keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY,
2219af1bba4SBjoern A. Zeeb 		       8);
2229af1bba4SBjoern A. Zeeb 	}
2239af1bba4SBjoern A. Zeeb 
2249af1bba4SBjoern A. Zeeb 	ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
2259af1bba4SBjoern A. Zeeb 	if (ret)
2269af1bba4SBjoern A. Zeeb 		return ret;
2279af1bba4SBjoern A. Zeeb 
2289af1bba4SBjoern A. Zeeb 	/*
2299af1bba4SBjoern A. Zeeb 	 * For WEP, the same key is used for multicast and unicast so need to
2309af1bba4SBjoern A. Zeeb 	 * upload it again. If this fails, remove the original as well.
2319af1bba4SBjoern A. Zeeb 	 */
2329af1bba4SBjoern A. Zeeb 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
2339af1bba4SBjoern A. Zeeb 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
2349af1bba4SBjoern A. Zeeb 		cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY);
2359af1bba4SBjoern A. Zeeb 		ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
2369af1bba4SBjoern A. Zeeb 		if (ret)
2379af1bba4SBjoern A. Zeeb 			__iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
2389af1bba4SBjoern A. Zeeb 					      keyconf->keyidx, 0);
2399af1bba4SBjoern A. Zeeb 	}
2409af1bba4SBjoern A. Zeeb 
2419af1bba4SBjoern A. Zeeb 	return ret;
2429af1bba4SBjoern A. Zeeb }
2439af1bba4SBjoern A. Zeeb 
2449af1bba4SBjoern A. Zeeb int iwl_mvm_sec_key_add(struct iwl_mvm *mvm,
2459af1bba4SBjoern A. Zeeb 			struct ieee80211_vif *vif,
2469af1bba4SBjoern A. Zeeb 			struct ieee80211_sta *sta,
2479af1bba4SBjoern A. Zeeb 			struct ieee80211_key_conf *keyconf)
2489af1bba4SBjoern A. Zeeb {
2499af1bba4SBjoern A. Zeeb 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
2509af1bba4SBjoern A. Zeeb 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
2519af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
2529af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif_link_info *mvm_link = NULL;
2539af1bba4SBjoern A. Zeeb 	int ret;
2549af1bba4SBjoern A. Zeeb 
2559af1bba4SBjoern A. Zeeb 	if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
2569af1bba4SBjoern A. Zeeb 		unsigned int link_id = 0;
2579af1bba4SBjoern A. Zeeb 
2589af1bba4SBjoern A. Zeeb 		/* set to -1 for non-MLO right now */
2599af1bba4SBjoern A. Zeeb 		if (keyconf->link_id >= 0)
2609af1bba4SBjoern A. Zeeb 			link_id = keyconf->link_id;
2619af1bba4SBjoern A. Zeeb 
2629af1bba4SBjoern A. Zeeb 		mvm_link = mvmvif->link[link_id];
2639af1bba4SBjoern A. Zeeb 		if (WARN_ON(!mvm_link))
2649af1bba4SBjoern A. Zeeb 			return -EINVAL;
2659af1bba4SBjoern A. Zeeb 
2669af1bba4SBjoern A. Zeeb 		if (mvm_link->igtk) {
2679af1bba4SBjoern A. Zeeb 			IWL_DEBUG_MAC80211(mvm, "remove old IGTK %d\n",
2689af1bba4SBjoern A. Zeeb 					   mvm_link->igtk->keyidx);
2699af1bba4SBjoern A. Zeeb 			ret = iwl_mvm_sec_key_del(mvm, vif, sta,
2709af1bba4SBjoern A. Zeeb 						  mvm_link->igtk);
2719af1bba4SBjoern A. Zeeb 			if (ret)
2729af1bba4SBjoern A. Zeeb 				IWL_ERR(mvm,
2739af1bba4SBjoern A. Zeeb 					"failed to remove old IGTK (ret=%d)\n",
2749af1bba4SBjoern A. Zeeb 					ret);
2759af1bba4SBjoern A. Zeeb 		}
2769af1bba4SBjoern A. Zeeb 
2779af1bba4SBjoern A. Zeeb 		WARN_ON(mvm_link->igtk);
2789af1bba4SBjoern A. Zeeb 	}
2799af1bba4SBjoern A. Zeeb 
2809af1bba4SBjoern A. Zeeb 	ret = iwl_mvm_mld_send_key(mvm, sta_mask, key_flags, keyconf);
2819af1bba4SBjoern A. Zeeb 	if (ret)
2829af1bba4SBjoern A. Zeeb 		return ret;
2839af1bba4SBjoern A. Zeeb 
2849af1bba4SBjoern A. Zeeb 	if (mvm_link)
2859af1bba4SBjoern A. Zeeb 		mvm_link->igtk = keyconf;
2869af1bba4SBjoern A. Zeeb 
2879af1bba4SBjoern A. Zeeb 	/* We don't really need this, but need it to be not invalid,
2889af1bba4SBjoern A. Zeeb 	 * and if we switch links multiple times it might go to be
2899af1bba4SBjoern A. Zeeb 	 * invalid when removed.
2909af1bba4SBjoern A. Zeeb 	 */
2919af1bba4SBjoern A. Zeeb 	keyconf->hw_key_idx = 0;
2929af1bba4SBjoern A. Zeeb 
2939af1bba4SBjoern A. Zeeb 	return 0;
2949af1bba4SBjoern A. Zeeb }
2959af1bba4SBjoern A. Zeeb 
2969af1bba4SBjoern A. Zeeb static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
2979af1bba4SBjoern A. Zeeb 				struct ieee80211_vif *vif,
2989af1bba4SBjoern A. Zeeb 				struct ieee80211_sta *sta,
2999af1bba4SBjoern A. Zeeb 				struct ieee80211_key_conf *keyconf,
3009af1bba4SBjoern A. Zeeb 				u32 flags)
3019af1bba4SBjoern A. Zeeb {
3029af1bba4SBjoern A. Zeeb 	u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf);
3039af1bba4SBjoern A. Zeeb 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf);
3049af1bba4SBjoern A. Zeeb 	struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
3059af1bba4SBjoern A. Zeeb 	int ret;
3069af1bba4SBjoern A. Zeeb 
3079af1bba4SBjoern A. Zeeb 	if (WARN_ON(!sta_mask))
3089af1bba4SBjoern A. Zeeb 		return -EINVAL;
3099af1bba4SBjoern A. Zeeb 
3109af1bba4SBjoern A. Zeeb 	if (keyconf->keyidx == 4 || keyconf->keyidx == 5) {
3119af1bba4SBjoern A. Zeeb 		struct iwl_mvm_vif_link_info *mvm_link;
3129af1bba4SBjoern A. Zeeb 		unsigned int link_id = 0;
3139af1bba4SBjoern A. Zeeb 
3149af1bba4SBjoern A. Zeeb 		/* set to -1 for non-MLO right now */
3159af1bba4SBjoern A. Zeeb 		if (keyconf->link_id >= 0)
3169af1bba4SBjoern A. Zeeb 			link_id = keyconf->link_id;
3179af1bba4SBjoern A. Zeeb 
3189af1bba4SBjoern A. Zeeb 		mvm_link = mvmvif->link[link_id];
3199af1bba4SBjoern A. Zeeb 		if (WARN_ON(!mvm_link))
3209af1bba4SBjoern A. Zeeb 			return -EINVAL;
3219af1bba4SBjoern A. Zeeb 
3229af1bba4SBjoern A. Zeeb 		if (mvm_link->igtk == keyconf) {
3239af1bba4SBjoern A. Zeeb 			/* no longer in HW - mark for later */
3249af1bba4SBjoern A. Zeeb 			mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
3259af1bba4SBjoern A. Zeeb 			mvm_link->igtk = NULL;
3269af1bba4SBjoern A. Zeeb 		}
3279af1bba4SBjoern A. Zeeb 	}
3289af1bba4SBjoern A. Zeeb 
3299af1bba4SBjoern A. Zeeb 	ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
3309af1bba4SBjoern A. Zeeb 				    flags);
3319af1bba4SBjoern A. Zeeb 	if (ret)
3329af1bba4SBjoern A. Zeeb 		return ret;
3339af1bba4SBjoern A. Zeeb 
3349af1bba4SBjoern A. Zeeb 	/* For WEP, delete the key again as unicast */
3359af1bba4SBjoern A. Zeeb 	if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
3369af1bba4SBjoern A. Zeeb 	    keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
3379af1bba4SBjoern A. Zeeb 		key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY;
3389af1bba4SBjoern A. Zeeb 		ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags,
3399af1bba4SBjoern A. Zeeb 					    keyconf->keyidx, flags);
3409af1bba4SBjoern A. Zeeb 	}
3419af1bba4SBjoern A. Zeeb 
3429af1bba4SBjoern A. Zeeb 	return ret;
3439af1bba4SBjoern A. Zeeb }
3449af1bba4SBjoern A. Zeeb 
345*a4128aadSBjoern A. Zeeb int iwl_mvm_sec_key_del_pasn(struct iwl_mvm *mvm,
346*a4128aadSBjoern A. Zeeb 			     struct ieee80211_vif *vif,
347*a4128aadSBjoern A. Zeeb 			     u32 sta_mask,
348*a4128aadSBjoern A. Zeeb 			     struct ieee80211_key_conf *keyconf)
349*a4128aadSBjoern A. Zeeb {
350*a4128aadSBjoern A. Zeeb 	u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, NULL, keyconf) |
351*a4128aadSBjoern A. Zeeb 		IWL_SEC_KEY_FLAG_MFP;
352*a4128aadSBjoern A. Zeeb 
353*a4128aadSBjoern A. Zeeb 	if (WARN_ON(!sta_mask))
354*a4128aadSBjoern A. Zeeb 		return -EINVAL;
355*a4128aadSBjoern A. Zeeb 
356*a4128aadSBjoern A. Zeeb 	return  __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx,
357*a4128aadSBjoern A. Zeeb 				      0);
358*a4128aadSBjoern A. Zeeb }
359*a4128aadSBjoern A. Zeeb 
3609af1bba4SBjoern A. Zeeb int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
3619af1bba4SBjoern A. Zeeb 			struct ieee80211_vif *vif,
3629af1bba4SBjoern A. Zeeb 			struct ieee80211_sta *sta,
3639af1bba4SBjoern A. Zeeb 			struct ieee80211_key_conf *keyconf)
3649af1bba4SBjoern A. Zeeb {
3659af1bba4SBjoern A. Zeeb 	return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0);
3669af1bba4SBjoern A. Zeeb }
3679af1bba4SBjoern A. Zeeb 
3689af1bba4SBjoern A. Zeeb static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
3699af1bba4SBjoern A. Zeeb 					   struct ieee80211_vif *vif,
3709af1bba4SBjoern A. Zeeb 					   struct ieee80211_sta *sta,
3719af1bba4SBjoern A. Zeeb 					   struct ieee80211_key_conf *key,
3729af1bba4SBjoern A. Zeeb 					   void *data)
3739af1bba4SBjoern A. Zeeb {
3749af1bba4SBjoern A. Zeeb 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3759af1bba4SBjoern A. Zeeb 	unsigned int link_id = (uintptr_t)data;
3769af1bba4SBjoern A. Zeeb 
3779af1bba4SBjoern A. Zeeb 	if (key->hw_key_idx == STA_KEY_IDX_INVALID)
3789af1bba4SBjoern A. Zeeb 		return;
3799af1bba4SBjoern A. Zeeb 
3809af1bba4SBjoern A. Zeeb 	if (sta)
3819af1bba4SBjoern A. Zeeb 		return;
3829af1bba4SBjoern A. Zeeb 
3839af1bba4SBjoern A. Zeeb 	if (key->link_id >= 0 && key->link_id != link_id)
3849af1bba4SBjoern A. Zeeb 		return;
3859af1bba4SBjoern A. Zeeb 
3869af1bba4SBjoern A. Zeeb 	_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
3879af1bba4SBjoern A. Zeeb 	key->hw_key_idx = STA_KEY_IDX_INVALID;
3889af1bba4SBjoern A. Zeeb }
3899af1bba4SBjoern A. Zeeb 
3909af1bba4SBjoern A. Zeeb void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
3919af1bba4SBjoern A. Zeeb 			       struct ieee80211_vif *vif,
3929af1bba4SBjoern A. Zeeb 			       struct iwl_mvm_vif_link_info *link,
3939af1bba4SBjoern A. Zeeb 			       unsigned int link_id)
3949af1bba4SBjoern A. Zeeb {
3959af1bba4SBjoern A. Zeeb 	u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
3969af1bba4SBjoern A. Zeeb 	u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
3979af1bba4SBjoern A. Zeeb 
3989af1bba4SBjoern A. Zeeb 	if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
3999af1bba4SBjoern A. Zeeb 			 link->ap_sta_id == IWL_MVM_INVALID_STA))
4009af1bba4SBjoern A. Zeeb 		return;
4019af1bba4SBjoern A. Zeeb 
4029af1bba4SBjoern A. Zeeb 	if (!sec_key_ver)
4039af1bba4SBjoern A. Zeeb 		return;
4049af1bba4SBjoern A. Zeeb 
4059af1bba4SBjoern A. Zeeb 	ieee80211_iter_keys_rcu(mvm->hw, vif,
4069af1bba4SBjoern A. Zeeb 				iwl_mvm_sec_key_remove_ap_iter,
4079af1bba4SBjoern A. Zeeb 				(void *)(uintptr_t)link_id);
4089af1bba4SBjoern A. Zeeb }
409