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