Implement the PLDM Daemon.

The pldm daemon is a PLDM responder.

PLDM messages received by the PLDM daemon from the MCTP daemon are routed
to the respective command handler to create a response. This response will
be sent back by the PLDM daemon to the requester.

PLDM daemon and MCTP daemon interact with each other using UNIX domain sockets,
as documented in https://github.com/openbmc/docs/blob/master/designs/mctp.md

Implemented a way for the PLDM responder library to register handlers for
specific PLDM commands. This is as per the registration scheme
documented in README.md.

Support for enabling verbosity in the PLDM Daemon (tracing the receive and
response message packets) are conditionally compiled.You would need to
provide the --enable-verbose flag to configure to enable it.

We discard response messages received currently.

Fixed Handler function signature for bios and file_io types.

Tested :

Updated system with the Daemon and did a 'obmcutil poweron'
The Daemon was build with the verbose enabled configuration
Could boot a hypervisor that sends PLDM commands.

Below is the transactions recorded in the journal
Jun 25 13:35:27 witherspoon-128 pldmd[1980]: Received Msg
Jun 25 13:35:27 witherspoon-128 pldmd[1980]: Buffer Data: 09 01 81 3f 06 00
 00 00 00 00 00 00 00 00 00 08 00 00 00 01 00 00 00 00 00
Jun 25 13:35:27 witherspoon-128 pldmd[1980]: Sending Msg
Jun 25 13:35:27 witherspoon-128 pldmd[1980]: Buffer Data: 09 01 00 3f 06 80
 00 00 00 00

Change-Id: I22cfd85103bce167239219fbcc59c25b09528211
Signed-off-by: Jinu Joy Thomas <jinu.joy.thomas@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 0df10bb..db7bedf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -28,3 +28,23 @@
 endif
 
 SUBDIRS = libpldm libpldmresponder test
+
+sbin_PROGRAMS = pldmd
+pldmd_SOURCES = \
+    pldmd.cpp \
+    registration.cpp
+pldmd_LDADD = \
+        libpldmresponder/libpldmresponder.la \
+        libpldm/libpldm.la \
+	$(SDBUSPLUS_LIBS)
+pldmd_CXXFLAGS = -I$(top_builddir)/libpldm \
+	$(PHOSPHOR_LOGGING_CFLAGS) \
+	$(SDBUSPLUS_CFLAGS)
+
+if OEM_IBM
+pldmd_CXXFLAGS += \
+        -I$(top_builddir)/oem/ibm/
+endif
+
+ACLOCAL_AMFLAGS = -I m4
+
diff --git a/configure.ac b/configure.ac
index b1e7fc1..3ffeca4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,6 +6,7 @@
 AC_CONFIG_HEADERS([config.h])
 AM_INIT_AUTOMAKE([subdir-objects -Wall -Werror foreign dist-xz])
 AM_SILENT_RULES([yes])
+AC_CONFIG_MACRO_DIRS([m4])
 
 # Make sure the default CFLAGS of `-O2 -g` don't override CODE_COVERAGE_CFLAGS
 # It is important that this comes before AC_PROG_C{C,XX}, as we are attempting
@@ -73,8 +74,20 @@
 	Enable PLDM OEM command support For IBM.
 ]))
 AM_CONDITIONAL([OEM_IBM], [test "x$enable_oem_ibm" = "xyes"])
