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