oem-ibm: add readFileByType handler
Add a handler for file type 'LID', to be able to read LID files over the
LPC channel.
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I9db77f78b0aa4e289fb0ab940121569b431f4dfe
diff --git a/oem/ibm/libpldmresponder/file_io.cpp b/oem/ibm/libpldmresponder/file_io.cpp
index 0c7216b..05051b6 100644
--- a/oem/ibm/libpldmresponder/file_io.cpp
+++ b/oem/ibm/libpldmresponder/file_io.cpp
@@ -47,6 +47,8 @@
std::move(writeFileByTypeFromMemory));
registerHandler(PLDM_OEM, PLDM_READ_FILE_BY_TYPE_INTO_MEMORY,
std::move(readFileByTypeIntoMemory));
+ registerHandler(PLDM_OEM, PLDM_READ_FILE_BY_TYPE,
+ std::move(readFileByType));
}
} // namespace oem_ibm
@@ -612,5 +614,52 @@
payloadLength);
}
+Response readFileByType(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_READ_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_READ_FILE_BY_TYPE, rc, 0, responsePtr);
+ return response;
+ }
+
+ std::unique_ptr<FileHandler> handler{};
+ try
+ {
+ handler = getHandlerByType(fileType, fileHandle);
+ }
+ catch (const InternalFailure& e)
+ {
+ log<level::ERR>("unknown file type", entry("TYPE=%d", fileType));
+ encode_rw_file_by_type_resp(request->hdr.instance_id,
+ PLDM_READ_FILE_BY_TYPE,
+ PLDM_INVALID_FILE_TYPE, 0, responsePtr);
+ return response;
+ }
+
+ rc = handler->read(offset, length, response);
+ encode_rw_file_by_type_resp(request->hdr.instance_id,
+ PLDM_READ_FILE_BY_TYPE, rc, length,
+ responsePtr);
+ return response;
+}
+
} // namespace responder
} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io.hpp b/oem/ibm/libpldmresponder/file_io.hpp
index b67f0f9..07a13aa 100644
--- a/oem/ibm/libpldmresponder/file_io.hpp
+++ b/oem/ibm/libpldmresponder/file_io.hpp
@@ -160,6 +160,15 @@
Response readFileByTypeIntoMemory(const pldm_msg* request,
size_t payloadLength);
+/** @brief Handler for readFileByType command
+ *
+ * @param[in] request - pointer to PLDM request payload
+ * @param[in] payloadLength - length of the message
+ *
+ * @return PLDM response message
+ */
+Response readFileByType(const pldm_msg* request, size_t payloadLength);
+
/** @brief Handler for GetFileTable command
*
* @param[in] request - pointer to PLDM request payload
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.cpp b/oem/ibm/libpldmresponder/file_io_by_type.cpp
index 152efb9..efe8e37 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.cpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.cpp
@@ -12,6 +12,7 @@
#include <exception>
#include <filesystem>
+#include <fstream>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <vector>
@@ -29,7 +30,7 @@
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
int FileHandler::transferFileData(const fs::path& path, bool upstream,
- uint32_t offset, uint32_t length,
+ uint32_t offset, uint32_t& length,
uint64_t address)
{
if (upstream)
@@ -103,5 +104,43 @@
return nullptr;
}
+int FileHandler::readFile(const std::string& filePath, uint32_t offset,
+ uint32_t& length, Response& response)
+{
+ if (!fs::exists(filePath))
+ {
+ log<level::ERR>("File does not exist", entry("HANDLE=%d", fileHandle),
+ entry("PATH=%s", filePath.c_str()));
+ return PLDM_INVALID_FILE_HANDLE;
+ }
+
+ size_t fileSize = fs::file_size(filePath);
+ if (offset >= fileSize)
+ {
+ log<level::ERR>("Offset exceeds file size", entry("OFFSET=%d", offset),
+ entry("FILE_SIZE=%d", fileSize));
+ return PLDM_DATA_OUT_OF_RANGE;
+ }
+
+ if (offset + length > fileSize)
+ {
+ length = fileSize - offset;
+ }
+
+ size_t currSize = response.size();
+ response.resize(currSize + length);
+ auto filePos = reinterpret_cast<char*>(response.data());
+ filePos += currSize;
+ std::ifstream stream(filePath, std::ios::in | std::ios::binary);
+ if (stream)
+ {
+ stream.seekg(offset);
+ stream.read(filePos, length);
+ return PLDM_SUCCESS;
+ }
+ log<level::ERR>("Unable to read file", entry("FILE=%s", filePath.c_str()));
+ return PLDM_ERROR;
+}
+
} // namespace responder
} // namespace pldm
diff --git a/oem/ibm/libpldmresponder/file_io_by_type.hpp b/oem/ibm/libpldmresponder/file_io_by_type.hpp
index f39650d..779eaef 100644
--- a/oem/ibm/libpldmresponder/file_io_by_type.hpp
+++ b/oem/ibm/libpldmresponder/file_io_by_type.hpp
@@ -33,13 +33,31 @@
* file types need to override this method to do the file specific
* processing
* @param[in] offset - offset to read
- * @param[in] length - length to be read mentioned by Host
+ * @param[in/out] length - length to be read mentioned by Host
* @param[in] address - DMA address
* @return PLDM status code
*/
- virtual int readIntoMemory(uint32_t offset, uint32_t length,
+ virtual int readIntoMemory(uint32_t offset, uint32_t& length,
uint64_t address) = 0;
+ /** @brief Method to read an oem file type's content into the PLDM response.
+ * @param[in] offset - offset to read
+ * @param[in/out] length - length to be read
+ * @param[in] response - PLDM response
+ * @return PLDM status code
+ */
+ virtual int read(uint32_t offset, uint32_t& length, Response& response) = 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
+ * @param[in/out] length - length to be read
+ * @param[in] response - PLDM response
+ * @return PLDM status code
+ */
+ virtual int readFile(const std::string& filePath, uint32_t offset,
+ uint32_t& length, Response& response);
+
/** @brief Method to do the file content transfer ove DMA between host and
* bmc. This method is made virtual to be overridden in test case. And need
* not be defined in other child classes
@@ -48,13 +66,13 @@
* @param[in] upstream - direction of DMA transfer. "false" means a
* transfer from host to BMC
* @param[in] offset - offset to read/write
- * @param[in] length - length to be read/write mentioned by Host
+ * @param[in/out] length - length to be read/write mentioned by Host
* @param[in] address - DMA address
*
* @return PLDM status code
*/
virtual int transferFileData(const fs::path& path, bool upstream,
- uint32_t offset, uint32_t length,
+ uint32_t offset, uint32_t& length,
uint64_t address);
/** @brief Constructor to create a FileHandler object
diff --git a/oem/ibm/libpldmresponder/file_io_type_lid.hpp b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
index 45d4f73..d3a48a5 100644
--- a/oem/ibm/libpldmresponder/file_io_type_lid.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_lid.hpp
@@ -38,12 +38,17 @@
return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
}
- virtual int readIntoMemory(uint32_t offset, uint32_t length,
+ virtual int readIntoMemory(uint32_t offset, uint32_t& length,
uint64_t address)
{
return transferFileData(lidPath, true, offset, length, address);
}
+ virtual int read(uint32_t offset, uint32_t& length, Response& response)
+ {
+ return readFile(lidPath, offset, length, response);
+ }
+
/** @brief LidHandler destructor
*/
~LidHandler()
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.cpp b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
index 014511c..01919b9 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.cpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.cpp
@@ -25,12 +25,18 @@
using namespace phosphor::logging;
-int PelHandler::readIntoMemory(uint32_t /*offset*/, uint32_t /*length*/,
+int PelHandler::readIntoMemory(uint32_t /*offset*/, uint32_t& /*length*/,
uint64_t /*address*/)
{
return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
}
+int PelHandler::read(uint32_t /*offset*/, uint32_t& /*length*/,
+ Response& /*response*/)
+{
+ return PLDM_ERROR_UNSUPPORTED_PLDM_CMD;
+}
+
int PelHandler::writeFromMemory(uint32_t offset, uint32_t length,
uint64_t address)
{
diff --git a/oem/ibm/libpldmresponder/file_io_type_pel.hpp b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
index 4c79452..d2fb5cc 100644
--- a/oem/ibm/libpldmresponder/file_io_type_pel.hpp
+++ b/oem/ibm/libpldmresponder/file_io_type_pel.hpp
@@ -25,8 +25,9 @@
virtual int writeFromMemory(uint32_t offset, uint32_t length,
uint64_t address);
- virtual int readIntoMemory(uint32_t offset, uint32_t length,
+ virtual int readIntoMemory(uint32_t offset, uint32_t& length,
uint64_t address);
+ virtual int read(uint32_t offset, uint32_t& length, Response& response);
/** @brief method to store a pel file in tempfs and send
* d-bus notification to pel daemon that it is ready for consumption
diff --git a/oem/ibm/test/libpldmresponder_fileio_test.cpp b/oem/ibm/test/libpldmresponder_fileio_test.cpp
index 603c0c6..3894ff3 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_lid.hpp"
#include "libpldmresponder/file_io_type_pel.hpp"
#include "libpldmresponder/file_table.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
@@ -763,6 +764,103 @@
auto pelType = dynamic_cast<PelHandler*>(handler.get());
ASSERT_TRUE(pelType != nullptr);
+ handler = getHandlerByType(PLDM_FILE_TYPE_LID_PERM, fileHandle);
+ auto lidType = dynamic_cast<LidHandler*>(handler.get());
+ ASSERT_TRUE(lidType != nullptr);
+ pelType = dynamic_cast<PelHandler*>(handler.get());
+ ASSERT_TRUE(pelType == nullptr);
+ handler = getHandlerByType(PLDM_FILE_TYPE_LID_TEMP, fileHandle);
+ lidType = dynamic_cast<LidHandler*>(handler.get());
+ ASSERT_TRUE(lidType != nullptr);
+
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
ASSERT_THROW(getHandlerByType(0xFFFF, fileHandle), InternalFailure);
}
+
+TEST(readFileByTypeIntoMemory, testBadPath)
+{
+ const auto hdr_size = sizeof(pldm_msg_hdr);
+ std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES>
+ requestMsg{};
+ auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ struct pldm_read_write_file_by_type_memory_req* request =
+ reinterpret_cast<struct pldm_read_write_file_by_type_memory_req*>(
+ req->payload);
+ request->file_type = 0xFFFF;
+ request->file_handle = 0;
+ request->offset = 0;
+ request->length = 17;
+ request->address = 0;
+
+ auto response = readFileByTypeIntoMemory(req, 0);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_read_write_file_by_type_memory_resp* resp =
+ reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
+
+ response =
+ readFileByTypeIntoMemory(req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_INVALID_WRITE_LENGTH, resp->completion_code);
+
+ request->length = 16;
+ response =
+ readFileByTypeIntoMemory(req, PLDM_RW_FILE_BY_TYPE_MEM_REQ_BYTES);
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ resp = reinterpret_cast<struct pldm_read_write_file_by_type_memory_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code);
+}
+
+TEST(readFileByType, testBadPath)
+{
+ const auto hdr_size = sizeof(pldm_msg_hdr);
+ std::array<uint8_t, hdr_size + PLDM_RW_FILE_BY_TYPE_REQ_BYTES> requestMsg{};
+ auto payloadLength = requestMsg.size() - hdr_size;
+ auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+ struct pldm_read_write_file_by_type_req* request =
+ reinterpret_cast<struct pldm_read_write_file_by_type_req*>(
+ req->payload);
+ request->file_type = 0xFFFF;
+ request->file_handle = 0;
+ request->offset = 0;
+ request->length = 13;
+
+ auto response = readFileByType(req, 0);
+ auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ struct pldm_read_write_file_by_type_resp* resp =
+ reinterpret_cast<struct pldm_read_write_file_by_type_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_ERROR_INVALID_LENGTH, resp->completion_code);
+
+ response = readFileByType(req, payloadLength);
+ responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+ resp = reinterpret_cast<struct pldm_read_write_file_by_type_resp*>(
+ responsePtr->payload);
+ ASSERT_EQ(PLDM_INVALID_FILE_TYPE, resp->completion_code);
+}
+
+TEST(readFileByType, testReadFile)
+{
+ LidHandler handler(0, true);
+ Response response;
+ uint32_t length{};
+
+ auto rc = handler.readFile({}, 0, length, response);
+ ASSERT_EQ(PLDM_INVALID_FILE_HANDLE, rc);
+
+ char tmplt[] = "/tmp/lid.XXXXXX";
+ auto fd = mkstemp(tmplt);
+ std::vector<uint8_t> in = {100, 10, 56, 78, 34, 56, 79, 235, 111};
+ write(fd, in.data(), in.size());
+ close(fd);
+ length = in.size() + 1000;
+ rc = handler.readFile(tmplt, 0, length, response);
+ ASSERT_EQ(rc, PLDM_SUCCESS);
+ ASSERT_EQ(length, in.size());
+ ASSERT_EQ(response.size(), in.size());
+ ASSERT_EQ(std::equal(in.begin(), in.end(), response.begin()), true);
+}