dsp: firmware_update: Run-time state machine for package parsing

Encoding the necessary sequence of calls with an approximation of linear
types is hampered by DSP0267's introduction of entirely new sections
into the package format across revisions. The existing design enforced a
sequence that precluded _not_ calling the decoder for downstream device
records in the case of pinning to format revision 1. The choice had the
further effect of stunting the API to future expansion of the spec.

Switch from linear types to tracking parse state at runtime based on the
provided pin and the extracted package header.

The state machine implementation is modeled on the TLA+ specification
below, with NR_FORMATS set to 4 in the model:

```tla
---- MODULE pldm_package_parser ----
EXTENDS Integers, Sequences

\* pin and format have non-deterministic init, but are then constant
VARIABLE state, pin, format

vars == << state, pin, format >>

States == {
    "Init",
    "Header",
    "FirmwareDevices",
    "DownstreamDevices",
    "ComponentImageInfos",
    "Complete",
    "Unsupported",
    "Error"
}

Formats == 1..4

DecodeHeader ==
    /\ state = "Init"
    /\ state' = IF format <= pin THEN "Header" ELSE "Unsupported"
    /\ UNCHANGED << pin, format >>

DecodeFirmwareDevices ==
    /\ state = "Header"
    /\ state' = "FirmwareDevices"
    /\ UNCHANGED << pin, format >>

DecodeDownstreamDevices ==
    /\ state = "FirmwareDevices"
    /\ state' = IF pin = 1 THEN "Error" ELSE "DownstreamDevices"
    /\ UNCHANGED << pin, format >>

DecodeComponentImageInfos ==
    /\ \/ /\ state = "FirmwareDevices"
          /\ pin = 1
       \/ /\ state = "DownstreamDevices"
          /\ pin \in ( Formats \ { 1 } )
    /\ state' = "Complete"
    /\ UNCHANGED << pin, format >>

Done == state \in { "Complete", "Unsupported", "Error" } /\ UNCHANGED vars

Init ==
    /\ state = "Init"
    /\ pin \in Formats
    /\ format \in Formats

Next ==
    \/ DecodeHeader
    \/ DecodeFirmwareDevices
    \/ DecodeDownstreamDevices
    \/ DecodeComponentImageInfos
    \/ Done

Spec == Init /\ [][Next]_vars /\ WF_state(Next)

TypeInvariant ==
    /\ state \in States
    /\ pin \in Formats
    /\ format \in Formats

Safety ==
    /\ TypeInvariant
    /\ state \in States \ { "Init", "Unsupported" } => format <= pin

Liveness ==
    /\ [][(state \in { "Complete", "Unsupported", "Error" } => UNCHANGED state)]_vars
    /\ [][UNCHANGED <<pin, format>>]_vars

====
```

For an introduction to TLA+ see https://www.learntla.com/

Note that the implemented state machine does not exactly replicate that
specified in the model. Specifically:

- No "Unsupported" state is defined. Instead, the APIs return -ENOTSUP
- No "Error" state is defined. Instead, the APIs return -EPROTO

It is expected that callers perform appropriate error handling.

Change-Id: Id8780c1f5f130b77e6eea2519b5d5734aa79040e
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 36187c0..63bfec5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -62,6 +62,9 @@
   - `encode_pldm_file_df_heartbeat_req()`
   - `decode_pldm_file_df_heartbeat_resp()`
 
+- Reworked the firmware update package parsing APIs to track parse state using a
+  run-time state machine
+
 ### Deprecated
 
 ### Removed
diff --git a/include/libpldm/firmware_update.h b/include/libpldm/firmware_update.h
index e62635c..596f708 100644
--- a/include/libpldm/firmware_update.h
+++ b/include/libpldm/firmware_update.h
@@ -2274,6 +2274,20 @@
 	} format;
 };
 
+enum pldm_package_parse {
+	PLDM_PACKAGE_PARSE_INIT = 0,
+	PLDM_PACKAGE_PARSE_COMPLETE = 1,
+	PLDM_PACKAGE_PARSE_HEADER = 2,
+	PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES = 3,
+	PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES = 4,
+	PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION = 5,
+};
+
+struct pldm_package_iter {
+	struct variable_field field;
+	size_t entries;
+};
+
 /**
  * @brief Header information as parsed from the provided package
  *
@@ -2290,10 +2304,6 @@
 
 	/** A field pointing to the package version string in the provided package data */
 	struct variable_field package_version_string;
-
-	/* TODO: some metadata for the parsing process is stored here, reconsider */
-	struct variable_field areas;
-	struct variable_field package;
 };
 /* TODO: Deprecate the other struct pldm_package_header_information, remove, drop typedef */
 typedef struct pldm__package_header_information
@@ -2440,21 +2450,6 @@
 	struct variable_field component_opaque_data;
 };
 
-struct pldm_package_firmware_device_id_record_iter {
-	struct variable_field field;
-	size_t entries;
-};
-
-struct pldm_package_downstream_device_id_record_iter {
-	struct variable_field field;
-	size_t entries;
-};
-
-struct pldm_package_component_image_information_iter {
-	struct variable_field field;
-	size_t entries;
-};
-
 /**
  * @brief State tracking for firmware update package iteration
  *
@@ -2469,13 +2464,13 @@
  * - @ref foreach_pldm_package_downstream_device_id_record_descriptor
  * - @ref foreach_pldm_package_component_image_information
  */
-struct pldm_package_iter {
+struct pldm_package {
+	const struct pldm_package_format_pin *pin;
 	const pldm_package_header_information_pad *hdr;
-
-	/* Modified in the course of iteration */
-	struct pldm_package_firmware_device_id_record_iter fds;
-	struct pldm_package_downstream_device_id_record_iter dds;
-	struct pldm_package_component_image_information_iter infos;
+	enum pldm_package_parse state;
+	struct variable_field package;
+	struct variable_field areas;
+	struct pldm_package_iter iter;
 };
 
 /**
@@ -2485,10 +2480,12 @@
  * @param[in] length The length of the buffer pointed at by @p data
  * @param[in] pin The maximum supported package format revision of the caller
  * @param[out] hdr The parsed package header structure
- * @param[out] iter State-tracking for parsing subsequent package records and components
+ * @param[out] pkg State-tracking for parsing subsequent package records and components
+ *
+ * @pre @p pkg must be zero-initialised.
  *
  * Must be called to ensure version requirements for parsing are met by all
- * components, and to initialise @p iter prior to any subsequent extraction of
+ * components, and to initialise @p pkg prior to any subsequent extraction of
  * package records and components.
  *
  * @note @p data is stored in @iter for later reference, and therefore must
@@ -2510,40 +2507,38 @@
 int decode_pldm_firmware_update_package(
 	const void *data, size_t length,
 	const struct pldm_package_format_pin *pin,
-	pldm_package_header_information_pad *hdr,
-	struct pldm_package_iter *iter);
+	pldm_package_header_information_pad *hdr, struct pldm_package *pkg);
 
 LIBPLDM_ITERATOR
 bool pldm_package_firmware_device_id_record_iter_end(
-	const struct pldm_package_firmware_device_id_record_iter *iter)
+	const struct pldm_package *pkg)
 {
-	return iter->entries == 0;
+	assert(pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES);
+	return pkg->iter.entries == 0;
 }
 
 LIBPLDM_ITERATOR
-bool pldm_package_firmware_device_id_record_iter_next(
-	struct pldm_package_firmware_device_id_record_iter *iter)
+bool pldm_package_firmware_device_id_record_iter_next(struct pldm_package *pkg)
 {
-	if (!iter->entries) {
+	assert(pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES);
+	if (!pkg->iter.entries) {
 		return false;
 	}
-	iter->entries--;
+
+	pkg->iter.entries--;
 	return true;
 }
 
-int pldm_package_firmware_device_id_record_iter_init(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *iter);
+int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg);
 
 int decode_pldm_package_firmware_device_id_record_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_firmware_device_id_record *rec);
 
 /**
  * @brief Iterate over a package's firmware device ID records
  *
- * @param iter[in,out] The lvalue for the instance of @ref "struct pldm_package_iter"
+ * @param pkg[in,out] The lvalue for the instance of @ref "struct pldm_package"
  *             initialised by @ref decode_pldm_firmware_update_package
  * @param rec[out] An lvalue of type @ref "struct pldm_package_firmware_device_id_record"
  * @param rc[out] An lvalue of type int that holds the status result of parsing the
@@ -2561,15 +2556,15 @@
  *
  * struct pldm_package_firmware_device_id_record fdrec;
  * pldm_package_header_information_pad hdr;
- * struct pldm_package_iter iter;
+ * struct pldm_package pkg;
  * int rc;
  *
  * rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
- * 					 &iter);
+ * 					 &pkg);
  * if (rc < 0) {
  * 	   // Handle header parsing failure
  * }
- * foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc) {
+ * foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc) {
  * 	   // Do something with fdrec
  * }
  * if (rc) {
@@ -2577,22 +2572,22 @@
  * }
  * @endcode
  */
-#define foreach_pldm_package_firmware_device_id_record(iter, rec, rc)          \
-	for ((rc) = pldm_package_firmware_device_id_record_iter_init(          \
-		     (iter).hdr, &(iter).fds);                                 \
+#define foreach_pldm_package_firmware_device_id_record(pkg, rec, rc)           \
+	for ((rc) = pldm_package_firmware_device_id_record_iter_init(&(pkg));  \
 	     !(rc) &&                                                          \
-	     !pldm_package_firmware_device_id_record_iter_end(&(iter).fds) &&  \
+	     !pldm_package_firmware_device_id_record_iter_end(&(pkg)) &&       \
 	     !((rc) = decode_pldm_package_firmware_device_id_record_from_iter( \
-		       (iter).hdr, &(iter).fds, &(rec)));                      \
-	     pldm_package_firmware_device_id_record_iter_next(&(iter).fds))
+		       &(pkg), &(rec)));                                       \
+	     pldm_package_firmware_device_id_record_iter_next(&(pkg)))
 
 LIBPLDM_ITERATOR
 struct pldm_descriptor_iter
 pldm_package_firmware_device_id_record_descriptor_iter_init(
-	struct pldm_package_firmware_device_id_record_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_firmware_device_id_record *rec)
 {
-	(void)iter;
+	(void)pkg;
+	assert(pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES);
 	return (struct pldm_descriptor_iter){ &rec->record_descriptors,
 					      rec->descriptor_count };
 }
