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