Add NegotiateTransferParam responder handle - Adds a responder handle for NegotiateTransferParameters - This change adds the support for part sizes from multiple devices - Also adds the checksum for GetPLDMVersion responses Tested: Tested with unit tests Google-Bug-Id: 423027264 Change-Id: I9b4b276a4740e5cc7d963e6765f93becf5393553 Signed-off-by: Kasun Athukorala <kasunath@google.com>
diff --git a/libpldmresponder/base.cpp b/libpldmresponder/base.cpp index 37d0dab..318c3ee 100644 --- a/libpldmresponder/base.cpp +++ b/libpldmresponder/base.cpp
@@ -5,10 +5,15 @@ #include <libpldm/base.h> #include <libpldm/bios.h> +#include <libpldm/file.h> #include <libpldm/fru.h> #include <libpldm/platform.h> +#include <phosphor-logging/lg2.hpp> + +#include <algorithm> #include <array> +#include <bit> #include <cstring> #include <map> #include <stdexcept> @@ -19,6 +24,8 @@ #include <libpldm/oem/ibm/host.h> #endif +PHOSPHOR_LOG2_USING; + namespace pldm { using Type = uint8_t; @@ -30,7 +37,7 @@ 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_GET_PLDM_COMMANDS, PLDM_NEGOTIATE_TRANSFER_PARAMETERS}}, {PLDM_PLATFORM, {PLDM_GET_PDR, PLDM_SET_STATE_EFFECTER_STATES, PLDM_SET_EVENT_RECEIVER, PLDM_GET_SENSOR_READING, PLDM_GET_STATE_SENSOR_READINGS, @@ -43,6 +50,8 @@ {PLDM_FRU, {PLDM_GET_FRU_RECORD_TABLE_METADATA, PLDM_GET_FRU_RECORD_TABLE, PLDM_GET_FRU_RECORD_BY_OPTION}}, + {PLDM_FILE, + {PLDM_FILE_CMD_DF_OPEN, PLDM_FILE_CMD_DF_CLOSE, PLDM_FILE_CMD_DF_READ}}, #ifdef OEM_IBM {PLDM_OEM, {PLDM_HOST_GET_ALERT_STATUS, PLDM_GET_FILE_TABLE, PLDM_READ_FILE, @@ -58,11 +67,16 @@ {PLDM_PLATFORM, {0x00, 0xf0, 0xf2, 0xf1}}, {PLDM_BIOS, {0x00, 0xf0, 0xf0, 0xf1}}, {PLDM_FRU, {0x00, 0xf0, 0xf0, 0xf1}}, + {PLDM_FILE, {0x00, 0xf0, 0xf0, 0xf1}}, #ifdef OEM_IBM {PLDM_OEM, {0x00, 0xf0, 0xf0, 0xf1}}, #endif }; +static const std::vector<Type> multipartSupportedTypes{ + PLDM_FILE, +}; + namespace base { Response Handler::getPLDMTypes(const pldm_msg* request, @@ -136,8 +150,11 @@ uint32_t transferHandle; Type type; uint8_t transferFlag; + constexpr size_t checksumLen = sizeof(uint32_t); - Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0); + // Generate the response with 32bit checksum appended + Response response( + sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES + checksumLen, 0); auto responsePtr = new (response.data()) pldm_msg; uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle, @@ -161,6 +178,13 @@ rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0, PLDM_START_AND_END, &version, sizeof(pldm_version), responsePtr); + + // Calculate the crc32 + uint32_t checksum = pldm_edac_crc32(&version, sizeof(version)); + checksum = htole32(checksum); + memcpy(response.data() + sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, + &checksum, checksumLen); + if (rc != PLDM_SUCCESS) { return ccOnlyResponse(request, rc); @@ -198,6 +222,95 @@ return response; } +Response Handler::getNegotiateTransferParam( + pldm_tid_t tid, const pldm_msg* request, size_t payloadLength) +{ + struct pldm_base_negotiate_transfer_params_resp resp_payload_struct = {}; + struct pldm_base_negotiate_transfer_params_req decoded_req; + Response response(sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES, + 0); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + int rc = decode_pldm_base_negotiate_transfer_params_req( + request, payloadLength, &decoded_req); + if (rc != 0) + { + return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); + } + + // Part size should be a power of 2 and greater than PLDM_MIN_PART_SIZE + if ((decoded_req.requester_part_size < PLDM_MIN_PART_SIZE) || + !std::has_single_bit(decoded_req.requester_part_size)) + { + return CmdHandler::ccOnlyResponse(request, PLDM_ERROR_INVALID_DATA); + } + + // Only check the multipart types supported by the responder + for (const auto& type : multipartSupportedTypes) + { + if (type > PLDM_TYPES_MAX) + { + error("Invalid type '{TYPE}'", "TYPE", type); + return CmdHandler::ccOnlyResponse(request, PLDM_ERROR); + } + + // In the decoded_req.requester_protocol_support array, pldm type is + // array_index * 8 + bit + auto index = type / 8; + auto bit = type % 8; + + if (decoded_req.requester_protocol_support[index].byte & (1 << bit)) + { + std::map<uint8_t, uint16_t>& type_map_for_tid = + negotiatedPartSizes[tid]; + type_map_for_tid[type] = + std::min(decoded_req.requester_part_size, + (uint16_t)PLDM_RESPONDER_PART_SIZE); + + info( + "Multipart negotiated for tid:'{TID}' type:'{TYPE}' size:'{SIZE}'", + "TID", tid, "TYPE", type, "SIZE", + (uint16_t)type_map_for_tid[type]); + } + + resp_payload_struct.responder_protocol_support[index].byte |= + static_cast<uint8_t>(1 << bit); + } + + resp_payload_struct.completion_code = PLDM_SUCCESS; + resp_payload_struct.responder_part_size = PLDM_RESPONDER_PART_SIZE; + + size_t respPayloadLength = + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_RESP_BYTES; + rc = encode_pldm_base_negotiate_transfer_params_resp( + request->hdr.instance_id, &resp_payload_struct, responsePtr, + &respPayloadLength); + if (rc != 0) + { + return ccOnlyResponse(request, PLDM_ERROR); + } + + return response; +} + +uint16_t Handler::getNegotiatedPartSize(pldm_tid_t tid, uint8_t pldmType) +{ + auto tid_it = negotiatedPartSizes.find(tid); + if (tid_it == negotiatedPartSizes.end()) + { + return PLDM_MIN_PART_SIZE; + } + + auto type_it = tid_it->second.find(pldmType); + if (type_it == tid_it->second.end()) + { + return PLDM_MIN_PART_SIZE; + } + + return type_it->second; +} + } // namespace base } // namespace responder } // namespace pldm
diff --git a/libpldmresponder/base.hpp b/libpldmresponder/base.hpp index 3ed5c8f..98d1554 100644 --- a/libpldmresponder/base.hpp +++ b/libpldmresponder/base.hpp
@@ -18,7 +18,10 @@ namespace base { +#define PLDM_TYPES_MAX 63 #define PLDM_MIN_PART_SIZE 256 +// TODO: We can make the part size configurable for different platforms +#define PLDM_RESPONDER_PART_SIZE 4096 class Handler : public CmdHandler { @@ -45,6 +48,12 @@ [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { return this->getTID(request, payloadLength); }); + handlers.emplace(PLDM_NEGOTIATE_TRANSFER_PARAMETERS, + [this](pldm_tid_t tid, const pldm_msg* request, + size_t payloadLength) { + return this->getNegotiateTransferParam( + tid, request, payloadLength); + }); } /** @brief Handler for getPLDMTypes @@ -87,6 +96,18 @@ */ Response getTID(const pldm_msg* request, size_t payloadLength); + /** @brief Handler for negotiate transfer parameters + * + * This will save the negotiated part size based on the TID + * + * @param[in] tid - TID of the requester + * @param[in] request - Request message payload + * @param[in] payload_length - Request message payload length + * @param[return] Response - PLDM Response message + */ + Response getNegotiateTransferParam(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 @@ -97,6 +118,17 @@ oemPlatformHandler = handler; } + /* @brief Returns the negotiated part size for a given TID and PLDM type. + * + * If no negotiation has occurred for the given TID and type, it returns a + * default minimum part size. + * + * @param[in] tid - The Terminus ID. + * @param[in] pldmType - The PLDM type. + * @return The negotiated part size. + */ + uint16_t getNegotiatedPartSize(pldm_tid_t tid, uint8_t pldmType); + private: /** @brief reference of main event loop of pldmd, primarily used to schedule * work @@ -108,6 +140,10 @@ /** @brief sdeventplus event source */ std::unique_ptr<sdeventplus::source::Defer> survEvent; + + /** Negotiated multi part size of each possible PLDM type for different + * devices. */ + std::map<pldm_tid_t, std::map<uint8_t, uint16_t>> negotiatedPartSizes; }; } // namespace base
diff --git a/libpldmresponder/file_transfer.cpp b/libpldmresponder/file_transfer.cpp index 1dab5ae..2e3b866 100644 --- a/libpldmresponder/file_transfer.cpp +++ b/libpldmresponder/file_transfer.cpp
@@ -86,9 +86,10 @@ return 0; } -Handler::Handler(responder::platform::Handler* platformHandler) : - platformHandler(platformHandler), nextFileDescriptor(0), - multipartSize(PLDM_MIN_PART_SIZE) +Handler::Handler(responder::base::Handler* baseHandler, + responder::platform::Handler* platformHandler) : + baseHandler(baseHandler), platformHandler(platformHandler), + nextFileDescriptor(0) { // Register command handlers. The "handlers" come from CmdHandler class. handlers.emplace( @@ -105,16 +106,11 @@ handlers.emplace( PLDM_FILE_CMD_DF_READ, - [this](pldm_tid_t, const pldm_msg* request, size_t payloadLength) { - return this->dfRead(request, payloadLength); + [this](pldm_tid_t tid, const pldm_msg* request, size_t payloadLength) { + return this->dfRead(tid, request, payloadLength); }); } -void Handler::setMultipartSize(uint16_t size) -{ - multipartSize = size; -} - std::optional<uint16_t> Handler::getFreeFileDescriptor(uint16_t fileIdentifier) { uint16_t startValue = this->nextFileDescriptor; @@ -256,7 +252,7 @@ uint32_t Handler::getDataLengthBytesAndTransferFlag( const FileDescriptor& fileDescriptor, uint32_t currOffset, - uint8_t* transferFlag) + uint16_t multipartSize, uint8_t* transferFlag) { // Verify that the current offset is greater than the starting offset of the // data sequence. @@ -397,7 +393,7 @@ Response Handler::dfReadTransferFirstPart( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor) + uint16_t multipartSize, FileDescriptor& fileDescriptor) { // For the first part, transfer handle should be 0 if (decodedReq.transfer_handle != 0) @@ -433,7 +429,8 @@ // the corresponding transfer flag. uint8_t transfer_flag; uint32_t data_length_bytes = getDataLengthBytesAndTransferFlag( - fileDescriptor, fileDescriptor.startingOffset, &transfer_flag); + fileDescriptor, fileDescriptor.startingOffset, multipartSize, + &transfer_flag); if (data_length_bytes == 0) { // This can happen if the client is requesting data beyond initially @@ -457,7 +454,7 @@ Response Handler::dfReadTransferCurrentOrNextPart( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor) + uint16_t multipartSize, FileDescriptor& fileDescriptor) { // Validate transfer flag. This doesn't strictly check the transfer flag // with an expected value. Instead veryfying that it is within valid range. @@ -477,7 +474,8 @@ // the corresponding transfer flag. uint8_t transfer_flag; uint32_t data_length_bytes = getDataLengthBytesAndTransferFlag( - fileDescriptor, decodedReq.transfer_handle, &transfer_flag); + fileDescriptor, decodedReq.transfer_handle, multipartSize, + &transfer_flag); if (data_length_bytes == 0) { // This can happen if the client is requesting data beyond initially @@ -501,12 +499,13 @@ Response Handler::dfReadTransferCompleteOrAbort( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor) + uint16_t multipartSize, FileDescriptor& fileDescriptor) { // Check whether the requester wants to start a new connection if (decodedReq.section_length > 0 || decodedReq.section_offset > 0) { - return dfReadTransferFirstPart(request, decodedReq, fileDescriptor); + return dfReadTransferFirstPart(request, decodedReq, multipartSize, + fileDescriptor); } return createReadResponse( request, decodedReq, fileDescriptor, /*current_transfer_handle=*/0, @@ -514,7 +513,8 @@ /*next_transfer_handle*/ 0, /*data_length_bytes*/ 0); } -Response Handler::dfRead(const pldm_msg* request, size_t payloadLength) +Response Handler::dfRead(pldm_tid_t tid, const pldm_msg* request, + size_t payloadLength) { uint8_t pldmType; uint8_t transferOpflag; @@ -550,22 +550,25 @@ PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR); } + uint16_t multipartSize = baseHandler->getNegotiatedPartSize(tid, PLDM_FILE); + switch (transferOpflag) { case PLDM_XFER_FIRST_PART: - return dfReadTransferFirstPart(request, decodedReq, it->second); + return dfReadTransferFirstPart(request, decodedReq, multipartSize, + it->second); case PLDM_XFER_NEXT_PART: return dfReadTransferCurrentOrNextPart(request, decodedReq, - it->second); + multipartSize, it->second); case PLDM_XFER_ABORT: return dfReadTransferCompleteOrAbort(request, decodedReq, - it->second); + multipartSize, it->second); case PLDM_XFER_COMPLETE: return dfReadTransferCompleteOrAbort(request, decodedReq, - it->second); + multipartSize, it->second); case PLDM_XFER_CURRENT_PART: return dfReadTransferCurrentOrNextPart(request, decodedReq, - it->second); + multipartSize, it->second); default: break; }
diff --git a/libpldmresponder/file_transfer.hpp b/libpldmresponder/file_transfer.hpp index 92af1be..88f7500 100644 --- a/libpldmresponder/file_transfer.hpp +++ b/libpldmresponder/file_transfer.hpp
@@ -46,12 +46,8 @@ class Handler : public CmdHandler { public: - Handler(responder::platform::Handler* platformHandler); - - /** - * Sets the multipart size used for DfRead commands - */ - void setMultipartSize(uint16_t size); + Handler(responder::base::Handler* baseHandler, + responder::platform::Handler* platformHandler); private: /** @@ -79,7 +75,7 @@ */ uint32_t getDataLengthBytesAndTransferFlag( const FileDescriptor& fileDescriptor, uint32_t currOffset, - uint8_t* transferFlag); + uint16_t multipartSize, uint8_t* transferFlag); /** * @brief Calculates the next offset for a DfRead response @@ -102,7 +98,7 @@ Response dfReadTransferFirstPart( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor); + uint16_t multipartSize, FileDescriptor& fileDescriptor); /** * @brief Handles the current or next part of a DfRead transfer @@ -110,7 +106,7 @@ Response dfReadTransferCurrentOrNextPart( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor); + uint16_t multipartSize, FileDescriptor& fileDescriptor); /** * @brief Handles the completion or abort of a DfRead transfer @@ -118,12 +114,15 @@ Response dfReadTransferCompleteOrAbort( const pldm_msg* request, const pldm_base_multipart_receive_req& decodedReq, - FileDescriptor& fileDescriptor); + uint16_t multipartSize, FileDescriptor& fileDescriptor); /** * @brief Handler for the DfRead command */ - Response dfRead(const pldm_msg* request, size_t payloadLength); + Response dfRead(pldm_tid_t tid, const pldm_msg* request, + size_t payloadLength); + + responder::base::Handler* baseHandler; // PLDM Platform type handler. File pointers will be initialized during file // PDR descriptor handling. So This will allow the file transfer handler to @@ -137,10 +136,6 @@ // created. This is the simplest approach. We could change this later if we // need a better approach. uint16_t nextFileDescriptor; - - // Transfer size for DfRead command. Should be set by the base type - // handlers. If not set, min part size will be used. - uint16_t multipartSize; }; } // namespace file_transfer
diff --git a/libpldmresponder/test/libpldmresponder_base_test.cpp b/libpldmresponder/test/libpldmresponder_base_test.cpp index f169dff..93a7c7d 100644 --- a/libpldmresponder/test/libpldmresponder_base_test.cpp +++ b/libpldmresponder/test/libpldmresponder_base_test.cpp
@@ -4,11 +4,15 @@ #include "test/test_instance_id.hpp" #include <libpldm/base.h> +#include <libpldm/utils.h> #include <sdeventplus/event.hpp> +#include <algorithm> #include <array> #include <cstring> +#include <map> +#include <vector> #include <gtest/gtest.h> @@ -34,7 +38,7 @@ auto responsePtr = new (response.data()) pldm_msg; uint8_t* payload_ptr = responsePtr->payload; ASSERT_EQ(payload_ptr[0], 0); - ASSERT_EQ(payload_ptr[1], 29); // 0b11101 see DSP0240 table11 + ASSERT_EQ(payload_ptr[1], 157); // 0b10011101 see DSP0240 table11 ASSERT_EQ(payload_ptr[2], 0); } @@ -50,7 +54,7 @@ auto responsePtr = new (response.data()) pldm_msg; uint8_t* payload_ptr = responsePtr->payload; ASSERT_EQ(payload_ptr[0], 0); - ASSERT_EQ(payload_ptr[1], 60); // 60 = 0b111100 + ASSERT_EQ(payload_ptr[1], 188); // 188 = 0b10111100 ASSERT_EQ(payload_ptr[2], 0); } @@ -100,6 +104,13 @@ ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]) + sizeof(transferHandle) + sizeof(flag), &version, sizeof(version))); + + uint32_t expectedChecksum = pldm_edac_crc32(&version, sizeof(version)); + uint32_t responseChecksum = 0; + memcpy(&responseChecksum, + responsePtr->payload + PLDM_GET_VERSION_RESP_BYTES, + sizeof(responseChecksum)); + ASSERT_EQ(expectedChecksum, le32toh(responseChecksum)); } TEST_F(TestBaseCommands, testGetPLDMVersionBadRequest) @@ -109,7 +120,7 @@ auto request = new (requestPayload.data()) pldm_msg; size_t requestPayloadLength = requestPayload.size() - sizeof(pldm_msg_hdr); - uint8_t pldmType = 7; + uint8_t pldmType = 6; uint32_t transferHandle = 0x0; uint8_t flag = PLDM_GET_FIRSTPART; @@ -153,3 +164,194 @@ ASSERT_EQ(payload[0], 0); ASSERT_EQ(payload[1], 1); } + +TEST_F(TestBaseCommands, testSetMultiPartSizeCallback) +{ + base::Handler handler(event); + + // Prepare a NegotiateTransferParameters request + std::vector<uint8_t> requestMsg( + sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + struct pldm_base_negotiate_transfer_params_req req{}; + req.requester_part_size = 1024; + // PLDM_FILE is type 7. index = 7/8 = 0. bit = 7%8 = 7. + req.requester_protocol_support[0].byte |= (1 << 7); + + EXPECT_EQ(encode_pldm_base_negotiate_transfer_params_req( + /*instance_id=*/1, &req, request, &requestPayloadLength), + 0); + + // Call getNegotiateTransferParam to trigger the callback + requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + auto response = + handler.getNegotiateTransferParam(1, request, requestPayloadLength); + + // Verify the response + ASSERT_FALSE(response.empty()); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); + EXPECT_EQ(resp.responder_part_size, PLDM_RESPONDER_PART_SIZE); + EXPECT_TRUE(resp.responder_protocol_support[0].byte & (1 << 7)); +} + +TEST_F(TestBaseCommands, testNegotiateTransferParamMultipleTIDs) +{ + base::Handler handler(event); + + // Map of TIDs to their requested part sizes + std::map<pldm_tid_t, uint16_t> tidToPartSize = { + {10, 512}, // smaller than responder + {20, 8192}, // larger than responder + {30, 4096}, // equal to responder + {40, 1024}}; // smaller than responder + + for (const auto& [tid, requester_part_size] : tidToPartSize) + { + // Prepare a NegotiateTransferParameters request + std::vector<uint8_t> requestMsg( + sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + // Fill in the request payload + auto payload = + reinterpret_cast<pldm_base_negotiate_transfer_params_req*>( + request->payload); + payload->requester_part_size = htole16(requester_part_size); + + // Set the bit for PLDM_FILE_TRANSFER in requester_protocol_support + memset(payload->requester_protocol_support, 0, + sizeof(payload->requester_protocol_support)); + // PLDM_FILE is type 7. index = 7/8 = 0. bit = 7%8 = 7. + payload->requester_protocol_support[0].byte |= (1 << 7); + + // Call getNegotiateTransferParam + auto response = handler.getNegotiateTransferParam(tid, request, + requestPayloadLength); + + // Verify the response + ASSERT_FALSE(response.empty()) << "Failed for TID " << (int)tid; + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), + &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_SUCCESS) + << "Failed for TID " << (int)tid; + + // Verify the negotiated part size for this TID + uint16_t expectedNegotiatedSize = + std::min(requester_part_size, (uint16_t)PLDM_RESPONDER_PART_SIZE); + uint16_t negotiatedSize = handler.getNegotiatedPartSize(tid, PLDM_FILE); + EXPECT_EQ(negotiatedSize, expectedNegotiatedSize) + << "Failed for TID " << (int)tid; + } +} + +TEST_F(TestBaseCommands, testNegotiateTransferParamInvalidLength) +{ + std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 1); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t payloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + base::Handler handler(event); + auto response = + handler.getNegotiateTransferParam(1, request, payloadLength); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_ERROR); +} + +TEST_F(TestBaseCommands, testNegotiateTransferParamInvalidPartSizeZero) +{ + std::vector<uint8_t> requestMsg( + sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t payloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + auto payload = reinterpret_cast<pldm_base_negotiate_transfer_params_req*>( + request->payload); + payload->requester_part_size = 0; + + base::Handler handler(event); + auto response = + handler.getNegotiateTransferParam(1, request, payloadLength); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); +} + +TEST_F(TestBaseCommands, testNegotiateTransferParamInvalidPartSizeNotPowerOfTwo) +{ + std::vector<uint8_t> requestMsg( + sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t payloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + auto payload = reinterpret_cast<pldm_base_negotiate_transfer_params_req*>( + request->payload); + payload->requester_part_size = 3000; + + base::Handler handler(event); + auto response = + handler.getNegotiateTransferParam(1, request, payloadLength); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); +} + +TEST_F(TestBaseCommands, testNegotiateTransferParamGoodRequest) +{ + std::vector<uint8_t> requestMsg( + sizeof(pldm_msg_hdr) + + PLDM_BASE_NEGOTIATE_TRANSFER_PARAMETERS_REQ_BYTES); + auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); + size_t payloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); + + auto payload = reinterpret_cast<pldm_base_negotiate_transfer_params_req*>( + request->payload); + payload->requester_part_size = htole16(4096); + + base::Handler handler(event); + auto response = + handler.getNegotiateTransferParam(1, request, payloadLength); + auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); + + struct pldm_base_negotiate_transfer_params_resp resp; + EXPECT_EQ(decode_pldm_base_negotiate_transfer_params_resp( + responsePtr, response.size() - sizeof(pldm_msg_hdr), &resp), + 0); + + EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); + EXPECT_EQ(resp.responder_part_size, PLDM_RESPONDER_PART_SIZE); +}
diff --git a/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp b/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp index c3fc8f0..313f5d3 100644 --- a/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp +++ b/libpldmresponder/test/libpldmresponder_file_transfer_test.cpp
@@ -123,7 +123,7 @@ pdrRepo(pldm_pdr_init(), pldm_pdr_destroy), platformHandler(nullptr, 0, nullptr, pdrDir, pdrRepo.get(), nullptr, nullptr, nullptr, nullptr, nullptr, event, true), - handler(&platformHandler) + baseHandler(event), handler(&baseHandler, &platformHandler) {} void SetUp() override @@ -189,6 +189,7 @@ fs::path pdrDir; std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> pdrRepo; pldm::responder::platform::Handler platformHandler; + pldm::responder::base::Handler baseHandler; pldm::responder::file_transfer::Handler handler; fs::path targetFileDir; fs::path targetFilePath;