blob: 1a0d6e48f7ec1ee5efdcd48d58803abb8ea8d3aa [file] [log] [blame]
Willy Tu067ece12022-06-16 02:07:06 -07001#include "helper.hpp"
Patrick Ventureef3aead2018-09-12 08:53:29 -07002#include "ipmi.hpp"
Patrick Venturecd8dab42019-01-15 19:57:38 -08003#include "manager_mock.hpp"
Patrick Ventureef3aead2018-09-12 08:53:29 -07004#include "process.hpp"
5
Patrick Ventureef3aead2018-09-12 08:53:29 -07006#include <cstring>
Patrick Venturede8a16e2019-03-07 12:48:32 -08007#include <ipmiblob/test/crc_mock.hpp>
Willy Tu067ece12022-06-16 02:07:06 -07008#include <span>
Patrick Ventureef3aead2018-09-12 08:53:29 -07009
10#include <gtest/gtest.h>
11
Patrick Ventureef3aead2018-09-12 08:53:29 -070012// ipmid.hpp isn't installed where we can grab it and this value is per BMC
13// SoC.
14#define MAX_IPMI_BUFFER 64
15
Patrick Venturede8a16e2019-03-07 12:48:32 -080016using ::testing::_;
Willy Tu067ece12022-06-16 02:07:06 -070017using ::testing::ElementsAre;
Patrick Venturede8a16e2019-03-07 12:48:32 -080018using ::testing::Eq;
Patrick Venturede8a16e2019-03-07 12:48:32 -080019using ::testing::Return;
20using ::testing::StrictMock;
21
22namespace ipmiblob
23{
24CrcInterface* crcIntf = nullptr;
25
26std::uint16_t generateCrc(const std::vector<std::uint8_t>& data)
27{
28 return (crcIntf) ? crcIntf->generateCrc(data) : 0x00;
29}
30} // namespace ipmiblob
31
32namespace blobs
33{
Patrick Ventureef3aead2018-09-12 08:53:29 -070034namespace
35{
36
37void EqualFunctions(IpmiBlobHandler lhs, IpmiBlobHandler rhs)
38{
39 EXPECT_FALSE(lhs == nullptr);
40 EXPECT_FALSE(rhs == nullptr);
41
Willy Tu067ece12022-06-16 02:07:06 -070042 Resp (*const* lPtr)(ManagerInterface*, std::span<const uint8_t>) =
43 lhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
Patrick Ventureef3aead2018-09-12 08:53:29 -070044
Willy Tu067ece12022-06-16 02:07:06 -070045 Resp (*const* rPtr)(ManagerInterface*, std::span<const uint8_t>) =
46 rhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
Patrick Ventureef3aead2018-09-12 08:53:29 -070047
48 EXPECT_TRUE(lPtr);
49 EXPECT_TRUE(rPtr);
50 EXPECT_EQ(*lPtr, *rPtr);
Patrick Ventureef3aead2018-09-12 08:53:29 -070051}
52
53} // namespace
54
Patrick Venturede8a16e2019-03-07 12:48:32 -080055class ValidateBlobCommandTest : public ::testing::Test
56{
57 protected:
58 void SetUp() override
59 {
60 ipmiblob::crcIntf = &crcMock;
61 }
62
63 ipmiblob::CrcMock crcMock;
64};
65
66TEST_F(ValidateBlobCommandTest, InvalidCommandReturnsFailure)
Patrick Ventureef3aead2018-09-12 08:53:29 -070067{
68 // Verify we handle an invalid command.
Willy Tu067ece12022-06-16 02:07:06 -070069 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
70 // There is no command 0xff.
71 IpmiBlobHandler handler = validateBlobCommand(0xff, request);
72 EXPECT_EQ(ipmi::responseInvalidFieldRequest(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -070073}
74
Patrick Venturede8a16e2019-03-07 12:48:32 -080075TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -070076{
77 // Verify we handle a valid command that doesn't have a payload.
Willy Tu067ece12022-06-16 02:07:06 -070078 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
79 IpmiBlobHandler handler = validateBlobCommand(
80 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
81 EXPECT_FALSE(handler == nullptr);
82 EqualFunctions(getBlobCount, handler);
Patrick Ventureef3aead2018-09-12 08:53:29 -070083}
84
Patrick Venturede8a16e2019-03-07 12:48:32 -080085TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
Patrick Ventureef3aead2018-09-12 08:53:29 -070086{
87 // Verify that if there's a payload, it's at least one command byte and
88 // two bytes for the crc16 and then one data byte.
89
Willy Tu067ece12022-06-16 02:07:06 -070090 std::vector<uint8_t> request(sizeof(uint16_t));
Patrick Ventureef3aead2018-09-12 08:53:29 -070091 // There is a payload, but there are insufficient bytes.
92
Willy Tu067ece12022-06-16 02:07:06 -070093 IpmiBlobHandler handler = validateBlobCommand(
94 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
95 EXPECT_EQ(ipmi::responseReqDataLenInvalid(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -070096}
97
Patrick Venturede8a16e2019-03-07 12:48:32 -080098TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -070099{
100 // Verify that the CRC is checked, and failure is reported.
Willy Tu067ece12022-06-16 02:07:06 -0700101 std::vector<uint8_t> request;
102 BmcBlobWriteTx req;
103 req.crc = 0x34;
104 req.sessionId = 0x54;
105 req.offset = 0x100;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700106
Willy Tu067ece12022-06-16 02:07:06 -0700107 std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
108 request.resize(sizeof(struct BmcBlobWriteTx));
109 std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
110 request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700111
112 // skip over cmd and crc.
Willy Tu067ece12022-06-16 02:07:06 -0700113 std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
114 request.end());
Patrick Venturede8a16e2019-03-07 12:48:32 -0800115 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700116
Willy Tu067ece12022-06-16 02:07:06 -0700117 IpmiBlobHandler handler = validateBlobCommand(
118 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
119 EXPECT_EQ(ipmi::responseUnspecifiedError(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700120}
121
Patrick Venturede8a16e2019-03-07 12:48:32 -0800122TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700123{
124 // Verify the CRC is checked and if it matches, return the handler.
Willy Tu067ece12022-06-16 02:07:06 -0700125 std::vector<uint8_t> request;
126 BmcBlobWriteTx req;
127 req.crc = 0x3412;
128 req.sessionId = 0x54;
129 req.offset = 0x100;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700130
Willy Tu067ece12022-06-16 02:07:06 -0700131 std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
132 request.resize(sizeof(struct BmcBlobWriteTx));
133 std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
134 request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700135
136 // skip over cmd and crc.
Willy Tu067ece12022-06-16 02:07:06 -0700137 std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
138 request.end());
Patrick Venturede8a16e2019-03-07 12:48:32 -0800139 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700140
Willy Tu067ece12022-06-16 02:07:06 -0700141 IpmiBlobHandler handler = validateBlobCommand(
142 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
143 EXPECT_FALSE(handler == nullptr);
144 EqualFunctions(writeBlob, handler);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700145}
146
Patrick Venturede8a16e2019-03-07 12:48:32 -0800147class ProcessBlobCommandTest : public ::testing::Test
Patrick Ventureef3aead2018-09-12 08:53:29 -0700148{
Patrick Venturede8a16e2019-03-07 12:48:32 -0800149 protected:
150 void SetUp() override
151 {
152 ipmiblob::crcIntf = &crcMock;
153 }
Patrick Ventureef3aead2018-09-12 08:53:29 -0700154
Patrick Venturede8a16e2019-03-07 12:48:32 -0800155 ipmiblob::CrcMock crcMock;
156};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700157
Patrick Venturede8a16e2019-03-07 12:48:32 -0800158TEST_F(ProcessBlobCommandTest, CommandReturnsNotOk)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700159{
160 // Verify that if the IPMI command handler returns not OK that this is
161 // noticed and returned.
162
Patrick Ventureef3aead2018-09-12 08:53:29 -0700163 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700164 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700165
Willy Tu067ece12022-06-16 02:07:06 -0700166 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
167 return ipmi::responseInvalidCommand();
168 };
Patrick Ventureef3aead2018-09-12 08:53:29 -0700169
Willy Tu067ece12022-06-16 02:07:06 -0700170 EXPECT_EQ(ipmi::responseInvalidCommand(),
Willy Tu83f99922022-06-22 14:59:07 -0700171 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700172}
173
Patrick Venturede8a16e2019-03-07 12:48:32 -0800174TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700175{
176 // Verify that if the IPMI command handler returns OK but without a payload
177 // it doesn't try to compute a CRC.
178
Patrick Ventureef3aead2018-09-12 08:53:29 -0700179 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700180 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700181
Willy Tu067ece12022-06-16 02:07:06 -0700182 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
183 return ipmi::responseSuccess(std::vector<uint8_t>());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700184 };
185
Willy Tu067ece12022-06-16 02:07:06 -0700186 EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>()),
Willy Tu83f99922022-06-22 14:59:07 -0700187 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700188}
189
Patrick Venturede8a16e2019-03-07 12:48:32 -0800190TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700191{
Patrick Ventured1c3e862019-01-10 13:12:20 -0800192 // There is a minimum payload length of 2 bytes (the CRC only, no data, for
193 // read), this returns 1.
Patrick Ventureef3aead2018-09-12 08:53:29 -0700194
Patrick Ventureef3aead2018-09-12 08:53:29 -0700195 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700196 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700197
Willy Tu067ece12022-06-16 02:07:06 -0700198 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
199 return ipmi::responseSuccess(std::vector<uint8_t>(1));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700200 };
201
Willy Tu067ece12022-06-16 02:07:06 -0700202 EXPECT_EQ(ipmi::responseUnspecifiedError(),
Willy Tu83f99922022-06-22 14:59:07 -0700203 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700204}
205
Patrick Venturede8a16e2019-03-07 12:48:32 -0800206TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700207{
208 // There is a minimum payload length of 3 bytes, this command returns a
209 // payload of 3 bytes and the crc code is called to process the payload.
210
Patrick Ventureef3aead2018-09-12 08:53:29 -0700211 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700212 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700213 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
214
Willy Tu067ece12022-06-16 02:07:06 -0700215 IpmiBlobHandler h = [payloadLen](ManagerInterface*,
216 std::span<const uint8_t>) {
217 std::vector<uint8_t> output(payloadLen, 0);
218 output[2] = 0x56;
219 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700220 };
221
Patrick Venturede8a16e2019-03-07 12:48:32 -0800222 EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700223
Willy Tu83f99922022-06-22 14:59:07 -0700224 auto result = validateReply(
225 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700226
Willy Tu067ece12022-06-16 02:07:06 -0700227 EXPECT_EQ(result.size(), payloadLen);
228 EXPECT_THAT(result, ElementsAre(0x12, 0x34, 0x56));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700229}
Willy Tu067ece12022-06-16 02:07:06 -0700230
Willy Tu83f99922022-06-22 14:59:07 -0700231TEST_F(ProcessBlobCommandTest,
232 CommandReturnsErrorWithReplyExceededMaxTransferSize)
233{
234 // There is a minimum payload length of 3 bytes, this command returns a
235 // payload of 3 bytes and the crc code is called to process the payload.
236
237 StrictMock<ManagerMock> manager;
238 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
239 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
240
241 IpmiBlobHandler h = [payloadLen](ManagerInterface*,
242 std::span<const uint8_t>) {
243 std::vector<uint8_t> output(payloadLen, 0);
244 output[2] = 0x56;
245 return ipmi::responseSuccess(output);
246 };
247
248 EXPECT_EQ(ipmi::responseResponseError(),
249 processBlobCommand(h, &manager, request, 0));
250}
Patrick Ventureef3aead2018-09-12 08:53:29 -0700251} // namespace blobs