@@ -2600,7 +2595,7 @@
 /**
  * @brief Iterate over the descriptors in a package's firmware device ID record
  *
- * @param iter[in,out] The lvalue for the instance of @ref "struct pldm_package_iter"
+ * @param pkg[in,out] The lvalue for the instance of @ref "struct pldm_package"
  *             initialised by @ref decode_pldm_firmware_update_package
  * @param rec[in] An lvalue of type @ref "struct pldm_package_firmware_device_id_record"
  * @param desc[out] An lvalue of type @ref "struct pldm_descriptor" that holds
@@ -2620,20 +2615,20 @@
  *
  * struct pldm_package_firmware_device_id_record fdrec;
  * pldm_package_header_information_pad hdr;
- * struct pldm_package_iter iter;
+ * struct pldm_package pkg;
  * int rc;
  *
  * rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
- * 					 &iter);
+ * 					 &pkg);
  * if (rc < 0) { ... }
  *
- * foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc) {
+ * foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc) {
  *     struct pldm_descriptor desc;
  *
  * 	   ...
  *
  *     foreach_pldm_package_firmware_device_id_record_descriptor(
- *             iter, fdrec, desc, rc) {
+ *             pkg, fdrec, desc, rc) {
  *         // Do something with desc
  *     }
  *     if (rc) {
@@ -2643,12 +2638,12 @@
  * if (rc) { ... }
  * @endcode
  */
-#define foreach_pldm_package_firmware_device_id_record_descriptor(iter, rec,      \
+#define foreach_pldm_package_firmware_device_id_record_descriptor(pkg, rec,       \
 								  desc, rc)       \
 	for (struct pldm_descriptor_iter desc##_iter =                            \
 		     ((rc) = 0,                                                   \
 		     pldm_package_firmware_device_id_record_descriptor_iter_init( \
-			      &(iter).fds, &(rec)));                              \
+			      &(pkg), &(rec)));                                   \
 	     (!pldm_descriptor_iter_end(&(desc##_iter))) &&                       \
 	     !((rc) = decode_pldm_descriptor_from_iter(&(desc##_iter),            \
 						       &(desc)));                 \
@@ -2656,36 +2651,33 @@
 
 LIBPLDM_ITERATOR
 bool pldm_package_downstream_device_id_record_iter_end(
-	const struct pldm_package_downstream_device_id_record_iter *iter)
+	const struct pldm_package *pkg)
 {
-	return iter->entries == 0;
+	assert(pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES);
+	return pkg->iter.entries == 0;
 }
 
 LIBPLDM_ITERATOR
-bool pldm_package_downstream_device_id_record_iter_next(
-	struct pldm_package_downstream_device_id_record_iter *iter)
+bool pldm_package_downstream_device_id_record_iter_next(struct pldm_package *pkg)
 {
-	if (!iter->entries) {
+	assert(pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES);
+	if (!pkg->iter.entries) {
 		return false;
 	}
-	iter->entries--;
+	pkg->iter.entries--;
 	return true;
 }
 
-int pldm_package_downstream_device_id_record_iter_init(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *fds,
-	struct pldm_package_downstream_device_id_record_iter *dds);
+int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg);
 
 int decode_pldm_package_downstream_device_id_record_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_downstream_device_id_record_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_downstream_device_id_record *rec);
 
 /**
  * @brief Iterate over a package's downstream device ID records
  *
- * @param iter[in,out] The lvalue for the instance of @ref "struct pldm_package_iter"
+ * @param pkg[in,out] The lvalue for the instance of @ref "struct pldm_package"
  *             initialised by @ref decode_pldm_firmware_update_package
  * @param rec[out] An lvalue of type @ref "struct pldm_package_downstream_device_id_record"
  * @param rc[out] An lvalue of type int that holds the status result of parsing the
@@ -2704,25 +2696,25 @@
  * struct pldm_package_downstream_device_id_record ddrec;
  * struct pldm_package_firmware_device_id_record fdrec;
  * pldm_package_header_information_pad hdr;
- * struct pldm_package_iter iter;
+ * struct pldm_package pkg;
  * int rc;
  *
  * rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
- * 					 &iter);
+ * 					 &pkg);
  * if (rc < 0) { ... }
  *
- * foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc) {
+ * foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc) {
  *     struct pldm_descriptor desc;
  * 	   ...
  *     foreach_pldm_package_firmware_device_id_record_descriptor(
- *             iter, fdrec, desc, rc) {
+ *             pkg, fdrec, desc, rc) {
  *         ...
  *     }
  *     if (rc) { ... }
  * }
  * if (rc) { ... }
  *
- * foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc) {
+ * foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc) {
  * 	   // Do something with ddrec
  * }
  * if (rc) {
@@ -2730,23 +2722,22 @@
  * }
  * @endcode
  */
-#define foreach_pldm_package_downstream_device_id_record(iter, rec, rc)          \
+#define foreach_pldm_package_downstream_device_id_record(pkg, rec, rc)           \
 	for ((rc) = pldm_package_downstream_device_id_record_iter_init(          \
-		     (iter).hdr, &(iter).fds, &(iter).dds);                      \
+		     &(pkg));                                                    \
 	     !(rc) &&                                                            \
-	     !pldm_package_downstream_device_id_record_iter_end(                 \
-		     &(iter).dds) &&                                             \
+	     !pldm_package_downstream_device_id_record_iter_end(&(pkg)) &&       \
 	     !((rc) = decode_pldm_package_downstream_device_id_record_from_iter( \
-		       (iter).hdr, &(iter).dds, &(rec)));                        \
-	     pldm_package_downstream_device_id_record_iter_next(&(iter).dds))
+		       &(pkg), &(rec)));                                         \
+	     pldm_package_downstream_device_id_record_iter_next(&(pkg)))
 
 LIBPLDM_ITERATOR
 struct pldm_descriptor_iter
 pldm_package_downstream_device_id_record_descriptor_iter_init(
-	struct pldm_package_downstream_device_id_record_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_downstream_device_id_record *rec)
 {
-	(void)iter;
+	(void)pkg;
 	return (struct pldm_descriptor_iter){ &rec->record_descriptors,
 					      rec->descriptor_count };
 }
@@ -2754,7 +2745,7 @@
 /**
  * @brief Iterate over the descriptors in a package's downstream device ID record
  *
- * @param iter[in,out] The lvalue for the instance of @ref "struct pldm_package_iter"
+ * @param pkg[in,out] The lvalue for the instance of @ref "struct pldm_package"
  *             initialised by @ref decode_pldm_firmware_update_package
  * @param rec[in] An lvalue of type @ref "struct pldm_package_downstream_device_id_record"
  * @param desc[out] An lvalue of type @ref "struct pldm_descriptor" that holds
@@ -2775,29 +2766,29 @@
  * struct pldm_package_downstream_device_id_record ddrec;
  * struct pldm_package_firmware_device_id_record fdrec;
  * pldm_package_header_information_pad hdr;
- * struct pldm_package_iter iter;
+ * struct pldm_package pkg;
  * int rc;
  *
  * rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
- * 					 &iter);
+ * 					 &pkg);
  * if (rc < 0) { ... }
  *
- * foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc) {
+ * foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc) {
  *     struct pldm_descriptor desc;
  * 	   ...
  *     foreach_pldm_package_firmware_device_id_record_descriptor(
- *             iter, fdrec, desc, rc) {
+ *             pkg, fdrec, desc, rc) {
  *         ...
  *     }
  *     if (rc) { ... }
  * }
  * if (rc) { ... }
  *
- * foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc) {
+ * foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc) {
  *     struct pldm_descriptor desc;
  * 	   ...
  *     foreach_pldm_package_downstream_device_id_record_descriptor(
- *             iter, ddrec, desc, rc)
+ *             pkg, ddrec, desc, rc)
  *     {
  *         // Do something with desc
  *     }
@@ -2808,12 +2799,12 @@
  * if (rc) { ... }
  * @endcode
  */
