1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause 2 /* 3 * Copyright (C) 2022 Intel Corporation 4 */ 5 #include <linux/kernel.h> 6 #include <net/mac80211.h> 7 #include "mvm.h" 8 #include "fw/api/context.h" 9 #include "fw/api/datapath.h" 10 11 static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm, 12 struct ieee80211_vif *vif, 13 struct ieee80211_sta *sta, 14 struct ieee80211_key_conf *keyconf) 15 { 16 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 17 18 if (vif->type == NL80211_IFTYPE_AP && 19 !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 20 return BIT(mvmvif->mcast_sta.sta_id); 21 22 if (sta) { 23 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 24 25 return BIT(mvmsta->sta_id); 26 } 27 28 if (vif->type == NL80211_IFTYPE_STATION && 29 mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) 30 return BIT(mvmvif->ap_sta_id); 31 32 /* invalid */ 33 return 0; 34 } 35 36 static u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm, 37 struct ieee80211_vif *vif, 38 struct ieee80211_sta *sta, 39 struct ieee80211_key_conf *keyconf) 40 { 41 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 42 u32 flags = 0; 43 44 if (!(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 45 flags |= IWL_SEC_KEY_FLAG_MCAST_KEY; 46 47 switch (keyconf->cipher) { 48 case WLAN_CIPHER_SUITE_WEP104: 49 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE; 50 fallthrough; 51 case WLAN_CIPHER_SUITE_WEP40: 52 flags |= IWL_SEC_KEY_FLAG_CIPHER_WEP; 53 break; 54 case WLAN_CIPHER_SUITE_TKIP: 55 flags |= IWL_SEC_KEY_FLAG_CIPHER_TKIP; 56 break; 57 case WLAN_CIPHER_SUITE_AES_CMAC: 58 case WLAN_CIPHER_SUITE_CCMP: 59 flags |= IWL_SEC_KEY_FLAG_CIPHER_CCMP; 60 break; 61 case WLAN_CIPHER_SUITE_GCMP_256: 62 case WLAN_CIPHER_SUITE_BIP_GMAC_256: 63 flags |= IWL_SEC_KEY_FLAG_KEY_SIZE; 64 fallthrough; 65 case WLAN_CIPHER_SUITE_GCMP: 66 case WLAN_CIPHER_SUITE_BIP_GMAC_128: 67 flags |= IWL_SEC_KEY_FLAG_CIPHER_GCMP; 68 break; 69 } 70 71 rcu_read_lock(); 72 if (!sta && vif->type == NL80211_IFTYPE_STATION && 73 mvmvif->ap_sta_id != IWL_MVM_INVALID_STA) { 74 u8 sta_id = mvmvif->ap_sta_id; 75 76 sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id], 77 lockdep_is_held(&mvm->mutex)); 78 } 79 80 if (!IS_ERR_OR_NULL(sta) && sta->mfp) 81 flags |= IWL_SEC_KEY_FLAG_MFP; 82 rcu_read_unlock(); 83 84 return flags; 85 } 86 87 static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask, 88 u32 key_flags, u32 keyidx, u32 flags) 89 { 90 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); 91 struct iwl_sec_key_cmd cmd = { 92 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), 93 .u.remove.sta_mask = cpu_to_le32(sta_mask), 94 .u.remove.key_id = cpu_to_le32(keyidx), 95 .u.remove.key_flags = cpu_to_le32(key_flags), 96 }; 97 98 return iwl_mvm_send_cmd_pdu(mvm, cmd_id, flags, sizeof(cmd), &cmd); 99 } 100 101 int iwl_mvm_sec_key_add(struct iwl_mvm *mvm, 102 struct ieee80211_vif *vif, 103 struct ieee80211_sta *sta, 104 struct ieee80211_key_conf *keyconf) 105 { 106 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); 107 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); 108 u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); 109 struct iwl_sec_key_cmd cmd = { 110 .action = cpu_to_le32(FW_CTXT_ACTION_ADD), 111 .u.add.sta_mask = cpu_to_le32(sta_mask), 112 .u.add.key_id = cpu_to_le32(keyconf->keyidx), 113 .u.add.key_flags = cpu_to_le32(key_flags), 114 .u.add.tx_seq = cpu_to_le64(atomic64_read(&keyconf->tx_pn)), 115 }; 116 int ret; 117 118 if (WARN_ON(keyconf->keylen > sizeof(cmd.u.add.key))) 119 return -EINVAL; 120 121 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || 122 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) 123 memcpy(cmd.u.add.key + IWL_SEC_WEP_KEY_OFFSET, keyconf->key, 124 keyconf->keylen); 125 else 126 memcpy(cmd.u.add.key, keyconf->key, keyconf->keylen); 127 128 if (keyconf->cipher == WLAN_CIPHER_SUITE_TKIP) { 129 memcpy(cmd.u.add.tkip_mic_rx_key, 130 keyconf->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, 131 8); 132 memcpy(cmd.u.add.tkip_mic_tx_key, 133 keyconf->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 134 8); 135 } 136 137 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); 138 if (ret) 139 return ret; 140 141 /* 142 * For WEP, the same key is used for multicast and unicast so need to 143 * upload it again. If this fails, remove the original as well. 144 */ 145 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || 146 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { 147 cmd.u.add.key_flags ^= cpu_to_le32(IWL_SEC_KEY_FLAG_MCAST_KEY); 148 ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd); 149 if (ret) 150 __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, 151 keyconf->keyidx, 0); 152 } 153 154 return ret; 155 } 156 157 static int _iwl_mvm_sec_key_del(struct iwl_mvm *mvm, 158 struct ieee80211_vif *vif, 159 struct ieee80211_sta *sta, 160 struct ieee80211_key_conf *keyconf, 161 u32 flags) 162 { 163 u32 sta_mask = iwl_mvm_get_sec_sta_mask(mvm, vif, sta, keyconf); 164 u32 key_flags = iwl_mvm_get_sec_flags(mvm, vif, sta, keyconf); 165 int ret; 166 167 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, keyconf->keyidx, 168 flags); 169 if (ret) 170 return ret; 171 172 /* For WEP, delete the key again as unicast */ 173 if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 || 174 keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) { 175 key_flags ^= IWL_SEC_KEY_FLAG_MCAST_KEY; 176 ret = __iwl_mvm_sec_key_del(mvm, sta_mask, key_flags, 177 keyconf->keyidx, flags); 178 } 179 180 return ret; 181 } 182 183 int iwl_mvm_sec_key_del(struct iwl_mvm *mvm, 184 struct ieee80211_vif *vif, 185 struct ieee80211_sta *sta, 186 struct ieee80211_key_conf *keyconf) 187 { 188 return _iwl_mvm_sec_key_del(mvm, vif, sta, keyconf, 0); 189 } 190 191 static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw, 192 struct ieee80211_vif *vif, 193 struct ieee80211_sta *sta, 194 struct ieee80211_key_conf *key, 195 void *data) 196 { 197 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 198 199 if (key->hw_key_idx == STA_KEY_IDX_INVALID) 200 return; 201 202 if (sta) 203 return; 204 205 _iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC); 206 key->hw_key_idx = STA_KEY_IDX_INVALID; 207 } 208 209 void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm, 210 struct ieee80211_vif *vif) 211 { 212 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 213 u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD); 214 u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0); 215 216 if (WARN_ON(vif->type != NL80211_IFTYPE_STATION || 217 mvmvif->ap_sta_id == IWL_MVM_INVALID_STA)) 218 return; 219 220 if (!sec_key_ver) 221 return; 222 223 ieee80211_iter_keys_rcu(mvm->hw, vif, 224 iwl_mvm_sec_key_remove_ap_iter, 225 NULL); 226 } 227