implement commands for dump xfer

This commit implements the writeFile command
for dumpHandler in PLDM oem. This is for offloading
the dump from host memory to an external location
via bmc. Also it implements the newfileAvailable
notification handler in libpldmresponder.This caters
to the new dump notification coming from the Host

Change-Id: Ibf7c1facea282ec4f772dfee646cca9f7877bb7d
Signed-off-by: Sampa Misra <sampmisr@in.ibm.com>
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index 15a6818..53f4343 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -51,6 +51,7 @@
 	PLDM_FILE_TYPE_PEL = 0,
 	PLDM_FILE_TYPE_LID_PERM = 1,
 	PLDM_FILE_TYPE_LID_TEMP = 2,
+	PLDM_FILE_TYPE_DUMP = 3,
 };
 
 #define PLDM_RW_FILE_MEM_REQ_BYTES 20
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index bf622c3..9322d9d 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -611,6 +611,56 @@
                                   payloadLength);
 }
 
+Response Handler::writeFileByType(const pldm_msg* request, size_t payloadLength)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    if (payloadLength != PLDM_RW_FILE_BY_TYPE_REQ_BYTES)
+    {
+        encode_rw_file_by_type_resp(request->hdr.instance_id,
+                                    PLDM_WRITE_FILE_BY_TYPE,
+                                    PLDM_ERROR_INVALID_LENGTH, 0, responsePtr);
+        return response;
+    }
+    uint16_t fileType{};
+    uint32_t fileHandle{};
+    uint32_t offset{};
+    uint32_t length{};
+
+    auto rc = decode_rw_file_by_type_req(request, payloadLength, &fileType,
+                                         &fileHandle, &offset, &length);
+    if (rc != PLDM_SUCCESS)
+    {
+        encode_rw_file_by_type_resp(request->hdr.instance_id,
+                                    PLDM_WRITE_FILE_BY_TYPE, rc, 0,
+                                    responsePtr);
+        return response;
+    }
+
+    std::unique_ptr<FileHandler> handler{};
+    try
+    {
+        handler = getHandlerByType(fileType, fileHandle);
+    }
+    catch (const InternalFailure& e)
+    {
+        std::cerr << "unknown file type, TYPE=" << fileType << "\n";
+        encode_rw_file_by_type_resp(request->hdr.instance_id,
+                                    PLDM_WRITE_FILE_BY_TYPE,
+                                    PLDM_INVALID_FILE_TYPE, 0, responsePtr);
+        return response;
+    }
+
+    rc = handler->write(reinterpret_cast<const char*>(
+                            request->payload + PLDM_RW_FILE_BY_TYPE_RESP_BYTES),
+                        offset, length);
+    encode_rw_file_by_type_resp(request->hdr.instance_id,
+                                PLDM_WRITE_FILE_BY_TYPE, rc, length,
+                                responsePtr);
+    return response;
+}
+
 Response Handler::readFileByType(const pldm_msg* request, size_t payloadLength)
 {
     Response response(sizeof(pldm_msg_hdr) + PLDM_RW_FILE_BY_TYPE_RESP_BYTES);
@@ -687,6 +737,7 @@
     {
         handler = getHandlerByType(fileType, fileHandle);
     }
+
     catch (const InternalFailure& e)
     {
         encode_file_ack_resp(request->hdr.instance_id, PLDM_INVALID_FILE_TYPE,
@@ -735,6 +786,44 @@
     return response;
 }
 
+Response Handler::newFileAvailable(const pldm_msg* request,
+                                   size_t payloadLength)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_NEW_FILE_RESP_BYTES);
+
+    if (payloadLength != PLDM_NEW_FILE_REQ_BYTES)
+    {
+        return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
+    }
+    uint16_t fileType{};
+    uint32_t fileHandle{};
+    uint64_t length{};
+
+    auto rc = decode_new_file_req(request, payloadLength, &fileType,
+                                  &fileHandle, &length);
+
+    if (rc != PLDM_SUCCESS)
+    {
+        return CmdHandler::ccOnlyResponse(request, rc);
+    }
+
+    std::unique_ptr<FileHandler> handler{};
+    try
+    {
+        handler = getHandlerByType(fileType, fileHandle);
+    }
+    catch (const InternalFailure& e)
+    {
+        std::cerr << "unknown file type, TYPE=" << fileType << "\n";
+        return CmdHandler::ccOnlyResponse(request, PLDM_INVALID_FILE_TYPE);
+    }
+
+    rc = handler->newFileAvailable(length);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+    encode_new_file_resp(request->hdr.instance_id, rc, responsePtr);
+    return response;
+}
+
 } // namespace oem_ibm
 } // namespace responder
 } // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index f0555d7..9ff8f86 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -173,6 +173,11 @@
                                                         size_t payloadLength) {
             return this->readFileByType(request, payloadLength);
         });