-#define foreach_pldm_package_downstream_device_id_record_descriptor(iter, rec,      \
+#define foreach_pldm_package_downstream_device_id_record_descriptor(pkg, rec,       \
 								    desc, rc)       \
 	for (struct pldm_descriptor_iter desc##_iter =                              \
 		     ((rc) = 0,                                                     \
 		     pldm_package_downstream_device_id_record_descriptor_iter_init( \
-			      &(iter).dds, &(rec)));                                \
+			      &(pkg), &(rec)));                                     \
 	     (!pldm_descriptor_iter_end(&(desc##_iter))) &&                         \
 	     !((rc) = decode_pldm_descriptor_from_iter(&(desc##_iter),              \
 						       &(desc)));                   \
@@ -2821,36 +2812,44 @@
 
 LIBPLDM_ITERATOR
 bool pldm_package_component_image_information_iter_end(
-	const struct pldm_package_component_image_information_iter *iter)
+	const struct pldm_package *pkg)
 {
-	return (iter->entries == 0);
+	assert((pkg->state == PLDM_PACKAGE_PARSE_COMPLETE &&
+		pkg->iter.entries == 0) ||
+	       pkg->state == PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION);
+	return pkg->state == PLDM_PACKAGE_PARSE_COMPLETE;
 }
 
 LIBPLDM_ITERATOR
-bool pldm_package_component_image_information_iter_next(
-	struct pldm_package_component_image_information_iter *iter)
+bool pldm_package_component_image_information_iter_next(struct pldm_package *pkg)
 {
-	if (!iter->entries) {
+	if (pkg->state == PLDM_PACKAGE_PARSE_COMPLETE) {
 		return false;
 	}
-	iter->entries--;
+
+	assert(pkg->state == PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION);
+	pkg->iter.entries--;
+	if (!pkg->iter.entries) {
+		/*
+		 * Perform the final transition to complete now as there should be no further
+		 * interaction with the package parsing APIs
+		 */
+		pkg->state = PLDM_PACKAGE_PARSE_COMPLETE;
+		return false;
+	}
 	return true;
 }
 
-int pldm_package_component_image_information_iter_init(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_downstream_device_id_record_iter *dds,
-	struct pldm_package_component_image_information_iter *infos);
+int pldm_package_component_image_information_iter_init(struct pldm_package *pkg);
 
 int decode_pldm_package_component_image_information_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_component_image_information_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_component_image_information *info);
 
 /**
  * @brief Iterate over the component image information contained in the package
  *
- * @param iter[in,out] The lvalue for the instance of @ref "struct pldm_package_iter"
+ * @param pkg[in,out] The lvalue for the instance of @ref "struct pldm_package"
  *             initialised by @ref decode_pldm_firmware_update_package
  * @param rec[in] An lvalue of type @ref "struct pldm_package_downstream_device_id_record"
  * @param desc[out] An lvalue of type @ref "struct pldm_descriptor" that holds
@@ -2872,36 +2871,36 @@
  * struct pldm_package_component_image_information info;
  * struct pldm_package_firmware_device_id_record fdrec;
  * pldm_package_header_information_pad hdr;
- * struct pldm_package_iter iter;
+ * struct pldm_package pkg;
  * int rc;
  *
  * rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
- * 					 &iter);
+ * 					 &pkg);
  * if (rc < 0) { ... }
  *
- * foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc) {
+ * foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc) {
  *     struct pldm_descriptor desc;
  * 	   ...
  *     foreach_pldm_package_firmware_device_id_record_descriptor(
- *             iter, fdrec, desc, rc) {
+ *             pkg, fdrec, desc, rc) {
  *         ...
  *     }
  *     if (rc) { ... }
  * }
  * if (rc) { ... }
  *
- * foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc) {
+ * foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc) {
  *     struct pldm_descriptor desc;
  * 	   ...
  *     foreach_pldm_package_downstream_device_id_record_descriptor(
- *             iter, ddrec, desc, rc) {
+ *             pkg, ddrec, desc, rc) {
  *         ...
  *     }
  *     if (rc) { ... }
  * }
  * if (rc) { ... }
  *
- * foreach_pldm_package_component_image_information(iter, info, rc) {
+ * foreach_pldm_package_component_image_information(pkg, info, rc) {
  *     // Do something with info
  * }
  * if (rc) {
@@ -2909,16 +2908,14 @@
  * }
  * @endcode
  */
-#define foreach_pldm_package_component_image_information(iter, info, rc)         \
+#define foreach_pldm_package_component_image_information(pkg, info, rc)          \
 	for ((rc) = pldm_package_component_image_information_iter_init(          \
-		     (iter).hdr, &(iter).dds, &(iter).infos);                    \
+		     &(pkg));                                                    \
 	     !(rc) &&                                                            \
-	     !pldm_package_component_image_information_iter_end(                 \
-		     &(iter).infos) &&                                           \
+	     !pldm_package_component_image_information_iter_end(&(pkg)) &&       \
 	     !((rc) = decode_pldm_package_component_image_information_from_iter( \
-		       (iter).hdr, &(iter).infos, &(info)));                     \
-	     pldm_package_component_image_information_iter_next(                 \
-		     &(iter).infos))
+		       &(pkg), &(info)));                                        \
+	     pldm_package_component_image_information_iter_next(&(pkg)))
 
 /**
  * Declare consumer support for at most revision 1 of the firmware update
@@ -2932,11 +2929,11 @@
 	struct pldm_package_format_pin name = { \
 		.meta = { \
 			.magic = ( \
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) + \
+				LIBPLDM_SIZEAT(struct pldm_package, iter) + \
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) + \
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) + \
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) + \
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos) \
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) \
 			), \
 			.version = 0u, \
 		}, \
@@ -2958,12 +2955,12 @@
 	struct pldm_package_format_pin name = { \
 		.meta = { \
 			.magic = ( \
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) + \
+				LIBPLDM_SIZEAT(struct pldm_package, iter) + \
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) + \
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) + \
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) + \
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) + \
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos) \
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) \
 			), \
 			.version = 0u, \
 		}, \
@@ -2985,12 +2982,12 @@
 	struct pldm_package_format_pin name = { \
 		.meta = { \
 			.magic = ( \
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) + \
+				LIBPLDM_SIZEAT(struct pldm_package, iter) + \
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) + \
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) + \
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) + \
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos) \
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) \
 			), \
 			.version = 0u, \
 		}, \
@@ -3012,12 +3009,12 @@
 	struct pldm_package_format_pin name = { \
 		.meta = { \
 			.magic = ( \
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) + \
+				LIBPLDM_SIZEAT(struct pldm_package, iter) + \
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) + \
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, reference_manifest_data) + \
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) + \
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, reference_manifest_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) + \
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos) \
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) \
 			), \
 			.version = 0u, \
 		}, \
diff --git a/src/dsp/firmware_update.c b/src/dsp/firmware_update.c
index d7e238b..8c2e1db 100644
--- a/src/dsp/firmware_update.c
+++ b/src/dsp/firmware_update.c
@@ -336,7 +336,8 @@
 static int
 decode_pldm_package_header_info_errno(const void *data, size_t length,
 				      const struct pldm_package_format_pin *pin,
-				      pldm_package_header_information_pad *hdr)
+				      pldm_package_header_information_pad *hdr,
+				      struct pldm_package *pkg)
 {
 	static const struct pldm_package_header_format_revision_info {
 		pldm_uuid identifier;
@@ -346,44 +347,44 @@
 			.identifier = {0},
 			.magic = 0,
 		},
-		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H */
+		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H] = {
 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_0,
 			.magic =
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
+				LIBPLDM_SIZEAT(struct pldm_package, iter) +
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos)
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string)
 		},
-		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H */
+		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H] = {
 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_1,
 			.magic =
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
+				LIBPLDM_SIZEAT(struct pldm_package, iter) +
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string) +
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_version_string)
 		},
-		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H */
+		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H] = {
 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_2,
 			.magic =
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
+				LIBPLDM_SIZEAT(struct pldm_package, iter) +
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, firmware_device_package_data) +
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, package_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data)
 		},
-		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H] = { /* PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H */
+		[PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H] = {
 			.identifier = PLDM_PACKAGE_HEADER_IDENTIFIER_V1_3,
 			.magic =
-				LIBPLDM_SIZEAT(struct pldm__package_header_information, package) +
+				LIBPLDM_SIZEAT(struct pldm_package, iter) +
+				LIBPLDM_SIZEAT(struct pldm__package_header_information, package_version_string) +
 				LIBPLDM_SIZEAT(struct pldm_package_firmware_device_id_record, reference_manifest_data) +
 				LIBPLDM_SIZEAT(struct pldm_descriptor, descriptor_data) +
 				LIBPLDM_SIZEAT(struct pldm_package_downstream_device_id_record, reference_manifest_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data) +
-				LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
+				LIBPLDM_SIZEAT(struct pldm_package_component_image_information, component_opaque_data)
 		},
 	};
 
@@ -400,11 +401,15 @@
 	int checksums = 1;
 	int rc;
 
