Add RDE discovery- Negotiate and medium params

Google-Bug-Id: 321094056
Change-Id: If405b07f98442119e0481adcfe26229835c11965
Signed-off-by: Harsh Tyagi <harshtya@google.com>
diff --git a/interface/pldm_interface.cpp b/interface/pldm_interface.cpp
index 33e88ec..5912746 100644
--- a/interface/pldm_interface.cpp
+++ b/interface/pldm_interface.cpp
@@ -16,11 +16,12 @@
                                                      size_t reqMsgLen)
 {
     struct sockaddr_mctp addr;
+    memset(&addr, 0, sizeof(addr));
     addr.smctp_family = AF_MCTP;
     addr.smctp_network = networkId;
     addr.smctp_addr.s_addr = eid;
     addr.smctp_type = MCTP_MSG_TYPE_PLDM;
-    addr.smctp_tag = DESTINATION_MCTP_TAG_OWNER;
+    addr.smctp_tag = MCTP_TAG_OWNER;
 
     int rc =
         sendto(mctpFd, reinterpret_cast<const uint8_t*>(pldmReqMsg), reqMsgLen,
diff --git a/meson.build b/meson.build
index 6ab0761..ce77f2a 100644
--- a/meson.build
+++ b/meson.build
@@ -7,14 +7,16 @@
           'c_std=c18',
         ])
 
