soft-off: Send soft off request to the host and wait the host soft off responds

The pldm-softpoweroff application will send a set state effecter states request
to host, then the host will soft off.

The pldm-softpoweroff need two timers. One of the timer is used to wait the
response of the pldm soft off request message(default 30s). Another timer
is used to wait the host graceful shutdown complete(default 7200s).If the host
response is not received within the timeout then log an error and exit the
application.

The pldm-softpowerroff application need Subscribe to the
xyz.openbmc_project.PLDM.Event StateSensorEvent signal,When the host soft off
is complete, it sends a pldm event Msg to BMC.After pldmd receive this
event Msg ,it will emit the StateSensorEvent signal.When the pldm-softpowerroff
receive the signal,it will stop the timer and exit.

Tested in fp5280g2 system:
1、If the host state is not "Running", this application will exit with success(0).
2、If no ACK of the soft off request is received within 30 seconds, this
   application will exit with error(-1).
3、If no pldm event Msg(host gracefully shutdown complete) is received within
   7200 seconds, this application will record an error log and exit with
   error(-1).
4、If the pldm event Msg(host gracefully shutdown complete) is received within
   7200 seconds, this application will exit with success(0).

Signed-off-by: Chicago Duan <duanzhijia01@inspur.com>
Change-Id: I486d8068d013766329f78685acc0508fc3cb6c95
diff --git a/libpldm/state_set.h b/libpldm/state_set.h
index 7bc364c..3a0528e 100644
--- a/libpldm/state_set.h
+++ b/libpldm/state_set.h
@@ -150,6 +150,18 @@
 	PLDM_STATE_SET_OPERATIONAL_RUNNING_STATUS_DORMANT = 6

 };

 

+/* @brief List of states for the Software-related state set (ID 129).

+ */

+enum pldm_software_termination_status_values {

+	PLDM_SW_TERM_NORMAL = 1,

+	PLDM_SW_TERM_SOFTWARE_TERMINATION_DETECTED = 2,

+	PLDM_SW_TERM_CRITICAL_STOP_DURING_LOAD_INITIALIZATION = 3,

+	PLDM_SW_TERM_RUN_TIME_CRITICAL_STOP = 4,

+	PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED = 5,

+	PLDM_SW_TERM_GRACEFUL_RESTART_REQUESTED = 6,

+	PLDM_SW_TERM_GRACEFUL_SHUTDOWN = 7,

+	PLDM_SW_TERM_TERMINATION_REQUEST_FAILED = 8,

+};

 #ifdef __cplusplus

 }

 #endif

diff --git a/softoff/main.cpp b/softoff/main.cpp
index e56a008..4ff2a4d 100644
--- a/softoff/main.cpp
+++ b/softoff/main.cpp
@@ -1,8 +1,55 @@
-#include "libpldm/platform.h"
+#include "common/utils.hpp"
+#include "softoff.hpp"
 
 #include <iostream>
 
 int main()
 {
+    // Get a default event loop
+    auto event = sdeventplus::Event::get_default();
+
+    // Get a handle to system D-Bus.
+    auto& bus = pldm::utils::DBusHandler::getBus();
+
+    // Attach the bus to sd_event to service user requests
+    bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
+
+    pldm::SoftPowerOff softPower(bus, event.get());
+
+    if (softPower.isError())
+    {
+        std::cerr << "Host failed to gracefully shutdown, exiting "
+                     "pldm-softpoweroff app\n";
+        return -1;
+    }
+
+    if (softPower.isCompleted())
+    {
+        std::cerr << "Host current state is not Running, exiting "
+                     "pldm-softpoweroff app\n";
+        return 0;
+    }
+
+    // Send the gracefully shutdown request to the host and
+    // wait the host gracefully shutdown.
+    if (softPower.hostSoftOff(event))
+    {
+        std::cerr << "pldm-softpoweroff:Failure in sending soft off request to "
+                     "the host. Exiting pldm-softpoweroff app\n";
+
+        return -1;
+    }
+
+    if (softPower.isTimerExpired() && softPower.isReceiveResponse())
+    {
+        pldm::utils::reportError(
+            "pldm soft off: Waiting for the host soft off timeout");
+        std::cerr
+            << "PLDM host soft off: ERROR! Wait for the host soft off timeout."
+            << "Exit the pldm-softpoweroff "
+            << "\n";
+        return -1;
+    }
+
     return 0;
 }
