1 #include "libpldmresponder/file_io.hpp" 2 #include "libpldmresponder/file_table.hpp" 3 4 #include <filesystem> 5 #include <fstream> 6 #include <nlohmann/json.hpp> 7 8 #include "libpldm/base.h" 9 #include "libpldm/file_io.h" 10 11 #include <gmock/gmock-matchers.h> 12 #include <gmock/gmock.h> 13 #include <gtest/gtest.h> 14 15 #define SD_JOURNAL_SUPPRESS_LOCATION 16 17 #include <systemd/sd-journal.h> 18 19 std::vector<std::string> logs; 20 21 extern "C" { 22 23 int sd_journal_send(const char* format, ...) 24 { 25 logs.push_back(format); 26 return 0; 27 } 28 29 int sd_journal_send_with_location(const char* file, const char* line, 30 const char* func, const char* format, ...) 31 { 32 logs.push_back(format); 33 return 0; 34 } 35 } 36 37 namespace fs = std::filesystem; 38 using Json = nlohmann::json; 39 using namespace pldm::filetable; 40 41 class TestFileTable : public testing::Test 42 { 43 public: 44 void SetUp() override 45 { 46 // Create a temporary directory to hold the config file and files to 47 // populate the file table. 48 char tmppldm[] = "/tmp/pldm_fileio_table.XXXXXX"; 49 dir = fs::path(mkdtemp(tmppldm)); 50 51 // Copy the sample image files to the directory 52 fs::copy("./files", dir); 53 54 imageFile = dir / "NVRAM-IMAGE"; 55 auto jsonObjects = Json::array(); 56 auto obj = Json::object(); 57 obj["path"] = imageFile.c_str(); 58 obj["file_traits"] = 1; 59 60 jsonObjects.push_back(obj); 61 obj.clear(); 62 cksumFile = dir / "NVRAM-IMAGE-CKSUM"; 63 obj["path"] = cksumFile.c_str(); 64 obj["file_traits"] = 4; 65 jsonObjects.push_back(obj); 66 67 fileTableConfig = dir / "configFile.json"; 68 std::ofstream file(fileTableConfig.c_str()); 69 file << std::setw(4) << jsonObjects << std::endl; 70 } 71 72 void TearDown() override 73 { 74 fs::remove_all(dir); 75 } 76 77 fs::path dir; 78 fs::path imageFile; 79 fs::path cksumFile; 80 fs::path fileTableConfig; 81 82 // <4 bytes - File handle - 0 (0x00 0x00 0x00 0x00)>, 83 // <2 bytes - Filename length - 11 (0x0b 0x00> 84 // <11 bytes - Filename - ASCII for NVRAM-IMAGE> 85 // <4 bytes - File size - 1024 (0x00 0x04 0x00 0x00)> 86 // <4 bytes - File traits - 1 (0x01 0x00 0x00 0x00)> 87 // <4 bytes - File handle - 1 (0x01 0x00 0x00 0x00)>, 88 // <2 bytes - Filename length - 17 (0x11 0x00> 89 // <17 bytes - Filename - ASCII for NVRAM-IMAGE-CKSUM> 90 // <4 bytes - File size - 16 (0x0f 0x00 0x00 0x00)> 91 // <4 bytes - File traits - 4 (0x04 0x00 0x00 0x00)> 92 // No pad bytes added since the length for both the file entries in the 93 // table is 56, which is a multiple of 4. 94 // <4 bytes - Checksum - 2088303182(0x4e 0xfa 0x78 0x7c)> 95 Table attrTable = { 96 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 0x2d, 97 0x49, 0x4d, 0x41, 0x47, 0x45, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x00, 98 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x4e, 0x56, 0x52, 0x41, 0x4d, 99 0x2d, 0x49, 0x4d, 0x41, 0x47, 0x45, 0x2d, 0x43, 0x4b, 0x53, 0x55, 0x4d, 100 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4e, 0xfa, 0x78, 0x7c}; 101 }; 102 103 namespace pldm 104 { 105 106 namespace responder 107 { 108 109 namespace dma 110 { 111 112 class MockDMA 113 { 114 public: 115 MOCK_METHOD5(transferDataHost, 116 int(const fs::path& file, uint32_t offset, uint32_t length, 117 uint64_t address, bool upstream)); 118 }; 119 120 } // namespace dma 121 } // namespace responder 122 } // namespace pldm 123 using namespace pldm::responder; 124 using ::testing::_; 125 using ::testing::Return; 126 127 TEST(TransferDataHost, GoodPath) 128 { 129 using namespace pldm::responder::dma; 130 131 MockDMA dmaObj; 132 fs::path path(""); 133 134 // Minimum length of 16 and expect transferDataHost to be called once 135 // returns the default value of 0 (the return type of transferDataHost is 136 // int, the default value for int is 0) 137 uint32_t length = minSize; 138 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1); 139 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, 140 path, 0, length, 0, true, 0); 141 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 142 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 143 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 144 &length, sizeof(length))); 145 146 // maxsize of DMA 147 length = maxSize; 148 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1); 149 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 150 0, length, 0, true, 0); 151 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 152 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 153 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 154 &length, sizeof(length))); 155 156 // length greater than maxsize of DMA 157 length = maxSize + minSize; 158 EXPECT_CALL(dmaObj, transferDataHost(path, 0, maxSize, 0, true)).Times(1); 159 EXPECT_CALL(dmaObj, transferDataHost(path, maxSize, minSize, maxSize, true)) 160 .Times(1); 161 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 162 0, length, 0, true, 0); 163 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 164 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 165 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 166 &length, sizeof(length))); 167 168 // length greater than 2*maxsize of DMA 169 length = 3 * maxSize; 170 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, true)).Times(3); 171 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 172 0, length, 0, true, 0); 173 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 174 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 175 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 176 &length, sizeof(length))); 177 178 // check for downstream(copy data from host to BMC) parameter 179 length = minSize; 180 EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, false)).Times(1); 181 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 182 0, length, 0, false, 0); 183 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 184 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 185 ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]), 186 &length, sizeof(length))); 187 } 188 189 TEST(TransferDataHost, BadPath) 190 { 191 using namespace pldm::responder::dma; 192 193 MockDMA dmaObj; 194 fs::path path(""); 195 196 // Minimum length of 16 and transferDataHost returning a negative errno 197 uint32_t length = minSize; 198 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1)); 199 auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, 200 path, 0, length, 0, true, 0); 201 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 202 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR); 203 204 // length greater than maxsize of DMA and transferDataHost returning a 205 // negative errno 206 length = maxSize + minSize; 207 EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1)); 208 response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path, 209 0, length, 0, true, 0); 210 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 211 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR); 212 } 213 214 TEST(ReadFileIntoMemory, BadPath) 215 { 216 uint32_t fileHandle = 0; 217 uint32_t offset = 0; 218 uint32_t length = 10; 219 uint64_t address = 0; 220 221 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 222 requestMsg{}; 223 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 224 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 225 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 226 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 227 sizeof(length)); 228 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 229 sizeof(length), 230 &address, sizeof(address)); 231 232 // Pass invalid payload length 233 auto response = readFileIntoMemory(request, 0); 234 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 235 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 236 } 237 238 TEST_F(TestFileTable, ReadFileInvalidFileHandle) 239 { 240 // Invalid file handle in the file table 241 uint32_t fileHandle = 2; 242 uint32_t offset = 0; 243 uint32_t length = 0; 244 uint64_t address = 0; 245 246 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 247 requestMsg{}; 248 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 249 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 250 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 251 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 252 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 253 sizeof(length)); 254 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 255 sizeof(length), 256 &address, sizeof(address)); 257 258 using namespace pldm::filetable; 259 // Initialise the file table with 2 valid file handles 0 & 1. 260 auto& table = buildFileTable(fileTableConfig.c_str()); 261 262 auto response = readFileIntoMemory(request, requestPayloadLength); 263 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 264 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 265 // Clear the file table contents. 266 table.clear(); 267 } 268 269 TEST_F(TestFileTable, ReadFileInvalidOffset) 270 { 271 uint32_t fileHandle = 0; 272 // The file size is 1024, so the offset is invalid 273 uint32_t offset = 1024; 274 uint32_t length = 0; 275 uint64_t address = 0; 276 277 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 278 requestMsg{}; 279 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 280 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 281 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 282 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 283 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 284 sizeof(length)); 285 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 286 sizeof(length), 287 &address, sizeof(address)); 288 289 using namespace pldm::filetable; 290 auto& table = buildFileTable(fileTableConfig.c_str()); 291 292 auto response = readFileIntoMemory(request, requestPayloadLength); 293 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 294 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 295 // Clear the file table contents. 296 table.clear(); 297 } 298 299 TEST_F(TestFileTable, ReadFileInvalidLength) 300 { 301 uint32_t fileHandle = 0; 302 uint32_t offset = 100; 303 // Length should be a multiple of dma min size(16) 304 uint32_t length = 10; 305 uint64_t address = 0; 306 307 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 308 requestMsg{}; 309 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 310 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 311 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 312 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 313 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 314 sizeof(length)); 315 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 316 sizeof(length), 317 &address, sizeof(address)); 318 319 using namespace pldm::filetable; 320 auto& table = buildFileTable(fileTableConfig.c_str()); 321 322 auto response = readFileIntoMemory(request, requestPayloadLength); 323 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 324 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH); 325 // Clear the file table contents. 326 table.clear(); 327 } 328 329 TEST_F(TestFileTable, ReadFileInvalidEffectiveLength) 330 { 331 uint32_t fileHandle = 0; 332 // valid offset 333 uint32_t offset = 100; 334 // length + offset exceeds the size, so effective length is 335 // filesize(1024) - offset(100). The effective length is not a multiple of 336 // DMA min size(16) 337 uint32_t length = 1024; 338 uint64_t address = 0; 339 340 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 341 requestMsg{}; 342 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 343 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 344 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 345 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 346 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 347 sizeof(length)); 348 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 349 sizeof(length), 350 &address, sizeof(address)); 351 352 using namespace pldm::filetable; 353 auto& table = buildFileTable(fileTableConfig.c_str()); 354 355 auto response = readFileIntoMemory(request, requestPayloadLength); 356 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 357 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_READ_LENGTH); 358 // Clear the file table contents. 359 table.clear(); 360 } 361 362 TEST(WriteFileFromMemory, BadPath) 363 { 364 uint32_t fileHandle = 0; 365 uint32_t offset = 0; 366 uint32_t length = 10; 367 uint64_t address = 0; 368 369 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 370 requestMsg{}; 371 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 372 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 373 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 374 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 375 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 376 sizeof(length)); 377 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 378 sizeof(length), 379 &address, sizeof(address)); 380 381 // Pass invalid payload length 382 auto response = writeFileFromMemory(request, 0); 383 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 384 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 385 386 // The length field is not a multiple of DMA minsize 387 response = writeFileFromMemory(request, requestPayloadLength); 388 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 389 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH); 390 } 391 392 TEST_F(TestFileTable, WriteFileInvalidFileHandle) 393 { 394 // Invalid file handle in the file table 395 uint32_t fileHandle = 2; 396 uint32_t offset = 0; 397 uint32_t length = 16; 398 uint64_t address = 0; 399 400 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 401 requestMsg{}; 402 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 403 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 404 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 405 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 406 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 407 sizeof(length)); 408 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 409 sizeof(length), 410 &address, sizeof(address)); 411 412 using namespace pldm::filetable; 413 // Initialise the file table with 2 valid file handles 0 & 1. 414 auto& table = buildFileTable(fileTableConfig.c_str()); 415 416 auto response = writeFileFromMemory(request, requestPayloadLength); 417 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 418 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 419 // Clear the file table contents. 420 table.clear(); 421 } 422 423 TEST_F(TestFileTable, WriteFileInvalidOffset) 424 { 425 uint32_t fileHandle = 0; 426 // The file size is 1024, so the offset is invalid 427 uint32_t offset = 1024; 428 uint32_t length = 16; 429 uint64_t address = 0; 430 431 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES> 432 requestMsg{}; 433 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 434 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 435 memcpy(request->payload, &fileHandle, sizeof(fileHandle)); 436 memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset)); 437 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length, 438 sizeof(length)); 439 memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) + 440 sizeof(length), 441 &address, sizeof(address)); 442 443 using namespace pldm::filetable; 444 // Initialise the file table with 2 valid file handles 0 & 1. 445 auto& table = buildFileTable(TestFileTable::fileTableConfig.c_str()); 446 447 auto response = writeFileFromMemory(request, requestPayloadLength); 448 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 449 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 450 // Clear the file table contents. 451 table.clear(); 452 } 453 454 TEST(FileTable, ConfigNotExist) 455 { 456 logs.clear(); 457 FileTable tableObj(""); 458 EXPECT_EQ(logs.size(), 1); 459 } 460 461 TEST_F(TestFileTable, ValidateFileEntry) 462 { 463 FileTable tableObj(fileTableConfig.c_str()); 464 465 // Test file handle 0, the file size is 1K bytes. 466 auto value = tableObj.at(0); 467 ASSERT_EQ(value.handle, 0); 468 ASSERT_EQ(strcmp(value.fsPath.c_str(), imageFile.c_str()), 0); 469 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value.fsPath)), 1024); 470 ASSERT_EQ(value.traits.value, 1); 471 ASSERT_EQ(true, fs::exists(value.fsPath)); 472 473 // Test file handle 1, the file size is 16 bytes 474 auto value1 = tableObj.at(1); 475 ASSERT_EQ(value1.handle, 1); 476 ASSERT_EQ(strcmp(value1.fsPath.c_str(), cksumFile.c_str()), 0); 477 ASSERT_EQ(static_cast<uint32_t>(fs::file_size(value1.fsPath)), 16); 478 ASSERT_EQ(value1.traits.value, 4); 479 ASSERT_EQ(true, fs::exists(value1.fsPath)); 480 481 // Test invalid file handle 482 ASSERT_THROW(tableObj.at(2), std::out_of_range); 483 } 484 485 TEST_F(TestFileTable, ValidateFileTable) 486 { 487 FileTable tableObj(fileTableConfig.c_str()); 488 489 // Validate file attribute table 490 auto table = tableObj(); 491 ASSERT_EQ(true, 492 std::equal(attrTable.begin(), attrTable.end(), table.begin())); 493 } 494 495 TEST_F(TestFileTable, GetFileTableCommand) 496 { 497 // Initialise the file table with a valid handle of 0 & 1 498 auto& table = buildFileTable(fileTableConfig.c_str()); 499 500 uint32_t transferHandle = 0; 501 uint8_t opFlag = 0; 502 uint8_t type = PLDM_FILE_ATTRIBUTE_TABLE; 503 uint32_t nextTransferHandle = 0; 504 uint8_t transferFlag = PLDM_START_AND_END; 505 506 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 507 requestMsg{}; 508 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 509 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 510 auto request = reinterpret_cast<pldm_get_file_table_req*>( 511 requestMsg.data() + sizeof(pldm_msg_hdr)); 512 request->transfer_handle = transferHandle; 513 request->operation_flag = opFlag; 514 request->table_type = type; 515 516 auto response = getFileTable(requestMsgPtr, requestPayloadLength); 517 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 518 ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS); 519 size_t offsetSize = sizeof(responsePtr->payload[0]); 520 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &nextTransferHandle, 521 sizeof(nextTransferHandle))); 522 offsetSize += sizeof(nextTransferHandle); 523 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, &transferFlag, 524 sizeof(transferFlag))); 525 offsetSize += sizeof(transferFlag); 526 ASSERT_EQ(0, memcmp(responsePtr->payload + offsetSize, attrTable.data(), 527 attrTable.size())); 528 table.clear(); 529 } 530 531 TEST_F(TestFileTable, GetFileTableCommandReqLengthMismatch) 532 { 533 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 534 requestMsg{}; 535 auto request = reinterpret_cast<pldm_msg*>(requestMsg.data()); 536 537 // Pass invalid command payload length 538 auto response = getFileTable(request, 0); 539 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 540 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 541 } 542 543 TEST_F(TestFileTable, GetFileTableCommandOEMAttrTable) 544 { 545 uint32_t transferHandle = 0; 546 uint8_t opFlag = 0; 547 uint8_t type = PLDM_OEM_FILE_ATTRIBUTE_TABLE; 548 549 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_FILE_TABLE_REQ_BYTES> 550 requestMsg{}; 551 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 552 size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr); 553 auto request = reinterpret_cast<pldm_get_file_table_req*>( 554 requestMsg.data() + sizeof(pldm_msg_hdr)); 555 request->transfer_handle = transferHandle; 556 request->operation_flag = opFlag; 557 request->table_type = type; 558 559 auto response = getFileTable(requestMsgPtr, requestPayloadLength); 560 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 561 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_TABLE_TYPE); 562 } 563 564 TEST_F(TestFileTable, ReadFileBadPath) 565 { 566 uint32_t fileHandle = 1; 567 uint32_t offset = 0; 568 uint32_t length = 0x4; 569 570 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 571 requestMsg{}; 572 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 573 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 574 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 575 sizeof(pldm_msg_hdr)); 576 577 request->file_handle = fileHandle; 578 request->offset = offset; 579 request->length = length; 580 581 using namespace pldm::filetable; 582 // Initialise the file table with 2 valid file handles 0 & 1. 583 auto& table = buildFileTable(fileTableConfig.c_str()); 584 585 // Invalid payload length 586 auto response = readFile(requestMsgPtr, 0); 587 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 588 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 589 590 // Data out of range. File size is 1024, offset = 1024 is invalid. 591 request->offset = 1024; 592 593 response = readFile(requestMsgPtr, payload_length); 594 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 595 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 596 597 // Invalid file handle 598 request->file_handle = 2; 599 600 response = readFile(requestMsgPtr, payload_length); 601 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 602 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 603 604 table.clear(); 605 } 606 607 TEST_F(TestFileTable, ReadFileGoodPath) 608 { 609 uint32_t fileHandle = 0; 610 uint32_t offset = 0; 611 uint32_t length = 0x4; 612 613 std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_READ_FILE_REQ_BYTES> 614 requestMsg{}; 615 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 616 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 617 auto request = reinterpret_cast<pldm_read_file_req*>(requestMsg.data() + 618 sizeof(pldm_msg_hdr)); 619 620 request->file_handle = fileHandle; 621 request->offset = offset; 622 request->length = length; 623 624 using namespace pldm::filetable; 625 // Initialise the file table with 2 valid file handles 0 & 1. 626 auto& table = buildFileTable(fileTableConfig.c_str()); 627 FileEntry value{}; 628 value = table.at(fileHandle); 629 630 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 631 stream.seekg(offset); 632 std::vector<char> buffer(length); 633 stream.read(buffer.data(), length); 634 635 auto responseMsg = readFile(requestMsgPtr, payload_length); 636 auto response = reinterpret_cast<pldm_read_file_resp*>( 637 responseMsg.data() + sizeof(pldm_msg_hdr)); 638 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 639 ASSERT_EQ(response->length, length); 640 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), length)); 641 642 // Test condition offset + length > fileSize; 643 size_t fileSize = 1024; 644 request->offset = 1023; 645 request->length = 10; 646 647 stream.seekg(request->offset); 648 buffer.resize(fileSize - request->offset); 649 stream.read(buffer.data(), (fileSize - request->offset)); 650 651 responseMsg = readFile(requestMsgPtr, payload_length); 652 response = reinterpret_cast<pldm_read_file_resp*>(responseMsg.data() + 653 sizeof(pldm_msg_hdr)); 654 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 655 ASSERT_EQ(response->length, (fileSize - request->offset)); 656 ASSERT_EQ(0, memcmp(response->file_data, buffer.data(), 657 (fileSize - request->offset))); 658 659 table.clear(); 660 } 661 662 TEST_F(TestFileTable, WriteFileBadPath) 663 { 664 uint32_t fileHandle = 0; 665 uint32_t offset = 0; 666 uint32_t length = 0x10; 667 668 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 669 PLDM_WRITE_FILE_REQ_BYTES + length); 670 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 671 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 672 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 673 sizeof(pldm_msg_hdr)); 674 675 using namespace pldm::filetable; 676 // Initialise the file table with 2 valid file handles 0 & 1. 677 auto& table = buildFileTable(fileTableConfig.c_str()); 678 679 request->file_handle = fileHandle; 680 request->offset = offset; 681 request->length = length; 682 683 // Invalid payload length 684 auto response = writeFile(requestMsgPtr, 0); 685 auto responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 686 ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH); 687 688 // Data out of range. File size is 1024, offset = 1024 is invalid. 689 request->offset = 1024; 690 691 response = writeFile(requestMsgPtr, payload_length); 692 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 693 ASSERT_EQ(responsePtr->payload[0], PLDM_DATA_OUT_OF_RANGE); 694 695 // Invalid file handle 696 request->file_handle = 2; 697 698 response = writeFile(requestMsgPtr, payload_length); 699 responsePtr = reinterpret_cast<pldm_msg*>(response.data()); 700 ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_FILE_HANDLE); 701 702 table.clear(); 703 } 704 705 TEST_F(TestFileTable, WriteFileGoodPath) 706 { 707 uint32_t fileHandle = 1; 708 uint32_t offset = 0; 709 std::array<uint8_t, 4> fileData = {0x41, 0x42, 0x43, 0x44}; 710 uint32_t length = fileData.size(); 711 712 std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) + 713 PLDM_WRITE_FILE_REQ_BYTES + length); 714 auto requestMsgPtr = reinterpret_cast<pldm_msg*>(requestMsg.data()); 715 auto payload_length = requestMsg.size() - sizeof(pldm_msg_hdr); 716 auto request = reinterpret_cast<pldm_write_file_req*>(requestMsg.data() + 717 sizeof(pldm_msg_hdr)); 718 719 using namespace pldm::filetable; 720 // Initialise the file table with 2 valid file handles 0 & 1. 721 auto& table = buildFileTable(fileTableConfig.c_str()); 722 FileEntry value{}; 723 value = table.at(fileHandle); 724 725 request->file_handle = fileHandle; 726 request->offset = offset; 727 request->length = length; 728 memcpy(request->file_data, fileData.data(), fileData.size()); 729 730 auto responseMsg = writeFile(requestMsgPtr, payload_length); 731 auto response = reinterpret_cast<pldm_read_file_resp*>( 732 responseMsg.data() + sizeof(pldm_msg_hdr)); 733 734 std::ifstream stream(value.fsPath, std::ios::in | std::ios::binary); 735 stream.seekg(offset); 736 std::vector<char> buffer(length); 737 stream.read(buffer.data(), length); 738 739 ASSERT_EQ(response->completion_code, PLDM_SUCCESS); 740 ASSERT_EQ(response->length, length); 741 ASSERT_EQ(0, memcmp(fileData.data(), buffer.data(), length)); 742 743 table.clear(); 744 } 745