-AS_IF([test "x$oem-ibm" == "xtrue"], [
+AS_IF([test "x$enable_oem_ibm" == "xyes"], [
     AX_APPEND_COMPILE_FLAGS([-DOEM_IBM], [CXXFLAGS])
+    AX_APPEND_COMPILE_FLAGS([-DOEM_IBM], [CFLAGS])
+])
+
+# Setup verbose option
+AC_ARG_ENABLE([verbose], AS_HELP_STRING([
+	--enable-verbose
+	], [
+	Enable verbosity for PLDM Daemon.
+]))
+AS_IF([test "x$enable_verbose" == "xyes"], [
+    AX_APPEND_COMPILE_FLAGS([-DVERBOSE], [CXXFLAGS])
+    AX_APPEND_COMPILE_FLAGS([-DVERBOSE], [CFLAGS])
 ])
 
 # Create configured output
diff --git a/libpldm/base.h b/libpldm/base.h
index ca367ef..6a044ad 100644
--- a/libpldm/base.h
+++ b/libpldm/base.h
@@ -17,6 +17,7 @@
 	PLDM_BASE = 0x00,
 	PLDM_PLATFORM = 0x02,
 	PLDM_BIOS = 0x03,
+	PLDM_OEM = 0x3F,
 };
 
 /** @brief PLDM Commands
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index 48ccd54..682b1a7 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -1,6 +1,7 @@
 #include "libpldm/base.h"
 
 #include "base.hpp"
+#include "registration.hpp"
 
 #include <array>
 #include <cstring>
@@ -24,6 +25,20 @@
     {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}},
 };
 
+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));
+}
+
+} // namespace base
+
 Response getPLDMTypes(const pldm_msg* request, size_t payloadLength)
 {
     // DSP0240 has this as a bitfield8[N], where N = 0 to 7
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp
index 466559a..c4afa18 100644
--- a/libpldmresponder/base.hpp
+++ b/libpldmresponder/base.hpp
@@ -16,6 +16,13 @@
 namespace responder
 {
 
+namespace base
+{
+/** @brief Register handlers for command from the base spec
+ */
+void registerHandlers();
+} // namespace base
+
 /** @brief Handler for getPLDMTypes
  *
  *  @param[in] request - Request message payload
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 11c8251..51d5415 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -1,6 +1,7 @@
 #include "bios.hpp"
 
 #include "libpldmresponder/utils.hpp"
+#include "registration.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
 #include <array>
@@ -25,6 +26,16 @@
 namespace responder
 {
 
+namespace bios
+{
+
+void registerHandlers()
+{
+    registerHandler(PLDM_BIOS, PLDM_GET_DATE_TIME, std::move(getDateTime));
+}
+
+} // namespace bios
+
 namespace utils
 {
 
@@ -47,7 +58,7 @@
 
 } // namespace utils
 
-Response getDateTime(const pldm_msg* request)
+Response getDateTime(const pldm_msg* request, size_t payloadLength)
 {
     uint8_t seconds = 0;
     uint8_t minutes = 0;
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 915a367..2befe24 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -14,12 +14,19 @@
 namespace responder
 {
 
+namespace bios
+{
+/** @brief Register handlers for command from the platform spec
+ */
+void registerHandlers();
+} // namespace bios
+
 /** @brief Handler for GetDateTime
  *
  *  @param[in] request - Request message payload
  *  @param[return] Response - PLDM Response message
  */
