]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: iwlwifi: implement wowlan status notification API update
authorRotem Kerem <rotem.kerem@intel.com>
Tue, 9 Sep 2025 03:21:22 +0000 (06:21 +0300)
committerMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 9 Sep 2025 09:08:34 +0000 (12:08 +0300)
Add per key status indication in the WOWLAN status notification.
This update is required for fips. Each key entry now
includes a status field.

Keys are now processed as follows:
0: no key, ignore entry
1: old, use only metadata
2: new, use key material and metadata

While at it, fix tid_offloaded_tx error message to print the
actual variable being validated in iwl_mld_handle_wowlan_info_notif.

Signed-off-by: Rotem Kerem <rotem.kerem@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20250909061931.0a2e7a62504c.Id195c9c83f9f767d1e3e458468af2d933774daa1@changeid
drivers/net/wireless/intel/iwlwifi/fw/api/d3.h
drivers/net/wireless/intel/iwlwifi/fw/api/offload.h
drivers/net/wireless/intel/iwlwifi/mld/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/d3.c

index 9103f70c41c02d27fa4f2bed1923fc69bb0f1b81..d3bed0216df4831d3e330bf6b6ea2703cc10c82f 100644 (file)
@@ -632,9 +632,64 @@ struct iwl_wowlan_gtk_status_v3 {
        struct iwl_wowlan_all_rsc_tsc_v5 sc;
 } __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */
 
+/**
+ * enum iwl_wowlan_key_status - Status of security keys in WoWLAN notifications
+ * @IWL_WOWLAN_NOTIF_NO_KEY: No key is present; this entry should be ignored.
+ * @IWL_WOWLAN_STATUS_OLD_KEY: old key exists; no rekey occurred, and only
+ *     metadata is available.
+ * @IWL_WOWLAN_STATUS_NEW_KEY: A new key was created after a rekey; new key
+ *     material is available.
+ */
+enum iwl_wowlan_key_status {
+       IWL_WOWLAN_NOTIF_NO_KEY = 0,
+       IWL_WOWLAN_STATUS_OLD_KEY = 1,
+       IWL_WOWLAN_STATUS_NEW_KEY = 2
+};
+
+/**
+ * struct iwl_wowlan_gtk_status - GTK status
+ * @key: GTK material
+ * @key_len: GTK length, if set to 0, the key is not available
+ * @key_flags: information about the key:
+ *     bits[0:1]:  key index assigned by the AP
+ *     bits[2:6]:  GTK index of the key in the internal DB
+ *     bit[7]:     Set iff this is the currently used GTK
+ * @key_status: key status, see &enum iwl_wowlan_key_status
+ * @reserved: padding
+ * @tkip_mic_key: TKIP RX MIC key
+ * @sc: RSC/TSC counters
+ */
+struct iwl_wowlan_gtk_status {
+       u8 key[WOWLAN_KEY_MAX_SIZE];
+       u8 key_len;
+       u8 key_flags;
+       u8 key_status;
+       u8 reserved;
+       u8 tkip_mic_key[IWL_MIC_KEY_SIZE];
+       struct iwl_wowlan_all_rsc_tsc_v5 sc;
+} __packed; /* WOWLAN_GTK_MATERIAL_VER_4 */
+
 #define IWL_WOWLAN_GTK_IDX_MASK                (BIT(0) | BIT(1))
 #define IWL_WOWLAN_IGTK_BIGTK_IDX_MASK (BIT(0))
 
