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 if (WARN_ON(!sta_mask)) 133 return -EINVAL; 134 135 if (WARN_ON(key->keylen > max_key_len)) 136 return -EINVAL; 137 138 memcpy(cmd.u.add.key, key->key, key->keylen); 139 140 if (tkip) { 141 memcpy(cmd.u.add.tkip_mic_rx_key, 142 key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, 143 8); 144 memcpy(cmd.u.add.tkip_mic_tx_key, 145 key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, 146 8); 147 } 148 149 return iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), 150 &cmd); 151 } 152 153 static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask, 154 u32 key_flags, u32 keyidx) 155 { 156 struct iwl_sec_key_cmd cmd = { 157 .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), 158 .u.remove.sta_mask = cpu_to_le32(sta_mask), 159 .u.remove.key_id = cpu_to_le32(keyidx), 160 .u.remove.key_flags = cpu_to_le32(key_flags), 161 }; 162 163 if (WARN_ON(!sta_mask)) 164 return; 165 166 iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), &cmd); 167 } 168 169 void iwl_mld_remove_key(struct iwl_mld *mld, struct ieee80211_vif *vif, 170 struct ieee80211_sta *sta, 171 struct ieee80211_key_conf *key) 172 { 173 u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key); 174 u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key); 175 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 176 177 lockdep_assert_wiphy(mld->wiphy); 178 179 if (!sta_mask) 180 return; 181 182 if (key->keyidx == 4 || key->keyidx == 5) { 183 struct iwl_mld_link *mld_link; 184 unsigned int link_id = 0; 185 186 /* set to -1 for non-MLO right now */ 187 if (key->link_id >= 0) 188 link_id = key->link_id; 189 190 mld_link = iwl_mld_link_dereference_check(mld_vif, link_id); 191 if (WARN_ON(!mld_link)) 192 return; 193 194 if (mld_link->igtk == key) 195 mld_link->igtk = NULL; 196 197 mld->num_igtks--; 198 } 199 200 iwl_mld_remove_key_from_fw(mld, sta_mask, key_flags, key->keyidx); 201 202 /* no longer in HW */ 203 key->hw_key_idx = STA_KEY_IDX_INVALID; 204 } 205 206 int iwl_mld_add_key(struct iwl_mld *mld, 207 struct ieee80211_vif *vif, 208 struct ieee80211_sta *sta, 209 struct ieee80211_key_conf *key) 210 { 211 u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key); 212 u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key); 213 struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); 214 struct iwl_mld_link *mld_link = NULL; 215 bool igtk = key->keyidx == 4 || key->keyidx == 5; 216 int ret; 217 218 lockdep_assert_wiphy(mld->wiphy); 219 220 if (!sta_mask) 221 return -EINVAL; 222 223 if (igtk) { 224 if (mld->num_igtks == IWL_MAX_NUM_IGTKS) 225 return -EOPNOTSUPP; 226 227 u8 link_id = 0; 228 229 /* set to -1 for non-MLO right now */ 230 if (key->link_id >= 0) 231 link_id = key->link_id; 232 233 mld_link = iwl_mld_link_dereference_check(mld_vif, link_id); 234 235 if (WARN_ON(!mld_link)) 236 return -EINVAL; 237 238 if (mld_link->igtk) { 239 IWL_DEBUG_MAC80211(mld, "remove old IGTK %d\n", 240 mld_link->igtk->keyidx); 241 iwl_mld_remove_key(mld, vif, sta, mld_link->igtk); 242 } 243 244 WARN_ON(mld_link->igtk); 245 } 246 247 ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key); 248 if (ret) 249 return ret; 250 251 if (mld_link) { 252 mld_link->igtk = key; 253 mld->num_igtks++; 254 } 255 256 /* We don't really need this, but need it to be not invalid, 257 * so we will know if the key is in fw. 258 */ 259 key->hw_key_idx = 0; 260 261 return 0; 262 } 263 264 struct remove_ap_keys_iter_data { 265 u8 link_id; 266 struct ieee80211_sta *sta; 267 }; 268 269 static void iwl_mld_remove_ap_keys_iter(struct ieee80211_hw *hw, 270 struct ieee80211_vif *vif, 271 struct ieee80211_sta *sta, 272 struct ieee80211_key_conf *key, 273 void *_data) 274 { 275 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); 276 struct remove_ap_keys_iter_data *data = _data; 277 278 if (key->hw_key_idx == STA_KEY_IDX_INVALID) 279 return; 280 281 /* All the pairwise keys should have been removed by now */ 282 if (WARN_ON(sta)) 283 return; 284 285 if (key->link_id >= 0 && key->link_id != data->link_id) 286 return; 287 288 iwl_mld_remove_key(mld, vif, data->sta, key); 289 } 290 291 void iwl_mld_remove_ap_keys(struct iwl_mld *mld, struct ieee80211_vif *vif, 292 struct ieee80211_sta *sta, unsigned int link_id) 293 { 294 struct remove_ap_keys_iter_data iter_data = { 295 .link_id = link_id, 296 .sta = sta, 297 }; 298 299 if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION)) 300 return; 301 302 ieee80211_iter_keys(mld->hw, vif, 303 iwl_mld_remove_ap_keys_iter, 304 &iter_data); 305 } 306 307 struct iwl_mvm_sta_key_update_data { 308 struct ieee80211_sta *sta; 309 u32 old_sta_mask; 310 u32 new_sta_mask; 311 int err; 312 }; 313 314 static void iwl_mld_update_sta_key_iter(struct ieee80211_hw *hw, 315 struct ieee80211_vif *vif, 316 struct ieee80211_sta *sta, 317 struct ieee80211_key_conf *key, 318 void *_data) 319 { 320 struct iwl_mvm_sta_key_update_data *data = _data; 321 struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); 322 struct iwl_sec_key_cmd cmd = { 323 .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY), 324 .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask), 325 .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask), 326 .u.modify.key_id = cpu_to_le32(key->keyidx), 327 .u.modify.key_flags = 328 cpu_to_le32(iwl_mld_get_key_flags(mld, vif, sta, key)), 329 }; 330 int err; 331 332 /* only need to do this for pairwise keys (link_id == -1) */ 333 if (sta != data->sta || key->link_id >= 0) 334 return; 335 336 err = iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), 337 &cmd); 338 339 if (err) 340 data->err = err; 341 } 342 343 int iwl_mld_update_sta_keys(struct iwl_mld *mld, 344 struct ieee80211_vif *vif, 345 struct ieee80211_sta *sta, 346 u32 old_sta_mask, 347 u32 new_sta_mask) 348 { 349 struct iwl_mvm_sta_key_update_data data = { 350 .sta = sta, 351 .old_sta_mask = old_sta_mask, 352 .new_sta_mask = new_sta_mask, 353 }; 354 355 ieee80211_iter_keys(mld->hw, vif, iwl_mld_update_sta_key_iter, 356 &data); 357 return data.err; 358 } 359