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