diff --git a/softoff/meson.build b/softoff/meson.build
index 09c9d2c..753375b 100644
--- a/softoff/meson.build
+++ b/softoff/meson.build
@@ -1,9 +1,24 @@
-deps = [ libpldm ]
+deps = [
+    libpldm,
+    libpldmutils,
+    dependency('sdeventplus'),
+    dependency('sdbusplus'),
+    dependency('phosphor-dbus-interfaces'),
+    ]
 
-source = ['main.cpp']
+source = ['main.cpp','softoff.cpp']
 
 executable('pldm-softpoweroff',source,
            implicit_include_directories: false,
            dependencies: deps,
            install: true,
            install_dir: get_option('bindir'))
+
+systemd = dependency('systemd')
+servicedir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
+
+configure_file(input: 'services/pldmSoftPowerOff.service',
+                 output: 'pldmSoftPowerOff.service',
+                 copy: true,
+                 install_dir: servicedir)
+
diff --git a/softoff/services/pldmSoftPowerOff.service b/softoff/services/pldmSoftPowerOff.service
new file mode 100644
index 0000000..80960cd
--- /dev/null
+++ b/softoff/services/pldmSoftPowerOff.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=PLDM soft power off app
+Wants=pldmd.service
+After=pldmd.service
+Wants=obmc-host-stopping@0.target
+Before=obmc-host-stopping@0.target
+Conflicts=obmc-host-start@0.target
+
+[Service]
+Restart=no
+ExecStart=/usr/bin/pldm-softpoweroff
+Type=oneshot
diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp
new file mode 100644
index 0000000..c2f2051
--- /dev/null
+++ b/softoff/softoff.cpp
@@ -0,0 +1,434 @@
+#include "config.h"
+
+#include "softoff.hpp"
+
+#include "libpldm/entity.h"
+#include "libpldm/platform.h"
+#include "libpldm/requester/pldm.h"
+#include "libpldm/state_set.h"
+
+#include "common/utils.hpp"
+
+#include <sdbusplus/bus.hpp>
+#include <sdeventplus/clock.hpp>
+#include <sdeventplus/source/io.hpp>
+#include <sdeventplus/source/time.hpp>
+
+#include <array>
+#include <iostream>
+
+namespace pldm
+{
+
+using namespace sdeventplus;
+using namespace sdeventplus::source;
+constexpr auto clockId = sdeventplus::ClockId::RealTime;
+using Clock = Clock<clockId>;
+using Timer = Time<clockId>;
+
+using sdbusplus::exception::SdBusError;
+
+constexpr pldm::pdr::TerminusID TID = 0; // TID will be implemented later.
+namespace sdbusRule = sdbusplus::bus::match::rules;
+
+SoftPowerOff::SoftPowerOff(sdbusplus::bus::bus& bus, sd_event* event) :
+    bus(bus), timer(event)
+{
+    auto rc = getHostState();
+    if (hasError || completed)
+    {
+        return;
+    }
+
+    rc = getEffecterID();
+    if (rc != PLDM_SUCCESS)
+    {
+        hasError = true;
+        return;
+    }
+
+    rc = getSensorInfo();
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Message get Sensor PDRs error. PLDM "
+                     "error code = "
+                  << std::hex << std::showbase << rc << "\n";
+        hasError = true;
+        return;
+    }
+
+    // Matches on the pldm StateSensorEvent signal
+    pldmEventSignal = std::make_unique<sdbusplus::bus::match_t>(
+        bus,
+        sdbusRule::type::signal() + sdbusRule::member("StateSensorEvent") +
+            sdbusRule::path("/xyz/openbmc_project/pldm") +
+            sdbusRule::interface("xyz.openbmc_project.PLDM.Event"),
+        std::bind(std::mem_fn(&SoftPowerOff::hostSoftOffComplete), this,
+                  std::placeholders::_1));
+}
+
+int SoftPowerOff::getHostState()
+{
+    try
+    {
+        pldm::utils::PropertyValue propertyValue =
+            pldm::utils::DBusHandler().getDbusPropertyVariant(
+                "/xyz/openbmc_project/state/host0", "CurrentHostState",
+                "xyz.openbmc_project.State.Host");
+
+        if (std::get<std::string>(propertyValue) !=
+            "xyz.openbmc_project.State.Host.HostState.Running")
+        {
+            // Host state is not "Running", this app should return success
+            completed = true;
+            return PLDM_SUCCESS;
+        }
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "PLDM host soft off: Can't get current host state.\n";
+        hasError = true;
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+void SoftPowerOff::hostSoftOffComplete(sdbusplus::message::message& msg)
+{
+    pldm::pdr::TerminusID msgTID;
+    pldm::pdr::SensorID msgSensorID;
+    pldm::pdr::SensorOffset msgSensorOffset;
+    pldm::pdr::EventState msgEventState;
+    pldm::pdr::EventState msgPreviousEventState;
+
+    // Read the msg and populate each variable
+    msg.read(msgTID, msgSensorID, msgSensorOffset, msgEventState,
+             msgPreviousEventState);
+
+    if (msgSensorID == sensorID && msgSensorOffset == sensorOffset &&
+        msgEventState == PLDM_SW_TERM_GRACEFUL_SHUTDOWN)
+    {
+        // Receive Graceful shutdown completion event message. Disable the timer
+        auto rc = timer.stop();
+        if (rc < 0)
+        {
+            std::cerr << "PLDM soft off: Failure to STOP the timer. ERRNO="
+                      << rc << "\n";
+        }
+
+        // This marks the completion of pldm soft power off.
+        completed = true;
+    }
+}
+
+int SoftPowerOff::getEffecterID()
+{
+    auto& bus = pldm::utils::DBusHandler::getBus();
+
+    // VMM is a logical entity, so the bit 15 in entity type is set.
+    pdr::EntityType entityType = PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER | 0x8000;
+
+    try
+    {
+        std::vector<std::vector<uint8_t>> VMMResponse{};
+        auto VMMMethod = bus.new_method_call(
+            "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
+            "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
+        VMMMethod.append(TID, entityType,
+                         (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
+
+        auto VMMResponseMsg = bus.call(VMMMethod);
+
+        VMMResponseMsg.read(VMMResponse);
+        if (VMMResponse.size() != 0)
+        {
+            for (auto& rep : VMMResponse)
+            {
+                auto VMMPdr =
+                    reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
+                effecterID = VMMPdr->effecter_id;
+            }
+        }
+        else
+        {
+            VMMPdrExist = false;
+        }
+    }
+    catch (const SdBusError& e)
+    {
+        std::cerr << "PLDM soft off: Error get VMM PDR,ERROR=" << e.what()
+                  << "\n";
+        VMMPdrExist = false;
+    }
+
+    if (VMMPdrExist)
+    {
+        return PLDM_SUCCESS;
+    }
+
+    // If the Virtual Machine Manager PDRs doesn't exist, go find the System
+    // Firmware PDRs.
+    // System Firmware is a logical entity, so the bit 15 in entity type is set
+    entityType = PLDM_ENTITY_SYS_FIRMWARE | 0x8000;
+    try
+    {
+        std::vector<std::vector<uint8_t>> sysFwResponse{};
+        auto sysFwMethod = bus.new_method_call(
+            "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
+            "xyz.openbmc_project.PLDM.PDR", "FindStateEffecterPDR");
+        sysFwMethod.append(TID, entityType,
+                           (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
+
+        auto sysFwResponseMsg = bus.call(sysFwMethod);
+
+        sysFwResponseMsg.read(sysFwResponse);
+
+        if (sysFwResponse.size() == 0)
+        {
+            std::cerr
+                << "No effecter ID has been found that matches the criteria"
+                << "\n";
+            return PLDM_ERROR;
+        }
+
+        for (auto& rep : sysFwResponse)
+        {
+            auto sysFwPdr =
+                reinterpret_cast<pldm_state_effecter_pdr*>(rep.data());
+            effecterID = sysFwPdr->effecter_id;
+        }
+    }
+    catch (const SdBusError& e)
+    {
+        std::cerr << "PLDM soft off: Error get system firmware PDR,ERROR="
+                  << e.what() << "\n";
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+int SoftPowerOff::getSensorInfo()
+{
+    pldm::pdr::EntityType entityType;
+
+    entityType = VMMPdrExist ? PLDM_ENTITY_VIRTUAL_MACHINE_MANAGER
+                             : PLDM_ENTITY_SYS_FIRMWARE;
+
+    // The Virtual machine manager/System firmware is logical entity, so bit 15
+    // need to be set.
+    entityType = entityType | 0x8000;
+
+    try
+    {
+        auto& bus = pldm::utils::DBusHandler::getBus();
+        std::vector<std::vector<uint8_t>> Response{};
+        auto method = bus.new_method_call(
+            "xyz.openbmc_project.PLDM", "/xyz/openbmc_project/pldm",
+            "xyz.openbmc_project.PLDM.PDR", "FindStateSensorPDR");
+        method.append(TID, entityType,
+                      (uint16_t)PLDM_STATE_SET_SW_TERMINATION_STATUS);
+
+        auto ResponseMsg = bus.call(method);
+
+        ResponseMsg.read(Response);
+
+        if (Response.size() == 0)
+        {
+            std::cerr
+                << "No sensor PDR has been found that matches the criteria"
+                << "\n";
+            return PLDM_ERROR;
+        }
+
+        pldm_state_sensor_pdr* pdr;
+        for (auto& rep : Response)
+        {
+            pdr = reinterpret_cast<pldm_state_sensor_pdr*>(rep.data());
+        }
+
+        sensorID = pdr->sensor_id;
+
+        auto compositeSensorCount = pdr->composite_sensor_count;
+        auto possibleStatesStart = pdr->possible_states;
+
+        for (auto offset = 0; offset < compositeSensorCount; offset++)
+        {
+            auto possibleStates =
+                reinterpret_cast<state_sensor_possible_states*>(
+                    possibleStatesStart);
+            auto setId = possibleStates->state_set_id;
+            auto possibleStateSize = possibleStates->possible_states_size;
+
+            if (setId == PLDM_STATE_SET_SW_TERMINATION_STATUS)
+            {
+                sensorOffset = offset;
+                break;
+            }
+            possibleStatesStart +=
+                possibleStateSize + sizeof(setId) + sizeof(possibleStateSize);
+        }
+    }
+    catch (const SdBusError& e)
+    {
+        std::cerr << "PLDM soft off: Error get State Sensor PDR,ERROR="
+                  << e.what() << "\n";
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
+{
+    constexpr uint8_t effecterCount = 1;
+    uint8_t mctpEID;
+    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);
+
+        ResponseMsg.read(instanceID);
+    }
+    catch (const SdBusError& e)
+    {
+        std::cerr << "PLDM soft off: Error get instanceID,ERROR=" << e.what()
+                  << "\n";
+        return PLDM_ERROR;
+    }
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterID) +
+                            sizeof(effecterCount) +
+                            sizeof(set_effecter_state_field)>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    set_effecter_state_field stateField{
+        PLDM_REQUEST_SET, PLDM_SW_TERM_GRACEFUL_SHUTDOWN_REQUESTED};
+    auto rc = encode_set_state_effecter_states_req(
+        instanceID, effecterID, effecterCount, &stateField, request);
+    if (rc != PLDM_SUCCESS)
+    {
+        std::cerr << "Message encode failure. PLDM error code = " << std::hex
+                  << std::showbase << rc << "\n";
+        return PLDM_ERROR;
+    }
+
+    // Open connection to MCTP socket
+    int fd = pldm_open();
+    if (-1 == fd)
+    {
+        std::cerr << "Failed to connect to mctp demux daemon"
+                  << "\n";
+        return PLDM_ERROR;
+    }
+
+    // Add a timer to the event loop, default 30s.
+    auto timerCallback = [=](Timer& /*source*/, Timer::TimePoint /*time*/) {
+        if (!responseReceived)
+        {
+            std::cerr << "PLDM soft off: ERROR! Can't get the response for the "
+                         "PLDM request msg. Time out!\n"
+                      << "Exit the pldm-softpoweroff\n";
+            exit(-1);
+        }
+        return;
+    };
+    Timer time(event, (Clock(event).now() + std::chrono::seconds{30}),
+               std::chrono::seconds{1}, std::move(timerCallback));
+
+    // Add a callback to handle EPOLLIN on fd
+    auto callback = [=](IO& io, int fd, uint32_t revents) {
+        if (!(revents & EPOLLIN))
+        {
+            return;
+        }
+
+        uint8_t* responseMsg = nullptr;
+        size_t responseMsgSize{};
+
+        auto rc = pldm_recv(mctpEID, fd, request->hdr.instance_id, &responseMsg,
+                            &responseMsgSize);
+        if (rc)
+        {
+            return;
+        }
+
+        std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
+            responseMsg, std::free};
+
+        // We've got the response meant for the PLDM request msg that was
+        // sent out
+        io.set_enabled(Enabled::Off);
+        auto response = reinterpret_cast<pldm_msg*>(responseMsgPtr.get());
+        std::cerr << "Getting the response. PLDM RC = " << std::hex
+                  << std::showbase
+                  << static_cast<uint16_t>(response->payload[0]) << "\n";
+
+        responseReceived = true;
+
+        // Start Timer
+        using namespace std::chrono;
+        auto timeMicroseconds =
+            duration_cast<microseconds>(seconds(SOFTOFF_TIMEOUT_SECONDS));
+
+        auto ret = startTimer(timeMicroseconds);
+        if (ret < 0)
+        {
+            std::cerr << "Failure to start Host soft off wait timer, ERRNO = "
+                      << ret << "Exit the pldm-softpoweroff\n";
+            exit(-1);
+        }
+        else
+        {
+            std::cerr << "Timer started waiting for host soft off, "
+                         "TIMEOUT_IN_SEC = "
+                      << SOFTOFF_TIMEOUT_SECONDS << "\n";
+        }
+        return;
+    };
+    IO io(event, fd, EPOLLIN, std::move(callback));
+
+    // Send PLDM Request message - pldm_send doesn't wait for response
+    rc = pldm_send(mctpEID, fd, requestMsg.data(), requestMsg.size());
+    if (0 > rc)
+    {
+        std::cerr << "Failed to send message/receive response. RC = " << rc
+                  << ", errno = " << errno << "\n";
+        return PLDM_ERROR;
+    }
+
+    // Time out or soft off complete
+    while (!isCompleted() && !isTimerExpired())
+    {
+        try
+        {
+            event.run(std::nullopt);
+        }
+        catch (const sdeventplus::SdEventError& e)
+        {
+            std::cerr
+                << "PLDM host soft off: Failure in processing request.ERROR= "
+                << e.what() << "\n";
+            return PLDM_ERROR;
+        }
+    }
+
+    return PLDM_SUCCESS;
+}
+
+int SoftPowerOff::startTimer(const std::chrono::microseconds& usec)
+{
+    return timer.start(usec);
+}
+} // namespace pldm
diff --git a/softoff/softoff.hpp b/softoff/softoff.hpp
new file mode 100644
index 0000000..302144c
--- /dev/null
+++ b/softoff/softoff.hpp
@@ -0,0 +1,148 @@
+#pragma once
+
+#include "libpldm/requester/pldm.h"
+
+#include "common/types.hpp"
+
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/server.hpp>
+#include <sdbusplus/server/object.hpp>
+#include <sdbusplus/timer.hpp>
+#include <sdeventplus/event.hpp>
+
+namespace pldm
+{
+
+/** @class SoftPowerOff
+ *  @brief Responsible for coordinating Host SoftPowerOff operation
+ */
+class SoftPowerOff
+{
+  public:
+    /** @brief Constructs SoftPowerOff object.
+     *
+     *  @param[in] bus       - system D-Bus handler
+     *  @param[in] event     - sd_event handler
+     */
+    SoftPowerOff(sdbusplus::bus::bus& bus, sd_event* event);
+
+    /** @brief Is the pldm-softpoweroff has error.
+     * if hasError is true, that means the pldm-softpoweroff failed to
+     * trigger the host soft off,so the pldm-softpoweroff will exit.
+     */
+    inline bool isError()
+    {
+        return hasError;
+    }
+
+    /** @brief Is the timer expired.
+     */
+    inline bool isTimerExpired()
+    {
+        return timer.isExpired();
+    }
+
+    /** @brief Is the host soft off completed.
+     */
+    inline bool isCompleted()
+    {
+        return completed;
+    }
+
+    /** @brief Is receive the response for the PLDM request msg.
+     */
+    inline bool isReceiveResponse()
+    {
+        return responseReceived;
+    }
+
+    /** @brief Send PLDM Set State Effecter States command and
+     * wait the host gracefully shutdown.
+     *
+     *  @param[in] event - The event loop.
+     *
+     *  @return PLDM_SUCCESS or PLDM_ERROR.
+     */
+    int hostSoftOff(sdeventplus::Event& event);
+
+  private:
+    /** @brief Getting the host current state.
+     */
+    int getHostState();
+
+    /** @brief Stop the timer.
+     */
+    inline auto stopTimer()
+    {
+        return timer.stop();
+    }
+
+    /** @brief When host soft off completed, stop the timer and
+     *         set the completed to true.
+     *
+     *  @param[in] msg - Data associated with subscribed signal
+     */
+    void hostSoftOffComplete(sdbusplus::message::message& msg);
+
+    /** @brief Start the timer.
+     *
+     *  @param[in] usec - Time to wait for the Host to gracefully shutdown.
+     *
+     *  @return Success or exception thrown
+     */
+    int startTimer(const std::chrono::microseconds& usec);
+
+    /** @brief Get effecterID from PDRs.
+     *
+     *  @return PLDM_SUCCESS or PLDM_ERROR
+     */
+    int getEffecterID();
+
+    /** @brief Get VMM/SystemFirmware Sensor info from PDRs.
+     *
+     *  @return PLDM_SUCCESS or PLDM_ERROR
+     */
+    int getSensorInfo();
+
+    /** @brief effecterID
+     */
+    uint16_t effecterID;
+
+    /** @brief sensorID.
+     */
+    pldm::pdr::SensorID sensorID;
+
+    /** @brief sensorOffset.
+     */
+    pldm::pdr::SensorOffset sensorOffset;
+
+    /** @brief Failed to send host soft off command flag.
+     */
+    bool hasError = false;
+
+    /** @brief Host soft off completed flag.
+     */
+    bool completed = false;
+
+    /** @brief The response for the PLDM request msg is received flag.
+     */
+    bool responseReceived = false;
+
+    /** @brief Is the Virtual Machine Manager/VMM state effecter available.
+     */
+    bool VMMPdrExist = true;
+
+    /* @brief sdbusplus handle */
+    sdbusplus::bus::bus& bus;
+
+    /** @brief Reference to Timer object */
+    phosphor::Timer timer;
+
+    /** @brief Used to subscribe to dbus pldm StateSensorEvent signal
+     * When the host soft off is complete, it sends an platform event message
+     * to BMC's pldmd, and the pldmd will emit the StateSensorEvent signal.
+     **/
+    std::unique_ptr<sdbusplus::bus::match_t> pldmEventSignal;
+};
+
+} // namespace pldm