-sources = [
-  'rded.cpp',
+lib_sources = [
   'interface/pldm_interface.cpp',
   'interface/pldm_rde.cpp',
   'util/matcher/rde_match_handler.cpp',
   'util/state_machine/discovery/base/base_disc_state_machine.cpp',
+  'util/state_machine/discovery/rde/rde_disc_state_machine.cpp',
 ]
 
+all_sources = ['rded.cpp'] + lib_sources
+
 cpp = meson.get_compiler('cpp')
 phosphor_dbus_interfaces = dependency('phosphor-dbus-interfaces')
 sdbusplus = dependency('sdbusplus')
@@ -83,12 +85,7 @@
 
 rded_lib = static_library(
   'rded_lib',
-  [
-    'interface/pldm_interface.cpp',
-    'interface/pldm_rde.cpp',
-    'util/matcher/rde_match_handler.cpp',
-    'util/state_machine/discovery/base/base_disc_state_machine.cpp'
-  ],
+  lib_sources,
   include_directories: headers,
   implicit_include_directories: false,
   dependencies: deps)
@@ -104,7 +101,7 @@
 
 executable(
   'rded',
-  sources,
+  all_sources,
   implicit_include_directories: false,
   dependencies: deps,
   install: true,
diff --git a/rded.cpp b/rded.cpp
index 75b78d3..e0d8135 100644
--- a/rded.cpp
+++ b/rded.cpp
@@ -48,6 +48,7 @@
         return -1;
     }
 
+    ASSERT_MIN_MCTP_RETRIES(MAX_RETRIES_MCTP_SOCK_FAILURE);
     RdeMatchHandler matcher(fd);
     matcher.triggerMatcher();
     stdplus::print(stderr, "RDE Reactor stopped...\n");
diff --git a/tests/discovery/rde/rde_disc_state_machine_test.cpp b/tests/discovery/rde/rde_disc_state_machine_test.cpp
new file mode 100644
index 0000000..dd1c14e
--- /dev/null
+++ b/tests/discovery/rde/rde_disc_state_machine_test.cpp
@@ -0,0 +1,90 @@
+#include "libpldm/base.h"
+
+#include "tests/pldm_interface_mock.hpp"
+#include "util/state_machine/discovery/rde/rde_disc_state_machine.hpp"
+
+#include <stdplus/print.hpp>
+
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::Return;
+
+constexpr int testFd = 3;
+constexpr int testNetId = 6;
+constexpr std::string testDeviceId = "1_1_3_1";
+
+class RdeDiscoveryTest : public ::testing::Test
+{
+  protected:
+    std::shared_ptr<MockPldmInterface> mockInterface =
+        std::make_shared<MockPldmInterface>();
+};
+
+TEST_F(RdeDiscoveryTest, StateMachineRunSuccess)
+{
+    std::unique_ptr<RdeDiscoveryStateMachine> stateMachineRde =
+        std::make_unique<RdeDiscoveryStateMachine>(testFd, testDeviceId,
+                                                   testNetId, mockInterface);
+
+    EXPECT_CALL(*mockInterface, pldmSendAtNetwork(_, _, _, _, _))
+        .WillOnce(
+            Return(PLDM_REQUESTER_SUCCESS)) // send for Negotiate Redfish Params
+        .WillOnce(Return(PLDM_REQUESTER_SUCCESS)); // send for Medium Params
+
+    EXPECT_CALL(*mockInterface, pldmRecvAtNetwork(_, _, _, _, _, _))
+        .WillOnce(Return(
+            PLDM_REQUESTER_SUCCESS)) // receive for Negotiate Redfish Params
+        .WillOnce(Return(PLDM_REQUESTER_SUCCESS)); // receive for Medium Params
+    OperationStatus status = stateMachineRde.get()->run();
+    stdplus::println(stderr, "Status: {}", static_cast<int>(status));
+    // All invocations tested with success code (State machine runs fine)
+    EXPECT_EQ(status, OperationStatus::Success);
+}
+
+TEST_F(RdeDiscoveryTest, StateMachineRunReceiveFails)
+{
+    // Fails at the first receive and hence discovery should fail and no more
+    // calls to be made to the interface
+    std::unique_ptr<RdeDiscoveryStateMachine> stateMachineRde =
+        std::make_unique<RdeDiscoveryStateMachine>(testFd, testDeviceId,
+                                                   testNetId, mockInterface);
+
+    EXPECT_CALL(*mockInterface, pldmSendAtNetwork(_, _, _, _, _))
+        .WillOnce(Return(PLDM_REQUESTER_SUCCESS)); // send for Negotiate Redfish
+
+    EXPECT_CALL(*mockInterface, pldmRecvAtNetwork(_, _, _, _, _, _))
+        .WillOnce(Return(
+            PLDM_REQUESTER_RESP_MSG_TOO_SMALL)); // receive fails for negotiate
+                                                 // redfish params
+
+    // Since negotiate redfish params fail hence next command not invoked
+    OperationStatus status = stateMachineRde.get()->run();
+    stdplus::println(stderr, "Status: {}", static_cast<int>(status));
+
+    // Receive failure - hence discovery fails
+    EXPECT_EQ(status, OperationStatus::PldmRecvFailure);
+}
+
+TEST_F(RdeDiscoveryTest, StateMachineRunSendFails)
+{
+    // Fails at the first send and hence discovery should fail and no more
+    // calls to be made to the interface
+    std::unique_ptr<RdeDiscoveryStateMachine> stateMachineRde =
+        std::make_unique<RdeDiscoveryStateMachine>(testFd, testDeviceId,
+                                                   testNetId, mockInterface);
+
+    // send for Negotiate Redfish Params fails
+    EXPECT_CALL(*mockInterface, pldmSendAtNetwork(_, _, _, _, _))
+        .WillOnce(Return(PLDM_REQUESTER_SEND_FAIL));
+
+    // No receiveFrom calls are expected as it failed on first send
+    OperationStatus status = stateMachineRde.get()->run();
+    stdplus::println(stderr, "Status: {}", static_cast<int>(status));
+
+    // Send failure - hence discovery fails
+    EXPECT_EQ(status, OperationStatus::PldmSendFailure);
+}
diff --git a/tests/meson.build b/tests/meson.build
index cd2ed39..969f642 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -21,7 +21,8 @@
 
 tests = [
     'mctp_setup_test',
-    'discovery/base/base_disc_state_machine_test'
+    'discovery/base/base_disc_state_machine_test',
+    'discovery/rde/rde_disc_state_machine_test'
 ]
 
 foreach t : tests
diff --git a/util/common.hpp b/util/common.hpp
index 7bea407..9d365b9 100644
--- a/util/common.hpp
+++ b/util/common.hpp
@@ -4,10 +4,12 @@
 #include <string>
 #include <unordered_set>
 
-#define PLDM_RDE 0x06
 #define PLDM_MAX_REQUEST_BYTES 2048
 #define MAX_RETRIES_FOR_REQUEST 500
-#define MAX_RETRIES_MCTP_SOCK_FAILURE 5
+
+#define MAX_RETRIES_MCTP_SOCK_FAILURE 3 // should be always >= 1
+#define ASSERT_MIN_MCTP_RETRIES(value) assert((value) >= 1)
+
 #define MAX_LOOP_ITERATION_STATE_MACHINE 50
 #define DEFAULT_INITIAL_VAL 0
 
diff --git a/util/matcher/rde_match_handler.cpp b/util/matcher/rde_match_handler.cpp
index e9bd55d..1d072e9 100644
--- a/util/matcher/rde_match_handler.cpp
+++ b/util/matcher/rde_match_handler.cpp
@@ -12,7 +12,9 @@
 using ChangedPropertiesType = std::vector<std::pair<std::string, DbusVariant>>;
 
 RdeMatchHandler::RdeMatchHandler(int socketFd) : fd(socketFd)
-{}
+{
+    pldmInterface = std::make_shared<PldmInterface>();
+}
 
 RdeMatchHandler::~RdeMatchHandler()
 {}
@@ -20,19 +22,71 @@
 int RdeMatchHandler::initiateDiscovery(const int& fd, const std::string& udevId,
                                        const int& netId)
 {
-    int rc = 0;
     // Begin Base Discovery
     stdplus::print(stderr, "Initiating PLDM Discovery...\n");
 
-    // TODO(@harshtya): Add discovery calls
-    // TODO(@harshtya): Remove the log below after discovery calls
-    stdplus::print(stderr, "Call arguments: {}, {}, {}\n", fd, udevId, netId);
-    if (rc)
+    std::unique_ptr<BaseDiscoveryStateMachine> stateMachineBase =
+        std::make_unique<BaseDiscoveryStateMachine>(fd, udevId, netId,
+                                                    pldmInterface);
+
+    int rc = 0;
+    for (int retryCounter = 0; retryCounter < MAX_RETRIES_MCTP_SOCK_FAILURE;
+         retryCounter++)
     {
-        stdplus::print(stderr,
-                       "Failure in Base Discovery with error code: {}\n", rc);
-        return rc;
+        rc = static_cast<int>(stateMachineBase->run());
+        if (rc == 0)
+        {
+            break; // Successfully completed state machine run
+        }
+        if (retryCounter == (MAX_RETRIES_MCTP_SOCK_FAILURE - 1))
+        {
+            stdplus::println(stderr,
+                             "Initial base discovery failed with all retries.");
+            return rc;
+        }
+        stdplus::println(stderr,
+                         "Initial Base Discovery failed."
+                         "Retrying with retryCounter: {}",
+                         (retryCounter + 1));
     }
+
+    this->deviceToBaseStateMap.emplace(udevId, std::move(stateMachineBase));
+    if constexpr (DEBUG)
+    {
+        this->deviceToBaseStateMap[udevId]->printState();
+    }
+
+    std::unique_ptr<RdeDiscoveryStateMachine> stateMachineRde =
+        std::make_unique<RdeDiscoveryStateMachine>(fd, udevId, netId,
+                                                   pldmInterface);
+
+    for (int retryCounter = 0; retryCounter < MAX_RETRIES_MCTP_SOCK_FAILURE;
+         retryCounter++)
+    {
+        rc = static_cast<int>(stateMachineRde->run());
+        if (rc == 0)
+        {
+            break; // Successfully completed state machine run
+        }
+
+        if (retryCounter == (MAX_RETRIES_MCTP_SOCK_FAILURE - 1))
+        {
+            stdplus::println(stderr,
+                             "Initial RDE discovery failed with all retries.");
+            return rc;
+        }
+        stdplus::println(stderr,
+                         "Initial RDE discovery failed."
+                         "Retrying with retryCounter: {}",
+                         (retryCounter + 1));
+    }
+
+    this->deviceToRdeStateMap.emplace(udevId, std::move(stateMachineRde));
+    if constexpr (DEBUG)
+    {
+        this->deviceToRdeStateMap[udevId]->printState();
+    }
+
     return rc;
 }
 
@@ -159,7 +213,7 @@
                 continue;
             }
 