-	if (pin->meta.version > 0) {
+	if (pkg->state != PLDM_PACKAGE_PARSE_INIT) {
+		return -EINVAL;
+	}
+
+	if (pin->meta.version > 0u) {
 		return -ENOTSUP;
 	}
 
-	if (pin->format.revision == 0) {
+	if (pin->format.revision == 0u) {
 		return -EINVAL;
 	}
 
@@ -415,7 +420,7 @@
 			      1 + PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H,
 		      "Mismatched array bounds test");
 
-	info = &revision_info[pin->format.revision];
+	info = &revision_info[(size_t)pin->format.revision];
 	if (memcmp(&pin->format.identifier, info->identifier,
 		   sizeof(info->identifier)) != 0) {
 		return -ENOTSUP;
@@ -525,11 +530,11 @@
 	package_header_areas_size = package_header_variable_size -
 				    hdr->package_version_string.length;
 	rc = pldm_msgbuf_span_required(buf, package_header_areas_size,
-				       (void **)&hdr->areas.ptr);
+				       (void **)&pkg->areas.ptr);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
-	hdr->areas.length = package_header_areas_size;
+	pkg->areas.length = package_header_areas_size;
 
 	pldm_msgbuf_extract(buf, package_header_checksum);
 
@@ -574,8 +579,11 @@
 	}
 
 	/* We stash these to resolve component images later */
-	hdr->package.ptr = data;
-	hdr->package.length = length;
+	pkg->pin = pin;
+	pkg->hdr = hdr;
+	pkg->state = PLDM_PACKAGE_PARSE_HEADER;
+	pkg->package.ptr = data;
+	pkg->package.length = length;
 
 	return 0;
 }
@@ -588,13 +596,15 @@
 {
 	DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
 	pldm_package_header_information_pad hdr;
+	struct pldm_package pkg = { 0 };
 	int rc;
 
 	if (!data || !package_header_info || !package_version_str) {
 		return PLDM_ERROR_INVALID_DATA;
 	}
 
-	rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr);
+	rc = decode_pldm_package_header_info_errno(data, length, &pin, &hdr,
+						   &pkg);
 	if (rc < 0) {
 		return pldm_xlate_errno(rc);
 	}
@@ -693,10 +703,6 @@
 		return -EINVAL;
 	}
 
-	if (hdr->component_bitmap_bit_length & 7) {
-		return -EPROTO;
-	}
-
 	rc = pldm_msgbuf_init_dynamic_uint16(
 		buf, PLDM_FWUP_FIRMWARE_DEVICE_ID_RECORD_MIN_SIZE,
 		(void *)field->ptr, field->length, (void **)&field->ptr,
@@ -746,6 +752,7 @@
 		rec->reference_manifest_data.length = 0;
 	}
 
+	assert((hdr->component_bitmap_bit_length & 7) == 0);
 	rc = pldm_msgbuf_span_required(
 		buf, hdr->component_bitmap_bit_length / 8,
 		(void **)&rec->applicable_components.bitmap.ptr);
