| #include "libpldmresponder/base.hpp" |
| #include "libpldmresponder/file_transfer.hpp" |
| #include "libpldmresponder/platform.hpp" |
| |
| #include <libpldm/base.h> |
| #include <libpldm/edac.h> |
| #include <libpldm/file.h> |
| |
| #include <algorithm> |
| #include <filesystem> |
| #include <fstream> |
| #include <numeric> |
| #include <random> |
| #include <vector> |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| namespace fs = std::filesystem; |
| using namespace pldm::responder; |
| using namespace pldm::responder::file_transfer; |
| |
| using ::testing::_; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| |
| // Test fixture for the standalone fileRead function |
| class FileReadTest : public ::testing::Test |
| { |
| protected: |
| void SetUp() override |
| { |
| // Create a temporary file with known content |
| char tmppath[] = "/tmp/pldm_fileread_test.XXXXXX"; |
| dir = fs::path(mkdtemp(tmppath)); |
| testFilePath = dir / "testfile.bin"; |
| std::ofstream testFile(testFilePath, std::ios::binary); |
| fileContent.resize(256); |
| std::iota(fileContent.begin(), fileContent.end(), 0); |
| testFile.write(reinterpret_cast<const char*>(fileContent.data()), |
| fileContent.size()); |
| testFile.close(); |
| fileSize = fileContent.size(); |
| } |
| |
| void TearDown() override |
| { |
| fs::remove_all(dir); |
| } |
| |
| fs::path dir; |
| fs::path testFilePath; |
| std::vector<uint8_t> fileContent; |
| uint32_t fileSize; |
| }; |
| |
| TEST_F(FileReadTest, SuccessCases) |
| { |
| FILE* fp = fopen(testFilePath.c_str(), "rb"); |
| ASSERT_NE(fp, nullptr); |
| |
| // Read from start |
| uint32_t readSize = 64; |
| |
| std::vector<uint8_t> buffer(readSize); |
| EXPECT_EQ(fileRead(fp, fileSize, 0, readSize, buffer.data()), 0); |
| EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data(), readSize)); |
| |
| // Read from middle |
| uint32_t offset = 100; |
| readSize = 50; |
| buffer.resize(readSize); |
| EXPECT_EQ(fileRead(fp, fileSize, offset, readSize, buffer.data()), 0); |
| EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data() + offset, readSize)); |
| |
| // Test case where offset + readSize == fileSize |
| offset = 128; |
| readSize = fileSize - offset; |
| buffer.resize(readSize); |
| EXPECT_EQ(fileRead(fp, fileSize, offset, readSize, buffer.data()), 0); |
| EXPECT_EQ(0, memcmp(buffer.data(), fileContent.data() + offset, readSize)); |
| |
| // Read the full file |
| buffer.resize(fileSize); |
| EXPECT_EQ(fileRead(fp, fileSize, 0, fileSize, buffer.data()), 0); |
| EXPECT_EQ(buffer, fileContent); |
| |
| fclose(fp); |
| } |
| |
| TEST_F(FileReadTest, FailureCases) |
| { |
| std::vector<uint8_t> buffer(10); |
| |
| // Null file pointer |
| EXPECT_EQ(fileRead(nullptr, fileSize, 0, 10, buffer.data()), -1); |
| |
| FILE* fp = fopen(testFilePath.c_str(), "rb"); |
| ASSERT_NE(fp, nullptr); |
| |
| // Null data buffer |
| EXPECT_EQ(fileRead(fp, fileSize, 0, 10, nullptr), -1); |
| |
| // Offset >= fileSize |
| EXPECT_EQ(fileRead(fp, fileSize, fileSize, 1, buffer.data()), -1); |
| EXPECT_EQ(fileRead(fp, fileSize, fileSize + 1, 1, buffer.data()), -1); |
| |
| // Read size > fileSize |
| std::vector<uint8_t> largeBuffer(fileSize + 1); |
| EXPECT_EQ(fileRead(fp, fileSize, 0, fileSize + 1, largeBuffer.data()), -1); |
| |
| // Read would go beyond file |
| EXPECT_EQ(fileRead(fp, fileSize, fileSize - 5, 10, buffer.data()), -1); |
| |
| fclose(fp); |
| } |
| |
| class FileTransferTests : public ::testing::Test |
| { |
| protected: |
| FileTransferTests() : |
| event(sdeventplus::Event::get_default()), |
| // platform::Handler needs a valid directory for PDRs |
| pdrDir(fs::temp_directory_path() / "pldm_pdr"), |
| pdrRepo(pldm_pdr_init(), pldm_pdr_destroy), |
| 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 |
| { |
| // Create a directory to hold the PDR JSON files |
| fs::create_directories(pdrDir); |
| |
| // Create a target file that the PDR will point to |
| char tmppath[] = "/tmp/pldm_target_file.XXXXXX"; |
| targetFileDir = fs::path(mkdtemp(tmppath)); |
| targetFilePath = targetFileDir / "testfile.bin"; |
| fileContent.resize(400); |
| // Assign random values to the file |
| std::random_device rd; |
| std::mt19937 gen(rd()); |
| std::uniform_int_distribution<> distrib(0, 255); |
| std::generate(fileContent.begin(), fileContent.end(), |
| [&]() { return distrib(gen); }); |
| std::ofstream testFile(targetFilePath, std::ios::binary); |
| testFile.write(reinterpret_cast<const char*>(fileContent.data()), |
| fileContent.size()); |
| } |
| |
| void TearDown() override |
| { |
| // Clean up the created directories and files |
| fs::remove_all(targetFileDir); |
| fs::remove_all(pdrDir); |
| } |
| |
| /** |
| * @brief Creates a PDR JSON file to set up the platform handler's state |
| * |
| * @param fileIdentifier The identifier for the file PDR |
| * @param filePath The path to the file on disk |
| */ |
| void setupPDR(uint16_t fileIdentifier, const fs::path& filePath, |
| pldm_tid_t tid = 0) |
| { |
| uint32_t fileSize = fs::file_size(filePath); |
| |
| // Construct the JSON content |
| nlohmann::json pdrJson = { |
| {"fileDescriptorPDRs", |
| {{{"entries", |
| {{{"EntityType", 9}, |
| {"Path", targetFileDir.string()}, |
| {"Files", |
| {{{"FileIdentifier", fileIdentifier}, |
| {"FileName", filePath.filename().string()}, |
| {"FileSize", fileSize}}}}}}}}}}}; |
| |
| // Write the JSON to a file in the PDR directory |
| std::ofstream jsonFile(pdrDir / "test_pdr.json"); |
| jsonFile << pdrJson; |
| jsonFile.close(); |
| |
| uint32_t handle = 0; |
| do |
| { |
| std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_PDR_REQ_BYTES> |
| getPdrReq{}; |
| auto req = reinterpret_cast<pldm_msg*>(getPdrReq.data()); |
| auto reqPayload = reinterpret_cast<pldm_get_pdr_req*>(req->payload); |
| reqPayload->record_handle = handle; |
| reqPayload->request_count = 100; |
| auto respMsg = |
| platformHandler.getPDR(tid, req, PLDM_GET_PDR_REQ_BYTES); |
| if (respMsg.size() < |
| sizeof(pldm_msg_hdr) + sizeof(pldm_get_pdr_resp)) |
| { |
| std::cerr << "getPDR failed with cc: " |
| << (int)respMsg[sizeof(pldm_msg_hdr)] << std::endl; |
| break; |
| } |
| auto respPtr = reinterpret_cast<pldm_msg*>(respMsg.data()); |
| auto respPayload = |
| reinterpret_cast<pldm_get_pdr_resp*>(respPtr->payload); |
| handle = respPayload->next_record_handle; |
| } while (handle != 0); |
| } |
| |
| sdeventplus::Event event; |
| 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; |
| std::vector<uint8_t> fileContent; |
| }; |
| |
| // Verify successfully opening a file |
| TEST_F(FileTransferTests, DfOpenSuccess) |
| { |
| uint16_t fileIdentifier = 1; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> request_msg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| struct pldm_msg* openRequest = |
| reinterpret_cast<struct pldm_msg*>(request_msg.data()); |
| |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int encode_rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &requestPayloadLength); |
| ASSERT_EQ(encode_rc, 0); |
| |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(response.data(), nullptr); |
| |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| ASSERT_GE(response.size(), sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_RESP_BYTES); |
| |
| struct pldm_file_df_open_resp decoded_resp{}; |
| decode_pldm_file_df_open_resp( |
| responsePtr, response.size() - sizeof(pldm_msg_hdr), &decoded_resp); |
| ASSERT_EQ(decoded_resp.completion_code, PLDM_SUCCESS); |
| } |
| |
| // Invalid DfOpen request length |
| TEST_F(FileTransferTests, InvalidDfOpenRequestLength) |
| { |
| pldm_msg request{}; |
| // Use an incorrect payload length |
| size_t invalidPayloadLength = PLDM_DF_OPEN_REQ_BYTES - 1; |
| |
| // FIX: Use the correct 'handle' method name |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, &request, |
| invalidPayloadLength); |
| |
| ASSERT_NE(response.data(), nullptr); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| EXPECT_EQ(responsePtr->payload[0], PLDM_ERROR); |
| } |
| |
| // Successfully open a file and read a section |
| TEST_F(FileTransferTests, DfOpenAndRead) |
| { |
| // Setup PDR for the test file |
| uint16_t fileIdentifier = 1; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| // Open the file via dfOpen |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Read a portion of the file via dfRead |
| uint32_t offset = 10; |
| uint32_t lengthToRead = 64; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handlers |
| auto readResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(readResponse.data(), nullptr); |
| |
| // Verify the response |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END); |
| EXPECT_EQ(resp.data.length, lengthToRead); |
| |
| const uint8_t* responseData = resp.data.ptr; |
| EXPECT_EQ(0, |
| memcmp(responseData, fileContent.data() + offset, lengthToRead)); |
| |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(responseData, lengthToRead)); |
| } |
| |
| // Opening a file with an invalid file identifier |
| TEST_F(FileTransferTests, InvalidFileIdentifier) |
| { |
| // Setup: We set up a PDR for a specific ID. |
| uint16_t validFileIdentifier = 1; |
| setupPDR(validFileIdentifier, targetFilePath); |
| |
| // Create request for a DIFFERENT, invalid ID. |
| uint16_t invalidFileIdentifier = 99; |
| std::vector<uint8_t> requestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = invalidFileIdentifier; |
| size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int encode_rc = |
| encode_pldm_file_df_open_req(0, &req, request, &requestPayloadLength); |
| ASSERT_EQ(encode_rc, 0); |
| |
| // Process request and check for the expected error. |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, request, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(response.data(), nullptr); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| ASSERT_EQ(decode_pldm_file_df_open_resp( |
| responsePtr, response.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp), |
| 0); |
| ASSERT_EQ(decodedOpenResp.completion_code, |
| PLDM_FILE_CC_INVALID_FILE_IDENTIFIER); |
| } |
| |
| // Successfully open a file and close it |
| TEST_F(FileTransferTests, OpenAndClose) |
| { |
| uint16_t fileIdentifier = 1; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openeRquestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| struct pldm_msg* openRequest = |
| reinterpret_cast<struct pldm_msg*>(openeRquestMsg.data()); |
| |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t requestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int encode_rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &requestPayloadLength); |
| ASSERT_EQ(encode_rc, 0); |
| |
| // Send the request to the handler |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(response.data(), nullptr); |
| |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| struct pldm_file_df_open_resp decoded_resp{}; |
| decode_pldm_file_df_open_resp( |
| responsePtr, response.size() - sizeof(pldm_msg_hdr), &decoded_resp); |
| uint16_t new_fd = decoded_resp.file_descriptor; |
| |
| std::vector<uint8_t> closeRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES); |
| struct pldm_msg* closeRequest = |
| reinterpret_cast<struct pldm_msg*>(closeRequestMsg.data()); |
| |
| struct pldm_file_df_close_req close_req{}; |
| close_req.file_descriptor = new_fd; |
| size_t closePayloadLength = PLDM_DF_CLOSE_REQ_BYTES; |
| encode_rc = encode_pldm_file_df_close_req(0, &close_req, closeRequest, |
| &closePayloadLength); |
| ASSERT_EQ(encode_rc, 0); |
| |
| // Send the request to the handler |
| auto close_response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE, |
| closeRequest, PLDM_DF_CLOSE_REQ_BYTES); |
| |
| ASSERT_NE(close_response.data(), nullptr); |
| auto closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data()); |
| EXPECT_EQ(closeResponsePtr->payload[0], PLDM_SUCCESS); |
| } |
| |
| // Close with a invalid file descriptor |
| TEST_F(FileTransferTests, DfCloseInvalidFileDescriptor) |
| { |
| // Attempt to close a file descriptor that was never opened. |
| uint16_t invalidFileDescriptor = 999; |
| std::vector<uint8_t> requestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES); |
| auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); |
| |
| struct pldm_file_df_close_req req{}; |
| req.file_descriptor = invalidFileDescriptor; |
| size_t payloadLength = PLDM_DF_CLOSE_REQ_BYTES; |
| int rc = encode_pldm_file_df_close_req(0, &req, request, &payloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE, request, |
| PLDM_DF_CLOSE_REQ_BYTES); |
| |
| ASSERT_NE(response.data(), nullptr); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| EXPECT_EQ(responsePtr->payload[0], PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR); |
| } |
| |
| // Invalid DfClose request length |
| TEST_F(FileTransferTests, DfCloseInvalidRequestLength) |
| { |
| // Attempt to close with an incorrect payload length. |
| uint16_t fileDescriptor = 123; // Can be any value |
| std::vector<uint8_t> requestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES); |
| auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); |
| |
| struct pldm_file_df_close_req req{}; |
| req.file_descriptor = fileDescriptor; |
| size_t payloadLength = PLDM_DF_CLOSE_REQ_BYTES; |
| int rc = encode_pldm_file_df_close_req(0, &req, request, &payloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Use an invalid length |
| size_t invalidPayloadLength = PLDM_DF_CLOSE_REQ_BYTES - 1; |
| auto response = handler.handle(0, PLDM_FILE_CMD_DF_CLOSE, request, |
| invalidPayloadLength); |
| |
| ASSERT_NE(response.data(), nullptr); |
| auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); |
| EXPECT_EQ(responsePtr->payload[0], PLDM_ERROR); |
| } |
| |
| // Open and read a file completely with multiple multipart request messages |
| TEST_F(FileTransferTests, DfReadCompleteFile) |
| { |
| uint16_t fileIdentifier = 2; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Initialize variables for multi-part read |
| uint32_t offset = 0; |
| uint32_t transferHandle = 0; |
| uint8_t transferFlag = PLDM_XFER_FIRST_PART; |
| std::vector<uint8_t> receivedData; |
| uint32_t lengthToRead = fileContent.size(); |
| uint32_t final_checksum = 0; |
| |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| |
| // Read the file in multiple parts |
| while (transferFlag != PLDM_END && transferFlag != PLDM_START_AND_END) |
| { |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = transferFlag; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = transferHandle; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, |
| readResponse.size() - sizeof(pldm_msg_hdr), &resp, |
| &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| transferFlag = resp.transfer_flag; |
| final_checksum = data_integrity_checksum; |
| uint32_t dataLengthBytes = resp.data.length; |
| |
| const uint8_t* responseData = resp.data.ptr; |
| receivedData.insert(receivedData.end(), responseData, |
| responseData + dataLengthBytes); |
| |
| offset += dataLengthBytes; |
| transferHandle = offset; // Update transferHandle for next request |
| lengthToRead = 0; |
| offset = 0; |
| } |
| |
| // Verify that all data has been read correctly |
| ASSERT_EQ(receivedData.size(), fileContent.size()); |
| EXPECT_EQ(0, memcmp(receivedData.data(), fileContent.data(), |
| fileContent.size())); |
| EXPECT_EQ(final_checksum, |
| pldm_edac_crc32(fileContent.data(), fileContent.size())); |
| |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_COMPLETE; |
| read_req.transfer_ctx = fileDescriptor; |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_ACKNOWLEDGE_COMPLETION); |
| } |
| |
| // Open and read a file at a given offset |
| TEST_F(FileTransferTests, DfReadWithOffset) |
| { |
| uint16_t fileIdentifier = 3; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| uint32_t offset = 35; |
| uint32_t lengthToRead = 100; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END); |
| EXPECT_EQ(resp.data.length, lengthToRead); |
| |
| const uint8_t* responseData = resp.data.ptr; |
| EXPECT_EQ(0, |
| memcmp(responseData, fileContent.data() + offset, lengthToRead)); |
| } |
| |
| // Open and read a file then restart read without closing the file |
| TEST_F(FileTransferTests, DfReadRestart) |
| { |
| uint16_t fileIdentifier = 4; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| uint32_t offset1 = 0; |
| uint32_t lengthToRead1 = 100; |
| std::vector<uint8_t> readRequestMsg1( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest1 = reinterpret_cast<pldm_msg*>(readRequestMsg1.data()); |
| size_t readRequestPayloadLength1 = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset1; |
| read_req1.section_length = lengthToRead1; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest1, |
| &readRequestPayloadLength1); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END); |
| EXPECT_EQ(resp.data.length, lengthToRead1); |
| |
| const uint8_t* responseData1 = resp.data.ptr; |
| EXPECT_EQ(0, memcmp(responseData1, fileContent.data(), lengthToRead1)); |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(fileContent.data(), lengthToRead1)); |
| |
| uint32_t offset2 = 35; |
| uint32_t lengthToRead2 = 200; |
| std::vector<uint8_t> readRequestMsg2( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest2 = reinterpret_cast<pldm_msg*>(readRequestMsg2.data()); |
| size_t readRequestPayloadLength2 = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req2.transfer_ctx = fileDescriptor; |
| read_req2.transfer_handle = 0; |
| read_req2.section_offset = offset2; |
| read_req2.section_length = lengthToRead2; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest2, |
| &readRequestPayloadLength2); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto readResponse2 = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest2, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(readResponse2.data(), nullptr); |
| |
| auto readResponsePtr2 = reinterpret_cast<pldm_msg*>(readResponse2.data()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_START_AND_END); |
| EXPECT_EQ(resp.data.length, lengthToRead2); |
| |
| const uint8_t* responseData2 = resp.data.ptr; |
| EXPECT_EQ(0, memcmp(responseData2, fileContent.data() + offset2, |
| lengthToRead2)); |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(fileContent.data() + offset2, lengthToRead2)); |
| } |
| |
| // Open and read a file then re request the current part |
| TEST_F(FileTransferTests, DfReadCurrentPart) |
| { |
| uint16_t fileIdentifier = 5; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| uint32_t offset = 10; |
| uint32_t lengthToRead = 380; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| |
| // Send the read request for the first part |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset; |
| read_req1.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| uint32_t request2TransferHandle = resp.next_transfer_handle; |
| uint32_t dataLengthBytes = resp.data.length; |
| ASSERT_EQ(dataLengthBytes, 239); |
| ASSERT_EQ(request2TransferHandle, 239); |
| EXPECT_EQ(0, memcmp(readResponsePtr1->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| fileContent.data() + offset, dataLengthBytes)); |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(fileContent.data() + offset, dataLengthBytes)); |
| |
| // Send the read request for the next part |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_NEXT_PART; |
| read_req2.transfer_ctx = fileDescriptor; |
| read_req2.transfer_handle = request2TransferHandle; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.data.length, 141); |
| EXPECT_EQ(0, memcmp(readResponsePtr2->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| fileContent.data() + offset + 239, resp.data.length)); |
| // Verify the checksum over data in both responses. |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(fileContent.data() + offset, lengthToRead)); |
| |
| // Try requesting the current part |
| struct pldm_base_multipart_receive_req read_req3{}; |
| read_req3.pldm_type = PLDM_FILE; |
| read_req3.transfer_opflag = PLDM_XFER_CURRENT_PART; |
| read_req3.transfer_ctx = fileDescriptor; |
| read_req3.transfer_handle = request2TransferHandle; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req3, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr3, readResponse3.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(readResponse2.size(), readResponse3.size()); |
| EXPECT_EQ(0, memcmp(readResponsePtr3->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| fileContent.data() + offset + 239, 141)); |
| EXPECT_EQ(0, memcmp(readResponse2.data(), readResponse3.data(), |
| readResponse2.size())); |
| } |
| |
| // Open and read the first part and then re-request the current part |
| TEST_F(FileTransferTests, DfReadCurrentPartAgain) |
| { |
| uint16_t fileIdentifier = 12; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| uint32_t offset = 10; |
| uint32_t lengthToRead = 380; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| |
| // Send the read request for the first part |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset; |
| read_req1.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr1, readResponse1.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| uint32_t dataLengthBytes = resp.data.length; |
| ASSERT_EQ(dataLengthBytes, 239); |
| EXPECT_EQ(0, memcmp(readResponsePtr1->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| fileContent.data() + offset, dataLengthBytes)); |
| EXPECT_EQ(data_integrity_checksum, |
| pldm_edac_crc32(fileContent.data() + offset, dataLengthBytes)); |
| |
| // Try requesting the current part |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_CURRENT_PART; |
| read_req2.transfer_ctx = fileDescriptor; |
| read_req2.transfer_handle = 0; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| 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()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr2, readResponse2.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(readResponse1.size(), readResponse2.size()); |
| EXPECT_EQ(0, memcmp(readResponsePtr1->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| readResponsePtr2->payload + |
| PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES, |
| dataLengthBytes)); |
| EXPECT_EQ(0, memcmp(readResponse1.data(), readResponse2.data(), |
| readResponse1.size())); |
| } |
| |
| // Open and read the first part and then abort the read |
| TEST_F(FileTransferTests, DfReadAbort) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 9; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Send a first read request to start a transfer |
| uint32_t offset = 0; |
| uint32_t lengthToRead = 100; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset; |
| read_req1.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto firstReadResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(firstReadResponse.data(), nullptr); |
| auto firstReadResponsePtr = |
| reinterpret_cast<pldm_msg*>(firstReadResponse.data()); |
| ASSERT_EQ(firstReadResponsePtr->payload[0], PLDM_SUCCESS); |
| |
| // Send an abort request |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_ABORT; |
| read_req2.transfer_ctx = fileDescriptor; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto abortResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| |
| // Verify the abort response |
| ASSERT_NE(abortResponse.data(), nullptr); |
| auto abortResponsePtr = reinterpret_cast<pldm_msg*>(abortResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| abortResponsePtr, abortResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| EXPECT_EQ(resp.transfer_flag, PLDM_ACKNOWLEDGE_COMPLETION); |
| EXPECT_EQ(resp.data.length, 0); |
| } |
| |
| // Open the file and send a read request with an invalid transfer handle |
| TEST_F(FileTransferTests, DfReadFirstPartInvalidTransferHandle) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 6; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Send dfRead with non-zero transfer handle for FIRST_PART |
| uint32_t offset = 0; |
| uint32_t lengthToRead = 64; |
| uint32_t invalidTransferHandle = 1; // Should be 0 for FIRST_PART |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = invalidTransferHandle; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto readResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| |
| // Verify the error response |
| ASSERT_NE(readResponse.data(), nullptr); |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); |
| } |
| |
| // Open the file and send a read request with an invalid offset |
| TEST_F(FileTransferTests, DfReadFirstPartInvalidOffset) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 7; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Send dfRead with offset >= fileSize |
| uint32_t invalidOffset = fileContent.size(); // 400 |
| uint32_t lengthToRead = 1; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = invalidOffset; |
| read_req.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto readResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| |
| // Verify the error response |
| ASSERT_NE(readResponse.data(), nullptr); |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); |
| } |
| |
| // Open the file and send a read request with an invalid read length |
| TEST_F(FileTransferTests, DfReadFirstPartInvalidLength) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 8; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Send dfRead with offset + length > fileSize |
| uint32_t offset = 100; |
| uint32_t invalidLength = fileContent.size() - offset + 1; // 301 |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = offset; |
| read_req.section_length = invalidLength; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto readResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| |
| // Verify the error response |
| ASSERT_NE(readResponse.data(), nullptr); |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); |
| } |
| |
| // A client with a different TID should not be able to access the file |
| // descriptor. |
| TEST_F(FileTransferTests, DfOperationWithWrongTid) |
| { |
| // Setup PDR for the test file |
| uint16_t fileIdentifier = 1; |
| setupPDR(fileIdentifier, targetFilePath, 1); |
| |
| pldm_tid_t tid1 = 1; |
| pldm_tid_t tid2 = 2; |
| |
| // Open the file via dfOpen from client with TID 1 |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| auto openResponse = handler.handle(tid1, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Try to read a portion of the file via dfRead from client with TID 2 |
| uint32_t offset = 10; |
| uint32_t lengthToRead = 64; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = fileDescriptor; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handlers from client with TID 2 |
| auto readResponse = |
| baseHandler.handle(tid2, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(readResponse.data(), nullptr); |
| |
| // Verify the response |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR); |
| |
| // Try to close the file from client with TID 2 |
| std::vector<uint8_t> closeRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_CLOSE_REQ_BYTES); |
| struct pldm_msg* closeRequest = |
| reinterpret_cast<struct pldm_msg*>(closeRequestMsg.data()); |
| |
| struct pldm_file_df_close_req close_req{}; |
| close_req.file_descriptor = fileDescriptor; |
| size_t closePayloadLength = PLDM_DF_CLOSE_REQ_BYTES; |
| rc = encode_pldm_file_df_close_req(0, &close_req, closeRequest, |
| &closePayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto close_response = handler.handle(tid2, PLDM_FILE_CMD_DF_CLOSE, |
| closeRequest, PLDM_DF_CLOSE_REQ_BYTES); |
| |
| ASSERT_NE(close_response.data(), nullptr); |
| auto closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data()); |
| EXPECT_EQ(closeResponsePtr->payload[0], |
| PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR); |
| |
| // Read a portion of the file via dfRead from client with TID 1 |
| readResponse = baseHandler.handle(tid1, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(readResponse.data(), nullptr); |
| |
| readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| // Close the file from client with TID 1 |
| close_response = handler.handle(tid1, PLDM_FILE_CMD_DF_CLOSE, closeRequest, |
| PLDM_DF_CLOSE_REQ_BYTES); |
| |
| ASSERT_NE(close_response.data(), nullptr); |
| closeResponsePtr = reinterpret_cast<pldm_msg*>(close_response.data()); |
| EXPECT_EQ(closeResponsePtr->payload[0], PLDM_SUCCESS); |
| } |
| |
| // Try to read from a file descriptor that has not been opened. |
| TEST_F(FileTransferTests, DfReadWithInvalidFileDescriptor) |
| { |
| // Try to read a portion of the file via dfRead from client with TID 1 |
| uint32_t offset = 10; |
| uint32_t lengthToRead = 64; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req{}; |
| read_req.pldm_type = PLDM_FILE; |
| read_req.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req.transfer_ctx = 0; |
| read_req.transfer_handle = 0; |
| read_req.section_offset = offset; |
| read_req.section_length = lengthToRead; |
| int rc = encode_pldm_base_multipart_receive_req(0, &read_req, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handlers from client with TID 1 |
| auto readResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(readResponse.data(), nullptr); |
| |
| // Verify the response |
| auto readResponsePtr = reinterpret_cast<pldm_msg*>(readResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| readResponsePtr, readResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| |
| EXPECT_EQ(resp.completion_code, PLDM_FILE_CC_INVALID_FILE_DESCRIPTOR); |
| } |
| |
| // Open the file and read the first part. Then send a transfer handle less than |
| // the start offset |
| TEST_F(FileTransferTests, DfReadNextPartInvalidTransferHandleTooSmall) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 10; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| // Encode the request |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| |
| // Send a first read request to establish starting_offset |
| uint32_t offset = 100; |
| uint32_t lengthToRead = 50; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset; |
| read_req1.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto firstReadResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(firstReadResponse.data(), nullptr); |
| auto firstReadResponsePtr = |
| reinterpret_cast<pldm_msg*>(firstReadResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| firstReadResponsePtr, |
| firstReadResponse.size() - sizeof(pldm_msg_hdr), &resp, |
| &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| // Send a next part request with transfer_handle < starting_offset |
| uint32_t invalidTransferHandle = offset - 1; |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_NEXT_PART; |
| read_req2.transfer_ctx = fileDescriptor; |
| read_req2.transfer_handle = invalidTransferHandle; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto errorResponse = baseHandler.handle( |
| 0, PLDM_MULTIPART_RECEIVE, readRequest, readRequestPayloadLength); |
| |
| // Verify the error response |
| ASSERT_NE(errorResponse.data(), nullptr); |
| auto errorResponsePtr = reinterpret_cast<pldm_msg*>(errorResponse.data()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| errorResponsePtr, errorResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); |
| } |
| |
| // Open the file and read the first part. Then send a transfer handle greater |
| // than the end offset |
| TEST_F(FileTransferTests, DfReadNextPartInvalidTransferHandleTooLarge) |
| { |
| // Setup PDR and open the file |
| uint16_t fileIdentifier = 11; |
| setupPDR(fileIdentifier, targetFilePath); |
| |
| // Encode the request |
| std::vector<uint8_t> openRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_DF_OPEN_REQ_BYTES); |
| auto openRequest = reinterpret_cast<pldm_msg*>(openRequestMsg.data()); |
| struct pldm_file_df_open_req req{}; |
| req.file_identifier = fileIdentifier; |
| size_t openRequestPayloadLength = PLDM_DF_OPEN_REQ_BYTES; |
| int rc = encode_pldm_file_df_open_req(0, &req, openRequest, |
| &openRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| |
| // Send the request to the handler |
| auto openResponse = handler.handle(0, PLDM_FILE_CMD_DF_OPEN, openRequest, |
| PLDM_DF_OPEN_REQ_BYTES); |
| |
| // Verify the response |
| ASSERT_NE(openResponse.data(), nullptr); |
| auto openResponsePtr = reinterpret_cast<pldm_msg*>(openResponse.data()); |
| struct pldm_file_df_open_resp decodedOpenResp{}; |
| decode_pldm_file_df_open_resp(openResponsePtr, |
| openResponse.size() - sizeof(pldm_msg_hdr), |
| &decodedOpenResp); |
| ASSERT_EQ(decodedOpenResp.completion_code, PLDM_SUCCESS); |
| |
| // Send a first read request to establish starting_offset and section_length |
| uint16_t fileDescriptor = decodedOpenResp.file_descriptor; |
| uint32_t offset = 100; |
| uint32_t lengthToRead = 50; |
| std::vector<uint8_t> readRequestMsg( |
| sizeof(pldm_msg_hdr) + PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| auto readRequest = reinterpret_cast<pldm_msg*>(readRequestMsg.data()); |
| size_t readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| struct pldm_base_multipart_receive_req read_req1{}; |
| read_req1.pldm_type = PLDM_FILE; |
| read_req1.transfer_opflag = PLDM_XFER_FIRST_PART; |
| read_req1.transfer_ctx = fileDescriptor; |
| read_req1.transfer_handle = 0; |
| read_req1.section_offset = offset; |
| read_req1.section_length = lengthToRead; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req1, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| auto firstReadResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| ASSERT_NE(firstReadResponse.data(), nullptr); |
| auto firstReadResponsePtr = |
| reinterpret_cast<pldm_msg*>(firstReadResponse.data()); |
| |
| uint32_t data_integrity_checksum; |
| pldm_base_multipart_receive_resp resp; |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| firstReadResponsePtr, |
| firstReadResponse.size() - sizeof(pldm_msg_hdr), &resp, |
| &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_SUCCESS); |
| |
| // Send a next part request with transfer_handle >= starting_offset + |
| // section_length |
| uint32_t invalidTransferHandle = offset + lengthToRead; |
| struct pldm_base_multipart_receive_req read_req2{}; |
| read_req2.pldm_type = PLDM_FILE; |
| read_req2.transfer_opflag = PLDM_XFER_NEXT_PART; |
| read_req2.transfer_ctx = fileDescriptor; |
| read_req2.transfer_handle = invalidTransferHandle; |
| readRequestPayloadLength = PLDM_MULTIPART_RECEIVE_REQ_BYTES; |
| rc = encode_pldm_base_multipart_receive_req(0, &read_req2, readRequest, |
| &readRequestPayloadLength); |
| ASSERT_EQ(rc, 0); |
| auto errorResponse = |
| baseHandler.handle(0, PLDM_MULTIPART_RECEIVE, readRequest, |
| PLDM_MULTIPART_RECEIVE_REQ_BYTES); |
| |
| // Verify the error response |
| ASSERT_NE(errorResponse.data(), nullptr); |
| auto errorResponsePtr = reinterpret_cast<pldm_msg*>(errorResponse.data()); |
| |
| ASSERT_EQ(decode_pldm_base_multipart_receive_resp( |
| errorResponsePtr, errorResponse.size() - sizeof(pldm_msg_hdr), |
| &resp, &data_integrity_checksum), |
| 0); |
| EXPECT_EQ(resp.completion_code, PLDM_ERROR_INVALID_DATA); |
| } |