-Response getDateTime(const pldm_msg* request);
+Response getDateTime(const pldm_msg* request, size_t payloadLength);
 
 namespace utils
 {
diff --git a/libpldmresponder/utils.hpp b/libpldmresponder/utils.hpp
index d76b716..39c7ed6 100644
--- a/libpldmresponder/utils.hpp
+++ b/libpldmresponder/utils.hpp
@@ -2,6 +2,7 @@
 
 #include <stdint.h>
 #include <systemd/sd-bus.h>
+#include <unistd.h>
 
 #include <sdbusplus/server.hpp>
 #include <string>
@@ -10,6 +11,42 @@
 {
 namespace responder
 {
+namespace utils
+{
+
+/** @struct CustomFD
+ *
+ *  RAII wrapper for file descriptor.
+ */
+struct CustomFD
+{
+    CustomFD(const CustomFD&) = delete;
+    CustomFD& operator=(const CustomFD&) = delete;
+    CustomFD(CustomFD&&) = delete;
+    CustomFD& operator=(CustomFD&&) = delete;
+
+    CustomFD(int fd) : fd(fd)
+    {
+    }
+
+    ~CustomFD()
+    {
+        if (fd >= 0)
+        {
+            close(fd);
+        }
+    }
+
+    int operator()() const
+    {
+        return fd;
+    }
+
+  private:
+    int fd = -1;
+};
+
+} // namespace utils
 
 /**
  *  @brief Get the DBUS Service name for the input dbus path
diff --git a/oem/ibm/libpldm/file_io.c b/oem/ibm/libpldm/file_io.c
index ca33cef..2fa3034 100644
--- a/oem/ibm/libpldm/file_io.c
+++ b/oem/ibm/libpldm/file_io.c
@@ -37,7 +37,7 @@
 
 	header.msg_type = PLDM_RESPONSE;
 	header.instance = instance_id;
-	header.pldm_type = PLDM_IBM_OEM_TYPE;
+	header.pldm_type = PLDM_OEM;
 	header.command = command;
 
 	if ((rc = pack_pldm_header(&header, &(msg->hdr))) > PLDM_SUCCESS) {
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index 345b363..79a8035 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -10,8 +10,6 @@
 
 #include "base.h"
 
-#define PLDM_IBM_OEM_TYPE 0x3F
-
 /** @brief PLDM Commands in IBM OEM type
  */
 enum pldm_fileio_commands {
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 9cf093c..2fec526 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -1,5 +1,8 @@
 #include "file_io.hpp"
 
+#include "libpldmresponder/utils.hpp"
+#include "registration.hpp"
+
 #include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -18,6 +21,19 @@
 namespace responder
 {
 
+namespace oem_ibm
+{
+
+void registerHandlers()
+{
+    registerHandler(PLDM_OEM, PLDM_READ_FILE_INTO_MEMORY,
+                    std::move(readFileIntoMemory));
+    registerHandler(PLDM_OEM, PLDM_WRITE_FILE_FROM_MEMORY,
+                    std::move(writeFileFromMemory));
+}
+
+} // namespace oem_ibm
+
 namespace fs = std::filesystem;
 using namespace phosphor::logging;
 
@@ -126,7 +142,7 @@
 
 } // namespace dma
 
-Response readFileIntoMemory(const uint8_t* request, size_t payloadLength)
+Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -144,8 +160,8 @@
         return response;
     }
 
-    decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
-                              &length, &address);
+    decode_rw_file_memory_req(request->payload, payloadLength, &fileHandle,
+                              &offset, &length, &address);
 
     if (!fs::exists(path))
     {
@@ -185,7 +201,7 @@
                             length, address, true);
 }
 
-Response writeFileFromMemory(const uint8_t* request, size_t payloadLength)
+Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength)
 {
     uint32_t fileHandle = 0;
     uint32_t offset = 0;
@@ -203,8 +219,8 @@
         return response;
     }
 
-    decode_rw_file_memory_req(request, payloadLength, &fileHandle, &offset,
-                              &length, &address);
+    decode_rw_file_memory_req(request->payload, payloadLength, &fileHandle,
+                              &offset, &length, &address);
 
     if (length % dma::minSize)
     {
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index 17a6fe2..9f01782 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -14,44 +14,14 @@
 namespace responder
 {
 
-using Response = std::vector<uint8_t>;
-
-namespace utils
+namespace oem_ibm
 {
-
-/** @struct CustomFD
- *
- *  RAII wrapper for file descriptor.
+/** @brief Register handlers for command from the platform spec
  */
-struct CustomFD
-{
-    CustomFD(const CustomFD&) = delete;
-    CustomFD& operator=(const CustomFD&) = delete;
-    CustomFD(CustomFD&&) = delete;
-    CustomFD& operator=(CustomFD&&) = delete;
+void registerHandlers();
+} // namespace oem_ibm
 
-    CustomFD(int fd) : fd(fd)
-    {
-    }
-
-    ~CustomFD()
-    {
-        if (fd >= 0)
-        {
-            close(fd);
-        }
-    }
-
-    int operator()() const
-    {
-        return fd;
-    }
-
-  private:
-    int fd = -1;
-};
-
-} // namespace utils
+using Response = std::vector<uint8_t>;
 
 namespace dma
 {
@@ -150,19 +120,19 @@
 /** @brief Handler for readFileIntoMemory command
  *
  *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message payload
+ *  @param[in] payloadLength - length of the message
  *
  *  @return PLDM response message
  */
-Response readFileIntoMemory(const uint8_t* request, size_t payloadLength);
+Response readFileIntoMemory(const pldm_msg* request, size_t payloadLength);
 
 /** @brief Handler for writeFileIntoMemory command
  *
  *  @param[in] request - pointer to PLDM request payload
- *  @param[in] payloadLength - length of the message payload
+ *  @param[in] payloadLength - length of the message
  *
  *  @return PLDM response message
  */
-Response writeFileFromMemory(const uint8_t* request, size_t payloadLength);
+Response writeFileFromMemory(const pldm_msg* request, size_t payloadLength);
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/test/libpldm_fileio_test.cpp b/oem/ibm/test/libpldm_fileio_test.cpp
index 2a5dce1..e9fa325 100644
--- a/oem/ibm/test/libpldm_fileio_test.cpp
+++ b/oem/ibm/test/libpldm_fileio_test.cpp
@@ -81,7 +81,7 @@
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
     ASSERT_EQ(response->hdr.instance_id, 0);
-    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.type, PLDM_OEM);
     ASSERT_EQ(response->hdr.command, PLDM_READ_FILE_INTO_MEMORY);
     ASSERT_EQ(response->payload[0], PLDM_SUCCESS);
     ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
@@ -94,7 +94,7 @@
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
     ASSERT_EQ(response->hdr.instance_id, 0);
-    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.type, PLDM_OEM);
     ASSERT_EQ(response->hdr.command, PLDM_WRITE_FILE_FROM_MEMORY);
     ASSERT_EQ(response->payload[0], PLDM_SUCCESS);
     ASSERT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