@@ -3251,31 +3258,48 @@
 int decode_pldm_firmware_update_package(
 	const void *data, size_t length,
 	const struct pldm_package_format_pin *pin,
-	pldm_package_header_information_pad *hdr,
-	struct pldm_package_iter *iter)
+	pldm_package_header_information_pad *hdr, struct pldm_package *pkg)
 {
-	if (!data || !pin || !hdr || !iter) {
+	if (!data || !pin || !hdr || !pkg) {
 		return -EINVAL;
 	}
 
-	iter->hdr = hdr;
-
-	return decode_pldm_package_header_info_errno(data, length, pin, hdr);
+	return decode_pldm_package_header_info_errno(data, length, pin, hdr,
+						     pkg);
 }
 
 LIBPLDM_ABI_TESTING
-int pldm_package_firmware_device_id_record_iter_init(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *iter)
+int pldm_package_firmware_device_id_record_iter_init(struct pldm_package *pkg)
 {
+	struct pldm_package_iter *iter;
 	PLDM_MSGBUF_DEFINE_P(buf);
 	int rc;
 
-	if (!hdr || !iter || !hdr->areas.ptr) {
+	if (!pkg || !pkg->pin || !pkg->hdr) {
 		return -EINVAL;
 	}
 
-	iter->field = hdr->areas;
+	assert(pkg->pin->format.revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->pin->format.revision <=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
+	assert(pkg->hdr->package_header_format_revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->hdr->package_header_format_revision <=
+	       pkg->pin->format.revision);
+
+	if (pkg->state != PLDM_PACKAGE_PARSE_HEADER) {
+		return -EPROTO;
+	}
+
+	if (!pkg->areas.ptr) {
+		return -EINVAL;
+	}
+
+	pkg->state = PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES;
+
+	iter = &pkg->iter;
+	iter->field = pkg->areas;
 
 	/* Extract the fd record id count */
 	rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
@@ -3293,47 +3317,81 @@
 
 LIBPLDM_ABI_TESTING
 int decode_pldm_package_firmware_device_id_record_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *iter,
+	struct pldm_package *pkg LIBPLDM_CC_UNUSED,
 	struct pldm_package_firmware_device_id_record *rec)
 {
-	return decode_pldm_package_firmware_device_id_record_errno(
-		hdr, &iter->field, rec);
-}
-
-LIBPLDM_ABI_TESTING
-int pldm_package_downstream_device_id_record_iter_init(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_firmware_device_id_record_iter *fds,
-	struct pldm_package_downstream_device_id_record_iter *dds)
-{
-	PLDM_MSGBUF_DEFINE_P(buf);
-	int rc;
-
-	if (!hdr || !fds || !dds || !fds->field.ptr) {
+	if (!pkg) {
 		return -EINVAL;
 	}
 
-	dds->field = fds->field;
-	fds->field.ptr = NULL;
-	fds->field.length = 0;
+	if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
+		return -EPROTO;
+	}
 
-	/* Downstream device ID records aren't specified in revision 1 */
-	if (hdr->package_header_format_revision <
-	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
-		dds->entries = 0;
+	return decode_pldm_package_firmware_device_id_record_errno(
+		pkg->hdr, &pkg->iter.field, rec);
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_package_downstream_device_id_record_iter_init(struct pldm_package *pkg)
+{
+	struct pldm_package_iter *iter;
+	PLDM_MSGBUF_DEFINE_P(buf);
+	int rc;
+
+	if (!pkg || !pkg->pin || !pkg->hdr) {
+		return -EINVAL;
+	}
+
+	assert(pkg->pin->format.revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->pin->format.revision <=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
+	assert(pkg->hdr->package_header_format_revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->hdr->package_header_format_revision <=
+	       pkg->pin->format.revision);
+
+	if (pkg->state != PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
+		return -EPROTO;
+	}
+
+	if (pkg->pin->format.revision ==
+	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
+		return -EPROTO;
+	}
+
+	if (!pkg->iter.field.ptr) {
+		return -EINVAL;
+	}
+	iter = &pkg->iter;
+
+	pkg->state = PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES;
+
+	/* Where:
+	 *
+	 * 1. The pin revision is greater than 1, and
+	 * 2. The package header format revision is 1
+	 *
+	 * We must account for the invocation of this function but present no downstream
+   * devices, as they're not specified.
+	 */
+	if (pkg->hdr->package_header_format_revision ==
+	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H) {
+		iter->entries = 0;
 		return 0;
 	}
 
 	/* Extract the dd record id count */
-	rc = pldm_msgbuf_init_errno(buf, 1, dds->field.ptr, dds->field.length);
+	rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
+				    iter->field.length);
 	if (rc) {
 		return rc;
 	}
 
-	pldm_msgbuf_extract_uint8_to_size(buf, dds->entries);
-	pldm_msgbuf_span_remaining(buf, (void **)&dds->field.ptr,
-				   &dds->field.length);
+	pldm_msgbuf_extract_uint8_to_size(buf, iter->entries);
+	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
 }
@@ -3341,29 +3399,31 @@
 #define PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE 11
 LIBPLDM_ABI_TESTING
 int decode_pldm_package_downstream_device_id_record_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_downstream_device_id_record_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_downstream_device_id_record *rec)
 {
+	struct pldm_package_iter *iter;
 	size_t package_data_offset;
 	PLDM_MSGBUF_DEFINE_P(buf);
 	uint16_t record_len = 0;
 	int rc;
 
-	if (!hdr || !iter || !rec || !iter->field.ptr) {
+	if (!pkg || !rec || !pkg->hdr) {
 		return -EINVAL;
 	}
 
-	if (hdr->package_header_format_revision <
-	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR02H) {
-		/* Should not be reached due to corresponding test in iter initialisation */
-		return -ENOTSUP;
-	}
-
-	if (hdr->component_bitmap_bit_length & 7) {
+	if (pkg->state != PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
 		return -EPROTO;
 	}
 
+	assert(pkg->hdr->package_header_format_revision >
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+
+	if (!pkg->iter.field.ptr) {
+		return -EINVAL;
+	}
+	iter = &pkg->iter;
+
 	rc = pldm_msgbuf_init_dynamic_uint16(
 		buf, PLDM_FWUP_DOWNSTREAM_DEVICE_ID_RECORD_MIN_SIZE,
 		(void *)iter->field.ptr, iter->field.length,
@@ -3401,7 +3461,7 @@
 		return pldm_msgbuf_discard(buf, rc);
 	}
 
-	if (hdr->package_header_format_revision >=
+	if (pkg->hdr->package_header_format_revision >=
 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
 		pldm_msgbuf_extract_uint32_to_size(
 			buf, rec->reference_manifest_data.length);
@@ -3409,14 +3469,15 @@
 		rec->reference_manifest_data.length = 0;
 	}
 
+	assert((pkg->hdr->component_bitmap_bit_length & 7) == 0);
 	rc = pldm_msgbuf_span_required(
-		buf, hdr->component_bitmap_bit_length / 8,
+		buf, pkg->hdr->component_bitmap_bit_length / 8,
 		(void **)&rec->applicable_components.bitmap.ptr);
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
 	rec->applicable_components.bitmap.length =
-		hdr->component_bitmap_bit_length / 8;
+		pkg->hdr->component_bitmap_bit_length / 8;
 
 	pldm_msgbuf_span_required(
 		buf, rec->self_contained_activation_min_version_string.length,
@@ -3441,7 +3502,7 @@
 				  (void **)&rec->package_data.ptr);
 
 	/* Supported in package header revision 1.3 (FR04H) and above. */
-	if (hdr->package_header_format_revision >=
+	if (pkg->hdr->package_header_format_revision >=
 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H) {
 		pldm_msgbuf_span_required(
 			buf, rec->reference_manifest_data.length,
@@ -3455,26 +3516,50 @@
 }
 
 LIBPLDM_ABI_TESTING
-int pldm_package_component_image_information_iter_init(
-	const pldm_package_header_information_pad *hdr LIBPLDM_CC_UNUSED,
-	struct pldm_package_downstream_device_id_record_iter *dds,
-	struct pldm_package_component_image_information_iter *infos)
+int pldm_package_component_image_information_iter_init(struct pldm_package *pkg)
 {
+	struct pldm_package_iter *iter;
 	uint16_t component_image_count;
 	PLDM_MSGBUF_DEFINE_P(buf);
 	int rc;
 
-	if (!dds || !infos) {
+	if (!pkg || !pkg->pin || !pkg->hdr) {
 		return -EINVAL;
 	}
 
-	infos->field = dds->field;
-	dds->field.ptr = NULL;
-	dds->field.length = 0;
+	assert(pkg->pin->format.revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->pin->format.revision <=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR04H);
+	assert(pkg->hdr->package_header_format_revision >=
+	       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	assert(pkg->hdr->package_header_format_revision <=
+	       pkg->pin->format.revision);
+
+	if (pkg->state == PLDM_PACKAGE_PARSE_FIRMWARE_DEVICES) {
+		if (pkg->pin->format.revision !=
+			    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H ||
+		    pkg->hdr->package_header_format_revision !=
+			    pkg->pin->format.revision) {
+			return -EPROTO;
+		}
+	} else if (pkg->state == PLDM_PACKAGE_PARSE_DOWNSTREAM_DEVICES) {
+		assert(pkg->pin->format.revision !=
+		       PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR01H);
+	} else {
+		return -EPROTO;
+	}
+
+	if (!pkg->iter.field.ptr) {
+		return -EINVAL;
+	}
+	iter = &pkg->iter;
+
+	pkg->state = PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION;
 
 	/* Extract the component image count */
-	rc = pldm_msgbuf_init_errno(buf, 1, infos->field.ptr,
-				    infos->field.length);
+	rc = pldm_msgbuf_init_errno(buf, 1, iter->field.ptr,
+				    iter->field.length);
 	if (rc) {
 		return rc;
 	}
@@ -3483,10 +3568,10 @@
 	if (rc) {
 		return pldm_msgbuf_discard(buf, rc);
 	}
-	infos->entries = component_image_count;
+	iter->entries = component_image_count;
 
-	pldm_msgbuf_span_remaining(buf, (void **)&infos->field.ptr,
-				   &infos->field.length);
+	pldm_msgbuf_span_remaining(buf, (void **)&iter->field.ptr,
+				   &iter->field.length);
 
 	return pldm_msgbuf_complete(buf);
 }
@@ -3494,23 +3579,28 @@
 #define PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE 22
 LIBPLDM_ABI_TESTING
 int decode_pldm_package_component_image_information_from_iter(
-	const pldm_package_header_information_pad *hdr,
-	struct pldm_package_component_image_information_iter *iter,
+	struct pldm_package *pkg,
 	struct pldm_package_component_image_information *info)
 {
 	uint32_t component_location_offset = 0;
+	struct pldm_package_iter *iter;
 	uint32_t component_size = 0;
 	PLDM_MSGBUF_DEFINE_P(buf);
 	int rc;
 
-	if (!hdr || !iter || !info || !iter->field.ptr) {
+	if (!pkg || !info) {
 		return -EINVAL;
 	}
 
-	if (hdr->component_bitmap_bit_length & 7) {
+	if (pkg->state != PLDM_PACKAGE_PARSE_COMPONENT_IMAGE_INFORMATION) {
 		return -EPROTO;
 	}
 
+	if (!pkg->iter.field.ptr) {
+		return -EINVAL;
+	}
+	iter = &pkg->iter;
+
 	rc = pldm_msgbuf_init_errno(
 		buf, PLDM_FWUP_COMPONENT_IMAGE_INFORMATION_MIN_SIZE,
 		iter->field.ptr, iter->field.length);
@@ -3545,7 +3635,7 @@
 				  (void **)&info->component_version_string.ptr);
 
 	/* Supported in package header revision 1.2 (FR03H) and above. */
-	if (hdr->package_header_format_revision >=
+	if (pkg->hdr->package_header_format_revision >=
 	    PLDM_PACKAGE_HEADER_FORMAT_REVISION_FR03H) {
 		rc = pldm_msgbuf_extract_uint32_to_size(
 			buf, info->component_opaque_data.length);
@@ -3577,8 +3667,8 @@
 	}
 
 	/* Resolve the component image in memory */
-	rc = pldm_msgbuf_init_errno(buf, 0, hdr->package.ptr,
-				    hdr->package.length);
+	rc = pldm_msgbuf_init_errno(buf, 0, pkg->package.ptr,
+				    pkg->package.length);
 	if (rc) {
 		return rc;
 	}
diff --git a/tests/dsp/firmware_update.cpp b/tests/dsp/firmware_update.cpp
index 21b65ca..d467f00 100644
--- a/tests/dsp/firmware_update.cpp
+++ b/tests/dsp/firmware_update.cpp
@@ -4828,19 +4828,19 @@
 {
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     uint8_t data;
     int rc;
 
-    rc = decode_pldm_firmware_update_package(nullptr, 0, &pin, &hdr, &iter);
+    rc = decode_pldm_firmware_update_package(nullptr, 0, &pin, &hdr, &pkg);
     EXPECT_EQ(rc, -EINVAL);
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), nullptr, &hdr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -EINVAL);
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &pin, nullptr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -EINVAL);
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &pin, &hdr,
@@ -4866,12 +4866,12 @@
     };
 
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     uint8_t data = 0;
     int rc;
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &pin, &hdr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -ENOTSUP);
 }
 #endif
@@ -4906,16 +4906,16 @@
     };
 
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     uint8_t data = 0;
     int rc;
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &lowPin, &hdr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -EINVAL);
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &highPin,
-                                             &hdr, &iter);
+                                             &hdr, &pkg);
     EXPECT_EQ(rc, -ENOTSUP);
 }
 #endif
@@ -4950,16 +4950,16 @@
     };
 
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     uint8_t data = 0;
     int rc;
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &lowPin, &hdr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -EINVAL);
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &highPin,
-                                             &hdr, &iter);
+                                             &hdr, &pkg);
     EXPECT_EQ(rc, -EINVAL);
 }
 #endif
@@ -4971,8 +4971,9 @@
         .meta =
             {
                 .magic =
+                    LIBPLDM_SIZEAT(struct pldm_package, iter) +
                     LIBPLDM_SIZEAT(struct pldm__package_header_information,
-                                   package) +
+                                   package_version_string) +
                     LIBPLDM_SIZEAT(
                         struct pldm_package_firmware_device_id_record,
                         firmware_device_package_data) +
@@ -4982,8 +4983,7 @@
                         package_data) +
                     LIBPLDM_SIZEAT(
                         struct pldm_package_component_image_information,
-                        component_version_string) +
-                    LIBPLDM_SIZEAT(struct pldm_package_iter, infos),
+                        component_version_string),
                 .version = 0,
             },
         .format =
@@ -4994,12 +4994,12 @@
     };
 
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     uint8_t data = 0;
     int rc;
 
     rc = decode_pldm_firmware_update_package(&data, sizeof(data), &pin, &hdr,
-                                             &iter);
+                                             &pkg);
     EXPECT_EQ(rc, -ENOTSUP);
 }
 #endif
@@ -5019,17 +5019,255 @@
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
 
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     int rc;
 
     rc = decode_pldm_firmware_update_package(package.data(), package.size(),
-                                             &pin, &hdr, &iter);
+                                             &pin, &hdr, &pkg);
     EXPECT_EQ(rc, -ENOTSUP);
 }
 #endif
 
 #ifdef LIBPLDM_API_TESTING
