pldmd: implement a new handler registration scheme

Implement a PLDM request handler registration scheme that requires
handlers to be C++ objects rather than plain functions. This was needed
for a couple of reasons:

- Perform specific actions at the PLDM daemon startup (that's when the
  handlers are loaded).
- Share data across PLDM request messages (for eg FRU/BIOS tables),
  without having to resort to globals and statics.

Tested:
- existing unit tests still pass
- added tests for the new registration scheme

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I1cf1c0a6fccd15da54f08120e61a5f256df6bc36
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index e94597a..b9f5ff1 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -1,7 +1,6 @@
 #include "libpldm/base.h"
 
 #include "base.hpp"
-#include "registration.hpp"
 
 #include <array>
 #include <cstring>
@@ -14,6 +13,9 @@
 
 namespace pldm
 {
+
+using Type = uint8_t;
+
 namespace responder
 {
 
@@ -36,19 +38,8 @@
 namespace base
 {
 
-void registerHandlers()
-{
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_TYPES, std::move(getPLDMTypes));
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_COMMANDS,
-                    std::move(getPLDMCommands));
-    registerHandler(PLDM_BASE, PLDM_GET_PLDM_VERSION,
-                    std::move(getPLDMVersion));
-    registerHandler(PLDM_BASE, PLDM_GET_TID, std::move(getTID));
-}
-
-} // namespace base
-
-Response getPLDMTypes(const pldm_msg* request, size_t /*payloadLength*/)
+Response Handler::getPLDMTypes(const pldm_msg* request,
+                               size_t /*payloadLength*/)
 {
     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
     std::array<bitfield8_t, 8> types{};
@@ -68,7 +59,7 @@
     return response;
 }
 
-Response getPLDMCommands(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
 {
     ver32_t version{};
     Type type;
@@ -109,7 +100,7 @@
     return response;
 }
 
-Response getPLDMVersion(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t transferHandle;
     Type type;
@@ -147,7 +138,7 @@
     return response;
 }
 
-Response getTID(const pldm_msg* request, size_t /*payloadLength*/)
+Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
 {
     // assigned 1 to the bmc as the PLDM terminus
     uint8_t tid = 1;
@@ -160,5 +151,6 @@
     return response;
 }
 
+} // namespace base
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp
index a6e5abd..519bff2 100644
--- a/libpldmresponder/base.hpp
+++ b/libpldmresponder/base.hpp
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "handler.hpp"
+
 #include <stdint.h>
 
 #include <vector>
@@ -8,51 +10,67 @@
 
 namespace pldm
 {
-
-using Type = uint8_t;
-
-using Response = std::vector<uint8_t>;
-
 namespace responder
 {
-
 namespace base
 {
-/** @brief Register handlers for command from the base spec
- */
-void registerHandlers();
+
+class Handler : public CmdHandler
+{
+  public:
+    Handler()
+    {
+        handlers.emplace(PLDM_GET_PLDM_TYPES,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getPLDMTypes(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_GET_PLDM_COMMANDS, [this](const pldm_msg* request,
+                                                        size_t payloadLength) {
+            return this->getPLDMCommands(request, payloadLength);
+        });
+        handlers.emplace(PLDM_GET_PLDM_VERSION, [this](const pldm_msg* request,
+                                                       size_t payloadLength) {
+            return this->getPLDMVersion(request, payloadLength);
+        });
+        handlers.emplace(PLDM_GET_TID,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getTID(request, payloadLength);
+                         });
+    }
+
+    /** @brief Handler for getPLDMTypes
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMTypes(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getPLDMCommands
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMCommands(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getPLDMCommands
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getPLDMVersion(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for getTID
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getTID(const pldm_msg* request, size_t payloadLength);
+};
+
 } // namespace base
-
-/** @brief Handler for getPLDMTypes
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMTypes(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getPLDMCommands
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMCommands(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getPLDMCommands
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getPLDMVersion(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for getTID
- *
- *  @param[in] request - Request message payload
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getTID(const pldm_msg* request, size_t payloadLength);
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 1c48f1a..c3a1c53 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -1,7 +1,6 @@
 #include "bios.hpp"
 
 #include "libpldmresponder/utils.hpp"
-#include "registration.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <array>
@@ -72,7 +71,10 @@
 
 } // namespace utils
 
-Response getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
+namespace bios
+{
+
+Response Handler::getDateTime(const pldm_msg* request, size_t /*payloadLength*/)
 {
     uint8_t seconds = 0;
     uint8_t minutes = 0;
@@ -117,7 +119,8 @@
                            std::chrono::microseconds(timeUsec))
                            .count();
 
-    utils::epochToBCDTime(timeSec, seconds, minutes, hours, day, month, year);
+    pldm::responder::utils::epochToBCDTime(timeSec, seconds, minutes, hours,
+                                           day, month, year);
 
     encode_get_date_time_resp(request->hdr.instance_id, PLDM_SUCCESS, seconds,
                               minutes, hours, day, month, year, responsePtr);
@@ -163,7 +166,8 @@
         });
 
     Table stringTable;
-    stringTable.reserve(utils::getTableTotalsize(sizeWithoutPad));
+    stringTable.reserve(
+        pldm::responder::utils::getTableTotalsize(sizeWithoutPad));
 
     stringTable.resize(sizeWithoutPad);
     auto tablePtr = stringTable.data();
@@ -177,7 +181,7 @@
         sizeWithoutPad -= entry_length;
     }
 