+/**
+ * struct iwl_wowlan_igtk_status_v1 - IGTK status
+ * @key: IGTK material
+ * @ipn: the IGTK packet number (replay counter)
+ * @key_len: IGTK length, if set to 0, the key is not available
+ * @key_flags: information about the key:
+ *     bits[0]: key index assigned by the AP (0: index 4, 1: index 5)
+ *     (0: index 6, 1: index 7 with bigtk)
+ *     bits[1:5]: IGTK index of the key in the internal DB
+ *     bit[6]: Set iff this is the currently used IGTK
+ */
+struct iwl_wowlan_igtk_status_v1 {
+       u8 key[WOWLAN_KEY_MAX_SIZE];
+       u8 ipn[6];
+       u8 key_len;
+       u8 key_flags;
+} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */
+
 /**
  * struct iwl_wowlan_igtk_status - IGTK status
  * @key: IGTK material
@@ -645,13 +700,17 @@ struct iwl_wowlan_gtk_status_v3 {
  *     (0: index 6, 1: index 7 with bigtk)
  *     bits[1:5]: IGTK index of the key in the internal DB
  *     bit[6]: Set iff this is the currently used IGTK
+ * @key_status: key status, see &enum iwl_wowlan_key_status
+ * @reserved: padding
  */
 struct iwl_wowlan_igtk_status {
        u8 key[WOWLAN_KEY_MAX_SIZE];
        u8 ipn[6];
        u8 key_len;
        u8 key_flags;
-} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */
+       u8 key_status;
+       u8 reserved[3];
+} __packed; /* WOWLAN_IGTK_MATERIAL_VER_2 */
 
 /**
  * struct iwl_wowlan_status_v6 - WoWLAN status
@@ -701,7 +760,7 @@ struct iwl_wowlan_status_v6 {
  */
 struct iwl_wowlan_status_v7 {
        struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM];
-       struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM];
        __le64 replay_ctr;
        __le16 pattern_number;
        __le16 non_qos_seq_ctr;
@@ -736,7 +795,7 @@ struct iwl_wowlan_status_v7 {
  */
 struct iwl_wowlan_info_notif_v1 {
        struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
-       struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM];
        __le64 replay_ctr;
        __le16 pattern_number;
        __le16 reserved1;
@@ -818,8 +877,8 @@ struct iwl_wowlan_mlo_gtk {
  */
 struct iwl_wowlan_info_notif_v3 {
        struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
-       struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
-       struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM];
        __le64 replay_ctr;
        __le16 pattern_number;
        __le16 reserved1;
@@ -833,6 +892,45 @@ struct iwl_wowlan_info_notif_v3 {
        u8 reserved2[2];
 } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */
 
+/**
+ * struct iwl_wowlan_info_notif_v5 - WoWLAN information notification
+ * @gtk: GTK data
+ * @igtk: IGTK data
+ * @bigtk: BIGTK data
+ * @replay_ctr: GTK rekey replay counter
+ * @pattern_number: number of the matched patterns
+ * @qos_seq_ctr: QoS sequence counters to use next
+ * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason
+ * @num_of_gtk_rekeys: number of GTK rekeys
+ * @transmitted_ndps: number of transmitted neighbor discovery packets
+ * @received_beacons: number of received beacons
+ * @tid_tear_down: bit mask of tids whose BA sessions were closed
+ *     in suspend state
+ * @station_id: station id
+ * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs
+ *     following this notif
+ * @tid_offloaded_tx: tid used by the firmware to transmit data packets
+ *     while in wowlan
+ * @mlo_gtks: array of GTKs of size num_mlo_link_keys
+ */
+struct iwl_wowlan_info_notif_v5 {
+       struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM];
+       struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM];
+       __le64 replay_ctr;
+       __le16 pattern_number;
+       __le16 qos_seq_ctr;
+       __le32 wakeup_reasons;
+       __le32 num_of_gtk_rekeys;
+       __le32 transmitted_ndps;
+       __le32 received_beacons;
+       u8 tid_tear_down;
+       u8 station_id;
+       u8 num_mlo_link_keys;
+       u8 tid_offloaded_tx;
+       struct iwl_wowlan_mlo_gtk mlo_gtks[];
+} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */
+
 /**
  * struct iwl_wowlan_info_notif - WoWLAN information notification
  * @gtk: GTK data
@@ -855,7 +953,7 @@ struct iwl_wowlan_info_notif_v3 {
  * @mlo_gtks: array of GTKs of size num_mlo_link_keys
  */
 struct iwl_wowlan_info_notif {
-       struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM];
+       struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM];
        struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM];
        struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM];
        __le64 replay_ctr;
