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