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