fru: Add support to insert hot-plug PDRs into repository

This API helps to insert PDRs that are added or modified
during concurrent maintenance operations into the PDR repository.
The function assigns a new record handle (based on the last
BMC side PDR handle) and appends the provided PDR entry to the
repository.

Change-Id: I48989b8828837579e8eeb360d3e5d456612c9f05
Signed-off-by: Pavithra Barithaya <pavithrabarithaya07@gmail.com>
diff --git a/libpldmresponder/fru.cpp b/libpldmresponder/fru.cpp
index ff6643a..eb60cac 100644
--- a/libpldmresponder/fru.cpp
+++ b/libpldmresponder/fru.cpp
@@ -2,6 +2,10 @@
 
 #include "common/utils.hpp"
 
+#ifdef OEM_IBM
+#include "oem/ibm/libpldmresponder/utils.hpp"
+#endif
+
 #include <libpldm/entity.h>
 #include <libpldm/utils.h>
 #include <systemd/sd-journal.h>
@@ -504,6 +508,24 @@
     return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
 }
 
+uint32_t FruImpl::addHotPlugRecord(
+    pldm::responder::pdr_utils::PdrEntry pdrEntry)
+{
+    uint32_t lastHandle = 0;
+    uint32_t record_handle = 0;
+    if (oemUtilsHandler)
+    {
+        auto lastLocalRecord = pldm_pdr_find_last_in_range(
+            pdrRepo, pldm::responder::utils::BMC_PDR_START_RANGE,
+            pldm::responder::utils::BMC_PDR_END_RANGE);
+        lastHandle = pldm_pdr_get_record_handle(pdrRepo, lastLocalRecord);
+    }
+    pdrEntry.handle.recordHandle = lastHandle + 1;
+    pldm_pdr_add(pdrRepo, pdrEntry.data, pdrEntry.size, false,
+                 pdrEntry.handle.recordHandle, &record_handle);
+    return record_handle;
+}
+
 namespace fru
 {
 Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
diff --git a/libpldmresponder/fru.hpp b/libpldmresponder/fru.hpp
index 6586fad..781227a 100644
--- a/libpldmresponder/fru.hpp
+++ b/libpldmresponder/fru.hpp
@@ -15,6 +15,7 @@
 #include <variant>
 #include <vector>
 
+using namespace pldm::utils;
 namespace pldm
 {
 
@@ -69,7 +70,8 @@
             pldm_entity_association_tree* entityTree,
             pldm_entity_association_tree* bmcEntityTree) :
         parser(configPath, fruMasterJsonPath), pdrRepo(pdrRepo),
-        entityTree(entityTree), bmcEntityTree(bmcEntityTree)
+        entityTree(entityTree), bmcEntityTree(bmcEntityTree),
+        oemUtilsHandler(nullptr)
     {}
 
     /** @brief Total length of the FRU table in bytes, this includes the pad
@@ -150,6 +152,15 @@
         return associatedEntityMap;
     }
 
+    /* @brief Method to set the oem utils handler in FRU handler class
+     *
+     * @param[in] handler - oem utils handler
+     */
+    inline void setOemUtilsHandler(pldm::responder::oem_utils::Handler* handler)
+    {
+        oemUtilsHandler = handler;
+    }
+
     /** @brief Get pldm entity by the object path
      *
      *  @param[in] intfMaps - D-Bus interfaces and the associated property
@@ -236,6 +247,8 @@
     dbus::ObjectValueTree objects;
 
     std::map<dbus::ObjectPath, pldm_entity_node*> objToEntityNode{};
+    /** @OEM Utils handler */
+    pldm::responder::oem_utils::Handler* oemUtilsHandler;
 
     /** @brief populateRecord builds the FRU records for an instance of FRU and
      *         updates the FRU table with the FRU records.
@@ -256,6 +269,16 @@
      */
     void deleteFRURecord(uint16_t rsi);
 
+    /** @brief Add hotplug record that was modified or added to the PDR entry
+     *  HotPlug is a feature where a FRU can be removed or added when
+     *  the system is running, without needing it to power off.
+     *
+     *  @param[in] pdrEntry - PDR record structure in PDR repository
+     *
+     *  @return record handle of added or modified hotplug record
+     */
+    uint32_t addHotPlugRecord(pldm::responder::pdr_utils::PdrEntry pdrEntry);
+
     /** @brief Associate sensor/effecter to FRU entity
      */
     dbus::AssociatedEntityMap associatedEntityMap;
@@ -334,6 +357,15 @@
         return impl.getAssociateEntityMap();
     }
 
+    /* @brief Method to set the oem utils handler in host pdr handler class
+     *
+     * @param[in] handler - oem utils handler
+     */
+    void setOemUtilsHandler(pldm::responder::oem_utils::Handler* handler)
+    {
+        return impl.setOemUtilsHandler(handler);
+    }
+
     /** @brief Handler for GetFRURecordByOption
      *
      *  @param[in] request - Request message payload
diff --git a/oem/ibm/libpldmresponder/utils.hpp b/oem/ibm/libpldmresponder/utils.hpp
index bb111a4..5830fee 100644
--- a/oem/ibm/libpldmresponder/utils.hpp
+++ b/oem/ibm/libpldmresponder/utils.hpp
@@ -13,6 +13,9 @@
 namespace utils
 {
 
+constexpr uint32_t BMC_PDR_START_RANGE = 0x00000000;
+constexpr uint32_t BMC_PDR_END_RANGE = 0x00FFFFFF;
+
 /** @brief Setup UNIX socket
  *  This function creates listening socket in non-blocking mode and allows only
  *  one socket connection. returns accepted socket after accepting connection
diff --git a/pldmd/oem_ibm.hpp b/pldmd/oem_ibm.hpp
index e3fbddf..07b28ba 100644
--- a/pldmd/oem_ibm.hpp
+++ b/pldmd/oem_ibm.hpp
@@ -85,6 +85,7 @@
         codeUpdate->setOemPlatformHandler(oemPlatformHandler.get());
         hostPDRHandler->setOemPlatformHandler(oemPlatformHandler.get());
         hostPDRHandler->setOemUtilsHandler(oemUtilsHandler.get());
+        fruHandler->setOemUtilsHandler(oemUtilsHandler.get());
         platformHandler->setOemPlatformHandler(oemPlatformHandler.get());
         baseHandler->setOemPlatformHandler(oemPlatformHandler.get());
         slotHandler->setOemPlatformHandler(oemPlatformHandler.get());