-TEST(DecodePldmFirmwareUpdatePackage, v1h1fd1fdd1cii)
+TEST(DecodePldmFirmwareUpdatePackage, p1v1h1fd1cii)
+{
+    const std::array<uint8_t, 102> package{
+        0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00, 0xa0,
+        0x2f, 0x05, 0x9a, 0xca, 0x02, 0x01, 0x65, 0x00, 0x00, 0xe9, 0x07,
+        0x03, 0x0b, 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x08,
+        0x00, 0x01, 0x04, 't',  'e',  's',  't',
+
+        0x01, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+        0x00, 0x01, 'v',  '0',  '.',  '1',  0x01, 0x00, 0x04, 0x00, 0x9c,
+        0x01, 0x00, 0x00,
+
+        0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+        0x00, 0x01, 0x00, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x01, 0x04, 'v',  '0',  '.',  '2',  0x00, 0x00, 0x00, 0x00,
+
+        0xb5, 0x3f, 0xf6, 0x6a,
+
+        0x5a,
+    };
+
+    struct pldm_package_component_image_information info;
+    struct pldm_package_firmware_device_id_record fdrec;
+    DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
+    pldm_package_header_information_pad hdr;
+    struct pldm_package pkg{};
+    int nr_fdrec_desc = 0;
+    int nr_fdrec = 0;
+    int nr_infos = 0;
+    int rc;
+
+    rc = decode_pldm_firmware_update_package(package.data(), package.size(),
+                                             &pin, &hdr, &pkg);
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_0.data(),
+                     hdr.package_header_identifier,
+                     PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_0.size()),
+              0);
+    EXPECT_EQ(hdr.package_header_format_revision, 1);
+
+    static const std::array<uint8_t, 13> timestamp{0x00, 0xe9, 0x07, 0x03, 0x0b,
+                                                   0x16, 0x03, 0x00, 0x00, 0x00,
+                                                   0x00, 0x76, 0x02};
+    ASSERT_EQ(timestamp.size(), sizeof(hdr.package_release_date_time));
+    EXPECT_EQ(memcmp(timestamp.data(), hdr.package_release_date_time,
+                     timestamp.size()),
+              0);
+
+    EXPECT_EQ(hdr.component_bitmap_bit_length, 8);
+    EXPECT_EQ(hdr.package_version_string_type, 1);
+    ASSERT_EQ(hdr.package_version_string.length, 4);
+    EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
+                     hdr.package_version_string.length),
+              0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
+
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
+    {
+        struct pldm_descriptor desc;
+
+        EXPECT_EQ(fdrec.descriptor_count, 1);
+        EXPECT_EQ(fdrec.device_update_option_flags.value, 0);
+        EXPECT_EQ(fdrec.component_image_set_version_string_type, 1);
+        ASSERT_EQ(fdrec.component_image_set_version_string.length, 4);
+        EXPECT_EQ(memcmp("v0.1", fdrec.component_image_set_version_string.ptr,
+                         fdrec.component_image_set_version_string.length),
+                  0);
+        ASSERT_EQ(fdrec.applicable_components.bitmap.length, 1);
+        EXPECT_EQ(*fdrec.applicable_components.bitmap.ptr, 1);
+        EXPECT_NE(fdrec.record_descriptors.length, 0);
+        EXPECT_NE(fdrec.record_descriptors.ptr, nullptr);
+        ASSERT_EQ(fdrec.firmware_device_package_data.length, 0);
+
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
+                                                                  desc, rc)
+        {
+            static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
+
+            EXPECT_EQ(desc.descriptor_type, 1);
+            ASSERT_EQ(desc.descriptor_length, sizeof(iana_pen_dmtf));
+            EXPECT_EQ(memcmp(iana_pen_dmtf, desc.descriptor_data,
+                             sizeof(iana_pen_dmtf)),
+                      0);
+
+            nr_fdrec_desc++;
+        }
+        ASSERT_EQ(rc, 0);
+
+        nr_fdrec++;
+    }
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(nr_fdrec, 1);
+    EXPECT_EQ(nr_fdrec_desc, 1);
+
+    static const pldm_package_component_image_information expected_info{
+        0x000a,       0x0000, 0xffffffff,   {0},         {1},
+        {nullptr, 1}, 0x01,   {nullptr, 0}, {nullptr, 0}};
+
+    foreach_pldm_package_component_image_information(pkg, info, rc)
+    {
+        EXPECT_EQ(info.component_classification,
+                  expected_info.component_classification);
+        EXPECT_EQ(info.component_identifier,
+                  expected_info.component_identifier);
+        EXPECT_EQ(info.component_comparison_stamp,
+                  expected_info.component_comparison_stamp);
+        EXPECT_EQ(info.component_options.value,
+                  expected_info.component_options.value);
+        EXPECT_EQ(info.requested_component_activation_method.value,
+                  expected_info.requested_component_activation_method.value);
+        EXPECT_NE(nullptr, info.component_image.ptr);
+        EXPECT_EQ(info.component_image.length,
+                  expected_info.component_image.length);
+        EXPECT_EQ(info.component_version_string_type,
+                  expected_info.component_version_string_type);
+        ASSERT_EQ(info.component_version_string.length, 4);
+        EXPECT_EQ(memcmp("v0.2", info.component_version_string.ptr,
+                         info.component_version_string.length),
+                  0);
+
+        nr_infos++;
+    }
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(nr_infos, 1);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodePldmFirmwareUpdatePackage, invalidDownstreamDeviceIteration)
+{
+    const std::array<uint8_t, 102> package{
+        0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00, 0xa0,
+        0x2f, 0x05, 0x9a, 0xca, 0x02, 0x01, 0x65, 0x00, 0x00, 0xe9, 0x07,
+        0x03, 0x0b, 0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x08,
+        0x00, 0x01, 0x04, 't',  'e',  's',  't',
+
+        0x01, 0x18, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
+        0x00, 0x01, 'v',  '0',  '.',  '1',  0x01, 0x00, 0x04, 0x00, 0x9c,
+        0x01, 0x00, 0x00,
+
+        0x01, 0x00, 0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
+        0x00, 0x01, 0x00, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+        0x01, 0x04, 'v',  '0',  '.',  '2',  0x00, 0x00, 0x00, 0x00,
+
+        0xb5, 0x3f, 0xf6, 0x6a,
+
+        0x5a,
+    };
+
+    struct pldm_package_downstream_device_id_record ddrec;
+    struct pldm_package_firmware_device_id_record fdrec;
+    DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR01H(pin);
+    pldm_package_header_information_pad hdr;
+    struct pldm_package pkg{};
+    int nr_fdrec_desc = 0;
+    int nr_fdrec = 0;
+    int rc;
+
+    rc = decode_pldm_firmware_update_package(package.data(), package.size(),
+                                             &pin, &hdr, &pkg);
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_0.data(),
+                     hdr.package_header_identifier,
+                     PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_0.size()),
+              0);
+    EXPECT_EQ(hdr.package_header_format_revision, 1);
+
+    static const std::array<uint8_t, 13> timestamp{0x00, 0xe9, 0x07, 0x03, 0x0b,
+                                                   0x16, 0x03, 0x00, 0x00, 0x00,
+                                                   0x00, 0x76, 0x02};
+    ASSERT_EQ(timestamp.size(), sizeof(hdr.package_release_date_time));
+    EXPECT_EQ(memcmp(timestamp.data(), hdr.package_release_date_time,
+                     timestamp.size()),
+              0);
+
+    EXPECT_EQ(hdr.component_bitmap_bit_length, 8);
+    EXPECT_EQ(hdr.package_version_string_type, 1);
+    ASSERT_EQ(hdr.package_version_string.length, 4);
+    EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
+                     hdr.package_version_string.length),
+              0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
+
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
+    {
+        struct pldm_descriptor desc;
+
+        EXPECT_EQ(fdrec.descriptor_count, 1);
+        EXPECT_EQ(fdrec.device_update_option_flags.value, 0);
+        EXPECT_EQ(fdrec.component_image_set_version_string_type, 1);
+        ASSERT_EQ(fdrec.component_image_set_version_string.length, 4);
+        EXPECT_EQ(memcmp("v0.1", fdrec.component_image_set_version_string.ptr,
+                         fdrec.component_image_set_version_string.length),
+                  0);
+        ASSERT_EQ(fdrec.applicable_components.bitmap.length, 1);
+        EXPECT_EQ(*fdrec.applicable_components.bitmap.ptr, 1);
+        EXPECT_NE(fdrec.record_descriptors.length, 0);
+        EXPECT_NE(fdrec.record_descriptors.ptr, nullptr);
+        ASSERT_EQ(fdrec.firmware_device_package_data.length, 0);
+
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
+                                                                  desc, rc)
+        {
+            static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
+
+            EXPECT_EQ(desc.descriptor_type, 1);
+            ASSERT_EQ(desc.descriptor_length, sizeof(iana_pen_dmtf));
+            EXPECT_EQ(memcmp(iana_pen_dmtf, desc.descriptor_data,
+                             sizeof(iana_pen_dmtf)),
+                      0);
+
+            nr_fdrec_desc++;
+        }
+        ASSERT_EQ(rc, 0);
+
+        nr_fdrec++;
+    }
+    ASSERT_EQ(rc, 0);
+
+    EXPECT_EQ(nr_fdrec, 1);
+    EXPECT_EQ(nr_fdrec_desc, 1);
+
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
+        EXPECT_NE(rc, 0);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodePldmFirmwareUpdatePackage, p2v1h1fd1fdd1cii)
 {
     const std::array<uint8_t, 102> package{
         0xf0, 0x18, 0x87, 0x8c, 0xcb, 0x7d, 0x49, 0x43, 0x98, 0x00, 0xa0,
@@ -5055,7 +5293,7 @@
     struct pldm_package_firmware_device_id_record fdrec;
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     int nr_fdrec_desc = 0;
     int nr_ddrec_desc = 0;
     int nr_fdrec = 0;
@@ -5064,7 +5302,7 @@
     int rc;
 
     rc = decode_pldm_firmware_update_package(package.data(), package.size(),
-                                             &pin, &hdr, &iter);
+                                             &pin, &hdr, &pkg);
     ASSERT_EQ(rc, 0);
 
     EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_0.data(),
@@ -5087,12 +5325,12 @@
     EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
                      hdr.package_version_string.length),
               0);
