pldm: Convert to using libpldm transport APIs

A significant amount of logic can be removed by exploiting the new
transport APIs provided by libpldm. Switch the pldm repository over to
use these by introducing an RAII wrapper for the APIs. The current
stance is to continue using the legacy mctp-demux transport
implementation, but we also provide a build option to switch to the
AF_MCTP transport.

We don't currently have the infrastructure in place to get the correct
TIDs, so to keep everything working as before use the EID as the TID in
the EID-to-TID mapping.

Change-Id: I366f079082b102cfc0e90db0f62208581eb8693e
Signed-off-by: Rashmica Gupta <rashmica@linux.ibm.com>
Signed-off-by: Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>
Signed-off-by: Thu Nguyen <thu@os.amperecomputing.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
diff --git a/common/transport.cpp b/common/transport.cpp
new file mode 100644
index 0000000..d992415
--- /dev/null
+++ b/common/transport.cpp
@@ -0,0 +1,159 @@
+#include "common/transport.hpp"
+
+#include <libpldm/transport.h>
+#include <libpldm/transport/af-mctp.h>
+#include <libpldm/transport/mctp-demux.h>
+
+#include <algorithm>
+#include <ranges>
+#include <system_error>
+
+struct pldm_transport* transport_impl_init(TransportImpl& impl, pollfd& pollfd);
+void transport_impl_destroy(TransportImpl& impl);
+
+static constexpr uint8_t MCTP_EID_VALID_MIN = 8;
+static constexpr uint8_t MCTP_EID_VALID_MAX = 255;
+
+/*
+ * Currently the OpenBMC ecosystem assumes TID == EID. Pre-populate the TID
+ * mappings over the EID space excluding the Null (0), Reserved (1 to 7),
+ * Broadcast EIDs (255) defined by Section 8.2 Special endpoint IDs in DSP0236
+ * v1.3.1. Further, by Section 8.1.1 SetTID command (0x01) in DSP0240 v1.1.0,
+ * the TIDs 0x00 and 0xff are also reserved. These overlap with the reserved
+ * EIDs so no additional filtering is required.
+ *
+ * Further, pldmtool and pldmd are two separate processes. They are opening two
+ * different sockets, but with the mctp-demux-daemon, the response messages are
+ * broadcasted to all sockets. When pldmd receives the response for a request
+ * issued by pldmtool, pldm_transport_mctp_demux_recv() may return with error
+ * PLDM_REQUESTER_RECV_FAIL if it fails to map the EID of the source endpoint to
+ * its TID. The EID to TID mappings of pldmtool and pldmd should be coherent to
+ * prevent the failure of pldm_transport_mctp_demux_recv().
+ */
+
+[[maybe_unused]] static struct pldm_transport*
+    pldm_transport_impl_mctp_demux_init(TransportImpl& impl, pollfd& pollfd)
+{
+    impl.mctp_demux = nullptr;
+    pldm_transport_mctp_demux_init(&impl.mctp_demux);
+    if (!impl.mctp_demux)
+    {
+        return nullptr;
+    }
+
+    for (const auto eid :
+         std::views::iota(MCTP_EID_VALID_MIN, MCTP_EID_VALID_MAX))
+    {
+        int rc = pldm_transport_mctp_demux_map_tid(impl.mctp_demux, eid, eid);
+        if (rc)
+        {
+            pldm_transport_af_mctp_destroy(impl.af_mctp);
+            return nullptr;
+        }
+    }
+
+    pldm_transport* pldmTransport =
+        pldm_transport_mctp_demux_core(impl.mctp_demux);
+
+    if (pldmTransport != nullptr)
+    {
+        pldm_transport_mctp_demux_init_pollfd(pldmTransport, &pollfd);
+    }
+
+    return pldmTransport;
+}
+
+[[maybe_unused]] static struct pldm_transport*
+    pldm_transport_impl_af_mctp_init(TransportImpl& impl, pollfd& pollfd)
+{
+    impl.af_mctp = nullptr;
+    pldm_transport_af_mctp_init(&impl.af_mctp);
+    if (!impl.af_mctp)
+    {
+        return nullptr;
+    }
+
+    for (const auto eid :
+         std::views::iota(MCTP_EID_VALID_MIN, MCTP_EID_VALID_MAX))
+    {
+        int rc = pldm_transport_af_mctp_map_tid(impl.af_mctp, eid, eid);
+        if (rc)
+        {
+            pldm_transport_af_mctp_destroy(impl.af_mctp);
+            return nullptr;
+        }
+    }
+
+    /* Listen for requests on any interface */
+    if (pldm_transport_af_mctp_bind(impl.af_mctp, nullptr, 0))
+    {
+        return nullptr;
+    }
+
+    pldm_transport* pldmTransport = pldm_transport_af_mctp_core(impl.af_mctp);
+
+    if (pldmTransport != nullptr)
+    {
+        pldm_transport_af_mctp_init_pollfd(pldmTransport, &pollfd);
+    }
+
+    return pldmTransport;
+}
+
+struct pldm_transport* transport_impl_init(TransportImpl& impl, pollfd& pollfd)
+{
+#if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
+    return pldm_transport_impl_mctp_demux_init(impl, pollfd);
+#elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
+    return pldm_transport_impl_af_mctp_init(impl, pollfd);
+#else
+    return nullptr;
+#endif
+}
+
+void transport_impl_destroy(TransportImpl& impl)
+{
+#if defined(PLDM_TRANSPORT_WITH_MCTP_DEMUX)
+    pldm_transport_mctp_demux_destroy(impl.mctp_demux);
+#elif defined(PLDM_TRANSPORT_WITH_AF_MCTP)
+    pldm_transport_af_mctp_destroy(impl.af_mctp);
+#endif
+}
+
+PldmTransport::PldmTransport()
+{
+    transport = transport_impl_init(impl, pfd);
+    if (!transport)
+    {
+        throw std::system_error(ENOMEM, std::generic_category());
+    }
+}
+
+PldmTransport::~PldmTransport()
+{
+    transport_impl_destroy(impl);
+}
+
+int PldmTransport::getEventSource() const
+{
+    return pfd.fd;
+}
+
+pldm_requester_rc_t PldmTransport::sendMsg(pldm_tid_t tid, const void* tx,
+                                           size_t len)
+{
+    return pldm_transport_send_msg(transport, tid, tx, len);
+}
+
+pldm_requester_rc_t PldmTransport::recvMsg(pldm_tid_t& tid, void*& rx,
+                                           size_t& len)
+{
+    return pldm_transport_recv_msg(transport, &tid, (void**)&rx, &len);
+}
+
+pldm_requester_rc_t PldmTransport::sendRecvMsg(pldm_tid_t tid, const void* tx,
+                                               size_t txLen, void*& rx,
+                                               size_t& rxLen)
+{
+    return pldm_transport_send_recv_msg(transport, tid, tx, txLen, &rx, &rxLen);
+}
diff --git a/common/transport.hpp b/common/transport.hpp
new file mode 100644
index 0000000..0601488
--- /dev/null
+++ b/common/transport.hpp
@@ -0,0 +1,105 @@
+#pragma once
+
+#include <libpldm/base.h>
+#include <libpldm/pldm.h>
+#include <poll.h>
+#include <stddef.h>
+
+struct pldm_transport_mctp_demux;
+struct pldm_transport_af_mctp;
+
+union TransportImpl
+{
+    struct pldm_transport_mctp_demux* mctp_demux;
+    struct pldm_transport_af_mctp* af_mctp;
+};
+
+/* RAII for pldm_transport */
+class PldmTransport
+{
+  public:
+    PldmTransport();
+    PldmTransport(const PldmTransport& other) = delete;
+    PldmTransport(const PldmTransport&& other) = delete;
+    PldmTransport& operator=(const PldmTransport& other) = delete;
+    PldmTransport& operator=(const PldmTransport&& other) = delete;
+    ~PldmTransport();
+
+    /** @brief Provides a file descriptor that can be polled for readiness.
+     *
+     * Readiness generally indicates that a call to recvMsg() will immediately
+     * yield a message.
+     *
+     * @return The relevant file descriptor.
+     */
+    int getEventSource() const;
+
+    /** @brief Asynchronously send a PLDM message to the specified terminus
+     *
+     * The message may be either a request or a response.
+     *
+     * @param[in] tid - The terminus ID of the message destination
+     * @param[in] tx - The encoded and framed message to send
+     * @param[in] len - The length of the buffer pointed-to by tx
+     *
+     * @return PLDM_REQUESTER_SUCCESS on success, otherwise an appropriate
+     *         PLDM_REQUESTER_* error code.
+     */
+    pldm_requester_rc_t sendMsg(pldm_tid_t tid, const void* tx, size_t len);
+
+    /** @brief Asynchronously receive a PLDM message addressed to the local
+     * terminus
+     *
+     * The message may be either a request or a response.
+     *
+     * @param[out] tid - The terminus ID of the message source
+     * @param[out] rx - A pointer to the received, encoded message
+     * @param[out] len - The length of the buffer pointed-to by rx
+     *
+     * @return PLDM_REQUESTER_SUCCESS on success, otherwise an appropriate
+     *         PLDM_REQUESTER_* error code.
+     */
+    pldm_requester_rc_t recvMsg(pldm_tid_t& tid, void*& rx, size_t& len);
+
+    /** @brief Synchronously exchange a request and response with the specified
+     * terminus.
+     *
+     * sendRecvMsg() is a wrapper for the non-compliant
+     * pldm_transport_send_recv_msg() API from libpldm. It is a crutch that may
+     * be used for to fulfil a PLDM request until libpldm implements a correct
+     * requester flow in accordance with the PLDM base specification (DSP0240).
+     *
+     * The implementation blocks after the request is sent until a response is
+     * received, or the upper time-bound on a PLDM exchange is reached. Control
+     * is only handed back to the caller once one of these two outcomes is
+     * achieved.
+     *
+     * @param[in] tid - The terminus ID of the endpoint with which the exchange
+     *                  will occur
+     * @param[in] tx - The encoded and framed message to send
+     * @param[in] txLen - The length of the buffer pointed-to by tx
+     * @param[out] rx - A pointer to the received, encoded message
+     * @param[out] rxLen - The length of the buffer pointed-to by rx
+     *
+     * @return PLDM_REQUESTER_SUCCESS on success, otherwise an appropriate
+     *         PLDM_REQUESTER_* error code.
+     */
+    pldm_requester_rc_t sendRecvMsg(pldm_tid_t tid, const void* tx,
+                                    size_t txLen, void*& rx, size_t& rxLen);
+
+  private:
+    /** @brief A pollfd object for holding a file descriptor from the libpldm
+     *         transport implementation
+     */
+    pollfd pfd;
+
+    /** @brief A union holding an appropriately-typed pointer to the selected
+     *         libpldm transport implementation
+     */
+    TransportImpl impl;
+
+    /** @brief The abstract libpldm transport object for sending and receiving
+     *         PLDM messages.
+     */
+    struct pldm_transport* transport;
+};
diff --git a/fw-update/inventory_manager.hpp b/fw-update/inventory_manager.hpp
index fdb6369..a2e86ad 100644
--- a/fw-update/inventory_manager.hpp
+++ b/fw-update/inventory_manager.hpp
@@ -4,8 +4,6 @@
 #include "common/types.hpp"
 #include "requester/handler.hpp"
 