+        handlers.emplace(PLDM_WRITE_FILE_BY_TYPE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->writeFileByType(request,
+                                                          payloadLength);
+                         });
         handlers.emplace(PLDM_GET_FILE_TABLE,
                          [this](const pldm_msg* request, size_t payloadLength) {
                              return this->getFileTable(request, payloadLength);
@@ -194,6 +199,11 @@
                              return this->getAlertStatus(request,
                                                          payloadLength);
                          });
+        handlers.emplace(PLDM_NEW_FILE_AVAILABLE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->newFileAvailable(request,
+                                                           payloadLength);
+                         });
     }
 
     /** @brief Handler for readFileIntoMemory command
@@ -235,7 +245,7 @@
     Response readFileByTypeIntoMemory(const pldm_msg* request,
                                       size_t payloadLength);
 
-    /** @brief Handler for readFileByType command
+    /** @brief Handler for writeFileByType command
      *
      *  @param[in] request - pointer to PLDM request payload
      *  @param[in] payloadLength - length of the message
@@ -244,6 +254,8 @@
      */
     Response readFileByType(const pldm_msg* request, size_t payloadLength);
 
+    Response writeFileByType(const pldm_msg* request, size_t payloadLength);
+
     /** @brief Handler for GetFileTable command
      *
      *  @param[in] request - pointer to PLDM request payload
@@ -281,6 +293,15 @@
      *  @return PLDM response message
      */
     Response getAlertStatus(const pldm_msg* request, size_t payloadLength);
+
+    /** @brief Handler for newFileAvailable command
+     *
+     *  @param[in] request - PLDM request msg
+     *  @param[in] payloadLength - length of the message payload
+     *
+     *  @return PLDM response message
+     */
+    Response newFileAvailable(const pldm_msg* request, size_t payloadLength);
 };
 
 } // namespace oem_ibm
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.cpp b/oem/ibm/libpldmresponder/file_io_by_type.cpp
index e076253..2ecc3d9 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.cpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.cpp
@@ -2,6 +2,7 @@
 
 #include "file_io_by_type.hpp"
 
+#include "file_io_type_dump.hpp"
 #include "file_io_type_lid.hpp"
 #include "file_io_type_pel.hpp"
 #include "utils.hpp"
@@ -120,6 +121,11 @@
             return std::make_unique<LidHandler>(fileHandle, false);
             break;
         }
