Add support for using base type multipart receive

This change adds the support for using PLDM type 0 multipart
receive for other PLDM types.

Tested:
Tested with unit tests

Google-Bug-Id: 423027264
Change-Id: I7a158838623d273164b4e72aaae0821de5a50bdf
Signed-off-by: Kasun Athukorala <kasunath@google.com>
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp
index 318c3ee..311ad1a 100644
--- a/libpldmresponder/base.cpp
+++ b/libpldmresponder/base.cpp
@@ -37,7 +37,8 @@
 static const std::map<Type, Cmd> capabilities{
     {PLDM_BASE,
      {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES,
-      PLDM_GET_PLDM_COMMANDS, PLDM_NEGOTIATE_TRANSFER_PARAMETERS}},
+      PLDM_GET_PLDM_COMMANDS, PLDM_NEGOTIATE_TRANSFER_PARAMETERS,
+      PLDM_MULTIPART_RECEIVE}},
     {PLDM_PLATFORM,
      {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES, PLDM_SET_EVENT_RECEIVER,
       PLDM_GET_SENSOR_READING, PLDM_GET_STATE_SENSOR_READINGS,
@@ -311,6 +312,36 @@
     return type_it->second;
 }
 
+Response Handler::getMultipartReceive(pldm_tid_t tid, const pldm_msg* request,
+                                      size_t payloadLength)
+{
+    if (payloadLength != PLDM_MULTIPART_RECEIVE_REQ_BYTES)
+    {
+        error("Invalid MultipartReceive request length. Received: '{LEN}'",
+              "LEN", payloadLength);
+        return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
+    }
+
+    // First byte in the payload is the sub PLDM type.
+    uint8_t pldmType = *request->payload;
+
+    auto it = multipartReceivehandlers.find(pldmType);
+    if (it == multipartReceivehandlers.end())
+    {
+        error("No multipart receive handler registered for PLDM type '{TYPE}'",
+              "TYPE", pldmType);
+        return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
+    }
+
+    return it->second->handleMultipartReceive(tid, request, payloadLength);
+}
+
+void Handler::registerMultipartReceiveHandler(uint8_t pldmType,
+                                              CmdHandler* handler)
+{
+    multipartReceivehandlers.emplace(pldmType, handler);
+}
+
 } // namespace base
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp
index 98d1554..071d5e9 100644
--- a/libpldmresponder/base.hpp
+++ b/libpldmresponder/base.hpp
@@ -54,6 +54,11 @@
                              return this->getNegotiateTransferParam(
                                  tid, request, payloadLength);
                          });
+        handlers.emplace(PLDM_MULTIPART_RECEIVE, [this](pldm_tid_t tid,
+                                                        const pldm_msg* request,
+                                                        size_t payloadLength) {
+            return this->getMultipartReceive(tid, request, payloadLength);
+        });
     }
 
     /** @brief Handler for getPLDMTypes
@@ -108,6 +113,19 @@
     Response getNegotiateTransferParam(pldm_tid_t tid, const pldm_msg* request,
                                        size_t payloadLength);
 
+    /** @brief Handler for MultipartReceive requests
+     *
+     * This will call the corresponding MultipartReceive handler based on the
+     * PLDM type in the request.
+     *
+     *  @param[in] tid - TID of the requester
+     *  @param[in] request - Request message payload
+     *  @param[in] payloadLength - Request message payload length
+     *  @param[return] Response - PLDM Response message
+     */
+    Response getMultipartReceive(pldm_tid_t tid, const pldm_msg* request,
+                                 size_t payloadLength);
+
     /* @brief Method to set the oem platform handler in base handler class
      *
      * @param[in] handler - oem platform handler
@@ -129,6 +147,16 @@
      */
     uint16_t getNegotiatedPartSize(pldm_tid_t tid, uint8_t pldmType);
 
