]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: iwlwifi: implement the new RSC notification
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 12 May 2026 19:34:37 +0000 (22:34 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 26 May 2026 12:17:11 +0000 (15:17 +0300)
Add support for a new RSC notification that arrives on DATA queues.
The same RSC handling previously done in the WOWLAN flow is now done
through this notification, with backward compatibility maintained.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Link: https://patch.msgid.link/20260512222731.2c0cd8b43e67.I7cfee4b57e7f84b0d38667290f45ed5be4cdd270@changeid
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h
drivers/net/wireless/intel/iwlwifi/mld/d3.c
drivers/net/wireless/intel/iwlwifi/mld/d3.h
drivers/net/wireless/intel/iwlwifi/mld/iface.c
drivers/net/wireless/intel/iwlwifi/mld/mld.c
drivers/net/wireless/intel/iwlwifi/mld/notif.c
drivers/net/wireless/intel/iwlwifi/mld/rx.c
drivers/net/wireless/intel/iwlwifi/mld/rx.h

index 06370c161fe4bbb08b648a64cd5ae3cb023ec6e2..e494e5b18d2258e98fd5c0f92e80ade40278db63 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
  * Copyright (C) 2012-2014, 2018-2022 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
@@ -91,6 +91,13 @@ enum iwl_data_path_subcmd_ids {
         */
        SEC_KEY_CMD = 0x18,
 
+       /**
+        * @RSC_NOTIF: notification to update each Rx queue with the RSC. This
+        *      notification is sent after resume and uses
+        *      &struct iwl_wowlan_all_rsc_tsc_v5.
+        */
+       RSC_NOTIF = 0xF1,
+
        /**
         * @ESR_MODE_NOTIF: notification to recommend/force a wanted esr mode,
         *      uses &struct iwl_esr_mode_notif or &struct iwl_esr_mode_notif_v1
index c44f02f225ce8cbb90f7f745b5b27d6957f6a9a4..ca4222a9a6ff01d06ae6be1ea2009c40115b885e 100644 (file)
@@ -43,6 +43,12 @@ struct iwl_mld_resume_key_iter_data {
        struct iwl_mld_wowlan_status *wowlan_status;
 };
 
+struct iwl_mld_rsc_resume_iter_data {
+       struct iwl_mld *mld;
+       const struct iwl_wowlan_all_rsc_tsc_v5 *notif;
+       int queue;
+};
+
 struct iwl_mld_suspend_key_iter_data {
        struct iwl_wowlan_rsc_tsc_params_cmd *rsc;
        bool have_rsc;
@@ -282,7 +288,8 @@ static void
 iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld,
                                struct iwl_mld_wowlan_status *wowlan_status,
                                const struct iwl_wowlan_gtk_status *gtk_data,
-                               const struct iwl_wowlan_all_rsc_tsc_v5 *sc)
+                               const struct iwl_wowlan_all_rsc_tsc_v5 *sc,
+                               int rsc_notif_ver)
 {
        int status_idx = 0;
 
@@ -305,14 +312,18 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld,
                wowlan_status->gtk[status_idx].id =
                        wowlan_status->gtk[status_idx].flags &
                        IWL_WOWLAN_GTK_IDX_MASK;
-               /* The rsc for both gtk keys are stored in gtk[0]->sc->mcast_rsc
-                * The gtk ids can be any two numbers between 0 and 3,
-                * the id_map maps between the key id and the index in sc->mcast
-                */
-               rsc_idx =
-                       sc->mcast_key_id_map[wowlan_status->gtk[status_idx].id];
-               iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx],
-                                              sc, rsc_idx);
+               /* If RSC_NOTIF is not supported */
+               if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN) {
+                       /* The rsc for both gtk keys are stored in
+                        * gtk[0]->sc->mcast_rsc. The gtk ids can be any two
+                        * numbers between 0 and 3, the id_map maps between the
+                        * key id and the index in sc->mcast
+                        */
+                       rsc_idx =
+                               sc->mcast_key_id_map[wowlan_status->gtk[status_idx].id];
+                       iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx],
+                                                      sc, rsc_idx);
+               }
 
                if (key_status == IWL_WOWLAN_STATUS_NEW_KEY) {
                        memcpy(wowlan_status->gtk[status_idx].key,
@@ -598,6 +609,10 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
                                                      PROT_OFFLOAD_GROUP,
                                                      WOWLAN_INFO_NOTIFICATION,
                                                      IWL_FW_CMD_VER_UNKNOWN);
+       int rsc_notif_ver = iwl_fw_lookup_notif_ver(mld->fw,
+                                                   DATA_PATH_GROUP,
+                                                   RSC_NOTIF,
+                                                   IWL_FW_CMD_VER_UNKNOWN);
 
        if (wowlan_info_ver == 5) {
                /* v5 format - validate before conversion */
@@ -642,8 +657,10 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
                return true;
 
        iwl_mld_convert_gtk_resume_data(mld, wowlan_status, notif->gtk,
-                                       &notif->gtk[0].sc);
-       iwl_mld_convert_ptk_resume_seq(mld, wowlan_status, &notif->gtk[0].sc);
+                                       &notif->gtk[0].sc, rsc_notif_ver);
+       if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN)
+               iwl_mld_convert_ptk_resume_seq(mld, wowlan_status,
+                                              &notif->gtk[0].sc);
        /* only one igtk is passed by FW */
        iwl_mld_convert_igtk_resume_data(wowlan_status, &notif->igtk[0]);
        iwl_mld_convert_bigtk_resume_data(wowlan_status, notif->bigtk);