@@ -115,7 +115,7 @@
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
     ASSERT_EQ(response->hdr.instance_id, 0);
-    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.type, PLDM_OEM);
     ASSERT_EQ(response->hdr.command, PLDM_READ_FILE_INTO_MEMORY);
     ASSERT_EQ(response->payload[0], PLDM_ERROR);
 
@@ -126,7 +126,7 @@
     ASSERT_EQ(rc, PLDM_SUCCESS);
     ASSERT_EQ(response->hdr.request, PLDM_RESPONSE);
     ASSERT_EQ(response->hdr.instance_id, 0);
-    ASSERT_EQ(response->hdr.type, PLDM_IBM_OEM_TYPE);
+    ASSERT_EQ(response->hdr.type, PLDM_OEM);
     ASSERT_EQ(response->hdr.command, PLDM_WRITE_FILE_FROM_MEMORY);
     ASSERT_EQ(response->payload[0], PLDM_ERROR);
 }
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index 060b0ed..1338713 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -146,17 +146,19 @@
     uint32_t length = 10;
     uint64_t address = 0;
 
-    std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
-    memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
-    memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
-    memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+    memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+    memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
            sizeof(length));
-    memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+    memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
                sizeof(length),
            &address, sizeof(address));
 
     // Pass invalid payload length
-    auto response = readFileIntoMemory(requestMsg.data(), 0);
+    auto response = readFileIntoMemory(request, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 }
@@ -168,22 +170,25 @@
     uint32_t length = 10;
     uint64_t address = 0;
 
-    std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
-    memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
-    memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
-    memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
+    memcpy(request->payload, &fileHandle, sizeof(fileHandle));
+    memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
+    memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
            sizeof(length));
-    memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
+    memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
                sizeof(length),
            &address, sizeof(address));
 
     // Pass invalid payload length
-    auto response = writeFileFromMemory(requestMsg.data(), 0);
+    auto response = writeFileFromMemory(request, 0);
     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
 
     // The length field is not a multiple of DMA minsize
-    response = writeFileFromMemory(requestMsg.data(), requestMsg.size());
+    response = writeFileFromMemory(request, requestPayloadLength);
     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
 }
