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, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
150         requestMsg{};
151     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
152     memcpy(request->payload, &fileHandle, sizeof(fileHandle));
153     memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
154     memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
155            sizeof(length));
156     memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
157                sizeof(length),
158            &address, sizeof(address));
159 
160     // Pass invalid payload length
161     auto response = readFileIntoMemory(request, 0);
162     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
163     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
164 }
165 
166 TEST(WriteFileFromMemory, BadPath)
167 {
168     uint32_t fileHandle = 0;
169     uint32_t offset = 0;
170     uint32_t length = 10;
171     uint64_t address = 0;
172 
173     std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_RW_FILE_MEM_REQ_BYTES>
174         requestMsg{};
175     auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
176     size_t requestPayloadLength = requestMsg.size() - sizeof(pldm_msg_hdr);
177     memcpy(request->payload, &fileHandle, sizeof(fileHandle));
178     memcpy(request->payload + sizeof(fileHandle), &offset, sizeof(offset));
179     memcpy(request->payload + sizeof(fileHandle) + sizeof(offset), &length,
180            sizeof(length));
181     memcpy(request->payload + sizeof(fileHandle) + sizeof(offset) +
182                sizeof(length),
183            &address, sizeof(address));
184 
185     // Pass invalid payload length
186     auto response = writeFileFromMemory(request, 0);
187     auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
188     ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR_INVALID_LENGTH);
189 
190     // The length field is not a multiple of DMA minsize
191     response = writeFileFromMemory(request, requestPayloadLength);
192     responsePtr = reinterpret_cast<pldm_msg*>(response.data());
193     ASSERT_EQ(responsePtr->payload[0], PLDM_INVALID_WRITE_LENGTH);
194 }
195