-    EXPECT_NE(hdr.areas.ptr, nullptr);
-    EXPECT_NE(hdr.areas.length, 0);
-    EXPECT_NE(hdr.package.ptr, nullptr);
-    EXPECT_NE(hdr.package.length, 0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
 
-    foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5109,7 +5347,7 @@
         EXPECT_NE(fdrec.record_descriptors.ptr, nullptr);
         ASSERT_EQ(fdrec.firmware_device_package_data.length, 0);
 
-        foreach_pldm_package_firmware_device_id_record_descriptor(iter, fdrec,
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
                                                                   desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5131,38 +5369,13 @@
     EXPECT_EQ(nr_fdrec, 1);
     EXPECT_EQ(nr_fdrec_desc, 1);
 
-    foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
     {
         struct pldm_descriptor desc;
 
-        EXPECT_EQ(ddrec.descriptor_count, 1);
-        EXPECT_EQ(ddrec.update_option_flags.value, 0);
-        EXPECT_EQ(ddrec.self_contained_activation_min_version_string_type, 1);
-        ASSERT_EQ(ddrec.self_contained_activation_min_version_string.length, 4);
-        EXPECT_EQ(
-            memcmp("v1.0",
-                   ddrec.self_contained_activation_min_version_string.ptr,
-                   ddrec.self_contained_activation_min_version_string.length),
-            0);
-        EXPECT_EQ(ddrec.self_contained_activation_min_version_comparison_stamp,
-                  0);
-        ASSERT_EQ(ddrec.applicable_components.bitmap.length, 1);
-        EXPECT_EQ(*ddrec.applicable_components.bitmap.ptr, 2);
-        EXPECT_NE(ddrec.record_descriptors.length, 0);
-        EXPECT_NE(ddrec.record_descriptors.ptr, nullptr);
-        EXPECT_EQ(ddrec.package_data.length, 0);
-
-        foreach_pldm_package_downstream_device_id_record_descriptor(iter, ddrec,
+        foreach_pldm_package_downstream_device_id_record_descriptor(pkg, ddrec,
                                                                     desc, rc)
         {
-            static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
-
-            EXPECT_EQ(desc.descriptor_type, 1);
-            ASSERT_EQ(desc.descriptor_length, sizeof(iana_pen_dmtf));
-            EXPECT_EQ(memcmp(iana_pen_dmtf, desc.descriptor_data,
-                             sizeof(iana_pen_dmtf)),
-                      0);
-
             nr_ddrec_desc++;
         }
         ASSERT_EQ(rc, 0);
@@ -5178,7 +5391,7 @@
         0x000a,       0x0000, 0xffffffff,   {0},         {1},
         {nullptr, 1}, 0x01,   {nullptr, 0}, {nullptr, 0}};
 
-    foreach_pldm_package_component_image_information(iter, info, rc)
+    foreach_pldm_package_component_image_information(pkg, info, rc)
     {
         EXPECT_EQ(info.component_classification,
                   expected_info.component_classification);
@@ -5246,7 +5459,7 @@
     struct pldm_package_firmware_device_id_record fdrec;
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     int nr_fdrec_desc = 0;
     int nr_ddrec_desc = 0;
     int nr_fdrec = 0;
@@ -5255,7 +5468,7 @@
     int rc;
 
     rc = decode_pldm_firmware_update_package(package.data(), package.size(),
-                                             &pin, &hdr, &iter);
+                                             &pin, &hdr, &pkg);
     ASSERT_EQ(rc, 0);
 
     EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_1.data(),
@@ -5278,12 +5491,12 @@
     EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
                      hdr.package_version_string.length),
               0);
-    EXPECT_NE(hdr.areas.ptr, nullptr);
-    EXPECT_NE(hdr.areas.length, 0);
-    EXPECT_NE(hdr.package.ptr, nullptr);
-    EXPECT_NE(hdr.package.length, 0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
 
-    foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5300,7 +5513,7 @@
         EXPECT_NE(fdrec.record_descriptors.ptr, nullptr);
         ASSERT_EQ(fdrec.firmware_device_package_data.length, 0);
 
-        foreach_pldm_package_firmware_device_id_record_descriptor(iter, fdrec,
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
                                                                   desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5322,7 +5535,7 @@
     EXPECT_EQ(nr_fdrec, 1);
     EXPECT_EQ(nr_fdrec_desc, 1);
 
-    foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5343,7 +5556,7 @@
         EXPECT_NE(ddrec.record_descriptors.ptr, nullptr);
         EXPECT_EQ(ddrec.package_data.length, 0);
 
-        foreach_pldm_package_downstream_device_id_record_descriptor(iter, ddrec,
+        foreach_pldm_package_downstream_device_id_record_descriptor(pkg, ddrec,
                                                                     desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5390,7 +5603,7 @@
                          {nullptr, 0}}}};
     static const std::array<uint8_t, 2> expected_images{0x5a, 0xa5};
 
-    foreach_pldm_package_component_image_information(iter, info, rc)
+    foreach_pldm_package_component_image_information(pkg, info, rc)
     {
         const struct pldm_package_component_image_information* expected;
         const char* version;
@@ -5468,7 +5681,7 @@
     struct pldm_package_firmware_device_id_record fdrec;
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR03H(pin);
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     int nr_fdrec_desc = 0;
     int nr_ddrec_desc = 0;
     int nr_fdrec = 0;
@@ -5477,7 +5690,7 @@
     int rc;
 
     rc = decode_pldm_firmware_update_package(package.data(), package.size(),
-                                             &pin, &hdr, &iter);
+                                             &pin, &hdr, &pkg);
     ASSERT_EQ(rc, 0);
 
     EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_2.data(),
@@ -5500,12 +5713,12 @@
     EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
                      hdr.package_version_string.length),
               0);
-    EXPECT_NE(hdr.areas.ptr, nullptr);
-    EXPECT_NE(hdr.areas.length, 0);
-    EXPECT_NE(hdr.package.ptr, nullptr);
-    EXPECT_NE(hdr.package.length, 0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
 
-    foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5522,7 +5735,7 @@
         EXPECT_NE(fdrec.record_descriptors.ptr, nullptr);
         ASSERT_EQ(fdrec.firmware_device_package_data.length, 0);
 
-        foreach_pldm_package_firmware_device_id_record_descriptor(iter, fdrec,
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
                                                                   desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5544,7 +5757,7 @@
     EXPECT_EQ(nr_fdrec, 1);
     EXPECT_EQ(nr_fdrec_desc, 1);
 
-    foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5565,7 +5778,7 @@
         EXPECT_NE(ddrec.record_descriptors.ptr, nullptr);
         EXPECT_EQ(ddrec.package_data.length, 0);
 
-        foreach_pldm_package_downstream_device_id_record_descriptor(iter, ddrec,
+        foreach_pldm_package_downstream_device_id_record_descriptor(pkg, ddrec,
                                                                     desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5617,7 +5830,7 @@
               {expected_opaque_data.data(), expected_opaque_data.size()}}}};
     static const std::array<uint8_t, 2> expected_images{0x5a, 0xa5};
 
-    foreach_pldm_package_component_image_information(iter, info, rc)
+    foreach_pldm_package_component_image_information(pkg, info, rc)
     {
         const struct pldm_package_component_image_information* expected;
         const char* version;
@@ -5702,7 +5915,7 @@
     struct pldm_package_firmware_device_id_record fdrec;
     DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR04H(pin);
     pldm_package_header_information_pad hdr;
-    struct pldm_package_iter iter;
+    struct pldm_package pkg{};
     int nr_fdrec_desc = 0;
     int nr_ddrec_desc = 0;
     int nr_fdrec = 0;
@@ -5711,7 +5924,7 @@
     int rc;
 
     rc = decode_pldm_firmware_update_package(package.data(), package.size(),
-                                             &pin, &hdr, &iter);
+                                             &pin, &hdr, &pkg);
     ASSERT_EQ(rc, 0);
 
     EXPECT_EQ(memcmp(PLDM_FWUP_PACKAGE_HEADER_IDENTIFIER_V1_3.data(),
@@ -5734,12 +5947,12 @@
     EXPECT_EQ(memcmp("test", hdr.package_version_string.ptr,
                      hdr.package_version_string.length),
               0);
-    EXPECT_NE(hdr.areas.ptr, nullptr);
-    EXPECT_NE(hdr.areas.length, 0);
-    EXPECT_NE(hdr.package.ptr, nullptr);
-    EXPECT_NE(hdr.package.length, 0);
+    EXPECT_NE(pkg.areas.ptr, nullptr);
+    EXPECT_NE(pkg.areas.length, 0);
+    EXPECT_NE(pkg.package.ptr, nullptr);
+    EXPECT_NE(pkg.package.length, 0);
 
-    foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5763,7 +5976,7 @@
                          expected_reference_manifest_data,
                          sizeof(expected_reference_manifest_data)),
                   0);
-        foreach_pldm_package_firmware_device_id_record_descriptor(iter, fdrec,
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
                                                                   desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5785,7 +5998,7 @@
     EXPECT_EQ(nr_fdrec, 1);
     EXPECT_EQ(nr_fdrec_desc, 1);
 
-    foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
     {
         struct pldm_descriptor desc;
 
@@ -5814,7 +6027,7 @@
                          sizeof(expected_reference_manifest_data)),
                   0);
 
-        foreach_pldm_package_downstream_device_id_record_descriptor(iter, ddrec,
+        foreach_pldm_package_downstream_device_id_record_descriptor(pkg, ddrec,
                                                                     desc, rc)
         {
             static const uint8_t iana_pen_dmtf[] = {0x9c, 0x01, 0x00, 0x00};
@@ -5866,7 +6079,7 @@
               {expected_opaque_data.data(), expected_opaque_data.size()}}}};
     static const std::array<uint8_t, 2> expected_images{0x5a, 0xa5};
 
