event: Handling pldmPDRRepositoryChgEvent

Added a handler to react to the "pldmPDRRepositoryChgEvent" event and
extract the data. If the eventDataFormat is "formatIsPDRHandles" then
the changeRecords are further extracted. If the eventDataOperation is
"recordAdded" then the PDRHandles are extracted from the changeEntry
data and stored in the "pdrRecordHandle" vector.

"decode_pldm_pdr_repository_chg_event_data" function will extract the
eventData and changeRecord from the pldmPDRRepositoryChgEvent class
while the "decode_pldm_pdr_repository_change_record_data" will extract
the changeEntries data from the changeRecord. Unit tests for the above
decode functions have been added.

Extracted PDR handles are used to fetch PDRs corresponding to the same
from the host.

Signed-off-by: Zahed Hossain <zahzahed@in.ibm.com>
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I32e8745e04ac82393e067c0f0ab48802809495a6
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 86c5a2c..eb08a8c 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -360,6 +360,97 @@
     return PLDM_SUCCESS;
 }
 
+int Handler::pldmPDRRepositoryChgEvent(const pldm_msg* request,
+                                       size_t payloadLength,
+                                       uint8_t /*formatVersion*/,
+                                       uint8_t /*tid*/, size_t eventDataOffset)
+{
+    uint8_t eventDataFormat{};
+    uint8_t numberOfChangeRecords{};
+    size_t dataOffset{};
+
+    auto eventData =
+        reinterpret_cast<const uint8_t*>(request->payload) + eventDataOffset;
+    auto eventDataSize = payloadLength - eventDataOffset;
+
+    auto rc = decode_pldm_pdr_repository_chg_event_data(
+        eventData, eventDataSize, &eventDataFormat, &numberOfChangeRecords,
+        &dataOffset);
+    if (rc != PLDM_SUCCESS)
+    {
+        return rc;
+    }
+
+    PDRRecordHandles pdrRecordHandles;
+    if (eventDataFormat == FORMAT_IS_PDR_HANDLES)
+    {
+        uint8_t eventDataOperation{};
+        uint8_t numberOfChangeEntries{};
+
+        auto changeRecordData = eventData + dataOffset;
+        auto changeRecordDataSize = eventDataSize - dataOffset;
+
+        while (changeRecordDataSize)
+        {
+            rc = decode_pldm_pdr_repository_change_record_data(
+                changeRecordData, changeRecordDataSize, &eventDataOperation,
+                &numberOfChangeEntries, &dataOffset);
+
+            if (rc != PLDM_SUCCESS)
+            {
+                return rc;
+            }
+
+            if (eventDataOperation == PLDM_RECORDS_ADDED)
+            {
+                rc = getPDRRecordHandles(
+                    reinterpret_cast<const ChangeEntry*>(changeRecordData +
+                                                         dataOffset),
+                    changeRecordDataSize - dataOffset,
+                    static_cast<size_t>(numberOfChangeEntries),
+                    pdrRecordHandles);
+
+                if (rc != PLDM_SUCCESS)
+                {
+                    return rc;
+                }
+            }
+
+            changeRecordData +=
+                dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
+            changeRecordDataSize -=
+                dataOffset + (numberOfChangeEntries * sizeof(ChangeEntry));
+        }
+
+        if (hostPDRHandler && !pdrRecordHandles.empty())
+        {
+            hostPDRHandler->fetchPDR(std::move(pdrRecordHandles));
+        }
+    }
+    else
+    {
+        return PLDM_ERROR_INVALID_DATA;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+int Handler::getPDRRecordHandles(const ChangeEntry* changeEntryData,
+                                 size_t changeEntryDataSize,
+                                 size_t numberOfChangeEntries,
+                                 PDRRecordHandles& pdrRecordHandles)
+{
+    if (numberOfChangeEntries > (changeEntryDataSize / sizeof(ChangeEntry)))
+    {
+        return PLDM_ERROR_INVALID_DATA;
+    }
+    for (size_t i = 0; i < numberOfChangeEntries; i++)
+    {
+        pdrRecordHandles.push_back(changeEntryData[i]);
+    }
+    return PLDM_SUCCESS;
+}
+
 } // namespace platform
 } // namespace responder
 } // namespace pldm