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