diff --git a/pldmd.cpp b/pldmd.cpp
new file mode 100644
index 0000000..e02bb57
--- /dev/null
+++ b/pldmd.cpp
@@ -0,0 +1,217 @@
+#include "libpldmresponder/base.hpp"
+#include "libpldmresponder/bios.hpp"
+#include "libpldmresponder/utils.hpp"
+#include "registration.hpp"
+
+#include <err.h>
+#include <poll.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstring>
+#include <iomanip>
+#include <iterator>
+#include <phosphor-logging/log.hpp>
+#include <sstream>
+#include <vector>
+
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+
+#ifdef OEM_IBM
+#include "libpldmresponder/file_io.hpp"
+#endif
+
+constexpr uint8_t MCTP_MSG_TYPE_PLDM = 1;
+
+using namespace phosphor::logging;
+using namespace pldm;
+
+static Response processRxMsg(const std::vector<uint8_t>& requestMsg)
+{
+
+    Response response;
+    uint8_t eid = requestMsg[0];
+    uint8_t type = requestMsg[1];
+    pldm_header_info hdrFields{};
+    auto hdr = reinterpret_cast<const pldm_msg_hdr*>(
+        requestMsg.data() + sizeof(eid) + sizeof(type));
+    if (PLDM_SUCCESS != unpack_pldm_header(hdr, &hdrFields))
+    {
+        log<level::ERR>("Empty PLDM request header");
+    }
+    else if (PLDM_RESPONSE != hdrFields.msg_type)
+    {
+        auto request = reinterpret_cast<const pldm_msg*>(hdr);
+        size_t requestLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
+                            sizeof(eid) - sizeof(type);
+        response = pldm::responder::invokeHandler(
+            hdrFields.pldm_type, hdrFields.command, request, requestLen);
+        if (response.empty())
+        {
+            uint8_t completion_code = PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+            response.resize(sizeof(pldm_msg_hdr));
+            auto responseHdr = reinterpret_cast<pldm_msg_hdr*>(response.data());
+            pldm_header_info header{};
+            header.msg_type = PLDM_RESPONSE;
+            header.instance = hdrFields.instance;
+            header.pldm_type = hdrFields.pldm_type;
+            header.command = hdrFields.command;
+            auto result = pack_pldm_header(&header, responseHdr);
+            if (PLDM_SUCCESS != result)
+            {
+                log<level::ERR>("Failed adding response header");
+            }
+            response.insert(response.end(), completion_code);
+        }
+        response.insert(response.begin(), type);
+        response.insert(response.begin(), eid);
+    }
+    return response;
+}
+
+void printBuffer(const std::vector<uint8_t>& buffer)
+{
+    std::ostringstream tempStream;
+    tempStream << "Buffer Data: ";
+    if (!buffer.empty())
+    {
+        for (int byte : buffer)
+        {
+            tempStream << std::setfill('0') << std::setw(2) << std::hex << byte
+                       << " ";
+        }
+    }
+    log<level::INFO>(tempStream.str().c_str());
+}
+
+int main(int argc, char** argv)
+{
+
+    pldm::responder::base::registerHandlers();
+    pldm::responder::bios::registerHandlers();
+
+#ifdef OEM_IBM
+    pldm::responder::oem_ibm::registerHandlers();
+#endif
+
+    /* Create local socket. */
+    int returnCode = 0;
+    int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
+    if (-1 == sockfd)
+    {
+        returnCode = -errno;
+        log<level::ERR>("Failed to create the socket",
+                        entry("RC=%d", returnCode));
+        exit(EXIT_FAILURE);
+    }
+
+    responder::utils::CustomFD socketFd(sockfd);
+
+    struct sockaddr_un addr
+    {
+    };
+    addr.sun_family = AF_UNIX;
+    const char path[] = "\0mctp-mux";
+    memcpy(addr.sun_path, path, sizeof(path) - 1);
+    int result = connect(socketFd(), reinterpret_cast<struct sockaddr*>(&addr),
+                         sizeof(path) + sizeof(addr.sun_family) - 1);
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        log<level::ERR>("Failed to connect to the socket",
+                        entry("RC=%d", returnCode));
+        exit(EXIT_FAILURE);
+    }
+
+    result = write(socketFd(), &MCTP_MSG_TYPE_PLDM, sizeof(MCTP_MSG_TYPE_PLDM));
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        log<level::ERR>("Failed to send message type as pldm to mctp",
+                        entry("RC=%d", returnCode));
+        exit(EXIT_FAILURE);
+    }
+
+    do
+    {
+        ssize_t peekedLength =
+            recv(socketFd(), nullptr, 0, MSG_PEEK | MSG_TRUNC);
+        if (0 == peekedLength)
+        {
+            log<level::ERR>("Socket has been closed");
+            exit(EXIT_FAILURE);
+        }
+        else if (peekedLength <= -1)
+        {
+            returnCode = -errno;
+            log<level::ERR>("recv system call failed",
+                            entry("RC=%d", returnCode));
+            exit(EXIT_FAILURE);
+        }
+        else
+        {
+            std::vector<uint8_t> requestMsg(peekedLength);
+            auto recvDataLength = recv(
+                sockfd, static_cast<void*>(requestMsg.data()), peekedLength, 0);
+            if (recvDataLength == peekedLength)
+            {
+#ifdef VERBOSE
+                log<level::INFO>("Received Msg ",
+                                 entry("LENGTH=%zu", recvDataLength),
+                                 entry("EID=0x%02x", requestMsg[0]),
+                                 entry("TYPE=0x%02x", requestMsg[1]));
+                printBuffer(requestMsg);
+#endif
+                if (MCTP_MSG_TYPE_PLDM != requestMsg[1])
+                {
+                    // Skip this message and continue.
+                    log<level::ERR>("Encountered Non-PLDM type message",
+                                    entry("TYPE=0x%02x", requestMsg[1]));
+                }
+                else
+                {
+                    // process message and send response
+                    auto response = processRxMsg(requestMsg);
+                    if (!response.empty())
+                    {
+#ifdef VERBOSE
+                        log<level::INFO>("Sending Msg ");
+                        printBuffer(response);
+#endif
+                        result = sendto(socketFd(), response.data(),
+                                        response.size(), 0, nullptr, 0);
+                        if (-1 == result)
+                        {
+                            returnCode = -errno;
+                            log<level::ERR>("sendto system call failed",
+                                            entry("RC=%d", returnCode));
+                            exit(EXIT_FAILURE);
+                        }
+                    }
+                }
+            }
+            else
+            {
+                log<level::ERR>("Failure to read peeked length packet",
+                                entry("PEEKED_LENGTH=%zu", peekedLength),
+                                entry("READ_LENGTH=%zu", recvDataLength));
+                exit(EXIT_FAILURE);
+            }
+        }
+    } while (true);
+
+    result = shutdown(sockfd, SHUT_RDWR);
+    if (-1 == result)
+    {
+        returnCode = -errno;
+        log<level::ERR>("Failed to shutdown the socket",
+                        entry("RC=%d", returnCode));
+        exit(EXIT_FAILURE);
+    }
+    exit(EXIT_FAILURE);
+}
diff --git a/registration.cpp b/registration.cpp
new file mode 100644
index 0000000..7fb7957
--- /dev/null
+++ b/registration.cpp
@@ -0,0 +1,63 @@
+#include "registration.hpp"
+
+#include <map>
+#include <phosphor-logging/log.hpp>
+
+using namespace phosphor::logging;
+
+namespace pldm
+{
+
+namespace responder
+{
+
+namespace internal
+{
+using Command = uint8_t;
+using CommandHandler = std::map<Command, Handler>;
+using Type = uint8_t;
+std::map<Type, CommandHandler> typeHandlers;
+} // namespace internal
+
+void registerHandler(uint8_t pldmType, uint8_t pldmCommand, Handler&& handler)
+{
+    using namespace internal;
+    CommandHandler& ch = typeHandlers[pldmType];
+    ch.emplace(pldmCommand, std::move(handler));
+}
+
+Response invokeHandler(uint8_t pldmType, uint8_t pldmCommand,
+                       const pldm_msg* request, size_t payloadLength)
+{
+    using namespace internal;
+    Response response;
+    if (!(typeHandlers.end() == typeHandlers.find(pldmType)))
+    {
+        if (!((typeHandlers.at(pldmType)).end() ==
+              (typeHandlers.at(pldmType)).find(pldmCommand)))
+        {
+            response = typeHandlers.at(pldmType).at(pldmCommand)(request,
+                                                                 payloadLength);
+            if (response.empty())
+            {
+                log<level::ERR>("Encountered invalid response");
+            }
+        }
+        else
+        {
+            log<level::ERR>("Unsupported PLDM command",
+                            entry("TYPE=0x%02x", pldmType),
+                            entry("COMMAND=0x%02x", pldmCommand));
+        }
+    }
+    else
+    {
+        log<level::ERR>("Unsupported PLDM TYPE",
+                        entry("TYPE=0x%02x", pldmType));
+    }
+
+    return response;
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/registration.hpp b/registration.hpp
new file mode 100644
index 0000000..0bd496f
--- /dev/null
+++ b/registration.hpp
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <functional>
+#include <map>
+
+#include "libpldm/base.h"
+
+namespace pldm
+{
+
+using Response = std::vector<uint8_t>;
+
+namespace responder
+{
+
+using Handler =
+    std::function<Response(const pldm_msg* request, size_t payloadLength)>;
+
+/** @brief Register a handler for input PLDM command
+ *
+ *  @param[in] pldmType - PLDM type code
+ *  @param[in] pldmCommand - PLDM command code
+ *  @param[in] handler - PLDM command handler
+ */
+void registerHandler(uint8_t pldmType, uint8_t pldmCommand, Handler&& handler);
+
+/** @brief Invoke a handler for input PLDM command
+ *
+ *  @param[in] pldmType - PLDM type code
+ *  @param[in] pldmCommand - PLDM command code
+ *  @param[in] request - PLDM request message
+ *  @param[in] payloadLength - PLDM request message length
+ *  @return PLDM Response message
+ */
+Response invokeHandler(uint8_t pldmType, uint8_t pldmCommand,
+                       const pldm_msg* request, size_t payloadLength);
+
+} // namespace responder
+} // namespace pldm
diff --git a/test/Makefile.am b/test/Makefile.am
index 42663a1..d580416 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -23,17 +23,20 @@
 
 test_cxxflags = \
 	$(PTHREAD_CFLAGS) \
+	$(PHOSPHOR_LOGGING_CFLAGS) \
+	$(SDBUSPLUS_CFLAGS) \
 	$(CODE_COVERAGE_CXXFLAGS)
 
 test_ldflags = \
 	-lgtest_main \
 	-lgtest \
 	$(PTHREAD_LIBS) \
+	$(SDBUSPLUS_LIBS) \
+	$(PHOSPHOR_LOGGING_LIBS) \
 	$(OESDK_TESTCASE_FLAGS)
 
 if OEM_IBM
 test_ldflags += \
-	$(SDBUSPLUS_LIBS) \
 	-lgmock \
 	-lstdc++fs
 endif
@@ -70,6 +73,7 @@
 	$(test_ldflags) \
 	$(SDBUSPLUS_LIBS)
 libpldmresponder_bios_test_LDADD = \
+	$(top_builddir)/pldmd-registration.o \
 	$(top_builddir)/libpldmresponder/libpldmresponder_la-bios.o \
 	$(top_builddir)/libpldmresponder/libpldmresponder_la-utils.o \
 	$(top_builddir)/libpldm/libpldm_la-base.o  \
@@ -83,6 +87,7 @@
 libpldmresponder_base_test_CXXFLAGS = $(test_cxxflags)
 libpldmresponder_base_test_LDFLAGS = $(test_ldflags)
 libpldmresponder_base_test_LDADD = \
+	$(top_builddir)/pldmd-registration.o \
 	$(top_builddir)/libpldm/libpldm_la-base.o \
 	$(top_builddir)/libpldmresponder/libpldmresponder_la-base.o \
 	$(CODE_COVERAGE_LIBS)
@@ -105,6 +110,7 @@
 libpldmoemresponder_fileio_test_CXXFLAGS = $(test_cxxflags)
 libpldmoemresponder_fileio_test_LDFLAGS = $(test_ldflags)
 libpldmoemresponder_fileio_test_LDADD = \
+        $(top_builddir)/pldmd-registration.o \
 	$(top_builddir)/libpldm/libpldm_la-base.o \
 	$(top_builddir)/oem/ibm/libpldm/libpldm_la-file_io.o \
 	$(top_builddir)/oem/ibm/libpldmresponder/libpldmresponder_la-file_io.o