-            if (DEBUG)
+            if constexpr (DEBUG)
             {
                 stdplus::print(stderr, "New device detected: {}\n",
                                std::string(changedObject));
@@ -188,7 +242,8 @@
                 return;
             }
 
-            // TODO(@harshtya): Call RDE Setup here
+            rdeSetup(fd, objectServer, std::string(changedObject), port, udevId,
+                     vendorId, prefixPath);
         }
     });
 }
@@ -216,7 +271,7 @@
             if (it != objectPathToDeviceIdMap.end())
             {
                 cleanupMctpLink(it->second);
-                // TODO (@harshtya): clean up the Rde device from maps
+                cleanupDiscoveryStates(it->second);
                 // TODO (@harshtya): clean up the dictionaries
                 objectPathToDeviceIdMap.erase(std::string(changedObject));
                 deviceToNetIdMap.erase(it->second);
@@ -234,7 +289,18 @@
     objectServer.add_manager("/xyz/openbmc_project/rde_devices");
     std::string prefixPath = "/xyz/openbmc_project/rde_devices/";
 
-    // TODO(@harshtya): Add scan for existing devices
+    try
+    {
+        scanForExistingDevices(this->fd, objectServer, prefixPath, systemBus);
+    }
+    catch (const std::exception& e)
+    {
+        // skip scan and wait for new device detection
+        stdplus::println(
+            stderr,
+            "Some exception occured while scanning for existing rde devices {}",
+            e.what());
+    }
 
     // Initialize the match handler for interfacesAdded
     auto matchAdd =
@@ -257,7 +323,7 @@
     int netId = setupOnePort(port, udevId); // MCTP Setup
     deviceToNetIdMap.emplace(udevId, netId);
     int rc = initiateDiscovery(fd, udevId, netId);
-    if (rc)
+    if (rc != 0)
     {
         stdplus::print(stderr,
                        "PLDM/RDE Discovery failed for device: {}"
@@ -268,7 +334,7 @@
 
     std::string objectPath = std::format("{}{}", prefixPath, udevId);
 
-    if (DEBUG)
+    if constexpr (DEBUG)
     {
         stdplus::print(stderr, "Creating object path for RDE Operation: {}\n ",
                        objectPath);
@@ -283,10 +349,27 @@
     iface->register_property("UDEVID", udevId,
                              sdbusplus::asio::PropertyPermission::readOnly);
 
-    // TODO(@harshtya): Add RDE OPeration Handler Dbus method
+    // TODO(@harshtya): Add RDE Operation Handler Dbus method
 
     iface->initialize();
     deviceToDbusIntfMap.emplace(std::string(changedObject), iface);
     objectPathToDeviceIdMap.emplace(std::string(changedObject), udevId);
     return 0;
 }
+
+void RdeMatchHandler::cleanupDiscoveryStates(const std::string& udevId)
+{
+    // Remove Base discovery state if exists
+    auto it = deviceToBaseStateMap.find(udevId);
+    if (it != deviceToBaseStateMap.end())
+    {
+        deviceToBaseStateMap.erase(udevId);
+    }
+
+    // Remove RDE discovery state if exists
+    it = deviceToRdeStateMap.find(udevId);
+    if (it != deviceToRdeStateMap.end())
+    {
+        deviceToRdeStateMap.erase(udevId);
+    }
+}
diff --git a/util/matcher/rde_match_handler.hpp b/util/matcher/rde_match_handler.hpp
index 84d284f..afd865f 100644
--- a/util/matcher/rde_match_handler.hpp
+++ b/util/matcher/rde_match_handler.hpp
@@ -1,6 +1,10 @@
 #ifndef RDE_MATCH_HANDLER_HPP
 #define RDE_MATCH_HANDLER_HPP
 
+#include "util/state_machine/discovery/base/base_disc_state_machine.hpp"
+#include "util/state_machine/discovery/rde/rde_disc_state_machine.hpp"
+#include "util/state_machine/state_machine_factory.hpp"
+
 #include <sdbusplus/asio/connection.hpp>
 #include <sdbusplus/asio/object_server.hpp>
 #include <sdbusplus/asio/property.hpp>
@@ -33,6 +37,11 @@
 
     std::unordered_map<std::string, std::string> objectPathToDeviceIdMap;
 
+    std::unordered_map<std::string, std::unique_ptr<StateMachineFactory>>
+        deviceToBaseStateMap;
+
+    std::unordered_map<std::string, std::unique_ptr<StateMachineFactory>>
+        deviceToRdeStateMap;
     /**
      * @brief Scans for existing USB devices in the Entity Manager that can be
      * RDE Devices as soon as the RDE Daemon boots up
@@ -109,5 +118,14 @@
                  const std::string& changedObject, const std::string& port,
                  const std::string& udevId, const std::string& vendorId,
                  const std::string& prefixPath);
+
+    /**
+     * @brief Cleans up the objects of State Machine when device is removed
+     *
+     * @param[in] udevId - Unique udev identifier for the device removed
+     */
+    void cleanupDiscoveryStates(const std::string& udevId);
+
+    std::shared_ptr<PldmInterface> pldmInterface;
 };
 #endif // RDE_MATCH_HANDLER_HPP
diff --git a/util/resource_id_mapper.hpp b/util/resource_id_mapper.hpp
index 4ddf223..e56dff3 100644
--- a/util/resource_id_mapper.hpp
+++ b/util/resource_id_mapper.hpp
@@ -202,7 +202,7 @@
     auto it = resourceIdMap.find(uri);
     if (it != resourceIdMap.end())
     {
-        if (DEBUG)
+        if constexpr (DEBUG)
         {
             stdplus::print(stderr, "Resource id found: {}\n",
                            std::to_string(it->second));
diff --git a/util/state_machine/discovery/base/base_disc_state_machine.cpp b/util/state_machine/discovery/base/base_disc_state_machine.cpp
index 23973d2..9700150 100644
--- a/util/state_machine/discovery/base/base_disc_state_machine.cpp
+++ b/util/state_machine/discovery/base/base_disc_state_machine.cpp
@@ -8,7 +8,7 @@
 
 BaseDiscoveryStateMachine::BaseDiscoveryStateMachine(
     int fd, const std::string& deviceName, int netId,
-    std::shared_ptr<PldmInterface> pldmInterface) :
+    const std::shared_ptr<PldmInterface>& pldmInterface) :
     fd(fd),
     deviceName(deviceName), netId(netId), pldmInterface(pldmInterface)
 {
diff --git a/util/state_machine/discovery/base/base_disc_state_machine.hpp b/util/state_machine/discovery/base/base_disc_state_machine.hpp
index d773fcc..7d15984 100644
--- a/util/state_machine/discovery/base/base_disc_state_machine.hpp
+++ b/util/state_machine/discovery/base/base_disc_state_machine.hpp
@@ -28,8 +28,9 @@
 class BaseDiscoveryStateMachine : public StateMachineFactory
 {
   public:
-    BaseDiscoveryStateMachine(int fd, const std::string& deviceName, int netId,
-                              std::shared_ptr<PldmInterface> pldmInterface);
+    BaseDiscoveryStateMachine(
+        int fd, const std::string& deviceName, int netId,
+        const std::shared_ptr<PldmInterface>& pldmInterface);
 
     OperationStatus run() override;
 
diff --git a/util/state_machine/discovery/rde/rde_disc_state_machine.cpp b/util/state_machine/discovery/rde/rde_disc_state_machine.cpp
new file mode 100644
index 0000000..2126635
--- /dev/null
+++ b/util/state_machine/discovery/rde/rde_disc_state_machine.cpp
@@ -0,0 +1,293 @@
+#include "rde_disc_state_machine.hpp"
+
+#include "libpldm/base.h"
+#include "libpldm/pldm.h"
+
+#include "interface/pldm_interface.hpp"
+
+#include <common.hpp>
+#include <stdplus/print.hpp>
+
+#include <cstdint>
+#include <iostream>
+#include <optional>
+#include <set>
+#include <unordered_map>
+
+std::unordered_map<uint8_t, int> rdeCommandRequestSize = {
+    {PLDM_NEGOTIATE_REDFISH_PARAMETERS, 3},
+    {PLDM_NEGOTIATE_MEDIUM_PARAMETERS, 4},
+    {PLDM_GET_SCHEMA_DICTIONARY, 5},
+    {PLDM_RDE_MULTIPART_RECEIVE, 7}};
+
+RdeDiscoveryStateMachine::RdeDiscoveryStateMachine(
+    int fd, const std::string& deviceName, int netId,
+    const std::shared_ptr<PldmInterface>& pldmInterface) :
+    fd(fd),
+    deviceName(deviceName), netId(netId), pldmInterface(pldmInterface)
+{
+    this->initialized = true;
+    this->requesterStatus = StateMachineStatus::NoPendingAction;
+    this->eid = DEST_EID;
+    this->instanceId = INSTANCE_ID;
+    this->mcFeatures = {.value = 102};
+}
+
+OperationStatus RdeDiscoveryStateMachine::run()
+{
+    stdplus::println("Triggering RDE discovery...");
+    if (!this->initialized &&
+        (this->requesterStatus != StateMachineStatus::NoPendingAction))
+    {
+        return OperationStatus::StateMachineInitializationError;
+    }
+
+    this->nextCommand = PLDM_NEGOTIATE_REDFISH_PARAMETERS;
+    this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
+
+    for (int retryCounter = 0; retryCounter < RDE_REQUEST_RETRIES;
+         retryCounter++)
+    {
+        if (this->requesterStatus == StateMachineStatus::NoPendingAction)
+        {
+
+            stdplus::println(stderr,
+                             "RDE Negotiate discovery successfully completed!");
+            break;
+        }
+        OperationStatus status = triggerNextCommand();
+        if (status != OperationStatus::Success)
+        {
+            stdplus::println(
+                stderr, "RDE discovery failed at command: {} with status: {}",
+                std::to_string(this->nextCommand), static_cast<int>(status));
+            return status;
+        }
+    }
+
+    return OperationStatus::Success;
+}
+
+OperationStatus RdeDiscoveryStateMachine::triggerNextCommand()
+{
+    switch (this->nextCommand)
+    {
+        case PLDM_NEGOTIATE_REDFISH_PARAMETERS:
+        {
+            return processNegotiateRedfishParametersRequest();
+        }
+        case PLDM_NEGOTIATE_MEDIUM_PARAMETERS:
+        {
+            return processNegotiateMediumParameters();
+        }
+
+        default:
+            return OperationStatus::OperationFailure;
+    }
+    return OperationStatus::Success;
+}
+
+OperationStatus RdeDiscoveryStateMachine::pushCommandResponse(
+    const struct pldm_msg* respMsg, size_t respSize)
+{
+    switch (this->nextCommand)
+    {
+        case PLDM_NEGOTIATE_REDFISH_PARAMETERS:
+        {
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            int rc = decode_negotiate_redfish_parameters_resp(
+                respMsg, respSize - sizeof(struct pldm_msg_hdr),
+                &completionCode, &(this->rdeDeviceInfo));
+            if ((rc != 0) || (completionCode != 0))
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::println(
+                    stderr,
+                    "Negotiate redfish parameters response decode failed with "
+                    "rc: {} and completion code:",
+                    rc, completionCode);
+                return OperationStatus::IncorrectResponseMsg;
+            }
+            this->nextCommand = PLDM_NEGOTIATE_MEDIUM_PARAMETERS;
+            this->requesterStatus = StateMachineStatus::ReadyToPickNextRequest;
+            return OperationStatus::Success;
+        }
+        case PLDM_NEGOTIATE_MEDIUM_PARAMETERS:
+        {
+            uint8_t completionCode = DEFAULT_INITIAL_VAL;
+            uint32_t maxDeviceTransferSize = DEFAULT_INITIAL_VAL;
+            int rc = decode_negotiate_medium_parameters_resp(
+                respMsg, respSize - sizeof(struct pldm_msg_hdr),
+                &completionCode, &maxDeviceTransferSize);
+            if ((rc != 0) || (completionCode != 0))
+            {
+                this->requesterStatus = StateMachineStatus::RequestFailed;
+                stdplus::println(
+                    stderr,
+                    "Negotiate medium parameters response decode failed with "
+                    "rc: {} and completion code:",
+                    rc, completionCode);
+                return OperationStatus::IncorrectResponseMsg;
+            }
+            this->rdeDeviceInfo.device_maximum_transfer_chunk_size =
+                maxDeviceTransferSize;
+
+            this->negotiatedTransferSize =
+                (maxDeviceTransferSize >
+                 RdeDiscoveryStateMachine::mcTransferSize)
+                    ? RdeDiscoveryStateMachine::mcTransferSize
+                    : maxDeviceTransferSize;
+
+            this->nextCommand =
+                static_cast<int>(OperationStatus::NoNextCommandFound);
+            this->requesterStatus = StateMachineStatus::NoPendingAction;
+            return OperationStatus::Success;
+        }
+        default:
+            return OperationStatus::OperationFailure;
+    }
+}
+
+OperationStatus
+    RdeDiscoveryStateMachine::processNegotiateRedfishParametersRequest()
+{
+    stdplus::println(stderr, "Trigerring negotiate redfish params...");
+    int requestBytes = rdeCommandRequestSize[PLDM_NEGOTIATE_REDFISH_PARAMETERS];
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    int rc = encode_negotiate_redfish_parameters_req(
+        this->instanceId, RdeDiscoveryStateMachine::mcConcurrency,
+        &(this->mcFeatures), request);
+    if (rc)
+    {
+        stdplus::println(
+            stderr,
+            "Encoding Negotiate Redfish Params request failed in RDE discovery"
+            "with rc: {}",
+            rc);
+        return OperationStatus::EncodingRequestFailure;
+    }
+
+    if (pldmInterface->pldmSendAtNetwork(this->eid, this->netId, this->fd,
+                                         requestMsg.data(), requestMsg.size()))
+    {
+        this->requesterStatus = StateMachineStatus::RequestFailed;
+        return OperationStatus::PldmSendFailure;
+    }
+    std::vector<uint8_t> response(
+        sizeof(pldm_msg_hdr) + RDE_NEGOTIATE_REDFISH_PARAMS_RESP_SIZE, 0);
+    uint8_t* responseMsg = response.data();
+    size_t responseMsgSize = response.size();
+    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
+
+    if (pldmInterface->pldmRecvAtNetwork(this->eid, this->netId, this->fd,
+                                         this->instanceId, &responseMsg,
+                                         &responseMsgSize))
+    {
+        this->requesterStatus = StateMachineStatus::RequestFailed;
+        return OperationStatus::PldmRecvFailure;
+    }
+
+    stdplus::println(stderr,
+                     "Pushing Response for RDE_NEGOTIATE_REDFISH_PARAMS...");
+    OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
+    if (status != OperationStatus::Success)
+    {
+        stdplus::println(stderr,
+                         "Failed to push response for Negotiate Redfish"
+                         " Params in RDE discovery with status: {}",
+                         static_cast<int>(status));
+    }
+    return status;
+}
+
+OperationStatus RdeDiscoveryStateMachine::processNegotiateMediumParameters()
+{
+    stdplus::println(stderr, "Trigerring negotiate medium params...");
+    int requestBytes = rdeCommandRequestSize[PLDM_NEGOTIATE_MEDIUM_PARAMETERS];
+    std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + requestBytes);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    int rc = encode_negotiate_medium_parameters_req(
+        this->instanceId, RdeDiscoveryStateMachine::mcTransferSize, request);
+    if (rc)
+    {
+        stdplus::println(
+            stderr,
+            "Encoding Negotiate Medium Params request failed in RDE discovery"
+            "with rc: {}",
+            rc);
+        return OperationStatus::EncodingRequestFailure;
+    }
+
+    if (pldmInterface->pldmSendAtNetwork(this->eid, this->netId, this->fd,
+                                         requestMsg.data(), requestMsg.size()))
+    {
+        this->requesterStatus = StateMachineStatus::RequestFailed;
+        return OperationStatus::PldmSendFailure;
+    }
+
+    std::vector<uint8_t> response(
+        sizeof(pldm_msg_hdr) + RDE_NEGOTIATE_REDFISH_MEDIUM_PARAMS_RESP_SIZE,
+        0);
+    uint8_t* responseMsg = response.data();
+    size_t responseMsgSize = response.size();
+    auto responsePtr = reinterpret_cast<struct pldm_msg*>(responseMsg);
+    if (pldmInterface->pldmRecvAtNetwork(this->eid, this->netId, this->fd,
+                                         this->instanceId, &responseMsg,
+                                         &responseMsgSize))
+    {
+        this->requesterStatus = StateMachineStatus::RequestFailed;
+        return OperationStatus::PldmRecvFailure;
+    }
+    stdplus::println(stderr,
+                     "Pushing Response for RDE_NEGOTIATE_MED_PARAMS...");
+    OperationStatus status = pushCommandResponse(responsePtr, responseMsgSize);
+    if (status != OperationStatus::Success)
+    {
+        stdplus::println(stderr,
+                         "Failed to push response for RDE Negotiate "
+                         "Medium in RDE discovery with rc: {}",
+                         static_cast<int>(status));
+    }
+    return status;
+}
+
+void RdeDiscoveryStateMachine::printState()
+{
+    stdplus::println(stderr,
+                     "====================================================");
+    stdplus::println(stderr, "***RDE Negotiate/Medium Parameters Begins***");
+    stdplus::println(stderr,
+                     "====================================================");
+
+    stdplus::println(stderr, "MC Concurrency: {}",
+                     RdeDiscoveryStateMachine::mcConcurrency);
+
+    stdplus::println(stderr, "MC Transfer Size: {}",
+                     RdeDiscoveryStateMachine::mcTransferSize);
+
+    stdplus::println(stderr, "RDE device Concurrency: {}",
+                     this->rdeDeviceInfo.device_concurrency);
+
+    stdplus::println(stderr, "RDE device Device Capabilities Flag: {} ",
+                     this->rdeDeviceInfo.device_capabilities_flag.byte);
+
+    stdplus::println(stderr, "RDE device Device Feature Support: {}",
+                     this->rdeDeviceInfo.device_feature_support.value);
+
+    stdplus::println(stderr, "RDE device Device Configuration Signature: {}",
+                     this->rdeDeviceInfo.device_configuration_signature);
+
+    stdplus::println(
+        stderr, "RDE device Device Provider Name (Eid): {}",
+        this->rdeDeviceInfo.device_provider_name.string_length_bytes);
+
+    stdplus::println(stderr, "Negotiated Transfer Size (Medium Parameters): {}",
+                     this->negotiatedTransferSize);
+
+    stdplus::println(stderr,
+                     "====================================================");
+    stdplus::println(stderr, "***RDE Negotiate/Medium Parameters Ends***");
+    stdplus::println(stderr,
+                     "====================================================");
+}
diff --git a/util/state_machine/discovery/rde/rde_disc_state_machine.hpp b/util/state_machine/discovery/rde/rde_disc_state_machine.hpp
new file mode 100644
index 0000000..58bc8fa
--- /dev/null
+++ b/util/state_machine/discovery/rde/rde_disc_state_machine.hpp
@@ -0,0 +1,76 @@
+#ifndef RDE_DISC_STATE_MACHINE_HPP
+#define RDE_DISC_STATE_MACHINE_HPP
+
+#include "common.hpp"
+#include "interface/pldm_rde.hpp"
+#include "pldm_interface.hpp"
+#include "state_machine_factory.hpp"
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#define RDE_REQUEST_RETRIES 50
+#define RDE_NEGOTIATE_REDFISH_PARAMS_RESP_SIZE 12
+#define RDE_NEGOTIATE_REDFISH_MEDIUM_PARAMS_RESP_SIZE 6
+#define RDE_GET_DICT_SCHEMA_RESP_SIZE 6
+#define MC_CONCURRENCY 3
+#define INITIAL_TRANSFER_HANDLE 0x00
+#define DICTIONARY_EXTRACTION_RETRIES 3
+
+class RdeDiscoveryStateMachine : public StateMachineFactory
+{
+  public:
+    static constexpr uint8_t mcConcurrency = MC_CONCURRENCY;
+    static constexpr uint32_t mcTransferSize = PLDM_MAX_REQUEST_BYTES;
+
+    RdeDiscoveryStateMachine(
+        int fd, const std::string& deviceName, int netId,
+        const std::shared_ptr<PldmInterface>& pldmInterface);
+
+    OperationStatus run() override;
+
+    OperationStatus triggerNextCommand() override;
+
+    OperationStatus pushCommandResponse(const struct pldm_msg* respMsg,
+                                        size_t respSize) override;
+
+    void printState() override;
+
+    class Context
+    {
+      public:
+        Context();
+
+      private:
+        bool initialized;
+        int nextCommand;
+        int requesterStatus;
+        bool contextStatus;
+    };
+
+  private:
+    OperationStatus processNegotiateRedfishParametersRequest();
+    OperationStatus processNegotiateMediumParameters();
+    OperationStatus processGetSchemaDictionary();
+    OperationStatus processGetMultipart();
+
+    int fd;
+    std::string deviceName;
+    int netId;
+    uint8_t eid;
+    int instanceId;
+
+    // Store all the contexts
+    bitfield16_t mcFeatures;
+    pldm_rde_device_info rdeDeviceInfo;
+    uint32_t negotiatedTransferSize;
+
+    bool initialized;
+    int nextCommand;
+    StateMachineStatus requesterStatus;
+    std::vector<Context> contexts;
+
+    std::shared_ptr<PldmInterface> pldmInterface;
+};
+#endif // RDE_DISC_STATE_MACHINE_HPP