-#include <libpldm/pldm.h>
-
 namespace pldm
 {
 
diff --git a/fw-update/manager.hpp b/fw-update/manager.hpp
index 0608a62..018a703 100644
--- a/fw-update/manager.hpp
+++ b/fw-update/manager.hpp
@@ -8,8 +8,6 @@
 #include "requester/handler.hpp"
 #include "update_manager.hpp"
 
-#include <libpldm/pldm.h>
-
 #include <unordered_map>
 #include <vector>
 
diff --git a/fw-update/test/inventory_manager_test.cpp b/fw-update/test/inventory_manager_test.cpp
index 3876563..9d80be2 100644
--- a/fw-update/test/inventory_manager_test.cpp
+++ b/fw-update/test/inventory_manager_test.cpp
@@ -16,7 +16,7 @@
   protected:
     InventoryManagerTest() :
         event(sdeventplus::Event::get_default()), instanceIdDb(),
-        reqHandler(fd, event, instanceIdDb, false, 90000, seconds(1), 2,
+        reqHandler(nullptr, event, instanceIdDb, false, seconds(1), 2,
                    milliseconds(100)),
         inventoryManager(reqHandler, instanceIdDb, outDescriptorMap,
                          outComponentInfoMap)
diff --git a/fw-update/update_manager.hpp b/fw-update/update_manager.hpp
index 07c0ef9..b47f89d 100644
--- a/fw-update/update_manager.hpp
+++ b/fw-update/update_manager.hpp
@@ -8,7 +8,6 @@
 #include "watch.hpp"
 
 #include <libpldm/base.h>
-#include <libpldm/pldm.h>
 
 #include <chrono>
 #include <filesystem>
diff --git a/host-bmc/dbus_to_event_handler.cpp b/host-bmc/dbus_to_event_handler.cpp
index fcc56f9..2b55c6b 100644
--- a/host-bmc/dbus_to_event_handler.cpp
+++ b/host-bmc/dbus_to_event_handler.cpp
@@ -2,8 +2,6 @@
 
 #include "libpldmresponder/pdr.hpp"
 
-#include <libpldm/pldm.h>
-
 #include <phosphor-logging/lg2.hpp>
 
 PHOSPHOR_LOG2_USING;
diff --git a/host-bmc/dbus_to_host_effecters.cpp b/host-bmc/dbus_to_host_effecters.cpp
index a70b86b..b94d36a 100644
--- a/host-bmc/dbus_to_host_effecters.cpp
+++ b/host-bmc/dbus_to_host_effecters.cpp
@@ -2,7 +2,6 @@
 
 #include <libpldm/pdr.h>
 #include <libpldm/platform.h>
-#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
diff --git a/host-bmc/host_pdr_handler.cpp b/host-bmc/host_pdr_handler.cpp
index a9a914b..8317cf0 100644
--- a/host-bmc/host_pdr_handler.cpp
+++ b/host-bmc/host_pdr_handler.cpp
@@ -8,7 +8,6 @@
 #include "custom_dbus.hpp"
 
 #include <assert.h>
-#include <libpldm/pldm.h>
 
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/lg2.hpp>
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index e675be8..e1d86ec 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -7,7 +7,6 @@
 #include <libpldm/bios.h>
 #include <libpldm/fru.h>
 #include <libpldm/platform.h>
-#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 
diff --git a/meson.build b/meson.build
index 2c277ec..310f987 100644
--- a/meson.build
+++ b/meson.build
@@ -25,6 +25,12 @@
 package_localstatedir = join_paths(get_option('prefix'), get_option('localstatedir'), meson.project_name())
 
 conf_data = configuration_data()
+cpp = meson.get_compiler('cpp')
+
+# Enable POSIX poll APIs in libpldm
+if cpp.has_header('poll.h')
+    conf_data.set('PLDM_HAS_POLL', 1)
+endif
 if get_option('libpldmresponder').enabled()
 conf_data.set_quoted('BIOS_JSONS_DIR', join_paths(package_datadir, 'bios'))
 conf_data.set_quoted('BIOS_TABLES_DIR', join_paths(package_localstatedir, 'bios'))
@@ -59,13 +65,17 @@
 conf_data.set('FLIGHT_RECORDER_MAX_ENTRIES',get_option('flightrecorder-max-entries'))
 conf_data.set_quoted('HOST_EID_PATH', join_paths(package_datadir, 'host_eid'))
 conf_data.set('MAXIMUM_TRANSFER_SIZE', get_option('maximum-transfer-size'))
+if get_option('transport-implementation') == 'mctp-demux'
+  conf_data.set('PLDM_TRANSPORT_WITH_MCTP_DEMUX', 1)
+elif get_option('transport-implementation') == 'af-mctp'
+  conf_data.set('PLDM_TRANSPORT_WITH_AF_MCTP', 1)
+endif
 config = configure_file(output: 'config.h',
   configuration: conf_data
 )
 
 add_project_arguments('-include', '@0@'.format(config), language: 'cpp')
 
-cpp = meson.get_compiler('cpp')
 filesystem = import('fs')
 
 phosphor_dbus_interfaces = dependency('phosphor-dbus-interfaces')
@@ -129,6 +139,7 @@
 libpldmutils_headers = ['.']
 libpldmutils = library(
   'pldmutils',
+  'common/transport.cpp',
   'common/utils.cpp',
   version: meson.project_version(),
   dependencies: [
diff --git a/meson.options b/meson.options
index 9a7aaf2..b11c0fb 100644
--- a/meson.options
+++ b/meson.options
@@ -33,6 +33,13 @@
     description: 'Include systemd support'
 )
 
+option(
+    'transport-implementation',
+    type: 'combo',
+    choices: ['mctp-demux', 'af-mctp'],
+    description: 'transport via af-mctp or mctp-demux'
+)
+
 # As per PLDM spec DSP0240 version 1.1.0, in Timing Specification for PLDM messages (Table 6),
 # the instance ID for a given response will expire and become reusable if a response has not been
 # received within a maximum of 6 seconds after a request is sent. By setting the dbus timeout
diff --git a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
index b53addc..db248a2 100644
--- a/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
+++ b/oem/ibm/libpldmresponder/oem_ibm_handler.cpp
@@ -6,7 +6,6 @@
 
 #include <libpldm/entity.h>
 #include <libpldm/entity_oem_ibm.h>
-#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 
diff --git a/oem/ibm/libpldmresponder/platform_oem_ibm.cpp b/oem/ibm/libpldmresponder/platform_oem_ibm.cpp
index 022404c..ae608c8 100644
--- a/oem/ibm/libpldmresponder/platform_oem_ibm.cpp
+++ b/oem/ibm/libpldmresponder/platform_oem_ibm.cpp
@@ -4,7 +4,6 @@
 #include "libpldmresponder/pdr.hpp"
 
 #include <libpldm/platform_oem_ibm.h>
-#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 #include <xyz/openbmc_project/Common/error.hpp>
diff --git a/oem/ibm/requester/dbus_to_file_handler.cpp b/oem/ibm/requester/dbus_to_file_handler.cpp
index 6cb748a..57e6ab8 100644
--- a/oem/ibm/requester/dbus_to_file_handler.cpp
+++ b/oem/ibm/requester/dbus_to_file_handler.cpp
@@ -3,7 +3,6 @@
 #include "common/utils.hpp"
 
 #include <libpldm/file_io.h>
-#include <libpldm/pldm.h>
 
 #include <phosphor-logging/lg2.hpp>
 
diff --git a/pldmd/pldmd.cpp b/pldmd/pldmd.cpp
index da50615..23499e4 100644
--- a/pldmd/pldmd.cpp
+++ b/pldmd/pldmd.cpp
@@ -1,5 +1,7 @@
+
 #include "common/flight_recorder.hpp"
 #include "common/instance_id.hpp"
+#include "common/transport.hpp"
 #include "common/utils.hpp"
 #include "dbus_impl_requester.hpp"
 #include "fw-update/manager.hpp"
@@ -14,6 +16,7 @@
 #include <libpldm/bios.h>
 #include <libpldm/pdr.h>
 #include <libpldm/platform.h>
+#include <libpldm/transport.h>
 #include <poll.h>
 #include <stdlib.h>
 #include <sys/socket.h>
@@ -34,7 +37,7 @@
 #include <iostream>
 #include <iterator>
 #include <memory>
-#include <optional>
+#include <ranges>
 #include <sstream>
 #include <stdexcept>
 #include <string>
@@ -83,13 +86,12 @@
 static std::optional<Response>
     processRxMsg(const std::vector<uint8_t>& requestMsg, Invoker& invoker,
                  requester::Handler<requester::Request>& handler,
-                 fw_update::Manager* fwManager)
+                 fw_update::Manager* fwManager, pldm_tid_t tid)
 {
-    using type = uint8_t;
-    uint8_t eid = requestMsg[0];
+    uint8_t eid = tid;
+
     pldm_header_info hdrFields{};
-    auto hdr = reinterpret_cast<const pldm_msg_hdr*>(
-        requestMsg.data() + sizeof(eid) + sizeof(type));
+    auto hdr = reinterpret_cast<const pldm_msg_hdr*>(requestMsg.data());
     if (PLDM_SUCCESS != unpack_pldm_header(hdr, &hdrFields))
     {
         error("Empty PLDM request header");
@@ -100,8 +102,7 @@
     {
         Response response;
         auto request = reinterpret_cast<const pldm_msg*>(hdr);
-        size_t requestLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
-                            sizeof(eid) - sizeof(type);
+        size_t requestLen = requestMsg.size() - sizeof(struct pldm_msg_hdr);
         try
         {
             if (hdrFields.pldm_type != PLDM_FWUP)
@@ -138,8 +139,7 @@
     else if (PLDM_RESPONSE == hdrFields.msg_type)
     {
         auto response = reinterpret_cast<const pldm_msg*>(hdr);
-        size_t responseLen = requestMsg.size() - sizeof(struct pldm_msg_hdr) -
-                             sizeof(eid) - sizeof(type);
+        size_t responseLen = requestMsg.size() - sizeof(struct pldm_msg_hdr);
         handler.handleResponse(eid, hdrFields.instance, hdrFields.pldm_type,
                                hdrFields.command, response, responseLen);
     }
@@ -172,28 +172,12 @@
             exit(EXIT_FAILURE);
     }
 
-    /* Create local socket. */
-    int returnCode = 0;
-    int sockfd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
-    if (-1 == sockfd)
-    {
-        returnCode = -errno;
-        error("Failed to create the socket, RC= {RC}", "RC", returnCode);
-        exit(EXIT_FAILURE);
-    }
-    socklen_t optlen;
-    int currentSendbuffSize;
-
-    // Get Current send buffer size
-    optlen = sizeof(currentSendbuffSize);
-
-    int res = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &currentSendbuffSize,
-                         &optlen);
-    if (res == -1)
-    {
-        error("Error in obtaining the default send buffer size, Error : {ERR}",
-              "ERR", strerror(errno));
-    }
+    // Setup PLDM requester transport
+    auto hostEID = pldm::utils::readHostEID();
+    /* To maintain current behaviour until we have the infrastructure to find
+     * and use the correct TIDs */
+    pldm_tid_t TID = hostEID;
+    PldmTransport pldmTransport{};
     auto event = Event::get_default();
     auto& bus = pldm::utils::DBusHandler::getBus();
     sdbusplus::server::manager_t objManager(bus,
@@ -206,8 +190,8 @@
         bus, "/xyz/openbmc_project/inventory");
 
     Invoker invoker{};
-    requester::Handler<requester::Request> reqHandler(
-        sockfd, event, instanceIdDb, currentSendbuffSize, verbose);
+    requester::Handler<requester::Request> reqHandler(&pldmTransport, event,
+                                                      instanceIdDb, verbose);
 
 #ifdef LIBPLDMRESPONDER
     using namespace pldm::state_sensor;
@@ -241,22 +225,22 @@
         hostEffecterParser;
     std::unique_ptr<DbusToPLDMEvent> dbusToPLDMEventHandler;
     DBusHandler dbusHandler;
-    auto hostEID = pldm::utils::readHostEID();
     if (hostEID)
     {
         hostPDRHandler = std::make_shared<HostPDRHandler>(
-            sockfd, hostEID, event, pdrRepo.get(), EVENTS_JSONS_DIR,
-            entityTree.get(), bmcEntityTree.get(), instanceIdDb, &reqHandler);
+            pldmTransport.getEventSource(), hostEID, event, pdrRepo.get(),
+            EVENTS_JSONS_DIR, entityTree.get(), bmcEntityTree.get(),
+            instanceIdDb, &reqHandler);
         // HostFirmware interface needs access to hostPDR to know if host
         // is running
         dbusImplHost.setHostPdrObj(hostPDRHandler);
 
         hostEffecterParser =
             std::make_unique<pldm::host_effecters::HostEffecterParser>(
-                &instanceIdDb, sockfd, pdrRepo.get(), &dbusHandler,
-                HOST_JSONS_DIR, &reqHandler);
+                &instanceIdDb, pldmTransport.getEventSource(), pdrRepo.get(),
+                &dbusHandler, HOST_JSONS_DIR, &reqHandler);
         dbusToPLDMEventHandler = std::make_unique<DbusToPLDMEvent>(
-            sockfd, hostEID, instanceIdDb, &reqHandler);
+            pldmTransport.getEventSource(), hostEID, instanceIdDb, &reqHandler);
     }
     std::unique_ptr<oem_platform::Handler> oemPlatformHandler{};
     std::unique_ptr<oem_bios::Handler> oemBiosHandler{};
@@ -266,17 +250,19 @@
         std::make_unique<pldm::responder::CodeUpdate>(&dbusHandler);
     codeUpdate->clearDirPath(LID_STAGING_DIR);
     oemPlatformHandler = std::make_unique<oem_ibm_platform::Handler>(
-        &dbusHandler, codeUpdate.get(), sockfd, hostEID, instanceIdDb, event,
-        &reqHandler);
+        &dbusHandler, codeUpdate.get(), pldmTransport.getEventSource(), hostEID,
+        instanceIdDb, event, &reqHandler);
     codeUpdate->setOemPlatformHandler(oemPlatformHandler.get());
     invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>(
-                                          oemPlatformHandler.get(), sockfd,
+                                          oemPlatformHandler.get(),
+                                          pldmTransport.getEventSource(),
                                           hostEID, &instanceIdDb, &reqHandler));
     oemBiosHandler = std::make_unique<oem::ibm::bios::Handler>(&dbusHandler);
 #endif
 
     auto biosHandler = std::make_unique<bios::Handler>(
-        sockfd, hostEID, &instanceIdDb, &reqHandler, oemBiosHandler.get());
+        pldmTransport.getEventSource(), hostEID, &instanceIdDb, &reqHandler,
+        oemBiosHandler.get());
     auto fruHandler = std::make_unique<fru::Handler>(
         FRU_JSONS_DIR, FRU_MASTER_JSON, pdrRepo.get(), entityTree.get(),
         bmcEntityTree.get());