@@ -870,7 +968,7 @@ struct iwl_wowlan_info_notif {
        u8 num_mlo_link_keys;
        u8 tid_offloaded_tx;
        struct iwl_wowlan_mlo_gtk mlo_gtks[];
-} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */
+} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_6 */
 
 /**
  * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification
index 2a1c2b0f19e4d1df82646f3c9cbae8eefc2d67df..bb801650a5655059f33480d28e1c8fabb3a3314f 100644 (file)
@@ -20,7 +20,7 @@ enum iwl_prot_offload_subcmd_ids {
        /**
         * @WOWLAN_INFO_NOTIFICATION: Notification in
         * &struct iwl_wowlan_info_notif_v1, iwl_wowlan_info_notif_v3,
-        * or &struct iwl_wowlan_info_notif
+        * &struct iwl_wowlan_info_notif_v5 or &struct iwl_wowlan_info_notif
         */
        WOWLAN_INFO_NOTIFICATION = 0xFD,
 
index f10732d312422e0197a44ec2778af15280a83da7..1d4282a21f09e0f90a52dc02c8287ecc0e0fafe1 100644 (file)
@@ -281,7 +281,7 @@ iwl_mld_convert_gtk_resume_seq(struct iwl_mld_mcast_key_data *gtk_data,
 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_v3 *gtk_data,
+                               const struct iwl_wowlan_gtk_status *gtk_data,
                                const struct iwl_wowlan_all_rsc_tsc_v5 *sc)
 {
        int status_idx = 0;
@@ -293,8 +293,9 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld,
        for (int notif_idx = 0; notif_idx < ARRAY_SIZE(wowlan_status->gtk);
             notif_idx++) {
                int rsc_idx;
+               u8 key_status = gtk_data[notif_idx].key_status;
 
-               if (!(gtk_data[notif_idx].key_len))
+               if (!key_status)
                        continue;
 
                wowlan_status->gtk[status_idx].len =
@@ -304,10 +305,6 @@ 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;
-               memcpy(wowlan_status->gtk[status_idx].key,
-                      gtk_data[notif_idx].key,
-                      sizeof(gtk_data[notif_idx].key));
-
                /* 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
@@ -317,13 +314,27 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld,
                iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx],
                                               sc, rsc_idx);
 
-               /* if it's as long as the TKIP encryption key, copy MIC key */
-               if (wowlan_status->gtk[status_idx].len ==
-                   NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
-                       memcpy(wowlan_status->gtk[status_idx].key +
-                              NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
-                              gtk_data[notif_idx].tkip_mic_key,
-                              sizeof(gtk_data[notif_idx].tkip_mic_key));
+               if (key_status == IWL_WOWLAN_STATUS_NEW_KEY) {
+                       memcpy(wowlan_status->gtk[status_idx].key,
+                              gtk_data[notif_idx].key,
+                              sizeof(gtk_data[notif_idx].key));
+
+                       /* if it's as long as the TKIP encryption key,
+                        * copy MIC key
+                        */
+                       if (wowlan_status->gtk[status_idx].len ==
+                           NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY)
+                               memcpy(wowlan_status->gtk[status_idx].key +
+                                      NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY,
+                                      gtk_data[notif_idx].tkip_mic_key,
+                                      sizeof(gtk_data[notif_idx].tkip_mic_key));
+               } else {
+                       /* If the key status is WOWLAN_STATUS_OLD_KEY, it
+                        * indicates that no key material is present, Set the
+                        * key length to 0 as an indication
+                        */
+                       wowlan_status->gtk[status_idx].len = 0;
+               }
                status_idx++;
        }
 }
@@ -370,11 +381,11 @@ static void
 iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status,
                                 const struct iwl_wowlan_igtk_status *igtk)
 {
-       BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key));
-
-       if (!igtk->key_len)
+       if (!igtk->key_status)
                return;
 