-    foreach_pldm_package_component_image_information(iter, info, rc)
+    foreach_pldm_package_component_image_information(pkg, info, rc)
     {
         const struct pldm_package_component_image_information* expected;
         const char* version;
@@ -5908,4 +6121,180 @@
 
     EXPECT_EQ(nr_infos, 2);
 }
-#endif
\ No newline at end of file
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodePldmFirmwareUpdatePackage, downstreamDeviceBeforeFirmwareDevice)
+{
+    const std::array<uint8_t, 182> package{
+        0x7B, 0x29, 0x1C, 0x99, 0x6D, 0xB6, 0x42, 0x08, 0x80, 0x1B, 0x02, 0x02,
+        0x6E, 0x46, 0x3C, 0x78, 0x04, 0xB4, 0x00, 0x00, 0xe9, 0x07, 0x03, 0x0b,
+        0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x08, 0x00, 0x01, 0x04,
+        't',  'e',  's',  't',
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x01, 'v',  '0',  '.',  '1',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x02, 'v',  '1',  '.',  '0',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x02, 0x00,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '0',
+        '.',  '2',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB5, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '2',
+        '.',  '0',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0xf7, 0xf7, 0xfd, 0x79,
+
+        0x46, 0xf0, 0x31, 0xa7,
+
+        0x5a,
+
+        0xa5,
+
+    };
+
+    struct pldm_package_downstream_device_id_record ddrec;
+    DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR04H(pin);
+    pldm_package_header_information_pad hdr;
+    struct pldm_package pkg{};
+    int rc;
+
+    rc = decode_pldm_firmware_update_package(package.data(), package.size(),
+                                             &pin, &hdr, &pkg);
+    ASSERT_EQ(rc, 0);
+
+    foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
+    {
+    }
+    EXPECT_NE(rc, 0);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodePldmFirmwareUpdatePackage, componentImageInfosBeforeFirmwareDevice)
+{
+    const std::array<uint8_t, 182> package{
+        0x7B, 0x29, 0x1C, 0x99, 0x6D, 0xB6, 0x42, 0x08, 0x80, 0x1B, 0x02, 0x02,
+        0x6E, 0x46, 0x3C, 0x78, 0x04, 0xB4, 0x00, 0x00, 0xe9, 0x07, 0x03, 0x0b,
+        0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x08, 0x00, 0x01, 0x04,
+        't',  'e',  's',  't',
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x01, 'v',  '0',  '.',  '1',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x02, 'v',  '1',  '.',  '0',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x02, 0x00,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '0',
+        '.',  '2',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB5, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '2',
+        '.',  '0',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0xf7, 0xf7, 0xfd, 0x79,
+
+        0x46, 0xf0, 0x31, 0xa7,
+
+        0x5a,
+
+        0xa5,
+
+    };
+
+    struct pldm_package_component_image_information info;
+    DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR04H(pin);
+    pldm_package_header_information_pad hdr;
+    struct pldm_package pkg{};
+    int rc;
+
+    rc = decode_pldm_firmware_update_package(package.data(), package.size(),
+                                             &pin, &hdr, &pkg);
+    ASSERT_EQ(rc, 0);
+
+    foreach_pldm_package_component_image_information(pkg, info, rc)
+    {
+    }
+    EXPECT_NE(rc, 0);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodePldmFirmwareUpdatePackage,
+     p4v2ComponentImageInfosBeforeDownstreamDevice)
+{
+    const std::array<uint8_t, 182> package{
+        0x7B, 0x29, 0x1C, 0x99, 0x6D, 0xB6, 0x42, 0x08, 0x80, 0x1B, 0x02, 0x02,
+        0x6E, 0x46, 0x3C, 0x78, 0x04, 0xB4, 0x00, 0x00, 0xe9, 0x07, 0x03, 0x0b,
+        0x16, 0x03, 0x00, 0x00, 0x00, 0x00, 0x76, 0x02, 0x08, 0x00, 0x01, 0x04,
+        't',  'e',  's',  't',
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x01, 'v',  '0',  '.',  '1',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x01, 0x1E, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00,
+        0x02, 0x00, 0x00, 0x00, 0x02, 'v',  '1',  '.',  '0',  0x01, 0x00, 0x04,
+        0x00, 0x9c, 0x01, 0x00, 0x00, 0x87, 0x65,
+
+        0x02, 0x00,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '0',
+        '.',  '2',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0x0a, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00,
+        0xB5, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 'v',  '2',
+        '.',  '0',  0x04, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78,
+
+        0xf7, 0xf7, 0xfd, 0x79,
+
+        0x46, 0xf0, 0x31, 0xa7,
+
+        0x5a,
+
+        0xa5,
+
+    };
+
+    struct pldm_package_component_image_information info;
+    struct pldm_package_firmware_device_id_record fdrec;
+    DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR04H(pin);
+    pldm_package_header_information_pad hdr;
+    struct pldm_package pkg{};
+    int rc;
+
+    rc = decode_pldm_firmware_update_package(package.data(), package.size(),
+                                             &pin, &hdr, &pkg);
+    ASSERT_EQ(rc, 0);
+
+    foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
+    {
+        struct pldm_descriptor desc;
+
+        foreach_pldm_package_firmware_device_id_record_descriptor(pkg, fdrec,
+                                                                  desc, rc)
+        {
+        }
+        ASSERT_EQ(rc, 0);
+    }
+    ASSERT_EQ(rc, 0);
+
+    foreach_pldm_package_component_image_information(pkg, info, rc)
+    {
+    }
+    EXPECT_NE(rc, 0);
+}
+#endif
diff --git a/tools/pd.c b/tools/pd.c
index fe63a70..d88cea2 100644
--- a/tools/pd.c
+++ b/tools/pd.c
@@ -103,7 +103,7 @@
 	struct pldm_package_firmware_device_id_record fdrec;
 	DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
 	pldm_package_header_information_pad hdr;
-	struct pldm_package_iter iter;
+	struct pldm_package pkg = { 0 };
 	size_t nr_fdrecs = 0;
 	size_t nr_ddrecs = 0;
 	size_t nr_infos = 0;
@@ -119,8 +119,7 @@
 	}
 
 	in = fread(package, 1, PD_PACKAGE_BUFFER, stdin);
-	rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
-						 &iter);
+	rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr, &pkg);
 	if (rc < 0) {
 		warnx("Failed to parse PLDM package: %s\n",
 		      strerrorname_np(-rc));
@@ -135,7 +134,7 @@
 	       hdr.package_header_format_revision);
 	fwrite("\n", 1, 1, stdout);
 
-	foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
+	foreach_pldm_package_firmware_device_id_record(pkg, fdrec, rc)
 	{
 		struct pldm_descriptor desc;
 
@@ -153,7 +152,7 @@
 
 		printf("\tDescriptors:\n");
 		foreach_pldm_package_firmware_device_id_record_descriptor(
-			iter, fdrec, desc, rc)
+			pkg, fdrec, desc, rc)
 		{
 			pd_print_descriptor("\t\t", &desc, "\n");
 		}
@@ -172,7 +171,7 @@
 		goto cleanup_package;
 	}
 
-	foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
+	foreach_pldm_package_downstream_device_id_record(pkg, ddrec, rc)
 	{
 		struct pldm_descriptor desc;
 
@@ -190,7 +189,7 @@
 			       " ]\n");
 		printf("\tDescriptors:\n");
 		foreach_pldm_package_downstream_device_id_record_descriptor(
-			iter, ddrec, desc, rc)
+			pkg, ddrec, desc, rc)
 		{
 			pd_print_descriptor("\t\t", &desc, "\n");
 		}
@@ -209,7 +208,7 @@
 		goto cleanup_package;
 	}
 
-	foreach_pldm_package_component_image_information(iter, info, rc)
+	foreach_pldm_package_component_image_information(pkg, info, rc)
 	{
 		printf("Component image info: %zu\n", nr_infos++);
 		printf("\tComponent classification: %" PRIu16 "\n",