@@ -292,7 +278,6 @@
         dynamic_cast<pldm::responder::oem_ibm_platform::Handler*>(
             oemPlatformHandler.get());
     oemIbmPlatformHandler->setPlatformHandler(platformHandler.get());
-
 #endif
 
     invoker.registerHandler(PLDM_BIOS, std::move(biosHandler));
@@ -308,149 +293,77 @@
 
 #endif
 
-    pldm::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;
-        error("Failed to connect to the socket, RC= {RC}", "RC", returnCode);
-        exit(EXIT_FAILURE);
-    }
-
-    result = write(socketFd(), &MCTP_MSG_TYPE_PLDM, sizeof(MCTP_MSG_TYPE_PLDM));
-    if (-1 == result)
-    {
-        returnCode = -errno;
-        error("Failed to send message type as pldm to mctp, RC= {RC}", "RC",
-              returnCode);
-        exit(EXIT_FAILURE);
-    }
-
     std::unique_ptr<fw_update::Manager> fwManager =
         std::make_unique<fw_update::Manager>(event, reqHandler, instanceIdDb);
     std::unique_ptr<MctpDiscovery> mctpDiscoveryHandler =
         std::make_unique<MctpDiscovery>(bus, fwManager.get());
-
-    auto callback = [verbose, &invoker, &reqHandler, currentSendbuffSize,
-                     &fwManager](IO& io, int fd, uint32_t revents) mutable {
+    auto callback = [verbose, &invoker, &reqHandler, &fwManager, &pldmTransport,
+                     TID](IO& io, int fd, uint32_t revents) mutable {
         if (!(revents & EPOLLIN))
         {
             return;
         }
-
-        // Outgoing message.
-        struct iovec iov[2]{};
-
-        // This structure contains the parameter information for the response
-        // message.
-        struct msghdr msg
-        {};
+        if (fd < 0)
+        {
+            return;
+        }
 
         int returnCode = 0;
-        ssize_t peekedLength = recv(fd, nullptr, 0, MSG_PEEK | MSG_TRUNC);
-        if (0 == peekedLength)
+        void* requestMsg;
+        size_t recvDataLength;
+        returnCode = pldmTransport.recvMsg(TID, requestMsg, recvDataLength);
+
+        if (returnCode == PLDM_REQUESTER_SUCCESS)
+        {
+            std::vector<uint8_t> requestMsgVec(
+                static_cast<uint8_t*>(requestMsg),
+                static_cast<uint8_t*>(requestMsg) + recvDataLength);
+            FlightRecorder::GetInstance().saveRecord(requestMsgVec, false);
+            if (verbose)
+            {
+                printBuffer(Rx, requestMsgVec);
+            }
+            // process message and send response
+            auto response = processRxMsg(requestMsgVec, invoker, reqHandler,
+                                         fwManager.get(), TID);
+            if (response.has_value())
+            {
+                FlightRecorder::GetInstance().saveRecord(*response, true);
+                if (verbose)
+                {
+                    printBuffer(Tx, *response);
+                }
+
+                returnCode = pldmTransport.sendMsg(TID, (*response).data(),
+                                                   (*response).size());
+                if (returnCode != PLDM_REQUESTER_SUCCESS)
+                {
+                    warning("Failed to send PLDM response: {RETURN_CODE}",
+                            "RETURN_CODE", returnCode);
+                }
+            }
+        }
+        // TODO check that we get here if mctp-demux dies?
+        else if (returnCode == PLDM_REQUESTER_RECV_FAIL)
         {
             // MCTP daemon has closed the socket this daemon is connected to.
             // This may or may not be an error scenario, in either case the
             // recovery mechanism for this daemon is to restart, and hence exit
             // the event loop, that will cause this daemon to exit with a
             // failure code.
+            error("io exiting");
             io.get_event().exit(0);
         }
-        else if (peekedLength <= -1)
-        {
-            returnCode = -errno;
-            error("recv system call failed, RC= {RC}", "RC", returnCode);
-        }
         else
         {
-            std::vector<uint8_t> requestMsg(peekedLength);
-            auto recvDataLength = recv(
-                fd, static_cast<void*>(requestMsg.data()), peekedLength, 0);
-            if (recvDataLength == peekedLength)
-            {
-                FlightRecorder::GetInstance().saveRecord(requestMsg, false);
-                if (verbose)
-                {
-                    printBuffer(Rx, requestMsg);
-                }
-
-                if (MCTP_MSG_TYPE_PLDM != requestMsg[1])
-                {
-                    // Skip this message and continue.
-                }
-                else
-                {
-                    // process message and send response
-                    auto response = processRxMsg(requestMsg, invoker,
-                                                 reqHandler, fwManager.get());
-                    if (response.has_value())
-                    {
-                        FlightRecorder::GetInstance().saveRecord(*response,
-                                                                 true);
-                        if (verbose)
-                        {
-                            printBuffer(Tx, *response);
-                        }
-
-                        iov[0].iov_base = &requestMsg[0];
-                        iov[0].iov_len = sizeof(requestMsg[0]) +
-                                         sizeof(requestMsg[1]);
-                        iov[1].iov_base = (*response).data();
-                        iov[1].iov_len = (*response).size();
-
-                        msg.msg_iov = iov;
-                        msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
-                        if (currentSendbuffSize >= 0 &&
-                            (size_t)currentSendbuffSize < (*response).size())
-                        {
-                            int oldBuffSize = currentSendbuffSize;
-                            currentSendbuffSize = (*response).size();
-                            int res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
-                                                 &currentSendbuffSize,
-                                                 sizeof(currentSendbuffSize));
-                            if (res == -1)
-                            {
-                                error(
-                                    "Responder : Failed to set the new send buffer size [bytes] : {CURR_SND_BUF_SIZE}",
-                                    "CURR_SND_BUF_SIZE", currentSendbuffSize);
-                                error(
-                                    "from current size [bytes] : {OLD_BUF_SIZE}, Error : {ERR}",
-                                    "OLD_BUF_SIZE", oldBuffSize, "ERR",
-                                    strerror(errno));
-                                return;
-                            }
-                        }
-
-                        int result = sendmsg(fd, &msg, 0);
-                        if (-1 == result)
-                        {
-                            returnCode = -errno;
-                            error("sendto system call failed, RC= {RC}", "RC",
-                                  returnCode);
-                        }
-                    }
-                }
-            }
-            else
-            {
-                error(
-                    "Failure to read peeked length packet. peekedLength = {PEEK_LEN}, recvDataLength= {RECV_LEN}",
-                    "PEEK_LEN", peekedLength, "RECV_LEN", recvDataLength);
-            }
+            warning("Failed to receive PLDM request: {RETURN_CODE}",
+                    "RETURN_CODE", returnCode);
         }
     };
 
     bus.attach_event(event.get(), SD_EVENT_PRIORITY_NORMAL);
     bus.request_name("xyz.openbmc_project.PLDM");
