libpldm: decode APIs for pldmPDRRepositoryChgEvent

Change-Id: I5ee1280ed4033e8f8033808b0e150c75c2f01d01
Signed-off-by: Zahed Hossain <zahzahed@in.ibm.com>
diff --git a/libpldm/platform.c b/libpldm/platform.c
index 4c74b9b..97692a9 100644
--- a/libpldm/platform.c
+++ b/libpldm/platform.c
@@ -946,3 +946,61 @@
 	}
 	return PLDM_SUCCESS;
 }
+
+int decode_pldm_pdr_repository_chg_event_data(const uint8_t *event_data,
+					      size_t event_data_size,
+					      uint8_t *event_data_format,
+					      uint8_t *number_of_change_records,
+					      size_t *change_record_data_offset)
+{
+	if (event_data == NULL || event_data_format == NULL ||
+	    number_of_change_records == NULL ||
+	    change_record_data_offset == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (event_data_size < PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_pdr_repository_chg_event_data
+	    *pdr_repository_chg_event_data =
+		(struct pldm_pdr_repository_chg_event_data *)event_data;
+
+	*event_data_format = pdr_repository_chg_event_data->event_data_format;
+	*number_of_change_records =
+	    pdr_repository_chg_event_data->number_of_change_records;
+	*change_record_data_offset =
+	    sizeof(*event_data_format) + sizeof(*number_of_change_records);
+
+	return PLDM_SUCCESS;
+}
+
+int decode_pldm_pdr_repository_change_record_data(
+    const uint8_t *change_record_data, size_t change_record_data_size,
+    uint8_t *event_data_operation, uint8_t *number_of_change_entries,
+    size_t *change_entry_data_offset)
+{
+	if (change_record_data == NULL || event_data_operation == NULL ||
+	    number_of_change_entries == NULL ||
+	    change_entry_data_offset == NULL) {
+		return PLDM_ERROR_INVALID_DATA;
+	}
+	if (change_record_data_size <
+	    PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH) {
+		return PLDM_ERROR_INVALID_LENGTH;
+	}
+
+	struct pldm_pdr_repository_change_record_data
+	    *pdr_repository_change_record_data =
+		(struct pldm_pdr_repository_change_record_data *)
+		    change_record_data;
+
+	*event_data_operation =
+	    pdr_repository_change_record_data->event_data_operation;
+	*number_of_change_entries =
+	    pdr_repository_change_record_data->number_of_change_entries;
+	*change_entry_data_offset =
+	    sizeof(*event_data_operation) + sizeof(*number_of_change_entries);
+
+	return PLDM_SUCCESS;
+}
diff --git a/libpldm/platform.h b/libpldm/platform.h
index dd99633..1805f7d 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -42,6 +42,10 @@
 #define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_16BIT_DATA_LENGTH 5
 #define PLDM_SENSOR_EVENT_NUMERIC_SENSOR_STATE_32BIT_DATA_LENGTH 7
 
+/* Minimum length of data for pldmPDRRepositoryChgEvent */
+#define PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH 2
+#define PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH 2
+
 enum pldm_effecter_data_size {
 	PLDM_EFFECTER_DATA_SIZE_UINT8,
 	PLDM_EFFECTER_DATA_SIZE_SINT8,
@@ -174,6 +178,16 @@
 	FORMAT_IS_PDR_HANDLES
 };
 
+/** @brief PLDM pldmPDRRepositoryChgEvent class changeRecord format
+ * eventDataOperation
+ */
+enum pldm_pdr_repository_chg_event_change_record_event_data_operation {
+	PLDM_REFRESH_ALL_RECORDS,
+	PLDM_RECORDS_DELETED,
+	PLDM_RECORDS_ADDED,
+	PLDM_RECORDS_MODIFIED
+};
+
 /** @brief PLDM NumericSensorStatePresentReading data type
  */
 enum pldm_sensor_readings_data_type {
@@ -976,6 +990,45 @@
     uint8_t *effecter_data_size, uint8_t *effecter_oper_state,
     uint8_t *pending_value, uint8_t *present_value);
 
+/** @brief Decode pldmPDRRepositoryChgEvent response data
+ *
+ *  @param[in] event_data - eventData for pldmPDRRepositoryChgEvent
+ *  @param[in] event_data_size - Length of event_data
+ *  @param[out] event_data_format - This field indicates if the changedRecords
+ * are of PDR Types or PDR Record Handles
+ *  @param[out] number_of_change_records - The number of changeRecords following
+ * this field
+ *  @param[out] change_record_data_offset - Identifies where changeRecord data
+ * is located within event_data
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'event_data'
+ */
+int decode_pldm_pdr_repository_chg_event_data(
+    const uint8_t *event_data, size_t event_data_size,
+    uint8_t *event_data_format, uint8_t *number_of_change_records,
+    size_t *change_record_data_offset);
+
+/** @brief Decode PldmPDRRepositoryChangeRecord response data
+ *
+ *  @param[in] change_record_data - changeRecordData for
+ * pldmPDRRepositoryChgEvent
+ *  @param[in] change_record_data_size - Length of change_record_data
+ *  @param[out] event_data_operation - This field indicates the changeEntries
+ * operation types
+ *  @param[out] number_of_change_entries - The number of changeEntries following
+ * this field
+ *  @param[out] change_entry_data_offset - Identifies where changeEntries data
+ * is located within change_record_data
+ *  @return pldm_completion_codes
+ *  @note  Caller is responsible for memory alloc and dealloc of param
+ *         'change_record_data'
+ */
+int decode_pldm_pdr_repository_change_record_data(
+    const uint8_t *change_record_data, size_t change_record_data_size,
+    uint8_t *event_data_operation, uint8_t *number_of_change_entries,
+    size_t *change_entry_data_offset);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libpldm/tests/libpldm_platform_test.cpp b/libpldm/tests/libpldm_platform_test.cpp
index 9e790c2..1958ca0 100644
--- a/libpldm/tests/libpldm_platform_test.cpp
+++ b/libpldm/tests/libpldm_platform_test.cpp
@@ -1361,3 +1361,120 @@
 
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
 }
+
+TEST(PldmPDRRepositoryChgEventEvent, testGoodDecodeRequest)
+{
+    const uint8_t eventDataFormat = FORMAT_IS_PDR_HANDLES;
+    const uint8_t numberOfChangeRecords = 2;
+    uint8_t eventDataOperation1 = PLDM_RECORDS_DELETED;
+    const uint8_t numberOfChangeEntries1 = 2;
+    std::array<uint32_t, numberOfChangeEntries1> changeRecordArr1{
+        {0x00000000, 0x12345678}};
+    uint8_t eventDataOperation2 = PLDM_RECORDS_ADDED;
+    const uint8_t numberOfChangeEntries2 = 5;
+    std::array<uint32_t, numberOfChangeEntries2> changeRecordArr2{
+        {0x01234567, 0x11223344, 0x45678901, 0x21222324, 0x98765432}};
+    std::array<uint8_t, PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH +
+                            PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH *
+                                numberOfChangeRecords +
+                            (numberOfChangeEntries1 + numberOfChangeEntries2) *
+                                sizeof(uint32_t)>
+        eventDataArr{};
+
+    struct pldm_pdr_repository_chg_event_data* eventData =
+        reinterpret_cast<struct pldm_pdr_repository_chg_event_data*>(
+            eventDataArr.data());
+    eventData->event_data_format = eventDataFormat;
+    eventData->number_of_change_records = numberOfChangeRecords;
+    struct pldm_pdr_repository_change_record_data* changeRecord1 =
+        reinterpret_cast<struct pldm_pdr_repository_change_record_data*>(
+            eventData->change_records);
+    changeRecord1->event_data_operation = eventDataOperation1;
+    changeRecord1->number_of_change_entries = numberOfChangeEntries1;
+    memcpy(changeRecord1->change_entry, &changeRecordArr1[0],
+           changeRecordArr1.size() * sizeof(uint32_t));
+    struct pldm_pdr_repository_change_record_data* changeRecord2 =
+        reinterpret_cast<struct pldm_pdr_repository_change_record_data*>(
+            eventData->change_records +
+            PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH +
+            (changeRecordArr1.size() * sizeof(uint32_t)));
+    changeRecord2->event_data_operation = eventDataOperation2;
+    changeRecord2->number_of_change_entries = numberOfChangeEntries2;
+    memcpy(changeRecord2->change_entry, &changeRecordArr2[0],
+           changeRecordArr2.size() * sizeof(uint32_t));
+
+    uint8_t retEventDataFormat{};
+    uint8_t retNumberOfChangeRecords{};
+    size_t retChangeRecordDataOffset{0};
+    auto rc = decode_pldm_pdr_repository_chg_event_data(
+        reinterpret_cast<const uint8_t*>(eventData), eventDataArr.size(),
+        &retEventDataFormat, &retNumberOfChangeRecords,
+        &retChangeRecordDataOffset);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retEventDataFormat, FORMAT_IS_PDR_HANDLES);
+    EXPECT_EQ(retNumberOfChangeRecords, numberOfChangeRecords);
+
+    const uint8_t* changeRecordData =
+        reinterpret_cast<const uint8_t*>(changeRecord1);
+    size_t changeRecordDataSize =
+        eventDataArr.size() - PLDM_PDR_REPOSITORY_CHG_EVENT_MIN_LENGTH;
+    uint8_t retEventDataOperation;
+    uint8_t retNumberOfChangeEntries;
+    size_t retChangeEntryDataOffset;
+
+    rc = decode_pldm_pdr_repository_change_record_data(
+        reinterpret_cast<const uint8_t*>(changeRecordData),
+        changeRecordDataSize, &retEventDataOperation, &retNumberOfChangeEntries,
+        &retChangeEntryDataOffset);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retEventDataOperation, eventDataOperation1);
+    EXPECT_EQ(retNumberOfChangeEntries, numberOfChangeEntries1);
+    changeRecordData += retChangeEntryDataOffset;
+    EXPECT_EQ(0, memcmp(changeRecordData, &changeRecordArr1[0],
+                        sizeof(uint32_t) * retNumberOfChangeEntries));
+
+    changeRecordData += sizeof(uint32_t) * retNumberOfChangeEntries;
+    changeRecordDataSize -= sizeof(uint32_t) * retNumberOfChangeEntries -
+                            PLDM_PDR_REPOSITORY_CHANGE_RECORD_MIN_LENGTH;
+    rc = decode_pldm_pdr_repository_change_record_data(
+        reinterpret_cast<const uint8_t*>(changeRecordData),
+        changeRecordDataSize, &retEventDataOperation, &retNumberOfChangeEntries,
+        &retChangeEntryDataOffset);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retEventDataOperation, eventDataOperation2);
+    EXPECT_EQ(retNumberOfChangeEntries, numberOfChangeEntries2);
+    changeRecordData += retChangeEntryDataOffset;
+    EXPECT_EQ(0, memcmp(changeRecordData, &changeRecordArr2[0],
+                        sizeof(uint32_t) * retNumberOfChangeEntries));
+}
+
+TEST(PldmPDRRepositoryChgEventEvent, testBadDecodeRequest)
+{
+    uint8_t eventDataFormat{};
+    uint8_t numberOfChangeRecords{};
+    size_t changeRecordDataOffset{};
+    auto rc = decode_pldm_pdr_repository_chg_event_data(
+        NULL, 0, &eventDataFormat, &numberOfChangeRecords,
+        &changeRecordDataOffset);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    std::array<uint8_t, 2> eventData{};
+    rc = decode_pldm_pdr_repository_chg_event_data(
+        reinterpret_cast<const uint8_t*>(eventData.data()), 0, &eventDataFormat,
+        &numberOfChangeRecords, &changeRecordDataOffset);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    uint8_t eventDataOperation{};
+    uint8_t numberOfChangeEntries{};
+    size_t changeEntryDataOffset{};
+    rc = decode_pldm_pdr_repository_change_record_data(
+        NULL, 0, &eventDataOperation, &numberOfChangeEntries,
+        &changeEntryDataOffset);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    std::array<uint8_t, 2> changeRecord{};
+    rc = decode_pldm_pdr_repository_change_record_data(
+        reinterpret_cast<const uint8_t*>(changeRecord.data()), 0,
+        &eventDataOperation, &numberOfChangeEntries, &changeEntryDataOffset);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}