// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
*/
#include "mld.h"
iwl_mld_update_mcast_rx_seq(key_config, key_data);
- /* The FW holds only one igtk so we keep track of the valid one */
+ /* The FW holds only one IGTK so we keep track of the valid one */
if (key_config->keyidx == 4 || key_config->keyidx == 5) {
- struct iwl_mld_link *mld_link =
- iwl_mld_link_from_mac80211(link_conf);
+ struct iwl_mld_link_sta *mld_ap_link_sta;
+
+ mld_ap_link_sta = iwl_mld_get_ap_link_sta(vif,
+ link_conf->link_id);
+ if (WARN_ON(!mld_ap_link_sta))
+ return;
/* If we had more than one rekey, mac80211 will tell us to
* remove the old and add the new so we will update the IGTK in
* drv_set_key
*/
- if (mld_link->igtk && mld_link->igtk != key_config) {
+ if (mld_ap_link_sta->rx_igtk &&
+ mld_ap_link_sta->rx_igtk != key_config) {
/* mark the old IGTK as not in FW */
- mld_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
- mld_link->igtk = key_config;
+ mld_ap_link_sta->rx_igtk->hw_key_idx =
+ STA_KEY_IDX_INVALID;
+ mld_ap_link_sta->rx_igtk = key_config;
}
}
iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), &cmd);
}
+static struct ieee80211_key_conf **
+iwl_mld_get_igtk_ptr(struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+{
+ struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+ /* key's link ID is set to -1 for non-MLO */
+ int link_id = key->link_id < 0 ? 0 : key->link_id;
+ struct iwl_mld_link_sta *mld_ap_link_sta;
+ struct iwl_mld_link *mld_link;
+ struct iwl_mld_sta *mld_sta;
+
+ if (key->keyidx != 4 && key->keyidx != 5)
+ return NULL;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ if (WARN_ON(!sta))
+ return NULL;
+
+ mld_sta = iwl_mld_sta_from_mac80211(sta);
+ mld_ap_link_sta = iwl_mld_link_sta_dereference_check(mld_sta,
+ link_id);
+ if (WARN_ON(!mld_ap_link_sta))
+ return NULL;
+
+ return &mld_ap_link_sta->rx_igtk;
+ case NL80211_IFTYPE_NAN:
+ if (sta) {
+ mld_sta = iwl_mld_sta_from_mac80211(sta);
+
+ return &mld_sta->deflink.rx_igtk;
+ }
+
+ return &mld_vif->deflink.tx_igtk;
+ case NL80211_IFTYPE_AP:
+ mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
+ if (WARN_ON(!mld_link))
+ return NULL;
+
+ return &mld_link->tx_igtk;
+ default:
+ WARN_ONCE(1, "invalid iftype %d for IGTK\n", vif->type);
+ return NULL;
+ }
+}
+
void iwl_mld_remove_key(struct iwl_mld *mld, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
- struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+ struct ieee80211_key_conf **igtk_ptr;
lockdep_assert_wiphy(mld->wiphy);
if (!sta_mask)
return;
- if (key->keyidx == 4 || key->keyidx == 5) {
- struct iwl_mld_link *mld_link;
- unsigned int link_id = 0;
-
- /* set to -1 for non-MLO right now */
- if (key->link_id >= 0)
- link_id = key->link_id;
-
- mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
- if (WARN_ON(!mld_link))
- return;
-
- if (mld_link->igtk == key)
- mld_link->igtk = NULL;
-
+ igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key);
+ if (igtk_ptr && *igtk_ptr == key) {
+ *igtk_ptr = NULL;
mld->num_igtks--;
}
{
u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
- struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
- struct iwl_mld_link *mld_link = NULL;
- bool igtk = key->keyidx == 4 || key->keyidx == 5;
+ struct ieee80211_key_conf **igtk_ptr;
int ret;
lockdep_assert_wiphy(mld->wiphy);
if (!sta_mask)
return -EINVAL;
- if (igtk) {
+ igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key);
+ if (igtk_ptr) {
if (mld->num_igtks == IWL_MAX_NUM_IGTKS)
return -EOPNOTSUPP;
- u8 link_id = 0;
-
- /* set to -1 for non-MLO right now */
- if (key->link_id >= 0)
- link_id = key->link_id;
-
- mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
-
- if (WARN_ON(!mld_link))
- return -EINVAL;
-
- if (mld_link->igtk) {
+ if (*igtk_ptr) {
IWL_DEBUG_MAC80211(mld, "remove old IGTK %d\n",
- mld_link->igtk->keyidx);
- iwl_mld_remove_key(mld, vif, sta, mld_link->igtk);
+ (*igtk_ptr)->keyidx);
+ iwl_mld_remove_key(mld, vif, sta, *igtk_ptr);
}
-
- WARN_ON(mld_link->igtk);
}
ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key);
if (ret)
return ret;
- if (mld_link) {
- mld_link->igtk = key;
+ if (igtk_ptr) {
+ WARN_ON(*igtk_ptr);
+ *igtk_ptr = key;
mld->num_igtks++;
}
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
/*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
*/
#ifndef __iwl_mld_link_h__
#define __iwl_mld_link_h__
* @chan_ctx: pointer to the channel context assigned to the link. If a link
* has an assigned channel context it means that it is active.
* @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked.
- * @igtk: fw can only have one IGTK at a time, whereas mac80211 can have two.
- * This tracks the one IGTK that currently exists in FW.
+ * @tx_igtk: FW can only have one IGTK per MAC at a time, whereas mac80211 can
+ * have two. This tracks the one IGTK that currently exists in FW, for TX
+ * purposes. The RX IGTKs are tracked per station.
* @bigtks: BIGTKs of the AP. Only valid for STA mode.
* @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS.
* @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS.
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
struct ieee80211_chanctx_conf __rcu *chan_ctx;
bool he_ru_2mhz_block;
- struct ieee80211_key_conf *igtk;
+ struct ieee80211_key_conf *tx_igtk;
struct ieee80211_key_conf __rcu *bigtks[2];
);
/* And here fields that survive a fw restart */