@@ -902,8 +919,14 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
        struct iwl_mld_resume_key_iter_data *data = _data;
        struct iwl_mld_wowlan_status *wowlan_status = data->wowlan_status;
        u8 status_idx;
-
-       if (key->keyidx >= 0 && key->keyidx <= 3) {
+       int rsc_notif_ver = iwl_fw_lookup_notif_ver(data->mld->fw,
+                                                   DATA_PATH_GROUP,
+                                                   RSC_NOTIF,
+                                                   IWL_FW_CMD_VER_UNKNOWN);
+
+       /* If RSC_NOTIF is not supported */
+       if (rsc_notif_ver == IWL_FW_CMD_VER_UNKNOWN &&
+           key->keyidx >= 0 && key->keyidx <= 3) {
                /* PTK */
                if (sta) {
                        iwl_mld_update_ptk_rx_seq(data->mld, wowlan_status,
@@ -932,6 +955,105 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw,
        }
 }
 
+static void
+iwl_mld_rsc_update_key_iter(struct ieee80211_hw *hw,
+                           struct ieee80211_vif *vif,
+                           struct ieee80211_sta *sta,
+                           struct ieee80211_key_conf *key,
+                           void *_data)
+{
+       struct iwl_mld_rsc_resume_iter_data *data = _data;
+       struct ieee80211_key_seq seq;
+
+       if (key->keyidx > 3)
+               return;
+
+       if (sta) {
+               /* PTK */
+               BUILD_BUG_ON(ARRAY_SIZE(data->notif->ucast_rsc) !=
+                            IWL_MAX_TID_COUNT);
+
+               if (key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+                       /* TKIP: just update key sequences */
+                       for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+                               iwl_mld_le64_to_tkip_seq(data->notif->ucast_rsc[tid],
+                                                        &seq);
+                               ieee80211_set_key_rx_seq(key, tid, &seq);
+                       }
+               } else {
+                       struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+                       struct iwl_mld_ptk_pn *mld_ptk_pn =
+                               rcu_dereference_wiphy(data->mld->wiphy,
+                                                     mld_sta->ptk_pn[key->keyidx]);
+
+                       if (WARN_ON(!mld_ptk_pn))
+                               return;
+
+                       if (WARN_ON(data->queue >=
+                                   data->mld->trans->info.num_rxqs))
+                               return;
+
+                       for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+                               iwl_mld_le64_to_aes_seq(data->notif->ucast_rsc[tid],
+                                                       &seq);
+                               ieee80211_set_key_rx_seq(key, tid, &seq);
+                               memcpy(mld_ptk_pn->q[data->queue].pn[tid],
+                                      seq.ccmp.pn,
+                                      IEEE80211_CCMP_PN_LEN);
+                       }
+               }
+
+               IWL_DEBUG_WOWLAN(data->mld,
+                                "Updated PTK RSC for key %d on queue %d\n",
+                                key->keyidx, data->queue);
+       } else {
+               /* GTK */
+               int rsc_idx = data->notif->mcast_key_id_map[key->keyidx];
+
+               if (rsc_idx == IWL_MCAST_KEY_MAP_INVALID)
+                       return;
+
+               if (IWL_FW_CHECK(data->mld,
+                                rsc_idx >= ARRAY_SIZE(data->notif->mcast_rsc),
+                                "Invalid mcast key mapping: %d for key %d\n",
+                                rsc_idx, key->keyidx))
+                       return;
+
+               for (int tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
+                       __le64 rsc =
+                               data->notif->mcast_rsc[rsc_idx][tid];
+
+                       if (key->cipher == WLAN_CIPHER_SUITE_TKIP)
+                               iwl_mld_le64_to_tkip_seq(rsc, &seq);
+                       else
+                               iwl_mld_le64_to_aes_seq(rsc, &seq);
+                       ieee80211_set_key_rx_seq(key, tid, &seq);
+               }
+
+               IWL_DEBUG_WOWLAN(data->mld,
+                                "Updated GTK %d RSC (rsc_idx %d) on queue %d\n",
+                                key->keyidx, rsc_idx, data->queue);
+       }
+}
+
+void
+iwl_mld_process_rsc_notification(struct iwl_mld *mld,
+                                struct ieee80211_vif *vif,
+                                const struct iwl_wowlan_all_rsc_tsc_v5 *notif,
+                                int queue)
+{
+       struct iwl_mld_rsc_resume_iter_data iter_data = {
+               .mld = mld,
+               .notif = notif,
+               .queue = queue,
+       };
+
+       /* Iterate through all active keys and update RSC */
+       ieee80211_iter_keys_rcu(mld->hw, vif,
+                               iwl_mld_rsc_update_key_iter,
+                               &iter_data);
+}
+
 static void
 iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
                        struct iwl_mld *mld,
