PLDM: implement surveillance between Host and bmc

This commit is to implement surveillance between host
and bmc, wherein host monitors if bmc is up and
running through constant pings(by sending Platform
EventMessages) sent from host to BMC. And if BMC
fails to respond to the pings, then BMC will be
reset using the KCS interface.

1. Host->BMC - GetTID
2. BMC->Host - Respond to GetTID, SetEventReceiver
3. Host->BMC - Respond to SetEventReceiver
4. BMC->Host -  Send PlatformEventMessage after the
   elapsed time interval(specified with
   SetEventReceiver command)
4. Host->BMC - If BMC fails to send respond to host
   within specified interval, Host resets BMC via
   the KCS interface

Tested with PLDMTOOL:
SetEventReceiver command:
root@rain127bmc:/tmp# ./pldmtool base GetTID -m 8
Received Msg
08 01 81 00 02
Sending Msg
01 00 02 00 01
{
    "Response": 1
}

platformEventMessage command(which will be received
by host):
root@rain118bmc:/tmp# ./pldmtool raw -d 0x80 0x02
0x0A 0x01 0x01 0x06 0x01 0x01
Request Message:
08 01 80 02 0a 01 01 06 01 01
Received Msg
08 01 80 02 0a 01 01 06 01 01
eventClass Checking
Sending Msg
00 02 0a 00 00
Response Message:
08 01 00 02 0a 00 00
Received Msg
08 01 00 02 0a 00 00

Signed-off-by: Sagar Srinivas <sagar.srinivas@ibm.com>
Change-Id: Iac90b2233a873a54504ffa649d324d30525b7ce3
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index 395529b..7195b80 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -1,13 +1,19 @@
+#include "config.h"
+
 #include "libpldm/base.h"
 
 #include "libpldm/bios.h"
 #include "libpldm/fru.h"
 #include "libpldm/platform.h"
+#include "libpldm/requester/pldm.h"
 
 #include "base.hpp"
+#include "common/utils.hpp"
+#include "libpldmresponder/pdr.hpp"
 
 #include <array>
 #include <cstring>
+#include <iostream>
 #include <map>
 #include <stdexcept>
 #include <vector>
@@ -170,6 +176,64 @@
     return response;
 }
 
+void Handler::processSetEventReceiver(
+    sdeventplus::source::EventBase& /*source */)
+{
+    survEvent.reset();
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                    PLDM_SET_EVENT_RECEIVER_REQ_BYTES);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto instanceId = requester.getInstanceId(eid);
+    uint8_t eventMessageGlobalEnable =
+        PLDM_EVENT_MESSAGE_GLOBAL_ENABLE_ASYNC_KEEP_ALIVE;
+    uint8_t transportProtocolType = PLDM_TRANSPORT_PROTOCOL_TYPE_MCTP;
+    uint8_t eventReceiverAddressInfo = pldm::responder::pdr::BmcMctpEid;
+    uint16_t heartbeatTimer = HEARTBEAT_TIMEOUT;
+
+    auto rc = encode_set_event_receiver_req(
+        instanceId, eventMessageGlobalEnable, transportProtocolType,
+        eventReceiverAddressInfo, heartbeatTimer, request);
+    if (rc != PLDM_SUCCESS)
+    {
+        requester.markFree(eid, instanceId);
+        std::cerr << "Failed to encode_set_event_receiver_req, rc = "
+                  << std::hex << std::showbase << rc << std::endl;
+        return;
+    }
+
+    auto processSetEventReceiverResponse = [](mctp_eid_t /*eid*/,
+                                              const pldm_msg* response,
+                                              size_t respMsgLen) {
+        if (response == nullptr || !respMsgLen)
+        {
+            std::cerr << "Failed to receive response for "
+                         "setEventReceiver command \n";
+            return;
+        }
+
+        uint8_t completionCode{};
+        auto rc = decode_set_event_receiver_resp(response, respMsgLen,
+                                                 &completionCode);
+        if (rc || completionCode)
+        {
+            std::cerr << "Failed to decode setEventReceiver command response,"
+                      << " rc=" << rc << "cc=" << (uint8_t)completionCode
+                      << "\n";
+            pldm::utils::reportError(
+                "xyz.openbmc_project.bmc.pldm.InternalFailure");
+        }
+    };
+    rc = handler->registerRequest(
+        eid, instanceId, PLDM_PLATFORM, PLDM_SET_EVENT_RECEIVER,
+        std::move(requestMsg), std::move(processSetEventReceiverResponse));
+
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Failed to send the setEventReceiver request"
+                  << "\n";
+    }
+}
+
 Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
 {
     // assigned 1 to the bmc as the PLDM terminus
@@ -184,6 +248,9 @@
         return ccOnlyResponse(request, rc);
     }
 
+    survEvent = std::make_unique<sdeventplus::source::Defer>(
+        event, std::bind_front(&Handler::processSetEventReceiver, this));
+
     return response;
 }