+        case PLDM_FILE_TYPE_DUMP:
+        {
+            return std::make_unique<DumpHandler>(fileHandle);
+            break;
+        }
         default:
         {
             throw InternalFailure();
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.hpp b/oem/ibm/libpldmresponder/file_io_by_type.hpp
index b970886..0a5c1d8 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.hpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.hpp
@@ -48,8 +48,26 @@
      */
     virtual int read(uint32_t offset, uint32_t& length, Response& response) = 0;
 
+    /** @brief Method to write an oem file by type
+     *  @param[in] buffer - buffer to be written to file
+     *  @param[in] offset - offset to write to
+     *  @param[in/out] length - length to be written
+     *  @return PLDM status code
+     */
+    virtual int write(const char* buffer, uint32_t offset,
+                      uint32_t& length) = 0;
+
     virtual int fileAck(uint8_t fileStatus) = 0;
 
+    /** @brief Method to process a new file available notification from the
+     *  host. The bmc can chose to do different actions based on the file type.
+     *
+     *  @param[in] length - size of the file content to be transferred
+     *
+     *  @return PLDM status code
+     */
+    virtual int newFileAvailable(uint64_t length) = 0;
+
     /** @brief Method to read an oem file type's content into the PLDM response.
      *  @param[in] filePath - file to read from
      *  @param[in] offset - offset to read
diff --git a/oem/ibm/libpldmresponder/file_io_type_dump.cpp b/oem/ibm/libpldmresponder/file_io_type_dump.cpp
new file mode 100644
index 0000000..2360733
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_dump.cpp
@@ -0,0 +1,110 @@
+#include "file_io_type_dump.hpp"
+
+#include "utils.hpp"
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <stdint.h>
+#include <systemd/sd-bus.h>
+#include <unistd.h>
+
+#include <exception>
+#include <filesystem>
+#include <iostream>
+#include <sdbusplus/server.hpp>
+#include <xyz/openbmc_project/Dump/NewDump/server.hpp>
+
+#include "libpldm/base.h"
+#include "oem/ibm/libpldm/file_io.h"
+
+namespace pldm
+{
+namespace responder
+{
+
+static constexpr auto nbdInterface = "/dev/nbd1";
+
+int DumpHandler::fd = -1;
+
+int DumpHandler::newFileAvailable(uint64_t length)
+{
+    static constexpr auto dumpObjPath = "/xyz/openbmc_project/dump";
+    static constexpr auto dumpInterface = "xyz.openbmc_project.Dump.NewDump";
+
+    auto& bus = pldm::utils::DBusHandler::getBus();
+
+    try
+    {
+        auto service =
+            pldm::utils::DBusHandler().getService(dumpObjPath, dumpInterface);
+        using namespace sdbusplus::xyz::openbmc_project::Dump::server;
+        auto method = bus.new_method_call(service.c_str(), dumpObjPath,
+                                          dumpInterface, "Notify");
+        method.append(
+            sdbusplus::xyz::openbmc_project::Dump::server::convertForMessage(
+                NewDump::DumpType::System),
+            fileHandle, length);
+        bus.call_noreply(method);
+    }
+    catch (const std::exception& e)
+    {
+        std::cerr << "failed to make a d-bus call to DUMP manager, ERROR="
+                  << e.what() << "\n";
+        return PLDM_ERROR;
+    }
+
+    return PLDM_SUCCESS;
+}
+
+int DumpHandler::writeFromMemory(uint32_t offset, uint32_t length,
+                                 uint64_t address)
+{
+    int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
+
+    if (DumpHandler::fd == -1)
+    {
+        DumpHandler::fd = open(nbdInterface, flags);
+        if (DumpHandler::fd == -1)
+        {
+            std::cerr << "NBD file does not exist at " << nbdInterface
+                      << " ERROR=" << errno << "\n";
+            return PLDM_ERROR;
+        }
+    }
+    return transferFileData(DumpHandler::fd, false, offset, length, address);
+}
+
+int DumpHandler::write(const char* buffer, uint32_t offset, uint32_t& length)
+{
+    int flags = O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE;
+    if (DumpHandler::fd == -1)
+    {
+        DumpHandler::fd = open(nbdInterface, flags);
+        if (DumpHandler::fd == -1)
+        {
+            std::cerr << "NBD file does not exist at " << nbdInterface
+                      << " ERROR=" << errno << "\n";
+            return PLDM_ERROR;
+        }
+    }
+
+    int rc = lseek(DumpHandler::fd, offset, SEEK_SET);
+    if (rc == -1)
+    {
+        std::cerr << "lseek failed, ERROR=" << errno << ", OFFSET=" << offset
+                  << "\n";
+        return PLDM_ERROR;
+    }
+    rc = ::write(DumpHandler::fd, buffer, length);
+    if (rc == -1)
+    {
+        std::cerr << "file write failed, ERROR=" << errno
+                  << ", LENGTH=" << length << ", OFFSET=" << offset << "\n";
+        return PLDM_ERROR;
+    }
+    length = rc;
+
+    return PLDM_SUCCESS;
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io_type_dump.hpp b/oem/ibm/libpldmresponder/file_io_type_dump.hpp
new file mode 100644
index 0000000..e20d0d7
--- /dev/null
+++ b/oem/ibm/libpldmresponder/file_io_type_dump.hpp
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "file_io_by_type.hpp"
+
+namespace pldm
+{
+namespace responder
+{
+
+/** @class DumpHandler
+ *
+ *  @brief Inherits and implements FileHandler. This class is used
+ *  handle the dump offload/streaming from host to the destination via bmc
+ */
+class DumpHandler : public FileHandler
+{
+  public:
+    /** @brief DumpHandler constructor
+     */
+    DumpHandler(uint32_t fileHandle) : FileHandler(fileHandle)
+    {
+    }
+
+    virtual int writeFromMemory(uint32_t offset, uint32_t length,
+                                uint64_t address);
+
+    virtual int readIntoMemory(uint32_t /*offset*/, uint32_t& /*length*/,
+                               uint64_t /*address*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+    virtual int read(uint32_t /*offset*/, uint32_t& /*length*/,
+                     Response& /*response*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
+    virtual int write(const char* buffer, uint32_t offset, uint32_t& length);
+
+    virtual int newFileAvailable(uint64_t length);
+
+    virtual int fileAck(uint8_t /*fileStatus*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
+    /** @brief DumpHandler destructor
+     */
+    ~DumpHandler()
+    {
+    }
+
+  private:
+    static int fd; //!< fd to manage the dump offload to bmc
+};
+
+} // namespace responder
+} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io_type_lid.hpp b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
index 3a3332a..163629d 100644
--- a/oem/ibm/libpldmresponder/file_io_type_lid.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
@@ -44,6 +44,12 @@
         return transferFileData(lidPath, true, offset, length, address);
     }
 
