pldmtool/softoff: Use InstanceId APIs from libpldm

The af-mctp transport does not broadcast the PLDM messages between the
MCTP socket instances. Pldmtool/softoff have to handle get/free
instanceId instead of depending on the pldmd. Update pldmtool/softoff
to use get/free instanceId APIs in libpldm.

Tested.
1. Call more than 32 pldmtool commands to make sure the allocated
InstanceId are free correctly.
2. Repeat calling softoff more than 32 times. Make sure the functional
should work normally.

Signed-off-by: Dung Cao <dung@os.amperecomputing.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
Change-Id: I7cda124694d95d00c37f4993e22cfe33a980d364
diff --git a/pldmtool/pldm_cmd_helper.cpp b/pldmtool/pldm_cmd_helper.cpp
index 510f6df..db44c5a 100644
--- a/pldmtool/pldm_cmd_helper.cpp
+++ b/pldmtool/pldm_cmd_helper.cpp
@@ -133,28 +133,11 @@
 
 void CommandInterface::exec()
 {
-    static constexpr auto pldmObjPath = "/xyz/openbmc_project/pldm";
-    static constexpr auto pldmRequester = "xyz.openbmc_project.PLDM.Requester";
-    auto& bus = pldm::utils::DBusHandler::getBus();
-    try
-    {
-        auto service = pldm::utils::DBusHandler().getService(pldmObjPath,
-                                                             pldmRequester);
-        auto method = bus.new_method_call(service.c_str(), pldmObjPath,
-                                          pldmRequester, "GetInstanceId");
-        method.append(mctp_eid);
-        auto reply = bus.call(method, dbusTimeout);
-        reply.read(instanceId);
-    }
-    catch (const std::exception& e)
-    {
-        std::cerr << "GetInstanceId D-Bus call failed, MCTP id = "
-                  << (unsigned)mctp_eid << ", error = " << e.what() << "\n";
-        return;
-    }
+    instanceId = instanceIdDb.next(mctp_eid);
     auto [rc, requestMsg] = createRequestMsg();
     if (rc != PLDM_SUCCESS)
     {
+        instanceIdDb.free(mctp_eid, instanceId);
         std::cerr << "Failed to encode request message for " << pldmType << ":"
                   << commandName << " rc = " << rc << "\n";
         return;
@@ -165,12 +148,14 @@
 
     if (rc != PLDM_SUCCESS)
     {
+        instanceIdDb.free(mctp_eid, instanceId);
         std::cerr << "pldmSendRecv: Failed to receive RC = " << rc << "\n";
         return;
     }
 
     auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg.data());
     parseResponseMsg(responsePtr, responseMsg.size() - sizeof(pldm_msg_hdr));
+    instanceIdDb.free(mctp_eid, instanceId);
 }
 
 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
diff --git a/pldmtool/pldm_cmd_helper.hpp b/pldmtool/pldm_cmd_helper.hpp
index 1f21ea2..2488135 100644
--- a/pldmtool/pldm_cmd_helper.hpp
+++ b/pldmtool/pldm_cmd_helper.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "common/instance_id.hpp"
 #include "common/utils.hpp"
 
 #include <err.h>
@@ -137,6 +138,7 @@
 
   protected:
     uint8_t instanceId;
+    pldm::InstanceIdDb instanceIdDb;
 };
 
 } // namespace helper
diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp
index be78933..f80e048 100644
--- a/softoff/softoff.cpp
+++ b/softoff/softoff.cpp
@@ -1,5 +1,6 @@
 #include "softoff.hpp"
 
+#include "common/instance_id.hpp"
 #include "common/utils.hpp"
 
 #include <libpldm/entity.h>
@@ -294,26 +295,8 @@
     uint8_t instanceID;
 
     mctpEID = pldm::utils::readHostEID();
-
-    // Get instanceID
-    try
-    {
-        auto& bus = pldm::utils::DBusHandler::getBus();
-        auto method = bus.new_method_call(
-            "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
-            "xyz.openbmc_project.PLDM.Requester", "GetInstanceId");
-        method.append(mctpEID);
-
-        auto ResponseMsg = bus.call(method, dbusTimeout);
-
-        ResponseMsg.read(instanceID);
-    }
-    catch (const sdbusplus::exception_t& e)
-    {
-        error("PLDM soft off: Error get instanceID,ERROR={ERR_EXCEP}",
-              "ERR_EXCEP", e.what());
-        return PLDM_ERROR;
-    }
+    // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
+    pldm_tid_t pldmTID = static_cast<pldm_tid_t>(mctpEID);
 
     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
                             sizeof(effecterCount) +
@@ -322,10 +305,13 @@
     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
     set_effecter_state_field stateField{
         PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
+    pldm::InstanceIdDb instanceIdDb;
+    instanceID = instanceIdDb.next(pldmTID);
     auto rc = encode_set_state_effecter_states_req(
         instanceID, effecterID, effecterCount, &stateField, request);
     if (rc != PLDM_SUCCESS)
     {
+        instanceIdDb.free(pldmTID, instanceID);
         error("Message encode failure. PLDM error code = {RC}", "RC", lg2::hex,
               static_cast<int>(rc));
         return PLDM_ERROR;
@@ -341,9 +327,10 @@
 
     // Add a timer to the event loop, default 30s.
     auto timerCallback =
-        [=, this](Timer& /*source*/, Timer::TimePoint /*time*/) {
+        [=, this](Timer& /*source*/, Timer::TimePoint /*time*/) mutable {
         if (!responseReceived)
         {
+            instanceIdDb.free(pldmTID, instanceID);
             error(
                 "PLDM soft off: ERROR! Can't get the response for the PLDM request msg. Time out! Exit the pldm-softpoweroff");
             exit(-1);
@@ -354,7 +341,7 @@
                std::chrono::seconds{1}, std::move(timerCallback));
 
     // Add a callback to handle EPOLLIN on fd
-    auto callback = [=, this](IO& io, int fd, uint32_t revents) {
+    auto callback = [=, this](IO& io, int fd, uint32_t revents) mutable {
         if (!(revents & EPOLLIN))
         {
             return;
@@ -362,6 +349,7 @@
 
         uint8_t* responseMsg = nullptr;
         size_t responseMsgSize{};
+        pldm_tid_t srcTID = pldmTID;
 
         auto rc = pldm_recv(mctpEID, fd, request->hdr.instance_id, &responseMsg,
                             &responseMsgSize);
@@ -379,6 +367,18 @@
         // sent out
         io.set_enabled(Enabled::Off);
         auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
+
+        if (srcTID != pldmTID ||
+            !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
+        {
+            /* This isn't the response we were looking for */
+            return;
+        }
+
+        /* We have the right response, release the instance ID and process */
+        io.set_enabled(Enabled::Off);
+        instanceIdDb.free(pldmTID, instanceID);
+
         if (response->payload[0] != PLDM_SUCCESS)
         {
             error("Getting the wrong response. PLDM RC = {RC}", "RC",
@@ -415,6 +415,7 @@
     rc = pldm_send(mctpEID, fd, requestMsg.data(), requestMsg.size());
     if (0 > rc)
     {
+        instanceIdDb.free(pldmTID, instanceID);
         error(
             "Failed to send message/receive response. RC = {RC}, errno = {ERR}",
             "RC", static_cast<int>(rc), "ERR", errno);
@@ -430,6 +431,7 @@
         }
         catch (const sdeventplus::SdEventError& e)
         {
+            instanceIdDb.free(pldmTID, instanceID);
             error(
                 "PLDM host soft off: Failure in processing request.ERROR= {ERR_EXCEP}",
                 "ERR_EXCEP", e.what());