utils: Add an API to calculate cumulative crc32

Change-Id: I6c6fce214b98bc8f7284bc3e58319a9ef659e1b0
Signed-off-by: Kasun Athukorala <kasunath@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e7676c..6f5ae18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@
 
 - platform: Added file descriptor PDR encoding support
   - Added `encode_pldm_platform_file_descriptor_pdr()`
+- utils: Added `pldm_edac_crc32_extend()`
 
 ### Changed
 
diff --git a/include/libpldm/utils.h b/include/libpldm/utils.h
index 1c9fc72..2b04366 100644
--- a/include/libpldm/utils.h
+++ b/include/libpldm/utils.h
@@ -38,6 +38,15 @@
  */
 uint32_t pldm_edac_crc32(const void *data, size_t size);
 
+/** @brief Compute cumulative crc32 (same as the one used by IEEE802.3)
+ *
+ *  @param[in] data - Pointer to the target data
+ *  @param[in] size - Size of the data
+ *  @param[in] crc - cumulative CRC value
+ *  @return The checksum
+ */
+uint32_t pldm_edac_crc32_extend(const void *data, size_t size, uint32_t crc);
+
 /** @brief Convert ver32_t to string
  *  @param[in] version - Pointer to ver32_t
  *  @param[out] buffer - Pointer to the buffer
diff --git a/src/utils.c b/src/utils.c
index 53ed4f7..d559102 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -89,8 +89,14 @@
 LIBPLDM_ABI_STABLE
 uint32_t pldm_edac_crc32(const void *data, size_t size)
 {
+	return pldm_edac_crc32_extend(data, size, 0);
+}
+
+LIBPLDM_ABI_TESTING
+uint32_t pldm_edac_crc32_extend(const void *data, size_t size, uint32_t crc)
+{
 	const uint8_t *p = data;
-	uint32_t crc = ~0U;
+	crc ^= ~0U;
 	while (size--) {
 		crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
 	}
diff --git a/tests/utils.cpp b/tests/utils.cpp
index 0b4ca8b..a09e04c 100644
--- a/tests/utils.cpp
+++ b/tests/utils.cpp
@@ -13,6 +13,17 @@
     EXPECT_EQ(checksum, 0xcbf43926);
 }
 
+#ifdef LIBPLDM_API_TESTING
+TEST(Crc32, CumulativeCheckSumTest)
+{
+    const char* password = "123456789";
+    auto partial_checksum = pldm_edac_crc32_extend(password, 4, 0);
+    auto final_checksum =
+        pldm_edac_crc32_extend(password + 4, 5, partial_checksum);
+    EXPECT_EQ(final_checksum, 0xcbf43926);
+}
+#endif
+
 TEST(Crc8, CheckSumTest)
 {
     const char* data = "123456789";