]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: mld: track TX/RX IGTKs separately
authorJohannes Berg <johannes.berg@intel.com>
Mon, 11 May 2026 17:36:26 +0000 (20:36 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:10 +0000 (15:17 +0300)
Due to FW/HW limitations and the MME being at the end of the
frame, the devices only support a single IGTK for RX. For TX
multiple aren't needed, only the latest will be used, but in
the device there are space restrictions, so we can also only
install one.

For NAN, however, we will have one for RX for each peer, and
one for ourselves to transmit with.

Separate out the tracking of IGTK: instead of being per link
make the TX ones per link and the RX ones per (link) station.

Note that we currently hardcode that the FW can only have two
(IWL_MAX_NUM_IGTKS) IGTKs, which won't be sufficient for NAN
with security, concurrently with BSS.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Link: https://patch.msgid.link/20260511203428.8fa6859b185d.I584e8b9d238f0b9ef6b65f95114c255209d1c2a3@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/mld/d3.c
drivers/net/wireless/intel/iwlwifi/mld/iface.h
drivers/net/wireless/intel/iwlwifi/mld/key.c
drivers/net/wireless/intel/iwlwifi/mld/link.h
drivers/net/wireless/intel/iwlwifi/mld/sta.h

index ef98efc8fb1b2bdc89f597dea9dca986c73a0bbf..c44f02f225ce8cbb90f7f745b5b27d6957f6a9a4 100644 (file)
@@ -1,6 +1,6 @@
 // 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"
 
@@ -951,19 +951,25 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
 
        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;
                }
        }
 
index ce4f8ca885cfae1d5aab6cf7fc95c35b36e1edaa..147ff6787ed9d12db0ecf3b556bda11b6707c505 100644 (file)
@@ -289,4 +289,19 @@ static inline bool iwl_mld_vif_low_latency(const struct iwl_mld_vif *mld_vif)
 
 struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld);
 
+static inline struct iwl_mld_link_sta *
+iwl_mld_get_ap_link_sta(struct ieee80211_vif *vif, int link_id)
+{
+       struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+       struct ieee80211_sta *ap_sta = mld_vif->ap_sta;
+       struct iwl_mld_sta *mld_ap_sta;
+
+       if (!ap_sta)
+               return NULL;
+
+       mld_ap_sta = iwl_mld_sta_from_mac80211(ap_sta);
+
+       return iwl_mld_link_sta_dereference_check(mld_ap_sta, link_id);
+}
+
 #endif /* __iwl_mld_iface_h__ */
index 2cb312ebd7a7dece9c3206585cebc9c47335abe3..944d5487c110ebffcc23066a694acf9066d7cde6 100644 (file)
@@ -170,34 +170,69 @@ static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask,
        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--;
        }
 
@@ -214,9 +249,7 @@ int iwl_mld_add_key(struct iwl_mld *mld,
 {
        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);
@@ -224,36 +257,25 @@ int iwl_mld_add_key(struct iwl_mld *mld,
        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++;
        }
 
index 84d9a24134a82295e3a0da46c64547a641f589e0..2b3e6b55367f6ae9f2a36ed2f3df853eced9932b 100644 (file)
@@ -1,6 +1,6 @@
 /* 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__
@@ -34,8 +34,9 @@ struct iwl_probe_resp_data {
  * @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.
@@ -60,7 +61,7 @@ struct iwl_mld_link {
                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 */
index 13644ffd185d9eb5ebfb300b46f8a6e0171806a9..dff14ff0a5af23b1bd5e3c991524fcf52764b77a 100644 (file)
@@ -28,6 +28,9 @@ struct iwl_mld_rxq_dup_data {
  * This represents the link-level sta - the driver level equivalent to the
  * ieee80211_link_sta
  *
+ * @rx_igtk: FW can only have one IGTK for RX at a time, whereas mac80211 will
+ *     have two. This tracks the one IGTK that currently exists in FW, to
+ *     remove it there when a new one is installed.
  * @last_rate_n_flags: rate_n_flags from the last &iwl_tlc_update_notif
  * @signal_avg: the signal average coming from the firmware
  * @in_fw: whether the link STA is uploaded to the FW (false during restart)
@@ -37,6 +40,7 @@ struct iwl_mld_rxq_dup_data {
 struct iwl_mld_link_sta {
        /* Add here fields that need clean up on restart */
        struct_group(zeroed_on_hw_restart,
+               struct ieee80211_key_conf *rx_igtk;
                u32 last_rate_n_flags;
                bool in_fw;
                s8 signal_avg;