blob: 47359ccd1a3cb5b729b1b1d2b93c3d75aaa6246f [file] [log] [blame]
Patrick Ventureef3aead2018-09-12 08:53:29 -07001#include "ipmi.hpp"
Patrick Venturecd8dab42019-01-15 19:57:38 -08002#include "manager_mock.hpp"
Patrick Ventureef3aead2018-09-12 08:53:29 -07003#include "process.hpp"
4
Patrick Ventureef3aead2018-09-12 08:53:29 -07005#include <cstring>
Patrick Venturede8a16e2019-03-07 12:48:32 -08006#include <ipmiblob/test/crc_mock.hpp>
Patrick Ventureef3aead2018-09-12 08:53:29 -07007
8#include <gtest/gtest.h>
9
Patrick Ventureef3aead2018-09-12 08:53:29 -070010// ipmid.hpp isn't installed where we can grab it and this value is per BMC
11// SoC.
12#define MAX_IPMI_BUFFER 64
13
Patrick Venturede8a16e2019-03-07 12:48:32 -080014using ::testing::_;
15using ::testing::Eq;
16using ::testing::Invoke;
17using ::testing::Return;
18using ::testing::StrictMock;
19
20namespace ipmiblob
21{
22CrcInterface* crcIntf = nullptr;
23
24std::uint16_t generateCrc(const std::vector<std::uint8_t>& data)
25{
26 return (crcIntf) ? crcIntf->generateCrc(data) : 0x00;
27}
28} // namespace ipmiblob
29
30namespace blobs
31{
Patrick Ventureef3aead2018-09-12 08:53:29 -070032namespace
33{
34
35void EqualFunctions(IpmiBlobHandler lhs, IpmiBlobHandler rhs)
36{
37 EXPECT_FALSE(lhs == nullptr);
38 EXPECT_FALSE(rhs == nullptr);
39
40 ipmi_ret_t (*const* lPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
41 size_t*) =
42 lhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
43 size_t*)>();
44
45 ipmi_ret_t (*const* rPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
46 size_t*) =
47 rhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
48 size_t*)>();
49
50 EXPECT_TRUE(lPtr);
51 EXPECT_TRUE(rPtr);
52 EXPECT_EQ(*lPtr, *rPtr);
53 return;
54}
55
56} // namespace
57
Patrick Venturede8a16e2019-03-07 12:48:32 -080058class ValidateBlobCommandTest : public ::testing::Test
59{
60 protected:
61 void SetUp() override
62 {
63 ipmiblob::crcIntf = &crcMock;
64 }
65
66 ipmiblob::CrcMock crcMock;
67};
68
69TEST_F(ValidateBlobCommandTest, InvalidCommandReturnsFailure)
Patrick Ventureef3aead2018-09-12 08:53:29 -070070{
71 // Verify we handle an invalid command.
72
Patrick Ventureef3aead2018-09-12 08:53:29 -070073 size_t dataLen;
74 uint8_t request[MAX_IPMI_BUFFER] = {0};
75 uint8_t reply[MAX_IPMI_BUFFER] = {0};
76
77 request[0] = 0xff; // There is no command 0xff.
78 dataLen = sizeof(uint8_t); // There is no payload for CRC.
Patrick Venture41258802018-11-12 10:46:30 -080079 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -070080
Patrick Venturede8a16e2019-03-07 12:48:32 -080081 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -080082 EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -070083}
84
Patrick Venturede8a16e2019-03-07 12:48:32 -080085TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -070086{
87 // Verify we handle a valid command that doesn't have a payload.
88
Patrick Ventureef3aead2018-09-12 08:53:29 -070089 size_t dataLen;
90 uint8_t request[MAX_IPMI_BUFFER] = {0};
91 uint8_t reply[MAX_IPMI_BUFFER] = {0};
92
Patrick Venture00d5f0d2019-05-17 19:21:35 -070093 request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
Patrick Ventureef3aead2018-09-12 08:53:29 -070094 dataLen = sizeof(uint8_t); // There is no payload for CRC.
Patrick Venture41258802018-11-12 10:46:30 -080095 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -070096
Patrick Venturede8a16e2019-03-07 12:48:32 -080097 IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -070098 EXPECT_FALSE(res == nullptr);
99 EqualFunctions(getBlobCount, res);
100}
101
Patrick Venturede8a16e2019-03-07 12:48:32 -0800102TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700103{
104 // Verify that if there's a payload, it's at least one command byte and
105 // two bytes for the crc16 and then one data byte.
106
Patrick Ventureef3aead2018-09-12 08:53:29 -0700107 size_t dataLen;
108 uint8_t request[MAX_IPMI_BUFFER] = {0};
109 uint8_t reply[MAX_IPMI_BUFFER] = {0};
110
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700111 request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700112 dataLen = sizeof(uint8_t) + sizeof(uint16_t);
113 // There is a payload, but there are insufficient bytes.
Patrick Venture41258802018-11-12 10:46:30 -0800114 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700115
Patrick Venturede8a16e2019-03-07 12:48:32 -0800116 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -0800117 EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700118}
119
Patrick Venturede8a16e2019-03-07 12:48:32 -0800120TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700121{
122 // Verify that the CRC is checked, and failure is reported.
123
Patrick Ventureef3aead2018-09-12 08:53:29 -0700124 size_t dataLen;
125 uint8_t request[MAX_IPMI_BUFFER] = {0};
126 uint8_t reply[MAX_IPMI_BUFFER] = {0};
127
128 auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700129 req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700130 req->crc = 0x34;
131 req->sessionId = 0x54;
132 req->offset = 0x100;
133
134 uint8_t expectedBytes[2] = {0x66, 0x67};
William A. Kennington III117912d2021-06-15 18:22:44 -0700135 std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700136
137 dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
138
139 // skip over cmd and crc.
Patrick Venturede8a16e2019-03-07 12:48:32 -0800140 std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
141 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700142
Patrick Venture41258802018-11-12 10:46:30 -0800143 ipmi_ret_t rc;
144
Patrick Venturede8a16e2019-03-07 12:48:32 -0800145 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -0800146 EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700147}
148
Patrick Venturede8a16e2019-03-07 12:48:32 -0800149TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700150{
151 // Verify the CRC is checked and if it matches, return the handler.
152
Patrick Ventureef3aead2018-09-12 08:53:29 -0700153 size_t dataLen;
154 uint8_t request[MAX_IPMI_BUFFER] = {0};
155 uint8_t reply[MAX_IPMI_BUFFER] = {0};
156
157 auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700158 req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700159 req->crc = 0x3412;
160 req->sessionId = 0x54;
161 req->offset = 0x100;
162
163 uint8_t expectedBytes[2] = {0x66, 0x67};
William A. Kennington III117912d2021-06-15 18:22:44 -0700164 std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700165
166 dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
167
168 // skip over cmd and crc.
Patrick Venturede8a16e2019-03-07 12:48:32 -0800169 std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
170 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700171
Patrick Venture41258802018-11-12 10:46:30 -0800172 ipmi_ret_t rc;
173
Patrick Venturede8a16e2019-03-07 12:48:32 -0800174 IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700175 EXPECT_FALSE(res == nullptr);
176 EqualFunctions(writeBlob, res);
177}
178
Patrick Venturede8a16e2019-03-07 12:48:32 -0800179class ProcessBlobCommandTest : public ::testing::Test
Patrick Ventureef3aead2018-09-12 08:53:29 -0700180{
Patrick Venturede8a16e2019-03-07 12:48:32 -0800181 protected:
182 void SetUp() override
183 {
184 ipmiblob::crcIntf = &crcMock;
185 }
Patrick Ventureef3aead2018-09-12 08:53:29 -0700186
Patrick Venturede8a16e2019-03-07 12:48:32 -0800187 ipmiblob::CrcMock crcMock;
188};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700189
Patrick Venturede8a16e2019-03-07 12:48:32 -0800190TEST_F(ProcessBlobCommandTest, CommandReturnsNotOk)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700191{
192 // Verify that if the IPMI command handler returns not OK that this is
193 // noticed and returned.
194
Patrick Ventureef3aead2018-09-12 08:53:29 -0700195 StrictMock<ManagerMock> manager;
196 size_t dataLen;
197 uint8_t request[MAX_IPMI_BUFFER] = {0};
198 uint8_t reply[MAX_IPMI_BUFFER] = {0};
199
William A. Kennington III993f5412021-06-15 18:19:18 -0700200 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
201 size_t*) { return IPMI_CC_INVALID; };
Patrick Ventureef3aead2018-09-12 08:53:29 -0700202
203 dataLen = sizeof(request);
204
205 EXPECT_EQ(IPMI_CC_INVALID,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800206 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700207}
208
Patrick Venturede8a16e2019-03-07 12:48:32 -0800209TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700210{
211 // Verify that if the IPMI command handler returns OK but without a payload
212 // it doesn't try to compute a CRC.
213
Patrick Ventureef3aead2018-09-12 08:53:29 -0700214 StrictMock<ManagerMock> manager;
215 size_t dataLen;
216 uint8_t request[MAX_IPMI_BUFFER] = {0};
217 uint8_t reply[MAX_IPMI_BUFFER] = {0};
218
William A. Kennington III993f5412021-06-15 18:19:18 -0700219 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
220 size_t* dataLen) {
Patrick Ventureef3aead2018-09-12 08:53:29 -0700221 (*dataLen) = 0;
222 return IPMI_CC_OK;
223 };
224
225 dataLen = sizeof(request);
226
227 EXPECT_EQ(IPMI_CC_OK,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800228 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700229}
230
Patrick Venturede8a16e2019-03-07 12:48:32 -0800231TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700232{
Patrick Ventured1c3e862019-01-10 13:12:20 -0800233 // There is a minimum payload length of 2 bytes (the CRC only, no data, for
234 // read), this returns 1.
Patrick Ventureef3aead2018-09-12 08:53:29 -0700235
Patrick Ventureef3aead2018-09-12 08:53:29 -0700236 StrictMock<ManagerMock> manager;
237 size_t dataLen;
238 uint8_t request[MAX_IPMI_BUFFER] = {0};
239 uint8_t reply[MAX_IPMI_BUFFER] = {0};
240
William A. Kennington III993f5412021-06-15 18:19:18 -0700241 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
242 size_t* dataLen) {
Patrick Ventured1c3e862019-01-10 13:12:20 -0800243 (*dataLen) = sizeof(uint8_t);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700244 return IPMI_CC_OK;
245 };
246
247 dataLen = sizeof(request);
248
Patrick Venture41258802018-11-12 10:46:30 -0800249 EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800250 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700251}
252
Patrick Venturede8a16e2019-03-07 12:48:32 -0800253TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700254{
255 // There is a minimum payload length of 3 bytes, this command returns a
256 // payload of 3 bytes and the crc code is called to process the payload.
257
Patrick Ventureef3aead2018-09-12 08:53:29 -0700258 StrictMock<ManagerMock> manager;
259 size_t dataLen;
260 uint8_t request[MAX_IPMI_BUFFER] = {0};
261 uint8_t reply[MAX_IPMI_BUFFER] = {0};
262 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
263
William A. Kennington III993f5412021-06-15 18:19:18 -0700264 IpmiBlobHandler h = [payloadLen](ManagerInterface*, const uint8_t*,
Patrick Ventureef3aead2018-09-12 08:53:29 -0700265 uint8_t* replyCmdBuf, size_t* dataLen) {
266 (*dataLen) = payloadLen;
267 replyCmdBuf[2] = 0x56;
268 return IPMI_CC_OK;
269 };
270
271 dataLen = sizeof(request);
272
Patrick Venturede8a16e2019-03-07 12:48:32 -0800273 EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700274
275 EXPECT_EQ(IPMI_CC_OK,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800276 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700277 EXPECT_EQ(dataLen, payloadLen);
278
279 uint8_t expectedBytes[3] = {0x12, 0x34, 0x56};
280 EXPECT_EQ(0, std::memcmp(expectedBytes, reply, sizeof(expectedBytes)));
281}
282} // namespace blobs