1 #include "libpldmresponder/file_io.hpp"
2 
3 #include "libpldm/base.h"
4 #include "libpldm/file_io.h"
5 
6 #include <gmock/gmock-matchers.h>
7 #include <gmock/gmock.h>
8 #include <gtest/gtest.h>
9 #define SD_JOURNAL_SUPPRESS_LOCATION
10 
11 #include <systemd/sd-journal.h>
12 
13 std::vector<std::string> logs;
14 
15 extern "C" {
16 
17 int sd_journal_send(const char* format, ...)
18 {
19     logs.push_back(format);
20     return 0;
21 }
22 
23 int sd_journal_send_with_location(const char* file, const char* line,
24                                   const char* func, const char* format, ...)
25 {
26     logs.push_back(format);
27     return 0;
28 }
29 }
30 
31 namespace pldm
32 {
33 
34 namespace responder
35 {
36 
37 namespace dma
38 {
39 
40 class MockDMA
41 {
42   public:
43     MOCK_METHOD5(transferDataHost,
44                  int(const fs::path& file, uint32_t offset, uint32_t length,
45                      uint64_t address, bool upstream));
46 };
47 
48 } // namespace dma
49 } // namespace responder
50 } // namespace pldm
51 using namespace pldm::responder;
52 using ::testing::_;
53 using ::testing::Return;
54 
55 TEST(TransferDataHost, GoodPath)
56 {
57     using namespace pldm::responder::dma;
58 
59     MockDMA dmaObj;
60     fs::path path("");
61 
62     // Minimum length of 16 and expect transferDataHost to be called once
63     // returns the default value of 0 (the return type of transferDataHost is
64     // int, the default value for int is 0)
65     uint32_t length = minSize;
66     EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
67     auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY,
68                                          path, 0, length, 0, true);
69     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
70     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
71     ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
72                         &length, sizeof(length)));
73 
74     // maxsize of DMA
75     length = maxSize;
76     EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, true)).Times(1);
77     response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
78                                     0, length, 0, true);
79     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
80     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
81     ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
82                         &length, sizeof(length)));
83 
84     // length greater than maxsize of DMA
85     length = maxSize + minSize;
86     EXPECT_CALL(dmaObj, transferDataHost(path, 0, maxSize, 0, true)).Times(1);
87     EXPECT_CALL(dmaObj, transferDataHost(path, maxSize, minSize, maxSize, true))
88         .Times(1);
89     response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
90                                     0, length, 0, true);
91     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
92     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
93     ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
94                         &length, sizeof(length)));
95 
96     // length greater than 2*maxsize of DMA
97     length = 3 * maxSize;
98     EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, true)).Times(3);
99     response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
100                                     0, length, 0, true);
101     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
102     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
103     ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
104                         &length, sizeof(length)));
105 
106     // check for downstream(copy data from host to BMC) parameter
107     length = minSize;
108     EXPECT_CALL(dmaObj, transferDataHost(path, 0, length, 0, false)).Times(1);
109     response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
110                                     0, length, 0, false);
111     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
112     ASSERT_EQ(responsePtr->payload[0], PLDM_SUCCESS);
113     ASSERT_EQ(0, memcmp(responsePtr->payload + sizeof(responsePtr->payload[0]),
114                         &length, sizeof(length)));
115 }
116 
117 TEST(TransferDataHost, BadPath)
118 {
119     using namespace pldm::responder::dma;
120 
121     MockDMA dmaObj;
122     fs::path path("");
123 
124     // Minimum length of 16 and transferDataHost returning a negative errno
125     uint32_t length = minSize;
126     EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1));
127     auto response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY,
128                                          path, 0, length, 0, true);
129     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
130     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
131 
132     // length greater than maxsize of DMA and transferDataHost returning a
133     // negative errno
134     length = maxSize + minSize;
135     EXPECT_CALL(dmaObj, transferDataHost(_, _, _, _, _)).WillOnce(Return(-1));
136     response = transferAll<MockDMA>(&dmaObj, PLDM_READ_FILE_INTO_MEMORY, path,
137                                     0, length, 0, true);
138     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
139     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
140 }
141 
142 TEST(ReadFileIntoMemory, BadPath)
143 {
144     uint32_t fileHandle = 0;
145     uint32_t offset = 0;
146     uint32_t length = 10;
147     uint64_t address = 0;
148 
149     std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
150     memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
151     memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
152     memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
153            sizeof(length));
154     memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
155                sizeof(length),
156            &address, sizeof(address));
157 
158     // Pass invalid payload length
159     auto response = readFileIntoMemory(requestMsg.data(), 0);
160     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
161     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
162 }
163 
164 TEST(WriteFileFromMemory, BadPath)
165 {
166     uint32_t fileHandle = 0;
167     uint32_t offset = 0;
168     uint32_t length = 10;
169     uint64_t address = 0;
170 
171     std::array<uint8_t, PLDM_RW_FILE_MEM_REQ_BYTES> requestMsg{};
172     memcpy(requestMsg.data(), &fileHandle, sizeof(fileHandle));
173     memcpy(requestMsg.data() + sizeof(fileHandle), &offset, sizeof(offset));
174     memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset), &length,
175            sizeof(length));
176     memcpy(requestMsg.data() + sizeof(fileHandle) + sizeof(offset) +
177                sizeof(length),
178            &address, sizeof(address));
179 
180     // Pass invalid payload length
181     auto response = writeFileFromMemory(requestMsg.data(), 0);
182     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
183     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
184 
185     // The length field is not a multiple of DMA minsize
186     response = writeFileFromMemory(requestMsg.data(), requestMsg.size());
187     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
188     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
189 }
190