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