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