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 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 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 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 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 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 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 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 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 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 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