+    /** @brief Registers a handler for MultipartReceive commands for a specific
+     * PLDM type.
+     *
+     *  @param[in] pldmType - The PLDM type for which the handler is registered.
+     *  @param[in] handler - A pointer to the CmdHandler instance that will
+     *                       handle the MultipartReceive command for the given
+     *                       PLDM type.
+     */
+    void registerMultipartReceiveHandler(uint8_t pldmType, CmdHandler* handler);
+
   private:
     /** @brief reference of main event loop of pldmd, primarily used to schedule
      *  work
@@ -144,6 +172,9 @@
     /** Negotiated multi part size of each possible PLDM type for different
      * devices. */
     std::map<pldm_tid_t, std::map<uint8_t, uint16_t>> negotiatedPartSizes;
+
+    /** Store handlers to be called for  multipart receive commands*/
+    std::map<uint8_t, CmdHandler*> multipartReceivehandlers;
 };
 
 } // namespace base
diff --git a/libpldmresponder/file_transfer.cpp b/libpldmresponder/file_transfer.cpp
index 2e3b866..1374017 100644
--- a/libpldmresponder/file_transfer.cpp
+++ b/libpldmresponder/file_transfer.cpp
@@ -103,12 +103,6 @@
         [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) {
             return this->dfClose(request, payloadLength);
         });
-
-    handlers.emplace(
-        PLDM_FILE_CMD_DF_READ,
-        [this](pldm_tid_t tid, const pldm_msg* request, size_t payloadLength) {
-            return this->dfRead(tid, request, payloadLength);
-        });
 }
 
 std::optional<uint16_t> Handler::getFreeFileDescriptor(uint16_t fileIdentifier)
@@ -576,6 +570,12 @@
     return CmdHandler::ccOnlyResponse(request, PLDM_ERROR);
 }
 
+Response Handler::handleMultipartReceive(
+    pldm_tid_t tid, const pldm_msg* request, size_t reqMsgLen)
+{
+    return dfRead(tid, request, reqMsgLen);
+}
+
 } // namespace file_transfer
 } // namespace responder
 } // namespace pldm
diff --git a/libpldmresponder/file_transfer.hpp b/libpldmresponder/file_transfer.hpp
index 88f7500..8677093 100644
--- a/libpldmresponder/file_transfer.hpp
+++ b/libpldmresponder/file_transfer.hpp
@@ -122,6 +122,9 @@
     Response dfRead(pldm_tid_t tid, const pldm_msg* request,
                     size_t payloadLength);
 
+    Response handleMultipartReceive(pldm_tid_t tid, const pldm_msg* request,
+                                    size_t reqMsgLen) override;
+
     responder::base::Handler* baseHandler;
 
     // PLDM Platform type handler. File pointers will be initialized during file
diff --git a/libpldmresponder/test/libpldmresponder_base_test.cpp b/libpldmresponder/test/libpldmresponder_base_test.cpp
index 93a7c7d..7e271ef 100644
--- a/libpldmresponder/test/libpldmresponder_base_test.cpp
+++ b/libpldmresponder/test/libpldmresponder_base_test.cpp
@@ -55,7 +55,7 @@
     uint8_t* payload_ptr = responsePtr->payload;
     ASSERT_EQ(payload_ptr[0], 0);
     ASSERT_EQ(payload_ptr[1], 188); // 188 = 0b10111100
-    ASSERT_EQ(payload_ptr[2], 0);
+    ASSERT_EQ(payload_ptr[2], 2);   // 2 = 0b00000010
 }
 
 TEST_F(TestBaseCommands, testGetPLDMCommandsBadRequest)
diff --git a/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp b/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp
index 313f5d3..ef7b2c0 100644
--- a/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp
+++ b/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp
@@ -1,3 +1,4 @@
+#include "libpldmresponder/base.hpp"
 #include "libpldmresponder/file_transfer.hpp"
 #include "libpldmresponder/platform.hpp"
 
@@ -124,7 +125,9 @@
         platformHandler(nullptr, 0, nullptr, pdrDir, pdrRepo.get(), nullptr,
                         nullptr, nullptr, nullptr, nullptr, event, true),
         baseHandler(event), handler(&baseHandler, &platformHandler)
