blob: b72fe9a092bea8042849dfbbcd5f4b9ca9de6a5e [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;
Patrick Venturede8a16e2019-03-07 12:48:32 -080016using ::testing::Return;
17using ::testing::StrictMock;
18
19namespace ipmiblob
20{
21CrcInterface* crcIntf = nullptr;
22
23std::uint16_t generateCrc(const std::vector<std::uint8_t>& data)
24{
25 return (crcIntf) ? crcIntf->generateCrc(data) : 0x00;
26}
27} // namespace ipmiblob
28
29namespace blobs
30{
Patrick Ventureef3aead2018-09-12 08:53:29 -070031namespace
32{
33
34void EqualFunctions(IpmiBlobHandler lhs, IpmiBlobHandler rhs)
35{
36 EXPECT_FALSE(lhs == nullptr);
37 EXPECT_FALSE(rhs == nullptr);
38
39 ipmi_ret_t (*const* lPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
40 size_t*) =
41 lhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
42 size_t*)>();
43
44 ipmi_ret_t (*const* rPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
45 size_t*) =
46 rhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
47 size_t*)>();
48
49 EXPECT_TRUE(lPtr);
50 EXPECT_TRUE(rPtr);
51 EXPECT_EQ(*lPtr, *rPtr);
Patrick Ventureef3aead2018-09-12 08:53:29 -070052}
53
54} // namespace
55
Patrick Venturede8a16e2019-03-07 12:48:32 -080056class ValidateBlobCommandTest : public ::testing::Test
57{
58 protected:
59 void SetUp() override
60 {
61 ipmiblob::crcIntf = &crcMock;
62 }
63
64 ipmiblob::CrcMock crcMock;
65};
66
67TEST_F(ValidateBlobCommandTest, InvalidCommandReturnsFailure)
Patrick Ventureef3aead2018-09-12 08:53:29 -070068{
69 // Verify we handle an invalid command.
70
Patrick Ventureef3aead2018-09-12 08:53:29 -070071 size_t dataLen;
72 uint8_t request[MAX_IPMI_BUFFER] = {0};
73 uint8_t reply[MAX_IPMI_BUFFER] = {0};
74
75 request[0] = 0xff; // There is no command 0xff.
76 dataLen = sizeof(uint8_t); // There is no payload for CRC.
Patrick Venture41258802018-11-12 10:46:30 -080077 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -070078
Patrick Venturede8a16e2019-03-07 12:48:32 -080079 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -080080 EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -070081}
82
Patrick Venturede8a16e2019-03-07 12:48:32 -080083TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -070084{
85 // Verify we handle a valid command that doesn't have a payload.
86
Patrick Ventureef3aead2018-09-12 08:53:29 -070087 size_t dataLen;
88 uint8_t request[MAX_IPMI_BUFFER] = {0};
89 uint8_t reply[MAX_IPMI_BUFFER] = {0};
90
Patrick Venture00d5f0d2019-05-17 19:21:35 -070091 request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
Patrick Ventureef3aead2018-09-12 08:53:29 -070092 dataLen = sizeof(uint8_t); // There is no payload for CRC.
Patrick Venture41258802018-11-12 10:46:30 -080093 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -070094
Patrick Venturede8a16e2019-03-07 12:48:32 -080095 IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -070096 EXPECT_FALSE(res == nullptr);
97 EqualFunctions(getBlobCount, res);
98}
99
Patrick Venturede8a16e2019-03-07 12:48:32 -0800100TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700101{
102 // Verify that if there's a payload, it's at least one command byte and
103 // two bytes for the crc16 and then one data byte.
104
Patrick Ventureef3aead2018-09-12 08:53:29 -0700105 size_t dataLen;
106 uint8_t request[MAX_IPMI_BUFFER] = {0};
107 uint8_t reply[MAX_IPMI_BUFFER] = {0};
108
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700109 request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700110 dataLen = sizeof(uint8_t) + sizeof(uint16_t);
111 // There is a payload, but there are insufficient bytes.
Patrick Venture41258802018-11-12 10:46:30 -0800112 ipmi_ret_t rc;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700113
Patrick Venturede8a16e2019-03-07 12:48:32 -0800114 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -0800115 EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700116}
117
Patrick Venturede8a16e2019-03-07 12:48:32 -0800118TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700119{
120 // Verify that the CRC is checked, and failure is reported.
121
Patrick Ventureef3aead2018-09-12 08:53:29 -0700122 size_t dataLen;
123 uint8_t request[MAX_IPMI_BUFFER] = {0};
124 uint8_t reply[MAX_IPMI_BUFFER] = {0};
125
126 auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700127 req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700128 req->crc = 0x34;
129 req->sessionId = 0x54;
130 req->offset = 0x100;
131
132 uint8_t expectedBytes[2] = {0x66, 0x67};
William A. Kennington III117912d2021-06-15 18:22:44 -0700133 std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700134
135 dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
136
137 // skip over cmd and crc.
Patrick Venturede8a16e2019-03-07 12:48:32 -0800138 std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
139 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700140
Patrick Venture41258802018-11-12 10:46:30 -0800141 ipmi_ret_t rc;
142
Patrick Venturede8a16e2019-03-07 12:48:32 -0800143 EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
Patrick Venture41258802018-11-12 10:46:30 -0800144 EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR, rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700145}
146
Patrick Venturede8a16e2019-03-07 12:48:32 -0800147TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700148{
149 // Verify the CRC is checked and if it matches, return the handler.
150
Patrick Ventureef3aead2018-09-12 08:53:29 -0700151 size_t dataLen;
152 uint8_t request[MAX_IPMI_BUFFER] = {0};
153 uint8_t reply[MAX_IPMI_BUFFER] = {0};
154
155 auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
Patrick Venture00d5f0d2019-05-17 19:21:35 -0700156 req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700157 req->crc = 0x3412;
158 req->sessionId = 0x54;
159 req->offset = 0x100;
160
161 uint8_t expectedBytes[2] = {0x66, 0x67};
William A. Kennington III117912d2021-06-15 18:22:44 -0700162 std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700163
164 dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
165
166 // skip over cmd and crc.
Patrick Venturede8a16e2019-03-07 12:48:32 -0800167 std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
168 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700169
Patrick Venture41258802018-11-12 10:46:30 -0800170 ipmi_ret_t rc;
171
Patrick Venturede8a16e2019-03-07 12:48:32 -0800172 IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700173 EXPECT_FALSE(res == nullptr);
174 EqualFunctions(writeBlob, res);
175}
176
Patrick Venturede8a16e2019-03-07 12:48:32 -0800177class ProcessBlobCommandTest : public ::testing::Test
Patrick Ventureef3aead2018-09-12 08:53:29 -0700178{
Patrick Venturede8a16e2019-03-07 12:48:32 -0800179 protected:
180 void SetUp() override
181 {
182 ipmiblob::crcIntf = &crcMock;
183 }
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184
Patrick Venturede8a16e2019-03-07 12:48:32 -0800185 ipmiblob::CrcMock crcMock;
186};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700187
Patrick Venturede8a16e2019-03-07 12:48:32 -0800188TEST_F(ProcessBlobCommandTest, CommandReturnsNotOk)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700189{
190 // Verify that if the IPMI command handler returns not OK that this is
191 // noticed and returned.
192
Patrick Ventureef3aead2018-09-12 08:53:29 -0700193 StrictMock<ManagerMock> manager;
194 size_t dataLen;
195 uint8_t request[MAX_IPMI_BUFFER] = {0};
196 uint8_t reply[MAX_IPMI_BUFFER] = {0};
197
William A. Kennington III993f5412021-06-15 18:19:18 -0700198 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
199 size_t*) { return IPMI_CC_INVALID; };
Patrick Ventureef3aead2018-09-12 08:53:29 -0700200
201 dataLen = sizeof(request);
202
203 EXPECT_EQ(IPMI_CC_INVALID,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800204 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700205}
206
Patrick Venturede8a16e2019-03-07 12:48:32 -0800207TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700208{
209 // Verify that if the IPMI command handler returns OK but without a payload
210 // it doesn't try to compute a CRC.
211
Patrick Ventureef3aead2018-09-12 08:53:29 -0700212 StrictMock<ManagerMock> manager;
213 size_t dataLen;
214 uint8_t request[MAX_IPMI_BUFFER] = {0};
215 uint8_t reply[MAX_IPMI_BUFFER] = {0};
216
William A. Kennington III993f5412021-06-15 18:19:18 -0700217 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
218 size_t* dataLen) {
Patrick Ventureef3aead2018-09-12 08:53:29 -0700219 (*dataLen) = 0;
220 return IPMI_CC_OK;
221 };
222
223 dataLen = sizeof(request);
224
225 EXPECT_EQ(IPMI_CC_OK,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800226 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700227}
228
Patrick Venturede8a16e2019-03-07 12:48:32 -0800229TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700230{
Patrick Ventured1c3e862019-01-10 13:12:20 -0800231 // There is a minimum payload length of 2 bytes (the CRC only, no data, for
232 // read), this returns 1.
Patrick Ventureef3aead2018-09-12 08:53:29 -0700233
Patrick Ventureef3aead2018-09-12 08:53:29 -0700234 StrictMock<ManagerMock> manager;
235 size_t dataLen;
236 uint8_t request[MAX_IPMI_BUFFER] = {0};
237 uint8_t reply[MAX_IPMI_BUFFER] = {0};
238
William A. Kennington III993f5412021-06-15 18:19:18 -0700239 IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
240 size_t* dataLen) {
Patrick Ventured1c3e862019-01-10 13:12:20 -0800241 (*dataLen) = sizeof(uint8_t);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700242 return IPMI_CC_OK;
243 };
244
245 dataLen = sizeof(request);
246
Patrick Venture41258802018-11-12 10:46:30 -0800247 EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800248 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700249}
250
Patrick Venturede8a16e2019-03-07 12:48:32 -0800251TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700252{
253 // There is a minimum payload length of 3 bytes, this command returns a
254 // payload of 3 bytes and the crc code is called to process the payload.
255
Patrick Ventureef3aead2018-09-12 08:53:29 -0700256 StrictMock<ManagerMock> manager;
257 size_t dataLen;
258 uint8_t request[MAX_IPMI_BUFFER] = {0};
259 uint8_t reply[MAX_IPMI_BUFFER] = {0};
260 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
261
William A. Kennington III993f5412021-06-15 18:19:18 -0700262 IpmiBlobHandler h = [payloadLen](ManagerInterface*, const uint8_t*,
Patrick Ventureef3aead2018-09-12 08:53:29 -0700263 uint8_t* replyCmdBuf, size_t* dataLen) {
264 (*dataLen) = payloadLen;
265 replyCmdBuf[2] = 0x56;
266 return IPMI_CC_OK;
267 };
268
269 dataLen = sizeof(request);
270
Patrick Venturede8a16e2019-03-07 12:48:32 -0800271 EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700272
273 EXPECT_EQ(IPMI_CC_OK,
Patrick Venturede8a16e2019-03-07 12:48:32 -0800274 processBlobCommand(h, &manager, request, reply, &dataLen));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700275 EXPECT_EQ(dataLen, payloadLen);
276
277 uint8_t expectedBytes[3] = {0x12, 0x34, 0x56};
278 EXPECT_EQ(0, std::memcmp(expectedBytes, reply, sizeof(expectedBytes)));
279}
280} // namespace blobs