-    IO io(event, socketFd(), EPOLLIN, std::move(callback));
+    IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
 #ifdef LIBPLDMRESPONDER
     if (hostPDRHandler)
     {
@@ -460,12 +373,7 @@
     stdplus::signal::block(SIGUSR1);
     sdeventplus::source::Signal sigUsr1(
         event, SIGUSR1, std::bind_front(&interruptFlightRecorderCallBack));
-    returnCode = event.loop();
-
-    if (shutdown(sockfd, SHUT_RDWR))
-    {
-        error("Failed to shutdown the socket");
-    }
+    int returnCode = event.loop();
     if (returnCode)
     {
         exit(EXIT_FAILURE);
diff --git a/pldmtool/pldm_cmd_helper.cpp b/pldmtool/pldm_cmd_helper.cpp
index db44c5a..9c7f94a 100644
--- a/pldmtool/pldm_cmd_helper.cpp
+++ b/pldmtool/pldm_cmd_helper.cpp
@@ -1,8 +1,12 @@
 #include "pldm_cmd_helper.hpp"
 
+#include "common/transport.hpp"
 #include "xyz/openbmc_project/Common/error.hpp"
 
-#include <libpldm/pldm.h>
+#include <libpldm/transport.h>
+#include <libpldm/transport/af-mctp.h>
+#include <libpldm/transport/mctp-demux.h>
+#include <poll.h>
 #include <systemd/sd-bus.h>
 
 #include <sdbusplus/server.hpp>
@@ -16,120 +20,6 @@
 {
 namespace helper
 {
-/*
- * Initialize the socket, send pldm command & recieve response from socket
- *
- */
-int mctpSockSendRecv(const std::vector<uint8_t>& requestMsg,
-                     std::vector<uint8_t>& responseMsg, bool pldmVerbose)
-{
-    const char devPath[] = "\0mctp-mux";
-    int returnCode = 0;
-
-    int sockFd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
-    if (-1 == sockFd)
-    {
-        returnCode = -errno;
-        std::cerr << "Failed to create the socket : RC = " << sockFd << "\n";
-        return returnCode;
-    }
-    Logger(pldmVerbose, "Success in creating the socket : RC = ", sockFd);
-
-    struct sockaddr_un addr
-    {};
-    addr.sun_family = AF_UNIX;
-
-    memcpy(addr.sun_path, devPath, sizeof(devPath) - 1);
-
-    CustomFD socketFd(sockFd);
-    int result = connect(socketFd(), reinterpret_cast<struct sockaddr*>(&addr),
-                         sizeof(devPath) + sizeof(addr.sun_family) - 1);
-    if (-1 == result)
-    {
-        returnCode = -errno;
-        std::cerr << "Failed to connect to socket : RC = " << returnCode
-                  << "\n";
-        return returnCode;
-    }
-    Logger(pldmVerbose, "Success in connecting to socket : RC = ", returnCode);
-
-    auto pldmType = MCTP_MSG_TYPE_PLDM;
-    result = write(socketFd(), &pldmType, sizeof(pldmType));
-    if (-1 == result)
-    {
-        returnCode = -errno;
-        std::cerr << "Failed to send message type as pldm to mctp : RC = "
-                  << returnCode << "\n";
-        return returnCode;
-    }
-    Logger(
-        pldmVerbose,
-        "Success in sending message type as pldm to mctp : RC = ", returnCode);
-
-    result = send(socketFd(), requestMsg.data(), requestMsg.size(), 0);
-    if (-1 == result)
-    {
-        returnCode = -errno;
-        std::cerr << "Write to socket failure : RC = " << returnCode << "\n";
-        return returnCode;
-    }
-    Logger(pldmVerbose, "Write to socket successful : RC = ", result);
-
-    // Read the response from socket
-    ssize_t peekedLength = recv(socketFd(), nullptr, 0, MSG_TRUNC | MSG_PEEK);
-    if (0 == peekedLength)
-    {
-        std::cerr << "Socket is closed : peekedLength = " << peekedLength
-                  << "\n";
-        return returnCode;
-    }
-    else if (peekedLength <= -1)
-    {
-        returnCode = -errno;
-        std::cerr << "recv() system call failed : RC = " << returnCode << "\n";
-        return returnCode;
-    }
-    else
-    {
-        auto reqhdr = reinterpret_cast<const pldm_msg_hdr*>(&requestMsg[2]);
-        do
-        {
-            ssize_t peekedLength = recv(socketFd(), nullptr, 0,
-                                        MSG_PEEK | MSG_TRUNC);
-            responseMsg.resize(peekedLength);
-            auto recvDataLength =
-                recv(socketFd(), reinterpret_cast<void*>(responseMsg.data()),
-                     peekedLength, 0);
-            auto resphdr =
-                reinterpret_cast<const pldm_msg_hdr*>(&responseMsg[2]);
-            if (recvDataLength == peekedLength &&
-                resphdr->instance_id == reqhdr->instance_id &&
-                resphdr->request != PLDM_REQUEST)
-            {
-                Logger(pldmVerbose, "Total length:", recvDataLength);
-                break;
-            }
-            else if (recvDataLength != peekedLength)
-            {
-                std::cerr << "Failure to read response length packet: length = "
-                          << recvDataLength << "\n";
-                return returnCode;
-            }
-        } while (1);
-    }
-
-    returnCode = shutdown(socketFd(), SHUT_RDWR);
-    if (-1 == returnCode)
-    {
-        returnCode = -errno;
-        std::cerr << "Failed to shutdown the socket : RC = " << returnCode
-                  << "\n";
-        return returnCode;
-    }
-
-    Logger(pldmVerbose, "Shutdown Socket successful :  RC = ", returnCode);
-    return PLDM_SUCCESS;
-}
 
 void CommandInterface::exec()
 {
@@ -161,13 +51,6 @@
 int CommandInterface::pldmSendRecv(std::vector<uint8_t>& requestMsg,
                                    std::vector<uint8_t>& responseMsg)
 {
-    // Insert the PLDM message type and EID at the beginning of the
-    // msg.
-    requestMsg.insert(requestMsg.begin(), MCTP_MSG_TYPE_PLDM);
-    requestMsg.insert(requestMsg.begin(), mctp_eid);
-
-    bool mctpVerbose = pldmVerbose;
-
     // By default enable request/response msgs for pldmtool raw commands.
     if (CommandInterface::pldmType == "raw")
     {
@@ -180,43 +63,29 @@
         printBuffer(Tx, requestMsg);
     }
 
-    if (mctp_eid != PLDM_ENTITY_ID)
+    void* responseMessage = nullptr;
+    size_t responseMessageSize{};
+    auto tid = mctp_eid;
+    PldmTransport pldmTransport{};
+
+    int rc = pldmTransport.sendRecvMsg(tid, requestMsg.data(),
+                                       requestMsg.size(), responseMessage,
+                                       responseMessageSize);
+    if (rc)
     {
-        int fd = pldm_open();
-        if (-1 == fd)
-        {
-            std::cerr << "failed to init mctp "
-                      << "\n";
-            return -1;
-        }
-        uint8_t* responseMessage = nullptr;
-        size_t responseMessageSize{};
-        pldm_send_recv(mctp_eid, fd, requestMsg.data() + 2,
-                       requestMsg.size() - 2, &responseMessage,
-                       &responseMessageSize);
-
-        responseMsg.resize(responseMessageSize);
-        memcpy(responseMsg.data(), responseMessage, responseMsg.size());
-
-        shutdown(fd, SHUT_RDWR);
-        free(responseMessage);
-
-        if (pldmVerbose)
-        {
-            std::cout << "pldmtool: ";
-            printBuffer(Rx, responseMsg);
-        }
+        std::cerr << "failed to pldm send recv\n";
+        return rc;
     }
-    else
+
+    responseMsg.resize(responseMessageSize);
+    memcpy(responseMsg.data(), responseMessage, responseMsg.size());
+
+    free(responseMessage);
+
+    if (pldmVerbose)
     {
-        mctpSockSendRecv(requestMsg, responseMsg, mctpVerbose);
-        if (pldmVerbose)
-        {
-            std::cout << "pldmtool: ";
-            printBuffer(Rx, responseMsg);
-        }
-        responseMsg.erase(responseMsg.begin(),
-                          responseMsg.begin() + 2 /* skip the mctp header */);
+        std::cout << "pldmtool: ";
+        printBuffer(Rx, responseMsg);
     }
     return PLDM_SUCCESS;
 }
diff --git a/requester/handler.hpp b/requester/handler.hpp
index 9e5d8d1..6987b16 100644
--- a/requester/handler.hpp
+++ b/requester/handler.hpp
@@ -1,11 +1,11 @@
 #pragma once
 
 #include "common/instance_id.hpp"
+#include "common/transport.hpp"
 #include "common/types.hpp"
 #include "request.hpp"
 
 #include <libpldm/base.h>
-#include <libpldm/pldm.h>
 #include <sys/socket.h>
 
 #include <phosphor-logging/lg2.hpp>
@@ -87,26 +87,24 @@
 
     /** @brief Constructor
      *
-     *  @param[in] fd - fd of MCTP communications socket
+     *  @param[in] pldm_transport - PLDM requester
      *  @param[in] event - reference to PLDM daemon's main event loop
      *  @param[in] instanceIdDb - reference to an InstanceIdDb
-     *  @param[in] currentSendbuffSize - current send buffer size
      *  @param[in] verbose - verbose tracing flag
      *  @param[in] instanceIdExpiryInterval - instance ID expiration interval
      *  @param[in] numRetries - number of request retries
      *  @param[in] responseTimeOut - time to wait between each retry
      */
     explicit Handler(
-        int fd, sdeventplus::Event& event, pldm::InstanceIdDb& instanceIdDb,
-        int currentSendbuffSize, bool verbose,
+        PldmTransport* pldmTransport, sdeventplus::Event& event,
+        pldm::InstanceIdDb& instanceIdDb, bool verbose,
         std::chrono::seconds instanceIdExpiryInterval =
             std::chrono::seconds(INSTANCE_ID_EXPIRATION_INTERVAL),
         uint8_t numRetries = static_cast<uint8_t>(NUMBER_OF_REQUEST_RETRIES),
         std::chrono::milliseconds responseTimeOut =
             std::chrono::milliseconds(RESPONSE_TIME_OUT)) :
-        fd(fd),
-        event(event), instanceIdDb(instanceIdDb),
-        currentSendbuffSize(currentSendbuffSize), verbose(verbose),
+        pldmTransport(pldmTransport),
+        event(event), instanceIdDb(instanceIdDb), verbose(verbose),
         instanceIdExpiryInterval(instanceIdExpiryInterval),
         numRetries(numRetries), responseTimeOut(responseTimeOut)
     {}
@@ -171,8 +169,8 @@
         }
 
         auto request = std::make_unique<RequestInterface>(
-            fd, eid, event, std::move(requestMsg), numRetries, responseTimeOut,
-            currentSendbuffSize, verbose);
+            pldmTransport, eid, event, std::move(requestMsg), numRetries,
+            responseTimeOut, verbose);
         auto timer = std::make_unique<phosphor::Timer>(
             event.get(), instanceIdExpiryCallBack);
 
@@ -243,10 +241,9 @@
     }
 
   private:
-    int fd; //!< file descriptor of MCTP communications socket
+    PldmTransport* pldmTransport; //!< PLDM transport object
     sdeventplus::Event& event; //!< reference to PLDM daemon's main event loop
     pldm::InstanceIdDb& instanceIdDb; //!< reference to an InstanceIdDb
-    int currentSendbuffSize;          //!< current Send Buffer size
     bool verbose;                     //!< verbose tracing flag
     std::chrono::seconds
         instanceIdExpiryInterval;     //!< Instance ID expiration interval
diff --git a/requester/mctp_endpoint_discovery.cpp b/requester/mctp_endpoint_discovery.cpp
index bc50ee5..5f3451a 100644
--- a/requester/mctp_endpoint_discovery.cpp
+++ b/requester/mctp_endpoint_discovery.cpp
@@ -3,8 +3,6 @@
 #include "common/types.hpp"
 #include "common/utils.hpp"
 
-#include <libpldm/pldm.h>
-
 #include <algorithm>
 #include <map>
 #include <string>
diff --git a/requester/request.hpp b/requester/request.hpp
index 62615f8..27d94fc 100644
--- a/requester/request.hpp
+++ b/requester/request.hpp
@@ -1,11 +1,11 @@
 #pragma once
 
 #include "common/flight_recorder.hpp"
+#include "common/transport.hpp"
 #include "common/types.hpp"
 #include "common/utils.hpp"
 
 #include <libpldm/base.h>
-#include <libpldm/pldm.h>
 #include <sys/socket.h>
 
 #include <phosphor-logging/lg2.hpp>
@@ -142,7 +142,7 @@
 
     /** @brief Constructor
      *
-     *  @param[in] fd - fd of the MCTP communication socket
+     *  @param[in] pldm_transport - PLDM transport object
      *  @param[in] eid - endpoint ID of the remote MCTP endpoint
      *  @param[in] currrentSendbuffSize - the current send buffer size
      *  @param[in] event - reference to PLDM daemon's main event loop
@@ -151,21 +151,20 @@
      *  @param[in] timeout - time to wait between each retry in milliseconds
      *  @param[in] verbose - verbose tracing flag
      */
-    explicit Request(int fd, mctp_eid_t eid, sdeventplus::Event& event,
-                     pldm::Request&& requestMsg, uint8_t numRetries,
-                     std::chrono::milliseconds timeout, int currentSendbuffSize,
+    explicit Request(PldmTransport* pldmTransport, mctp_eid_t eid,
+                     sdeventplus::Event& event, pldm::Request&& requestMsg,
+                     uint8_t numRetries, std::chrono::milliseconds timeout,
                      bool verbose) :
         RequestRetryTimer(event, numRetries, timeout),
-        fd(fd), eid(eid), requestMsg(std::move(requestMsg)),
-        currentSendbuffSize(currentSendbuffSize), verbose(verbose)
+        pldmTransport(pldmTransport), eid(eid),
+        requestMsg(std::move(requestMsg)), verbose(verbose)
     {}
 
   private:
-    int fd;                   //!< file descriptor of MCTP communications socket
-    mctp_eid_t eid;           //!< endpoint ID of the remote MCTP endpoint
-    pldm::Request requestMsg; //!< PLDM request message
-    mutable int currentSendbuffSize; //!< current Send Buffer size
-    bool verbose;                    //!< verbose tracing flag
+    PldmTransport* pldmTransport; //!< PLDM transport
+    mctp_eid_t eid;               //!< endpoint ID of the remote MCTP endpoint
+    pldm::Request requestMsg;     //!< PLDM request message
+    bool verbose;                 //!< verbose tracing flag
 
     /** @brief Sends the PLDM request message on the socket
      *
@@ -177,26 +176,23 @@
         {
             pldm::utils::printBuffer(pldm::utils::Tx, requestMsg);
         }
-        if (currentSendbuffSize >= 0 &&
-            (size_t)currentSendbuffSize < requestMsg.size())
-        {
-            int oldSendbuffSize = currentSendbuffSize;
-            currentSendbuffSize = requestMsg.size();
-            int res = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
-                                 &currentSendbuffSize,
-                                 sizeof(currentSendbuffSize));
-            if (res == -1)
-            {
-                error(
-                    "Requester : Failed to set the new send buffer size [bytes] : {CURR_SND_BUF_SIZE} from current size [bytes]: {OLD_BUF_SIZE} , Error : {ERR}",
-                    "CURR_SND_BUF_SIZE", currentSendbuffSize, "OLD_BUF_SIZE",
-                    oldSendbuffSize, "ERR", strerror(errno));
-                return PLDM_ERROR;
-            }
-        }
         pldm::flightrecorder::FlightRecorder::GetInstance().saveRecord(
             requestMsg, true);
-        auto rc = pldm_send(eid, fd, requestMsg.data(), requestMsg.size());
+        const struct pldm_msg_hdr* hdr =
+            (struct pldm_msg_hdr*)(requestMsg.data());
+        if (!hdr->request)
+        {
+            return PLDM_REQUESTER_NOT_REQ_MSG;
+        }
+
+        if (pldmTransport == nullptr)
+        {
+            error("Invalid transport: Unable to send PLDM request");
+            return PLDM_ERROR;
+        }
+
+        auto rc = pldmTransport->sendMsg(static_cast<pldm_tid_t>(eid),
+                                         requestMsg.data(), requestMsg.size());
         if (rc < 0)
         {
             error("Failed to send PLDM message. RC = {RC}, errno = {ERR}", "RC",
diff --git a/requester/test/handler_test.cpp b/requester/test/handler_test.cpp
index 17a40fe..b656c1a 100644
--- a/requester/test/handler_test.cpp
+++ b/requester/test/handler_test.cpp
@@ -6,6 +6,7 @@
 #include "test/test_instance_id.hpp"
 
 #include <libpldm/base.h>
+#include <libpldm/transport.h>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -26,6 +27,7 @@
 
     int fd = 0;
     mctp_eid_t eid = 0;
+    PldmTransport* pldmTransport = nullptr;
     sdeventplus::Event event;
     TestInstanceIdDb instanceIdDb;
 
@@ -71,9 +73,9 @@
 
 TEST_F(HandlerTest, singleRequestResponseScenario)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, instanceIdDb, false,
-                                              90000, seconds(1), 2,
-                                              milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(pldmTransport, event,
+                                              instanceIdDb, false, seconds(1),
+                                              2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = instanceIdDb.next(eid);
     EXPECT_EQ(instanceId, 0);
@@ -92,9 +94,9 @@
 
 TEST_F(HandlerTest, singleRequestInstanceIdTimerExpired)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, instanceIdDb, false,
-                                              90000, seconds(1), 2,
-                                              milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(pldmTransport, event,
+                                              instanceIdDb, false, seconds(1),
+                                              2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = instanceIdDb.next(eid);
     EXPECT_EQ(instanceId, 0);
@@ -111,9 +113,9 @@
 
 TEST_F(HandlerTest, multipleRequestResponseScenario)
 {
-    Handler<NiceMock<MockRequest>> reqHandler(fd, event, instanceIdDb, false,
-                                              90000, seconds(2), 2,
-                                              milliseconds(100));
+    Handler<NiceMock<MockRequest>> reqHandler(pldmTransport, event,
+                                              instanceIdDb, false, seconds(2),
+                                              2, milliseconds(100));
     pldm::Request request{};
     auto instanceId = instanceIdDb.next(eid);
     EXPECT_EQ(instanceId, 0);
diff --git a/requester/test/mock_request.hpp b/requester/test/mock_request.hpp
index 7e6fc41..e77a3cb 100644
--- a/requester/test/mock_request.hpp
+++ b/requester/test/mock_request.hpp
@@ -1,7 +1,10 @@
 #pragma once
 
+#include "common/transport.hpp"
 #include "requester/request.hpp"
 
+#include <libpldm/transport.h>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -14,10 +17,10 @@
 class MockRequest : public RequestRetryTimer
 {
   public:
-    MockRequest(int /*fd*/, mctp_eid_t /*eid*/, sdeventplus::Event& event,
-                pldm::Request&& /*requestMsg*/, uint8_t numRetries,
-                std::chrono::milliseconds responseTimeOut,
-                int /*currentSendbuffSize*/, bool /*verbose*/) :
+    MockRequest(PldmTransport* /*pldmTransport*/, mctp_eid_t /*eid*/,
+                sdeventplus::Event& event, pldm::Request&& /*requestMsg*/,
+                uint8_t numRetries, std::chrono::milliseconds responseTimeOut,
+                bool /*verbose*/) :
         RequestRetryTimer(event, numRetries, responseTimeOut)
     {}
 
diff --git a/requester/test/request_test.cpp b/requester/test/request_test.cpp
index 2e3060d..51b337d 100644
--- a/requester/test/request_test.cpp
+++ b/requester/test/request_test.cpp
@@ -1,3 +1,4 @@
+#include "common/transport.hpp"
 #include "mock_request.hpp"
 
 #include <libpldm/base.h>
@@ -41,14 +42,15 @@
 
     int fd = 0;
     mctp_eid_t eid = 0;
+    PldmTransport* pldmTransport = nullptr;
     sdeventplus::Event event;
-    std::vector<uint8_t> requestMsg;
 };
 
 TEST_F(RequestIntfTest, 0Retries100msTimeout)
 {
-    MockRequest request(fd, eid, event, std::move(requestMsg), 0,
-                        milliseconds(100), 90000, false);
+    std::vector<uint8_t> requestMsg;
+    MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 0,
+                        milliseconds(100), false);
     EXPECT_CALL(request, send())
         .Times(Exactly(1))
         .WillOnce(Return(PLDM_SUCCESS));
@@ -58,8 +60,9 @@
 
 TEST_F(RequestIntfTest, 2Retries100msTimeout)
 {
-    MockRequest request(fd, eid, event, std::move(requestMsg), 2,
-                        milliseconds(100), 90000, false);
+    std::vector<uint8_t> requestMsg;
+    MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2,
+                        milliseconds(100), false);
     // send() is called a total of 3 times, the original plus two retries
     EXPECT_CALL(request, send()).Times(3).WillRepeatedly(Return(PLDM_SUCCESS));
     auto rc = request.start();
@@ -69,8 +72,9 @@
 
 TEST_F(RequestIntfTest, 9Retries100msTimeoutRequestStoppedAfter1sec)
 {
-    MockRequest request(fd, eid, event, std::move(requestMsg), 9,
-                        milliseconds(100), 90000, false);
+    std::vector<uint8_t> requestMsg;
+    MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 9,
+                        milliseconds(100), false);
     // send() will be called a total of 10 times, the original plus 9 retries.
     // In a ideal scenario send() would have been called 10 times in 1 sec (when
     // the timer is stopped) with a timeout of 100ms. Because there are delays
@@ -92,8 +96,9 @@
 
 TEST_F(RequestIntfTest, 2Retries100msTimeoutsendReturnsError)
 {
-    MockRequest request(fd, eid, event, std::move(requestMsg), 2,
-                        milliseconds(100), 90000, false);
+    std::vector<uint8_t> requestMsg;
+    MockRequest request(pldmTransport, eid, event, std::move(requestMsg), 2,
+                        milliseconds(100), false);
     EXPECT_CALL(request, send()).Times(Exactly(1)).WillOnce(Return(PLDM_ERROR));
     auto rc = request.start();
     EXPECT_EQ(rc, PLDM_ERROR);
diff --git a/softoff/softoff.cpp b/softoff/softoff.cpp
index f80e048..3135b3d 100644
--- a/softoff/softoff.cpp
+++ b/softoff/softoff.cpp
@@ -1,11 +1,11 @@
 #include "softoff.hpp"
 
 #include "common/instance_id.hpp"
+#include "common/transport.hpp"
 #include "common/utils.hpp"
 
 #include <libpldm/entity.h>
 #include <libpldm/platform.h>
-#include <libpldm/pldm.h>
 #include <libpldm/state_set.h>
 
 #include <phosphor-logging/lg2.hpp>
@@ -291,8 +291,9 @@
 int SoftPowerOff::hostSoftOff(sdeventplus::Event& event)
 {
     constexpr uint8_t effecterCount = 1;
-    uint8_t mctpEID;
+    PldmTransport pldmTransport{};
     uint8_t instanceID;
+    uint8_t mctpEID;
 
     mctpEID = pldm::utils::readHostEID();
     // TODO: fix mapping to work around OpenBMC ecosystem deficiencies
@@ -317,14 +318,6 @@
         return PLDM_ERROR;
     }
 
-    // Open connection to MCTP socket
-    int fd = pldm_open();
-    if (-1 == fd)
-    {
-        error("Failed to connect to mctp demux daemon");
-        return PLDM_ERROR;
-    }
-
     // Add a timer to the event loop, default 30s.
     auto timerCallback =
         [=, this](Timer& /*source*/, Timer::TimePoint /*time*/) mutable {
@@ -341,18 +334,23 @@
                std::chrono::seconds{1}, std::move(timerCallback));
 
     // Add a callback to handle EPOLLIN on fd
-    auto callback = [=, this](IO& io, int fd, uint32_t revents) mutable {
+    auto callback =
+        [=, &pldmTransport, this](IO& io, int fd, uint32_t revents) mutable {
+        if (fd != pldmTransport.getEventSource())
+        {
+            return;
+        }
+
         if (!(revents & EPOLLIN))
         {
             return;
         }
 
-        uint8_t* responseMsg = nullptr;
+        void* responseMsg = nullptr;
         size_t responseMsgSize{};
         pldm_tid_t srcTID = pldmTID;
 
-        auto rc = pldm_recv(mctpEID, fd, request->hdr.instance_id, &responseMsg,
-                            &responseMsgSize);
+        auto rc = pldmTransport.recvMsg(pldmTID, responseMsg, responseMsgSize);
         if (rc)
         {
             error("Soft off: failed to recv pldm data. PLDM RC = {RC}", "RC",
@@ -360,8 +358,8 @@
             return;
         }
 
-        std::unique_ptr<uint8_t, decltype(std::free)*> responseMsgPtr{
-            responseMsg, std::free};
+        std::unique_ptr<void, decltype(std::free)*> responseMsgPtr{responseMsg,
+                                                                   std::free};
 
         // We've got the response meant for the PLDM request msg that was
         // sent out
@@ -409,10 +407,10 @@
         }
         return;
     };
-    IO io(event, fd, EPOLLIN, std::move(callback));
+    IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
 
-    // Send PLDM Request message - pldm_send doesn't wait for response
-    rc = pldm_send(mctpEID, fd, requestMsg.data(), requestMsg.size());
+    // Asynchronously send the PLDM request
+    rc = pldmTransport.sendMsg(pldmTID, requestMsg.data(), requestMsg.size());
     if (0 > rc)
     {
         instanceIdDb.free(pldmTID, instanceID);
diff --git a/softoff/softoff.hpp b/softoff/softoff.hpp
index 85a4010..fce0a52 100644
--- a/softoff/softoff.hpp
+++ b/softoff/softoff.hpp
@@ -1,9 +1,8 @@
 #pragma once
 
+#include "common/transport.hpp"
 #include "common/types.hpp"
 
-#include <libpldm/pldm.h>
-
 #include <sdbusplus/bus.hpp>
 #include <sdbusplus/server.hpp>
 #include <sdbusplus/server/object.hpp>
diff --git a/utilities/meson.build b/utilities/meson.build
index 1977aa4..383cf29 100644
--- a/utilities/meson.build
+++ b/utilities/meson.build
@@ -1,14 +1,16 @@
 deps = [ CLI11_dep, libpldm_dep, sdeventplus, phosphor_logging_dep ]
 
-executable('set-state-effecter', 'requester/set_state_effecter.cpp',
+executable('set-state-effecter', 'requester/set_state_effecter.cpp', '../common/transport.cpp',
            implicit_include_directories: false,
+           include_directories: [ '..' ],
            dependencies: deps,
            install: true,
            install_dir: get_option('bindir'))
 
 executable('set-state-effecter-async',
-           'requester/set_state_effecter_async.cpp',
+           'requester/set_state_effecter_async.cpp', '../common/transport.cpp',
            implicit_include_directories: false,
+           include_directories: [ '..' ],
            dependencies: deps,
            install: true,
            install_dir: get_option('bindir'))
diff --git a/utilities/requester/set_state_effecter.cpp b/utilities/requester/set_state_effecter.cpp
index c71f079..4243f4c 100644
--- a/utilities/requester/set_state_effecter.cpp
+++ b/utilities/requester/set_state_effecter.cpp
@@ -1,5 +1,6 @@
+#include "common/transport.hpp"
+
 #include <libpldm/platform.h>
-#include <libpldm/pldm.h>
 
 #include <CLI/CLI.hpp>
 #include <phosphor-logging/lg2.hpp>
@@ -37,19 +38,14 @@
         return -1;
     }
 
-    // Open connection to MCTP socket
-    int fd = pldm_open();
-    if (-1 == fd)
-    {
-        error("Failed to init mctp");
-        return -1;
-    }
+    PldmTransport pldmTransport{};
 
-    uint8_t* responseMsg = nullptr;
+    void* responseMsg = nullptr;
     size_t responseMsgSize{};
     // Send PLDM request msg and wait for response
-    rc = pldm_send_recv(mctpEid, fd, requestMsg.data(), requestMsg.size(),
-                        &responseMsg, &responseMsgSize);
+    rc = pldmTransport.sendRecvMsg(static_cast<pldm_tid_t>(mctpEid),
+                                   requestMsg.data(), requestMsg.size(),
+                                   responseMsg, responseMsgSize);
     if (0 > rc)
     {
         error(
diff --git a/utilities/requester/set_state_effecter_async.cpp b/utilities/requester/set_state_effecter_async.cpp
index 8a7a041..bf905e3 100644
--- a/utilities/requester/set_state_effecter_async.cpp
+++ b/utilities/requester/set_state_effecter_async.cpp
@@ -1,6 +1,7 @@
+#include "common/transport.hpp"
+
 #include <libpldm/base.h>
 #include <libpldm/platform.h>
-#include <libpldm/pldm.h>
 
 #include <CLI/CLI.hpp>
 #include <phosphor-logging/lg2.hpp>
@@ -25,6 +26,8 @@
     app.add_option("-s,--state", state, "New state value")->required();
     CLI11_PARSE(app, argc, argv);
 
+    pldm_tid_t dstTid = static_cast<pldm_tid_t>(mctpEid);
+
     // Encode PLDM Request message
     uint8_t effecterCount = 1;
     std::array<uint8_t, sizeof(pldm_msg_hdr) + sizeof(effecterId) +
@@ -42,42 +45,44 @@
         return -1;
     }
 
-    // Get fd of MCTP socket
-    int fd = pldm_open();
-    if (-1 == fd)
-    {
-        error("Failed to init mctp");
-        return -1;
-    }
+    PldmTransport pldmTransport{};
 
     // Create event loop and add a callback to handle EPOLLIN on fd
     auto event = Event::get_default();
-    auto callback = [=](IO& io, int fd, uint32_t revents) {
+    auto callback =
+        [=, &pldmTransport](IO& io, int fd, uint32_t revents) mutable {
         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)
+        if (pldmTransport.getEventSource() != fd)
         {
-            // We've got the response meant for the PLDM request msg that was
-            // sent out
-            io.set_enabled(Enabled::Off);
-            pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg);
-            info("Done. PLDM RC = {RC}", "RC", lg2::hex,
-                 static_cast<uint16_t>(response->payload[0]));
-            free(responseMsg);
-            exit(EXIT_SUCCESS);
+            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());
+        void* responseMsg = nullptr;
+        size_t responseMsgSize{};
+        pldm_tid_t srcTid;
+        auto rc = pldmTransport.recvMsg(srcTid, responseMsg, responseMsgSize);
+        pldm_msg* response = reinterpret_cast<pldm_msg*>(responseMsg);
+        if (rc || dstTid != srcTid ||
+            !pldm_msg_hdr_correlate_response(&request->hdr, &response->hdr))
+        {
+            return;
+        }
+
+        // We've got the response meant for the PLDM request msg that was sent
+        // out
+        io.set_enabled(Enabled::Off);
+        info("Done. PLDM RC = {RC}", "RC", lg2::hex,
+             static_cast<uint16_t>(response->payload[0]));
+        free(responseMsg);
+        exit(EXIT_SUCCESS);
+    };
+    IO io(event, pldmTransport.getEventSource(), EPOLLIN, std::move(callback));
+
+    rc = pldmTransport.sendMsg(dstTid, requestMsg.data(), requestMsg.size());
     if (0 > rc)
     {
         error(