-    {}
+    {
+        baseHandler.registerMultipartReceiveHandler(PLDM_FILE, &handler);
+    }
 
     void SetUp() override
     {
@@ -295,7 +298,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handlers
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse.data(), nullptr);
 
@@ -514,7 +517,7 @@
 
         // Send the request to the handler
         auto readResponse =
-            handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+            baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                            PLDM_MULTIPART_RECEIVE_REQ_BYTES);
         ASSERT_NE(readResponse.data(), nullptr);
 
@@ -561,7 +564,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse.data(), nullptr);
     auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
@@ -626,7 +629,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse.data(), nullptr);
     auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data());
@@ -696,7 +699,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse1 = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest1,
+    auto readResponse1 = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest1,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse1.data(), nullptr);
     auto readResponsePtr1 = reinterpret_cast<pldm_msg*>(readResponse1.data());
@@ -735,7 +738,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse2 = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest2,
+    auto readResponse2 = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest2,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse2.data(), nullptr);
 
@@ -808,7 +811,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse1 = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse1 = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse1.data(), nullptr);
     auto readResponsePtr1 = reinterpret_cast<pldm_msg*>(readResponse1.data());
@@ -843,7 +846,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse2 = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse2 = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse2.data(), nullptr);
     auto readResponsePtr2 = reinterpret_cast<pldm_msg*>(readResponse2.data());
@@ -874,7 +877,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse3 = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse3 = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(readResponse3.data(), nullptr);
     auto readResponsePtr3 = reinterpret_cast<pldm_msg*>(readResponse3.data());
@@ -942,7 +945,7 @@
 
     // Send the request to the handler
     auto firstReadResponse =
-        handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+        baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(firstReadResponse.data(), nullptr);
     auto firstReadResponsePtr =
@@ -960,7 +963,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto abortResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto abortResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
 
     // Verify the abort response
@@ -1028,7 +1031,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
 
     // Verify the error response
@@ -1092,7 +1095,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
 
     // Verify the error response
@@ -1156,7 +1159,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto readResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto readResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
 
     // Verify the error response
@@ -1223,7 +1226,7 @@
 
     // Send the request to the handler
     auto firstReadResponse =
-        handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+        baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(firstReadResponse.data(), nullptr);
     auto firstReadResponsePtr =
@@ -1251,7 +1254,7 @@
     ASSERT_EQ(rc, 0);
 
     // Send the request to the handler
-    auto errorResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto errorResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         readRequestPayloadLength);
 
     // Verify the error response
@@ -1316,7 +1319,7 @@
                                                 &readRequestPayloadLength);
     ASSERT_EQ(rc, 0);
     auto firstReadResponse =
-        handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+        baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                        PLDM_MULTIPART_RECEIVE_REQ_BYTES);
     ASSERT_NE(firstReadResponse.data(), nullptr);
     auto firstReadResponsePtr =
@@ -1343,7 +1346,7 @@
     rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest,
                                                 &readRequestPayloadLength);
     ASSERT_EQ(rc, 0);
-    auto errorResponse = handler.handle(0, PLDM_FILE_CMD_DF_READ, readRequest,
+    auto errorResponse = baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest,
                                         PLDM_MULTIPART_RECEIVE_REQ_BYTES);
 
     // Verify the error response
diff --git a/pldmd/handler.hpp b/pldmd/handler.hpp
index 89b8a7f..b8c97e1 100644
--- a/pldmd/handler.hpp
+++ b/pldmd/handler.hpp
@@ -56,6 +56,12 @@
         return response;
     }
 
+    virtual Response handleMultipartReceive(pldm_tid_t, const pldm_msg* request,
+                                            size_t /*reqMsgLen*/)
+    {
+        return ccOnlyResponse(request, PLDM_ERROR);
+    }
+
   protected:
     /** @brief map of PLDM command code to handler - to be populated by derived
      *         classes.