+       BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key));
+
        wowlan_status->igtk.len = igtk->key_len;
        wowlan_status->igtk.flags = igtk->key_flags;
        wowlan_status->igtk.id =
@@ -382,7 +393,15 @@ iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status,
                             IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) +
                WOWLAN_IGTK_MIN_INDEX;
 
-       memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key));
+       if (igtk->key_status == IWL_WOWLAN_STATUS_NEW_KEY)
+               memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key));
+       else
+               /* If the key status is WOWLAN_STATUS_OLD_KEY, it indicates
+                * that no key material is present. Set the key length to 0
+                * as an indication.
+                */
+               wowlan_status->igtk.len = 0;
+
        iwl_mld_convert_mcast_ipn(&wowlan_status->igtk, igtk);
 }
 
@@ -396,7 +415,7 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status,
 
        for (int notif_idx = 0; notif_idx < WOWLAN_BIGTK_KEYS_NUM;
             notif_idx++) {
-               if (!bigtk[notif_idx].key_len)
+               if (!bigtk[notif_idx].key_status)
                        continue;
 
                wowlan_status->bigtk[status_idx].len = bigtk[notif_idx].key_len;
@@ -409,8 +428,17 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status,
 
                BUILD_BUG_ON(sizeof(wowlan_status->bigtk[status_idx].key) <
                             sizeof(bigtk[notif_idx].key));
-               memcpy(wowlan_status->bigtk[status_idx].key,
-                      bigtk[notif_idx].key, sizeof(bigtk[notif_idx].key));
+               if (bigtk[notif_idx].key_status == IWL_WOWLAN_STATUS_NEW_KEY)
+                       memcpy(wowlan_status->bigtk[status_idx].key,
+                              bigtk[notif_idx].key,
+                              sizeof(bigtk[notif_idx].key));
+               else
+                       /* If the key status is WOWLAN_STATUS_OLD_KEY, it
+                        * indicates that no key material is present. Set the
+                        * key length to 0 as an indication.
+                        */
+                       wowlan_status->bigtk[status_idx].len = 0;
+
                iwl_mld_convert_mcast_ipn(&wowlan_status->bigtk[status_idx],
                                          &bigtk[notif_idx]);
                status_idx++;
@@ -453,34 +481,165 @@ iwl_mld_convert_mlo_keys(struct iwl_mld *mld,
        }
 }
 