-    utils::padAndChecksum(stringTable);
+    pldm::responder::utils::padAndChecksum(stringTable);
     BIOSStringTable.store(stringTable);
     response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
                         stringTable.size(),
@@ -647,7 +651,7 @@
                                        response.size(), responsePtr);
             return response;
         }
-        utils::padAndChecksum(attributeTable);
+        pldm::responder::utils::padAndChecksum(attributeTable);
         BIOSAttributeTable.store(attributeTable);
         response.resize(sizeof(pldm_msg_hdr) +
                         PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
@@ -751,7 +755,7 @@
                                    response.size(), responsePtr);
         return response;
     }
-    utils::padAndChecksum(attributeValueTable);
+    pldm::responder::utils::padAndChecksum(attributeValueTable);
     BIOSAttributeValueTable.store(attributeValueTable);
 
     response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES +
@@ -764,7 +768,7 @@
     return response;
 }
 
-Response getBIOSTable(const pldm_msg* request, size_t payloadLength)
+Response Handler::getBIOSTable(const pldm_msg* request, size_t payloadLength)
 {
     fs::create_directory(BIOS_TABLES_DIR);
     auto response = internal::buildBIOSTables(request, payloadLength,
@@ -773,15 +777,6 @@
     return response;
 }
 
-namespace bios
-{
-
-void registerHandlers()
-{
-    registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
-    registerHandler(PLDM_BIOS, PLDM_GET_BIOS_TABLE, std::move(getBIOSTable));
-}
-
 namespace internal
 {
 
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 412e07a..e9abed2 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -4,6 +4,7 @@
 
 #include "bios_parser.hpp"
 #include "bios_table.hpp"
+#include "handler.hpp"
 
 #include <stdint.h>
 
@@ -17,7 +18,6 @@
 namespace pldm
 {
 
-using Response = std::vector<uint8_t>;
 using AttributeHandle = uint16_t;
 using StringHandle = uint16_t;
 using PossibleValuesByHandle = std::vector<StringHandle>;
@@ -25,18 +25,15 @@
 namespace responder
 {
 
+namespace bios
+{
+
 using AttrTableEntryHandler =
     std::function<void(const struct pldm_bios_attr_table_entry*)>;
 
 void traverseBIOSAttrTable(const bios::Table& BIOSAttrTable,
                            AttrTableEntryHandler handler);
 
-namespace bios
-{
-/** @brief Register handlers for command from the platform spec
- */
-void registerHandlers();
-
 namespace internal
 {
 
@@ -49,25 +46,41 @@
  */
 Response buildBIOSTables(const pldm_msg* request, size_t payloadLength,
                          const char* biosJsonDir, const char* biosTablePath);
-} // end namespace internal
+} // namespace internal
+
+class Handler : public CmdHandler
+{
+  public:
+    Handler()
+    {
+        handlers.emplace(PLDM_GET_DATE_TIME,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getDateTime(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_GET_BIOS_TABLE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getBIOSTable(request, payloadLength);
+                         });
+    }
+
+    /** @brief Handler for GetDateTime
+     *
+     *  @param[in] request - Request message payload
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getDateTime(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for GetBIOSTable
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payload_length - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
+};
 
 } // namespace bios
 
-/** @brief Handler for GetDateTime
- *
- *  @param[in] request - Request message payload
- *  @param[return] Response - PLDM Response message
- */
-Response getDateTime(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for GetBIOSTable
- *
- *  @param[in] request - Request message
- *  @param[in] payload_length - Request message payload length
- *  @param[return] Response - PLDM Response message
- */
-Response getBIOSTable(const pldm_msg* request, size_t payloadLength);
-
 namespace utils
 {
 
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index 770ef8c..8ad31d4 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -14,7 +14,6 @@
   'effecters.cpp',
   'utils.cpp',
   'platform.cpp',
-  '../registration.cpp'
 ]
 
 if get_option('oem-ibm').enabled()
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
index 538c49c..50237cf 100644
--- a/libpldmresponder/platform.cpp
+++ b/libpldmresponder/platform.cpp
@@ -1,30 +1,17 @@
 
 #include "platform.hpp"
 
-#include "registration.hpp"
-
 namespace pldm
 {
-
 namespace responder
 {
-
 namespace platform
 {
 
-void registerHandlers()
-{
-    registerHandler(PLDM_PLATFORM, PLDM_GET_PDR, std::move(getPDR));
-    registerHandler(PLDM_PLATFORM, PLDM_SET_STATE_EFFECTER_STATES,
-                    std::move(setStateEffecterStates));
-}
-
-} // namespace platform
-
 using namespace phosphor::logging;
 using namespace pldm::responder::effecter::dbus_mapping;
 
-Response getPDR(const pldm_msg* request, size_t payloadLength)
+Response Handler::getPDR(const pldm_msg* request, size_t payloadLength)
 {
     Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
@@ -92,7 +79,8 @@
     return response;
 }
 
-Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength)
+Response Handler::setStateEffecterStates(const pldm_msg* request,
+                                         size_t payloadLength)
 {
     Response response(
         sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES, 0);
@@ -129,5 +117,6 @@
     return response;
 }
 
+} // namespace platform
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
index ec168f4..be48950 100644
--- a/libpldmresponder/platform.hpp
+++ b/libpldmresponder/platform.hpp
@@ -2,6 +2,7 @@
 
 #include "config.h"
 
+#include "handler.hpp"
 #include "libpldmresponder/pdr.hpp"
 #include "libpldmresponder/utils.hpp"
 
@@ -14,254 +15,269 @@
 
 namespace pldm
 {
-
-using Response = std::vector<uint8_t>;
-
 namespace responder
 {
-
 namespace platform
 {
 
-/** @brief Register handlers for commands from the platform spec
- */
-void registerHandlers();
-
-} // namespace platform
-
-/** @brief Handler for GetPDR
- *
- *  @param[in] request - Request message payload
- *  @param[in] payloadLength - Request payload length
- *  @param[out] Response - Response message written here
- */
-Response getPDR(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Handler for setStateEffecterStates
- *
- *  @param[in] request - Request message
- *  @param[in] payloadLength - Request payload length
- *  @return Response - PLDM Response message
- */
-Response setStateEffecterStates(const pldm_msg* request, size_t payloadLength);
-
-/** @brief Function to set the effecter requested by pldm requester
- *  @param[in] dBusIntf - The interface object
- *  @param[in] effecterId - Effecter ID sent by the requester to act on
- *  @param[in] stateField - The state field data for each of the states, equal
- *        to composite effecter count in number
- *  @return - Success or failure in setting the states. Returns failure in terms
- *        of PLDM completion codes if atleast one state fails to be set
- */
-template <class DBusInterface>
-int setStateEffecterStatesHandler(
-    const DBusInterface& dBusIntf, effecter::Id effecterId,
-    const std::vector<set_effecter_state_field>& stateField)
+class Handler : public CmdHandler
 {
-    using namespace std::string_literals;
-    using DBusProperty = std::variant<std::string, bool>;
-    using StateSetId = uint16_t;
-    using StateSetNum = uint8_t;
-    using PropertyMap =
-        std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
-    static const PropertyMap stateNumToDbusProp = {
-        {PLDM_BOOT_PROGRESS_STATE,
-         {{PLDM_BOOT_NOT_ACTIVE,
-           "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-           "Standby"s},
-          {PLDM_BOOT_COMPLETED,
-           "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
-           "BootComplete"s}}},
-        {PLDM_SYSTEM_POWER_STATE,
-         {{PLDM_OFF_SOFT_GRACEFUL,
-           "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
-    using namespace phosphor::logging;
-    using namespace pldm::responder::pdr;
-    using namespace pldm::responder::effecter::dbus_mapping;
-
-    state_effecter_possible_states* states = nullptr;
-    pldm_state_effecter_pdr* pdr = nullptr;
-    uint8_t compEffecterCnt = stateField.size();
-    uint32_t recordHndl{};
-    Repo& pdrRepo = get(PDR_JSONS_DIR);
-    pdr::Entry pdrEntry{};
-
-    while (!pdr)
+  public:
+    Handler()
     {
-        pdrEntry = pdrRepo.at(recordHndl);
-        pldm_pdr_hdr* header = reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
-        if (header->type != PLDM_STATE_EFFECTER_PDR)
-        {
-            recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
-            if (recordHndl)
-            {
-                continue;
-            }
-            return PLDM_PLATFORM_INVALID_EFFECTER_ID;
-        }
-        pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
-        recordHndl = pdr->hdr.record_handle;
-        if (pdr->effecter_id == effecterId)
-        {
-            states = reinterpret_cast<state_effecter_possible_states*>(
-                pdr->possible_states);
-            if (compEffecterCnt > pdr->composite_effecter_count)
-            {
-                log<level::ERR>("The requester sent wrong composite effecter "
-                                "count for the effecter",
-                                entry("EFFECTER_ID=%d", effecterId),
-                                entry("COMP_EFF_CNT=%d", compEffecterCnt));
-                return PLDM_ERROR_INVALID_DATA;
-            }
-            break;
-        }
-        recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
-        if (!recordHndl)
-        {
-            return PLDM_PLATFORM_INVALID_EFFECTER_ID;
-        }
-        pdr = nullptr;
+        handlers.emplace(PLDM_GET_PDR,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getPDR(request, payloadLength);
+                         });
+        handlers.emplace(PLDM_SET_STATE_EFFECTER_STATES,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->setStateEffecterStates(request,
+                                                                 payloadLength);
+                         });
     }
 
-    std::map<StateSetId, std::function<int(const std::string& objPath,
-                                           const uint8_t currState)>>
-        effecterToDbusEntries = {
-            {PLDM_BOOT_PROGRESS_STATE,
-             [&](const std::string& objPath, const uint8_t currState) {
-                 auto stateSet =
-                     stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
-                 if (stateSet == stateNumToDbusProp.end())
-                 {
-                     log<level::ERR>("Couldn't find D-Bus mapping for "
-                                     "PLDM_BOOT_PROGRESS_STATE",
-                                     entry("EFFECTER_ID=%d", effecterId));
-                     return PLDM_ERROR;
-                 }
-                 auto iter = stateSet->second.find(
-                     stateField[currState].effecter_state);
-                 if (iter == stateSet->second.end())
-                 {
-                     log<level::ERR>(
-                         "Invalid state field passed or field not "
-                         "found for PLDM_BOOT_PROGRESS_STATE",
-                         entry("EFFECTER_ID=%d", effecterId),
-                         entry("FIELD=%d",
-                               stateField[currState].effecter_state),
-                         entry("OBJECT_PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR_INVALID_DATA;
-                 }
-                 auto dbusProp = "OperatingSystemState";
-                 std::variant<std::string> value{
-                     std::get<std::string>(iter->second)};
-                 auto dbusInterface =
-                     "xyz.openbmc_project.State.OperatingSystem.Status";
-                 try
-                 {
-                     dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
-                                              dbusInterface, value);
-                 }
-                 catch (const std::exception& e)
-                 {
-                     log<level::ERR>("Error setting property",
-                                     entry("ERROR=%s", e.what()),
-                                     entry("PROPERTY=%s", dbusProp),
-                                     entry("INTERFACE=%s", dbusInterface),
-                                     entry("PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR;
-                 }
-                 return PLDM_SUCCESS;
-             }},
-            {PLDM_SYSTEM_POWER_STATE,
-             [&](const std::string& objPath, const uint8_t currState) {
-                 auto stateSet =
-                     stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
-                 if (stateSet == stateNumToDbusProp.end())
-                 {
-                     log<level::ERR>("Couldn't find D-Bus mapping for "
-                                     "PLDM_SYSTEM_POWER_STATE",
-                                     entry("EFFECTER_ID=%d", effecterId));
-                     return PLDM_ERROR;
-                 }
-                 auto iter = stateSet->second.find(
-                     stateField[currState].effecter_state);
-                 if (iter == stateSet->second.end())
-                 {
-                     log<level::ERR>(
-                         "Invalid state field passed or field not "
-                         "found for PLDM_SYSTEM_POWER_STATE",
-                         entry("EFFECTER_ID=%d", effecterId),
-                         entry("FIELD=%d",
-                               stateField[currState].effecter_state),
-                         entry("OBJECT_PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR_INVALID_DATA;
-                 }
-                 auto dbusProp = "RequestedPowerTransition";
-                 std::variant<std::string> value{
-                     std::get<std::string>(iter->second)};
-                 auto dbusInterface = "xyz.openbmc_project.State.Chassis";
-                 try
-                 {
-                     dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
-                                              dbusInterface, value);
-                 }
-                 catch (const std::exception& e)
-                 {
-                     log<level::ERR>("Error setting property",
-                                     entry("ERROR=%s", e.what()),
-                                     entry("PROPERTY=%s", dbusProp),
-                                     entry("INTERFACE=%s", dbusInterface),
-                                     entry("PATH=%s", objPath.c_str()));
-                     return PLDM_ERROR;
-                 }
-                 return PLDM_SUCCESS;
-             }}};
+    /** @brief Handler for GetPDR
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payloadLength - Request payload length
+     *  @param[out] Response - Response message written here
+     */
+    Response getPDR(const pldm_msg* request, size_t payloadLength);
 
-    int rc = PLDM_SUCCESS;
-    auto paths = get(effecterId);
-    for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+    /** @brief Handler for setStateEffecterStates
+     *
+     *  @param[in] request - Request message
+     *  @param[in] payloadLength - Request payload length
+     *  @return Response - PLDM Response message
+     */
+    Response setStateEffecterStates(const pldm_msg* request,
+                                    size_t payloadLength);
+
+    /** @brief Function to set the effecter requested by pldm requester
+     *  @param[in] dBusIntf - The interface object
+     *  @param[in] effecterId - Effecter ID sent by the requester to act on
+     *  @param[in] stateField - The state field data for each of the states,
+     * equal to composite effecter count in number
+     *  @return - Success or failure in setting the states. Returns failure in
+     * terms of PLDM completion codes if atleast one state fails to be set
+     */
+    template <class DBusInterface>
+    int setStateEffecterStatesHandler(
+        const DBusInterface& dBusIntf, effecter::Id effecterId,
+        const std::vector<set_effecter_state_field>& stateField)
     {
-        std::vector<StateSetNum> allowed{};
-        // computation is based on table 79 from DSP0248 v1.1.1
-        uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
-        uint8_t bit =
-            stateField[currState].effecter_state - (8 * bitfieldIndex);
-        if (states->possible_states_size < bitfieldIndex ||
-            !(states->states[bitfieldIndex].byte & (1 << bit)))
+        using namespace std::string_literals;
+        using DBusProperty = std::variant<std::string, bool>;
+        using StateSetId = uint16_t;
+        using StateSetNum = uint8_t;
+        using PropertyMap =
+            std::map<StateSetId, std::map<StateSetNum, DBusProperty>>;
+        static const PropertyMap stateNumToDbusProp = {
+            {PLDM_BOOT_PROGRESS_STATE,
+             {{PLDM_BOOT_NOT_ACTIVE,
+               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
+               "Standby"s},
+              {PLDM_BOOT_COMPLETED,
+               "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus."
+               "BootComplete"s}}},
+            {PLDM_SYSTEM_POWER_STATE,
+             {{PLDM_OFF_SOFT_GRACEFUL,
+               "xyz.openbmc_project.State.Chassis.Transition.Off"s}}}};
+        using namespace phosphor::logging;
+        using namespace pldm::responder::pdr;
+        using namespace pldm::responder::effecter::dbus_mapping;
+
+        state_effecter_possible_states* states = nullptr;
+        pldm_state_effecter_pdr* pdr = nullptr;
+        uint8_t compEffecterCnt = stateField.size();
+        uint32_t recordHndl{};
+        Repo& pdrRepo = get(PDR_JSONS_DIR);
+        pdr::Entry pdrEntry{};
+
+        while (!pdr)
         {
-            log<level::ERR>(
-                "Invalid state set value", entry("EFFECTER_ID=%d", effecterId),
-                entry("VALUE=%d", stateField[currState].effecter_state),
-                entry("COMPOSITE_EFFECTER_ID=%d", currState),
-                entry("DBUS_PATH=%c", paths[currState].c_str()));
-            rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
-            break;
-        }
-        auto iter = effecterToDbusEntries.find(states->state_set_id);
-        if (iter == effecterToDbusEntries.end())
-        {
-            uint16_t setId = states->state_set_id;
-            log<level::ERR>(
-                "Did not find the state set for the state effecter pdr  ",
-                entry("STATE=%d", setId), entry("EFFECTER_ID=%d", effecterId));
-            rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
-            break;
-        }
-        if (stateField[currState].set_request == PLDM_REQUEST_SET)
-        {
-            rc = iter->second(paths[currState], currState);
-            if (rc != PLDM_SUCCESS)
+            pdrEntry = pdrRepo.at(recordHndl);
+            pldm_pdr_hdr* header =
+                reinterpret_cast<pldm_pdr_hdr*>(pdrEntry.data());
+            if (header->type != PLDM_STATE_EFFECTER_PDR)
             {
+                recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
+                if (recordHndl)
+                {
+                    continue;
+                }
+                return PLDM_PLATFORM_INVALID_EFFECTER_ID;
+            }
+            pdr = reinterpret_cast<pldm_state_effecter_pdr*>(pdrEntry.data());
+            recordHndl = pdr->hdr.record_handle;
+            if (pdr->effecter_id == effecterId)
+            {
+                states = reinterpret_cast<state_effecter_possible_states*>(
+                    pdr->possible_states);
+                if (compEffecterCnt > pdr->composite_effecter_count)
+                {
+                    log<level::ERR>(
+                        "The requester sent wrong composite effecter "
+                        "count for the effecter",
+                        entry("EFFECTER_ID=%d", effecterId),
+                        entry("COMP_EFF_CNT=%d", compEffecterCnt));
+                    return PLDM_ERROR_INVALID_DATA;
+                }
                 break;
             }
+            recordHndl = pdrRepo.getNextRecordHandle(recordHndl);
+            if (!recordHndl)
+            {
+                return PLDM_PLATFORM_INVALID_EFFECTER_ID;
+            }
+            pdr = nullptr;
         }
-        uint8_t* nextState =
-            reinterpret_cast<uint8_t*>(states) +
-            sizeof(state_effecter_possible_states) - sizeof(states->states) +
-            (states->possible_states_size * sizeof(states->states));
-        states = reinterpret_cast<state_effecter_possible_states*>(nextState);
-    }
-    return rc;
-}
 
+        std::map<StateSetId, std::function<int(const std::string& objPath,
+                                               const uint8_t currState)>>
+            effecterToDbusEntries = {
+                {PLDM_BOOT_PROGRESS_STATE,
+                 [&](const std::string& objPath, const uint8_t currState) {
+                     auto stateSet =
+                         stateNumToDbusProp.find(PLDM_BOOT_PROGRESS_STATE);
+                     if (stateSet == stateNumToDbusProp.end())
+                     {
+                         log<level::ERR>("Couldn't find D-Bus mapping for "
+                                         "PLDM_BOOT_PROGRESS_STATE",
+                                         entry("EFFECTER_ID=%d", effecterId));
+                         return PLDM_ERROR;
+                     }
+                     auto iter = stateSet->second.find(
+                         stateField[currState].effecter_state);
+                     if (iter == stateSet->second.end())
+                     {
+                         log<level::ERR>(
+                             "Invalid state field passed or field not "
+                             "found for PLDM_BOOT_PROGRESS_STATE",
+                             entry("EFFECTER_ID=%d", effecterId),
+                             entry("FIELD=%d",
+                                   stateField[currState].effecter_state),
+                             entry("OBJECT_PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR_INVALID_DATA;
+                     }
+                     auto dbusProp = "OperatingSystemState";
+                     std::variant<std::string> value{
+                         std::get<std::string>(iter->second)};
+                     auto dbusInterface =
+                         "xyz.openbmc_project.State.OperatingSystem.Status";
+                     try
+                     {
+                         dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
+                                                  dbusInterface, value);
+                     }
+                     catch (const std::exception& e)
+                     {
+                         log<level::ERR>("Error setting property",
+                                         entry("ERROR=%s", e.what()),
+                                         entry("PROPERTY=%s", dbusProp),
+                                         entry("INTERFACE=%s", dbusInterface),
+                                         entry("PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR;
+                     }
+                     return PLDM_SUCCESS;
+                 }},
+                {PLDM_SYSTEM_POWER_STATE,
+                 [&](const std::string& objPath, const uint8_t currState) {
+                     auto stateSet =
+                         stateNumToDbusProp.find(PLDM_SYSTEM_POWER_STATE);
+                     if (stateSet == stateNumToDbusProp.end())
+                     {
+                         log<level::ERR>("Couldn't find D-Bus mapping for "
+                                         "PLDM_SYSTEM_POWER_STATE",
+                                         entry("EFFECTER_ID=%d", effecterId));
+                         return PLDM_ERROR;
+                     }
+                     auto iter = stateSet->second.find(
+                         stateField[currState].effecter_state);
+                     if (iter == stateSet->second.end())
+                     {
+                         log<level::ERR>(
+                             "Invalid state field passed or field not "
+                             "found for PLDM_SYSTEM_POWER_STATE",
+                             entry("EFFECTER_ID=%d", effecterId),
+                             entry("FIELD=%d",
+                                   stateField[currState].effecter_state),
+                             entry("OBJECT_PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR_INVALID_DATA;
+                     }
+                     auto dbusProp = "RequestedPowerTransition";
+                     std::variant<std::string> value{
+                         std::get<std::string>(iter->second)};
+                     auto dbusInterface = "xyz.openbmc_project.State.Chassis";
+                     try
+                     {
+                         dBusIntf.setDbusProperty(objPath.c_str(), dbusProp,
+                                                  dbusInterface, value);
+                     }
+                     catch (const std::exception& e)
+                     {
+                         log<level::ERR>("Error setting property",
+                                         entry("ERROR=%s", e.what()),
+                                         entry("PROPERTY=%s", dbusProp),
+                                         entry("INTERFACE=%s", dbusInterface),
+                                         entry("PATH=%s", objPath.c_str()));
+                         return PLDM_ERROR;
+                     }
+                     return PLDM_SUCCESS;
+                 }}};
+
+        int rc = PLDM_SUCCESS;
+        auto paths = get(effecterId);
+        for (uint8_t currState = 0; currState < compEffecterCnt; ++currState)
+        {
+            std::vector<StateSetNum> allowed{};
+            // computation is based on table 79 from DSP0248 v1.1.1
+            uint8_t bitfieldIndex = stateField[currState].effecter_state / 8;
+            uint8_t bit =
+                stateField[currState].effecter_state - (8 * bitfieldIndex);
+            if (states->possible_states_size < bitfieldIndex ||
+                !(states->states[bitfieldIndex].byte & (1 << bit)))
+            {
+                log<level::ERR>(
+                    "Invalid state set value",
+                    entry("EFFECTER_ID=%d", effecterId),
+                    entry("VALUE=%d", stateField[currState].effecter_state),
+                    entry("COMPOSITE_EFFECTER_ID=%d", currState),
+                    entry("DBUS_PATH=%c", paths[currState].c_str()));
+                rc = PLDM_PLATFORM_SET_EFFECTER_UNSUPPORTED_SENSORSTATE;
+                break;
+            }
+            auto iter = effecterToDbusEntries.find(states->state_set_id);
+            if (iter == effecterToDbusEntries.end())
+            {
+                uint16_t setId = states->state_set_id;
+                log<level::ERR>(
+                    "Did not find the state set for the state effecter pdr  ",
+                    entry("STATE=%d", setId),
+                    entry("EFFECTER_ID=%d", effecterId));
+                rc = PLDM_PLATFORM_INVALID_STATE_VALUE;
+                break;
+            }
+            if (stateField[currState].set_request == PLDM_REQUEST_SET)
+            {
+                rc = iter->second(paths[currState], currState);
+                if (rc != PLDM_SUCCESS)
+                {
+                    break;
+                }
+            }
+            uint8_t* nextState =
+                reinterpret_cast<uint8_t*>(states) +
+                sizeof(state_effecter_possible_states) -
+                sizeof(states->states) +
+                (states->possible_states_size * sizeof(states->states));
+            states =
+                reinterpret_cast<state_effecter_possible_states*>(nextState);
+        }
+        return rc;
+    }
+};
+
+} // namespace platform
 } // namespace responder
 } // namespace pldm