blob: c4273c491c4fc84ec52fbf5b24d5d8fc19f81f4e [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 Venturede8a16e2019-03-07 12:48:32 -08006#include <ipmiblob/test/crc_mock.hpp>
Patrick Williams52509572023-05-10 07:51:18 -05007
8#include <cstring>
Willy Tu067ece12022-06-16 02:07:06 -07009#include <span>
Patrick Ventureef3aead2018-09-12 08:53:29 -070010
11#include <gtest/gtest.h>
12
Patrick Ventureef3aead2018-09-12 08:53:29 -070013// ipmid.hpp isn't installed where we can grab it and this value is per BMC
14// SoC.
15#define MAX_IPMI_BUFFER 64
16
Patrick Venturede8a16e2019-03-07 12:48:32 -080017using ::testing::_;
Willy Tu067ece12022-06-16 02:07:06 -070018using ::testing::ElementsAre;
Patrick Venturede8a16e2019-03-07 12:48:32 -080019using ::testing::Eq;
Patrick Venturede8a16e2019-03-07 12:48:32 -080020using ::testing::Return;
21using ::testing::StrictMock;
22
23namespace ipmiblob
24{
25CrcInterface* crcIntf = nullptr;
26
27std::uint16_t generateCrc(const std::vector<std::uint8_t>& data)
28{
29 return (crcIntf) ? crcIntf->generateCrc(data) : 0x00;
30}
31} // namespace ipmiblob
32
33namespace blobs
34{
Patrick Ventureef3aead2018-09-12 08:53:29 -070035namespace
36{
37
38void EqualFunctions(IpmiBlobHandler lhs, IpmiBlobHandler rhs)
39{
40 EXPECT_FALSE(lhs == nullptr);
41 EXPECT_FALSE(rhs == nullptr);
42
Willy Tu067ece12022-06-16 02:07:06 -070043 Resp (*const* lPtr)(ManagerInterface*, std::span<const uint8_t>) =
44 lhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
Patrick Ventureef3aead2018-09-12 08:53:29 -070045
Willy Tu067ece12022-06-16 02:07:06 -070046 Resp (*const* rPtr)(ManagerInterface*, std::span<const uint8_t>) =
47 rhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
Patrick Ventureef3aead2018-09-12 08:53:29 -070048
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.
Willy Tu067ece12022-06-16 02:07:06 -070070 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
71 // There is no command 0xff.
72 IpmiBlobHandler handler = validateBlobCommand(0xff, request);
73 EXPECT_EQ(ipmi::responseInvalidFieldRequest(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -070074}
75
Patrick Venturede8a16e2019-03-07 12:48:32 -080076TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -070077{
78 // Verify we handle a valid command that doesn't have a payload.
Willy Tu067ece12022-06-16 02:07:06 -070079 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
80 IpmiBlobHandler handler = validateBlobCommand(
81 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
82 EXPECT_FALSE(handler == nullptr);
83 EqualFunctions(getBlobCount, handler);
Patrick Ventureef3aead2018-09-12 08:53:29 -070084}
85
Patrick Venturede8a16e2019-03-07 12:48:32 -080086TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
Patrick Ventureef3aead2018-09-12 08:53:29 -070087{
88 // Verify that if there's a payload, it's at least one command byte and
89 // two bytes for the crc16 and then one data byte.
90
Willy Tu067ece12022-06-16 02:07:06 -070091 std::vector<uint8_t> request(sizeof(uint16_t));
Patrick Ventureef3aead2018-09-12 08:53:29 -070092 // There is a payload, but there are insufficient bytes.
93
Willy Tu067ece12022-06-16 02:07:06 -070094 IpmiBlobHandler handler = validateBlobCommand(
95 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
96 EXPECT_EQ(ipmi::responseReqDataLenInvalid(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -070097}
98
Patrick Venturede8a16e2019-03-07 12:48:32 -080099TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700100{
101 // Verify that the CRC is checked, and failure is reported.
Willy Tu067ece12022-06-16 02:07:06 -0700102 std::vector<uint8_t> request;
103 BmcBlobWriteTx req;
104 req.crc = 0x34;
105 req.sessionId = 0x54;
106 req.offset = 0x100;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700107
Willy Tu067ece12022-06-16 02:07:06 -0700108 std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
109 request.resize(sizeof(struct BmcBlobWriteTx));
110 std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
111 request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700112
113 // skip over cmd and crc.
Willy Tu067ece12022-06-16 02:07:06 -0700114 std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
115 request.end());
Patrick Venturede8a16e2019-03-07 12:48:32 -0800116 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700117
Willy Tu067ece12022-06-16 02:07:06 -0700118 IpmiBlobHandler handler = validateBlobCommand(
119 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
120 EXPECT_EQ(ipmi::responseUnspecifiedError(), handler(nullptr, {}));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700121}
122
Patrick Venturede8a16e2019-03-07 12:48:32 -0800123TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700124{
125 // Verify the CRC is checked and if it matches, return the handler.
Willy Tu067ece12022-06-16 02:07:06 -0700126 std::vector<uint8_t> request;
127 BmcBlobWriteTx req;
128 req.crc = 0x3412;
129 req.sessionId = 0x54;
130 req.offset = 0x100;
Patrick Ventureef3aead2018-09-12 08:53:29 -0700131
Willy Tu067ece12022-06-16 02:07:06 -0700132 std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
133 request.resize(sizeof(struct BmcBlobWriteTx));
134 std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
135 request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700136
137 // skip over cmd and crc.
Willy Tu067ece12022-06-16 02:07:06 -0700138 std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
139 request.end());
Patrick Venturede8a16e2019-03-07 12:48:32 -0800140 EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700141
Willy Tu067ece12022-06-16 02:07:06 -0700142 IpmiBlobHandler handler = validateBlobCommand(
143 static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
144 EXPECT_FALSE(handler == nullptr);
145 EqualFunctions(writeBlob, handler);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700146}
147
Patrick Venturede8a16e2019-03-07 12:48:32 -0800148class ProcessBlobCommandTest : public ::testing::Test
Patrick Ventureef3aead2018-09-12 08:53:29 -0700149{
Patrick Venturede8a16e2019-03-07 12:48:32 -0800150 protected:
151 void SetUp() override
152 {
153 ipmiblob::crcIntf = &crcMock;
154 }
Patrick Ventureef3aead2018-09-12 08:53:29 -0700155
Patrick Venturede8a16e2019-03-07 12:48:32 -0800156 ipmiblob::CrcMock crcMock;
157};
Patrick Ventureef3aead2018-09-12 08:53:29 -0700158
Patrick Venturede8a16e2019-03-07 12:48:32 -0800159TEST_F(ProcessBlobCommandTest, CommandReturnsNotOk)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700160{
161 // Verify that if the IPMI command handler returns not OK that this is
162 // noticed and returned.
163
Patrick Ventureef3aead2018-09-12 08:53:29 -0700164 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700165 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700166
Willy Tu067ece12022-06-16 02:07:06 -0700167 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
168 return ipmi::responseInvalidCommand();
169 };
Patrick Ventureef3aead2018-09-12 08:53:29 -0700170
Willy Tu067ece12022-06-16 02:07:06 -0700171 EXPECT_EQ(ipmi::responseInvalidCommand(),
Willy Tu83f99922022-06-22 14:59:07 -0700172 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700173}
174
Patrick Venturede8a16e2019-03-07 12:48:32 -0800175TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700176{
177 // Verify that if the IPMI command handler returns OK but without a payload
178 // it doesn't try to compute a CRC.
179
Patrick Ventureef3aead2018-09-12 08:53:29 -0700180 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700181 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700182
Willy Tu067ece12022-06-16 02:07:06 -0700183 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
184 return ipmi::responseSuccess(std::vector<uint8_t>());
Patrick Ventureef3aead2018-09-12 08:53:29 -0700185 };
186
Willy Tu067ece12022-06-16 02:07:06 -0700187 EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>()),
Willy Tu83f99922022-06-22 14:59:07 -0700188 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700189}
190
Patrick Venturede8a16e2019-03-07 12:48:32 -0800191TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700192{
Patrick Ventured1c3e862019-01-10 13:12:20 -0800193 // There is a minimum payload length of 2 bytes (the CRC only, no data, for
194 // read), this returns 1.
Patrick Ventureef3aead2018-09-12 08:53:29 -0700195
Patrick Ventureef3aead2018-09-12 08:53:29 -0700196 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700197 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700198
Willy Tu067ece12022-06-16 02:07:06 -0700199 IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
200 return ipmi::responseSuccess(std::vector<uint8_t>(1));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700201 };
202
Willy Tu067ece12022-06-16 02:07:06 -0700203 EXPECT_EQ(ipmi::responseUnspecifiedError(),
Willy Tu83f99922022-06-22 14:59:07 -0700204 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700205}
206
Patrick Venturede8a16e2019-03-07 12:48:32 -0800207TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
Patrick Ventureef3aead2018-09-12 08:53:29 -0700208{
209 // There is a minimum payload length of 3 bytes, this command returns a
210 // payload of 3 bytes and the crc code is called to process the payload.
211
Patrick Ventureef3aead2018-09-12 08:53:29 -0700212 StrictMock<ManagerMock> manager;
Willy Tu067ece12022-06-16 02:07:06 -0700213 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700214 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
215
Patrick Williams0dea6fa2023-10-20 11:19:46 -0500216 IpmiBlobHandler h = [payloadLen](ManagerInterface*,
217 std::span<const uint8_t>) {
Willy Tu067ece12022-06-16 02:07:06 -0700218 std::vector<uint8_t> output(payloadLen, 0);
219 output[2] = 0x56;
220 return ipmi::responseSuccess(output);
Patrick Ventureef3aead2018-09-12 08:53:29 -0700221 };
222
Patrick Venturede8a16e2019-03-07 12:48:32 -0800223 EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700224
Willy Tu83f99922022-06-22 14:59:07 -0700225 auto result = validateReply(
226 processBlobCommand(h, &manager, request, MAX_IPMI_BUFFER));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700227
Willy Tu067ece12022-06-16 02:07:06 -0700228 EXPECT_EQ(result.size(), payloadLen);
229 EXPECT_THAT(result, ElementsAre(0x12, 0x34, 0x56));
Patrick Ventureef3aead2018-09-12 08:53:29 -0700230}
Willy Tu067ece12022-06-16 02:07:06 -0700231
Willy Tu83f99922022-06-22 14:59:07 -0700232TEST_F(ProcessBlobCommandTest,
233 CommandReturnsErrorWithReplyExceededMaxTransferSize)
234{
235 // There is a minimum payload length of 3 bytes, this command returns a
236 // payload of 3 bytes and the crc code is called to process the payload.
237
238 StrictMock<ManagerMock> manager;
239 std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
240 uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
241
Patrick Williams0dea6fa2023-10-20 11:19:46 -0500242 IpmiBlobHandler h = [payloadLen](ManagerInterface*,
243 std::span<const uint8_t>) {
Willy Tu83f99922022-06-22 14:59:07 -0700244 std::vector<uint8_t> output(payloadLen, 0);
245 output[2] = 0x56;
246 return ipmi::responseSuccess(output);
247 };
248
249 EXPECT_EQ(ipmi::responseResponseError(),
250 processBlobCommand(h, &manager, request, 0));
251}
Patrick Ventureef3aead2018-09-12 08:53:29 -0700252} // namespace blobs