+    virtual int write(const char* /*buffer*/, uint32_t /*offset*/,
+                      uint32_t& /*length*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
     virtual int read(uint32_t offset, uint32_t& length, Response& response)
     {
         return readFile(lidPath, offset, length, response);
@@ -54,6 +60,12 @@
         return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
     }
 
+    virtual int newFileAvailable(uint64_t /*length*/)
+
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
     /** @brief LidHandler destructor
      */
     ~LidHandler()
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.hpp b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
index 34f4907..3d5019a 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
@@ -29,6 +29,12 @@
                                uint64_t address);
     virtual int read(uint32_t offset, uint32_t& length, Response& response);
 
+    virtual int write(const char* /*buffer*/, uint32_t /*offset*/,
+                      uint32_t& /*length*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
     virtual int fileAck(uint8_t fileStatus);
 
     /** @brief method to store a pel file in tempfs and send
@@ -38,6 +44,11 @@
      */
     virtual int storePel(std::string&& pelFileName);
 
+    virtual int newFileAvailable(uint64_t /*length*/)
+    {
+        return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+    }
+
     /** @brief PelHandler destructor
      */
     ~PelHandler()
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index 86df25e..a8d0722 100644
--- a/oem/ibm/test/libpldmresponder_fileio_test.cpp
+++ b/oem/ibm/test/libpldmresponder_fileio_test.cpp
@@ -1,5 +1,6 @@
 #include "libpldmresponder/file_io.hpp"
 #include "libpldmresponder/file_io_by_type.hpp"
+#include "libpldmresponder/file_io_type_dump.hpp"
 #include "libpldmresponder/file_io_type_lid.hpp"
 #include "libpldmresponder/file_io_type_pel.hpp"
 #include "libpldmresponder/file_table.hpp"
@@ -795,6 +796,10 @@
     lidType = dynamic_cast<LidHandler*>(handler.get());
     ASSERT_TRUE(lidType != nullptr);
 
+    handler = getHandlerByType(PLDM_FILE_TYPE_DUMP, fileHandle);
+    auto dumpType = dynamic_cast<DumpHandler*>(handler.get());
+    ASSERT_TRUE(dumpType != nullptr);
+
     using namespace sdbusplus::xyz::openbmc_project::Common::Error;
     ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure);
 }