+static void
+iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5,
+                               struct iwl_wowlan_info_notif *notif)
+{
+       /* Convert GTK from v3 to the new format */
+       BUILD_BUG_ON(ARRAY_SIZE(notif->gtk) != ARRAY_SIZE(notif_v5->gtk));
+
+       for (int i = 0; i < ARRAY_SIZE(notif_v5->gtk); i++) {
+               const struct iwl_wowlan_gtk_status_v3 *gtk_v3 = &notif_v5->gtk[i];
+               struct iwl_wowlan_gtk_status *gtk = &notif->gtk[i];
+
+               /* Copy key material and metadata */
+               BUILD_BUG_ON(sizeof(gtk->key) != sizeof(gtk_v3->key));
+               BUILD_BUG_ON(sizeof(gtk->tkip_mic_key) != sizeof(gtk_v3->tkip_mic_key));
+
+               memcpy(gtk->key, gtk_v3->key, sizeof(gtk_v3->key));
+
+               gtk->key_len = gtk_v3->key_len;
+               gtk->key_flags = gtk_v3->key_flags;
+
+               memcpy(gtk->tkip_mic_key, gtk_v3->tkip_mic_key,
+                      sizeof(gtk_v3->tkip_mic_key));
+               gtk->sc = gtk_v3->sc;
+
+               /* Set key_status based on whether key material is present.
+                * in v5, a key is either invalid (should be skipped) or has
+                * both meta data and the key itself.
+                */
+               if (gtk_v3->key_len)
+                       gtk->key_status = IWL_WOWLAN_STATUS_NEW_KEY;
+       }
+
+       /* Convert IGTK from v1 to the new format, only one IGTK is passed by FW */
+       BUILD_BUG_ON(offsetof(struct iwl_wowlan_igtk_status, key_status) !=
+                    sizeof(struct iwl_wowlan_igtk_status_v1));
+
+       memcpy(&notif->igtk[0], &notif_v5->igtk[0],
+              offsetof(struct iwl_wowlan_igtk_status, key_status));
+
+       /* Set key_status based on whether key material is present.
+        * in v5, a key is either invalid (should be skipped) or has
+        * both meta data and the key itself.
+        */
+       if (notif_v5->igtk[0].key_len)
+               notif->igtk[0].key_status = IWL_WOWLAN_STATUS_NEW_KEY;
+
+       /* Convert BIGTK from v1 to the new format */
+       BUILD_BUG_ON(ARRAY_SIZE(notif->bigtk) != ARRAY_SIZE(notif_v5->bigtk));
+
+       for (int i = 0; i < ARRAY_SIZE(notif_v5->bigtk); i++) {
+               /* Copy everything until key_status */
+               memcpy(&notif->bigtk[i], &notif_v5->bigtk[i],
+                      offsetof(struct iwl_wowlan_igtk_status, key_status));
+
+               /* Set key_status based on whether key material is present.
+                * in v5, a key is either invalid (should be skipped) or has
+                * both meta data and the key itself.
+                */
+               if (notif_v5->bigtk[i].key_len)
+                       notif->bigtk[i].key_status = IWL_WOWLAN_STATUS_NEW_KEY;
+       }
+
+       notif->replay_ctr = notif_v5->replay_ctr;
+       notif->pattern_number = notif_v5->pattern_number;
+       notif->qos_seq_ctr = notif_v5->qos_seq_ctr;
+       notif->wakeup_reasons = notif_v5->wakeup_reasons;
+       notif->num_of_gtk_rekeys = notif_v5->num_of_gtk_rekeys;
+       notif->transmitted_ndps = notif_v5->transmitted_ndps;
+       notif->received_beacons = notif_v5->received_beacons;
+       notif->tid_tear_down = notif_v5->tid_tear_down;
+       notif->station_id = notif_v5->station_id;
+       notif->num_mlo_link_keys = notif_v5->num_mlo_link_keys;
+       notif->tid_offloaded_tx = notif_v5->tid_offloaded_tx;
+
+       /* Copy MLO GTK keys */
+       if (notif_v5->num_mlo_link_keys) {
+               memcpy(notif->mlo_gtks, notif_v5->mlo_gtks,
+                      notif_v5->num_mlo_link_keys * sizeof(struct iwl_wowlan_mlo_gtk));
+       }
+}
+
+static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld,
+                                              u32 len,
+                                              u32 expected_len,
+                                              u8 num_mlo_keys,
+                                              int version)
+{
+       u32 len_with_mlo_keys;
+
+       if (IWL_FW_CHECK(mld, len < expected_len,
+                        "Invalid wowlan_info_notif v%d (expected=%u got=%u)\n",
+                        version, expected_len, len))
+               return false;
+
+       len_with_mlo_keys = expected_len +
+               (num_mlo_keys * sizeof(struct iwl_wowlan_mlo_gtk));
+
+       if (IWL_FW_CHECK(mld, len < len_with_mlo_keys,
+                        "Invalid wowlan_info_notif v%d with MLO keys (expected=%u got=%u)\n",
+                        version, len_with_mlo_keys, len))
+               return false;
+
+       return true;
+}
+
 static bool
 iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld,
                                 struct iwl_mld_wowlan_status *wowlan_status,
                                 struct iwl_rx_packet *pkt)
 {
-       const struct iwl_wowlan_info_notif *notif = (void *)pkt->data;
+       const struct iwl_wowlan_info_notif *notif;
+       struct iwl_wowlan_info_notif *converted_notif __free(kfree) = NULL;
        u32 len = iwl_rx_packet_payload_len(pkt);
-       u32 len_with_mlo_keys;
-
-       if (IWL_FW_CHECK(mld, len < sizeof(*notif),
-                        "Invalid wowlan_info_notif (expected=%zu got=%u)\n",
-                        sizeof(*notif), len))
-               return true;
-
-       /* Now that we know that we have at least sizeof(notif),
-        * check also the variable length part
-        */
-       len_with_mlo_keys = sizeof(*notif) +
-               notif->num_mlo_link_keys * sizeof(notif->mlo_gtks[0]);
+       int wowlan_info_ver = iwl_fw_lookup_notif_ver(mld->fw,
+                                                     PROT_OFFLOAD_GROUP,
+                                                     WOWLAN_INFO_NOTIFICATION,
+                                                     IWL_FW_CMD_VER_UNKNOWN);
+
+       if (wowlan_info_ver == 5) {
+               /* v5 format - validate before conversion */
+               const struct iwl_wowlan_info_notif_v5 *notif_v5 = (void *)pkt->data;
+
+               if (!iwl_mld_validate_wowlan_notif_size(mld, len,
+                                                       sizeof(*notif_v5),
+                                                       notif_v5->num_mlo_link_keys,
+                                                       5))
+                       return true;
+
+               converted_notif = kzalloc(struct_size(converted_notif,
+                                                     mlo_gtks,
+                                                     notif_v5->num_mlo_link_keys),
+                                         GFP_ATOMIC);
+               if (!converted_notif) {
+                       IWL_ERR(mld,
+                               "Failed to allocate memory for converted wowlan_info_notif\n");
+                       return true;
+               }
 
-       if (IWL_FW_CHECK(mld, len < len_with_mlo_keys,
-                        "Invalid wowlan_info_notif (expected=%ud got=%u)\n",
-                        len_with_mlo_keys, len))
+               iwl_mld_convert_wowlan_notif_v5(notif_v5,
+                                               converted_notif);
+               notif = converted_notif;
+       } else if (wowlan_info_ver == 6) {
+               notif = (void *)pkt->data;
+               if (!iwl_mld_validate_wowlan_notif_size(mld, len,
+                                                       sizeof(*notif),
+                                                       notif->num_mlo_link_keys,
+                                                       6))
+                       return true;
+       } else {
+               /* smaller versions are not supported */
+               IWL_WARN(mld,
+                        "Unsupported wowlan_info_notif version %d\n",
+                        wowlan_info_ver);
                return true;
+       }
 
        if (IWL_FW_CHECK(mld, notif->tid_offloaded_tx != IWL_WOWLAN_OFFLOAD_TID,
                         "Invalid tid_offloaded_tx %d\n",
-                        wowlan_status->tid_offloaded_tx))
+                        notif->tid_offloaded_tx))
                return true;
 
        iwl_mld_convert_gtk_resume_data(mld, wowlan_status, notif->gtk,
index 431504195e33bf16159031a5f7342227f2b936b9..07f1a84c274efe9e110c53b859fb08b72642fd94 100644 (file)
@@ -2082,7 +2082,7 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status,
 }
 
 static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
-                                struct iwl_wowlan_igtk_status *data)
+                                struct iwl_wowlan_igtk_status_v1 *data)
 {
        int i;
 
@@ -2106,7 +2106,7 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status,
 }
 
 static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,
-                                 const struct iwl_wowlan_igtk_status *data)
+                                 const struct iwl_wowlan_igtk_status_v1 *data)
 {
        int data_idx, status_idx = 0;
 
@@ -2137,7 +2137,7 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status,
 }
 
 static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm,
-                                           struct iwl_wowlan_info_notif *data,
+                                           struct iwl_wowlan_info_notif_v5 *data,
                                            struct iwl_wowlan_status_data *status,
                                            u32 len)
 {
@@ -2907,7 +2907,7 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
                        iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif,
                                                           d3_data->status, len);
                } else if (wowlan_info_ver == 5) {
-                       struct iwl_wowlan_info_notif *notif =
+                       struct iwl_wowlan_info_notif_v5 *notif =
                                (void *)pkt->data;
 
                        iwl_mvm_parse_wowlan_info_notif(mvm, notif,