index 618d6fb3c7964f4f9da6868044ddfa704322c9e4..c2e8ba877042f7d52a8854330149ea7e595d6012 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024, 2026 Intel Corporation
  */
 #ifndef __iwl_mld_d3_h__
 #define __iwl_mld_d3_h__
@@ -42,6 +42,10 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld);
 void iwl_mld_set_rekey_data(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
                            struct cfg80211_gtk_rekey_data *data);
+void iwl_mld_process_rsc_notification(struct iwl_mld *mld,
+                                     struct ieee80211_vif *vif,
+                                     const struct iwl_wowlan_all_rsc_tsc_v5 *notif,
+                                     int queue);
 #if IS_ENABLED(CONFIG_IPV6)
 void iwl_mld_ipv6_addr_change(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif,
index 4fe57d79daa6330040fb5580a3c6c491441eccd4..6f2590f9a69b223f6dda3091a492dd7902d7a6c8 100644 (file)
@@ -853,6 +853,6 @@ struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld)
 
        fw_id = __ffs(fw_id_bitmap);
 
-       return wiphy_dereference(mld->wiphy,
-                                mld->fw_id_to_vif[fw_id]);
+       return rcu_dereference_wiphy(mld->wiphy,
+                                    mld->fw_id_to_vif[fw_id]);
 }
