oem_ibm: Persist the remote PDRs before merging

This commit persists the remote range PDRs in the repo
before they are merged. This change was needed as the
remote terminus would not send down to BMC the entity
Association PDRs of the remote terminus after the BMC
takes a reset after the PDR exchange as the PDRs will be
in BMC range of record handles.

TESTED: Tested by triggering a PDR exchange with the
remote terminus by doing poweron test and also reset the
BMC after the PDR exchange.

Change-Id: Iec2109073f984e5980d9b6e445ce0fa4198d4a0f
Signed-off-by: Sagar Srinivas <sagar.srinivas@ibm.com>
diff --git a/host-bmc/host_pdr_handler.cpp b/host-bmc/host_pdr_handler.cpp
index 99bc13d..7b5e057 100644
--- a/host-bmc/host_pdr_handler.cpp
+++ b/host-bmc/host_pdr_handler.cpp
@@ -3,8 +3,9 @@
 #include "libpldm/fru.h"
 #ifdef OEM_IBM
 #include "libpldm/fru_oem_ibm.h"
-#endif
 
+#include "oem/ibm/libpldmresponder/utils.hpp"
+#endif
 #include "custom_dbus.hpp"
 
 #include <assert.h>
@@ -26,6 +27,7 @@
 using namespace pldm::responder::events;
 using namespace pldm::utils;
 using namespace sdbusplus::bus::match::rules;
+using namespace pldm::responder::pdr_utils;
 using Json = nlohmann::json;
 namespace fs = std::filesystem;
 using namespace pldm::dbus;
@@ -89,11 +91,13 @@
     const std::string& eventsJsonsDir, pldm_entity_association_tree* entityTree,
     pldm_entity_association_tree* bmcEntityTree,
     pldm::InstanceIdDb& instanceIdDb,
-    pldm::requester::Handler<pldm::requester::Request>* handler) :
+    pldm::requester::Handler<pldm::requester::Request>* handler,
+    pldm::responder::oem_platform::Handler* oemPlatformHandler) :
     mctp_fd(mctp_fd),
     mctp_eid(mctp_eid), event(event), repo(repo),
     stateSensorHandler(eventsJsonsDir), entityTree(entityTree),
-    bmcEntityTree(bmcEntityTree), instanceIdDb(instanceIdDb), handler(handler)
+    bmcEntityTree(bmcEntityTree), instanceIdDb(instanceIdDb), handler(handler),
+    oemPlatformHandler(oemPlatformHandler)
 {
     mergedHostParents = false;
     fs::path hostFruJson(fs::path(HOST_JSONS_DIR) / fruJson);
@@ -246,7 +250,9 @@
     return PLDM_SUCCESS;
 }
 
-void HostPDRHandler::mergeEntityAssociations(const std::vector<uint8_t>& pdr)
+void HostPDRHandler::mergeEntityAssociations(
+    const std::vector<uint8_t>& pdr, [[maybe_unused]] const uint32_t& size,
+    [[maybe_unused]] const uint32_t& record_handle)
 {
     size_t numEntities{};
     pldm_entity* entities = nullptr;
@@ -254,6 +260,14 @@
     auto entityPdr = reinterpret_cast<pldm_pdr_entity_association*>(
         const_cast<uint8_t*>(pdr.data()) + sizeof(pldm_pdr_hdr));
 
+    if (oemPlatformHandler &&
+        oemPlatformHandler->checkRecordHandleInRange(record_handle))
+    {
+        // Adding the remote range PDRs to the repo before merging it
+        uint32_t handle = record_handle;
+        pldm_pdr_add_check(repo, pdr.data(), size, true, 0xFFFF, &handle);
+    }
+
     pldm_entity_association_pdr_extract(pdr.data(), pdr.size(), &numEntities,
                                         &entities);
     if (numEntities > 0)
@@ -278,9 +292,21 @@
         entityAssoc.push_back(pNode);
         for (size_t i = 1; i < numEntities; ++i)
         {
+            bool isUpdateContainerId = true;
+            if (oemPlatformHandler)
+            {
+                isUpdateContainerId =
+                    pldm::responder::utils::checkIfLogicalBitSet(
+                        entities[i].entity_container_id);
+            }
             auto node = pldm_entity_association_tree_add_entity(
                 entityTree, &entities[i], entities[i].entity_instance_num,
-                pNode, entityPdr->association_type, true, true, 0xFFFF);
+                pNode, entityPdr->association_type, true, isUpdateContainerId,
+                0xFFFF);
+            if (!node)
+            {
+                continue;
+            }
             merged = true;
             entityAssoc.push_back(node);
         }
@@ -303,8 +329,25 @@
         }
         else
         {
-            int rc = pldm_entity_association_pdr_add_from_node_check(
-                node, repo, &entities, numEntities, true, TERMINUS_HANDLE);
+            int rc = 0;
+            if (oemPlatformHandler)
+            {
+                auto record = oemPlatformHandler->fetchLastBMCRecord(repo);
+
+                uint32_t record_handle = pldm_pdr_get_record_handle(repo,
+                                                                    record);
+
+                rc =
+                    pldm_entity_association_pdr_add_from_node_with_record_handle(
+                        node, repo, &entities, numEntities, true,
+                        TERMINUS_HANDLE, (record_handle + 1));
+            }
+            else
+            {
+                rc = pldm_entity_association_pdr_add_from_node_check(
+                    node, repo, &entities, numEntities, true, TERMINUS_HANDLE);
+            }
+
             if (rc)
             {
                 error(
@@ -509,7 +552,7 @@
 
             if (pdrHdr->type == PLDM_PDR_ENTITY_ASSOCIATION)
             {
-                this->mergeEntityAssociations(pdr);
+                this->mergeEntityAssociations(pdr, respCount, rh);
                 merged = true;
             }
             else
@@ -585,6 +628,14 @@
                 {
                     pldm_pdr_update_TL_pdr(repo, terminusHandle, tid, tlEid,
                                            tlValid);
+
+                    if (!isHostUp())
+                    {
+                        // The terminus PDR becomes invalid when the terminus
+                        // itself is down. We don't need to do PDR exchange in
+                        // that case, so setting the next record handle to 0.
+                        nextRecordHandle = 0;
+                    }
                 }
                 else
                 {