index 25bab6ab637554482796f7c1b74e5832a9e99059..3caa76b9b2cb1e48bb92515c10fdcfa7bae79314 100644 (file)
@@ -260,6 +260,7 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = {
        HCMD_NAME(RX_BAID_ALLOCATION_CONFIG_CMD),
        HCMD_NAME(SCD_QUEUE_CONFIG_CMD),
        HCMD_NAME(SEC_KEY_CMD),
+       HCMD_NAME(RSC_NOTIF),
        HCMD_NAME(ESR_MODE_NOTIF),
        HCMD_NAME(MONITOR_NOTIF),
        HCMD_NAME(TLC_MNG_UPDATE_NOTIF),
index 1c81152042ab95eb1c80a2f5f4ce6a4666d18ef6..6170953982b71d349a297f5657a3787200570de8 100644 (file)
@@ -599,6 +599,11 @@ void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi,
        else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
                                            RX_QUEUES_NOTIFICATION)))
                iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, 0);
+#ifdef CONFIG_PM_SLEEP
+       else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
+                                           RSC_NOTIF)))
+               iwl_mld_handle_rsc_notif(mld, pkt, 0);
+#endif
        else if (cmd_id == WIDE_ID(DATA_PATH_GROUP, PHY_AIR_SNIFFER_NOTIF))
                iwl_mld_handle_phy_air_sniffer_notif(mld, napi, pkt);
        else
@@ -622,6 +627,11 @@ void iwl_mld_rx_rss(struct iwl_op_mode *op_mode, struct napi_struct *napi,
                iwl_mld_handle_rx_queues_sync_notif(mld, napi, pkt, queue);
        else if (unlikely(cmd_id == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)))
                iwl_mld_handle_frame_release_notif(mld, napi, pkt, queue);
+#ifdef CONFIG_PM_SLEEP
+       else if (unlikely(cmd_id == WIDE_ID(DATA_PATH_GROUP,
+                                           RSC_NOTIF)))
+               iwl_mld_handle_rsc_notif(mld, pkt, queue);
+#endif
 }
 
 void iwl_mld_delete_handlers(struct iwl_mld *mld, const u16 *cmds, int n_cmds)
index 01603dc07f0afea33123d809aa83fffa3b02e1c4..269439d789f46a68b78c7f3e4057c9a50128d84e 100644 (file)
@@ -2260,6 +2260,30 @@ void iwl_mld_handle_rx_queues_sync_notif(struct iwl_mld *mld,
                wake_up(&mld->rxq_sync.waitq);
 }
 
+#ifdef CONFIG_PM_SLEEP
+void iwl_mld_handle_rsc_notif(struct iwl_mld *mld,
+                             struct iwl_rx_packet *pkt, int queue)
+{
+       const struct iwl_wowlan_all_rsc_tsc_v5 *notif = (void *)pkt->data;
+       u32 len = iwl_rx_packet_payload_len(pkt);
+       struct ieee80211_vif *bss_vif;
+
+       if (IWL_FW_CHECK(mld, len != sizeof(*notif),
+                        "invalid notification size %u (%zu)\n",
+                        len, sizeof(*notif)))
+               return;
+
+       /* for the bss lookup and updating the keys' pn */
+       guard(rcu)();
+
+       bss_vif = iwl_mld_get_bss_vif(mld);
+       if (WARN_ON(!bss_vif))
+               return;
+
+       iwl_mld_process_rsc_notification(mld, bss_vif, notif, queue);
+}
+#endif /* CONFIG_PM_SLEEP */
+
 static void iwl_mld_no_data_rx(struct iwl_mld *mld,
                               struct napi_struct *napi,
                               struct iwl_rx_phy_air_sniffer_ntfy *ntfy)
index 09dddbd40f55322e693f7200f9490266dd0504d7..573b89c3c9c610271bf500d8e9de032305e2ad3e 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_rx_h__
 #define __iwl_mld_rx_h__
@@ -61,6 +61,11 @@ void iwl_mld_handle_rx_queues_sync_notif(struct iwl_mld *mld,
                                         struct napi_struct *napi,
                                         struct iwl_rx_packet *pkt, int queue);
 
+#ifdef CONFIG_PM_SLEEP
+void iwl_mld_handle_rsc_notif(struct iwl_mld *mld,
+                             struct iwl_rx_packet *pkt, int queue);
+#endif
+
 void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld,
                                     struct napi_struct *napi,
                                     struct sk_buff *skb, int queue,