Refactor to use new version of OEM IPMI Handler
Using the new version of ipmi handler provide a higher level wrapper
over the same functionalities. It helps us parse the input and output to
have more control of the input/output we see.
Changes to note,
- All cmd are removed from the request data. That is automatically
extracted now.
Tested:
Unit Test Passed.
All IPMI OEM command still works the same as before this change.
```
$ burn_my_bmc -command stage -image /tmp/test.txt -interface ipmipci
Set up ipmi flash updater with /flash/dummy
Received failure on delete: Received IPMI_CC: 255
Sending over the firmware image.
Find [0x1050 0x750]
bar0[0x94000000]
Upload to BMC 100% |Goooooooooooooooooooooooooooooooooooooooooooooooooooooooogle| Time: 00:00:00
Opening the verification file
Committing to /flash/verify to trigger service
Calling stat on /flash/verify session to check status
success
succeeded
```
Also tested gBMC Update workflow which worked fine.
Change-Id: Ib2bfeab0c2ec5aa72ede1ff457ef5f90e488053c
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/ipmi.cpp b/ipmi.cpp
index 07f6cd8..9fd1491 100644
--- a/ipmi.cpp
+++ b/ipmi.cpp
@@ -17,6 +17,7 @@
#include "ipmi.hpp"
#include <cstring>
+#include <span>
#include <string>
#include <unordered_map>
@@ -63,137 +64,111 @@
return true;
}
-std::string stringFromBuffer(const char* start, size_t length)
+std::string stringFromBuffer(std::span<const uint8_t> data)
{
- if (!start)
+ if (data.empty() || data.back() != '\0')
{
- return "";
+ return std::string();
}
- auto end = static_cast<const char*>(std::memchr(start, '\0', length));
- if (end != &start[length - 1])
- {
- return "";
- }
-
- return (end == nullptr) ? std::string() : std::string(start, end);
+ // Last index is nul-terminator.
+ return std::string(data.begin(), data.end() - 1);
}
-ipmi_ret_t getBlobCount(ManagerInterface* mgr, const uint8_t*,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp getBlobCount(ManagerInterface* mgr, std::span<const uint8_t>)
{
struct BmcBlobCountRx resp;
resp.crc = 0;
resp.blobCount = mgr->buildBlobList();
/* Copy the response into the reply buffer */
- std::memcpy(replyCmdBuf, &resp, sizeof(resp));
- (*dataLen) = sizeof(resp);
+ std::vector<uint8_t> output(sizeof(BmcBlobCountRx), 0);
+ std::memcpy(output.data(), &resp, sizeof(resp));
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(output);
}
-ipmi_ret_t enumerateBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp enumerateBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
/* Verify datalen is >= sizeof(request) */
struct BmcBlobEnumerateTx request;
- auto reply = reinterpret_cast<struct BmcBlobEnumerateRx*>(replyCmdBuf);
- (*dataLen) = 0;
- std::memcpy(&request, reqBuf, sizeof(request));
+ std::memcpy(&request, data.data(), sizeof(request));
std::string blobId = mgr->getBlobId(request.blobIdx);
if (blobId.empty())
{
- return IPMI_CC_INVALID_FIELD_REQUEST;
+ return ipmi::responseInvalidFieldRequest();
}
- /* TODO(venture): Need to do a hard-code check against the maximum
- * reply buffer size. */
- reply->crc = 0;
- /* Explicilty copies the NUL-terminator. */
- std::memcpy(reply + 1, blobId.c_str(), blobId.length() + 1);
-
- (*dataLen) = sizeof(reply->crc) + blobId.length() + 1;
-
- return IPMI_CC_OK;
+ std::vector<uint8_t> output(sizeof(BmcBlobEnumerateRx), 0);
+ output.insert(output.end(), blobId.c_str(),
+ blobId.c_str() + blobId.length() + 1);
+ return ipmi::responseSuccess(output);
}
-ipmi_ret_t openBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp openBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
- auto request = reinterpret_cast<const struct BmcBlobOpenTx*>(reqBuf);
+ auto request = reinterpret_cast<const struct BmcBlobOpenTx*>(data.data());
uint16_t session;
- (*dataLen) = 0;
- std::string path =
- stringFromBuffer(reinterpret_cast<const char*>(request + 1),
- requestLen - sizeof(*request));
+ std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobOpenTx)));
if (path.empty())
{
- return IPMI_CC_REQ_DATA_LEN_INVALID;
+ return ipmi::responseReqDataLenInvalid();
}
/* Attempt to open. */
if (!mgr->open(request->flags, path, &session))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
struct BmcBlobOpenRx reply;
reply.crc = 0;
reply.sessionId = session;
- std::memcpy(replyCmdBuf, &reply, sizeof(reply));
- (*dataLen) = sizeof(reply);
-
- return IPMI_CC_OK;
+ std::vector<uint8_t> output(sizeof(BmcBlobOpenRx), 0);
+ std::memcpy(output.data(), &reply, sizeof(reply));
+ return ipmi::responseSuccess(output);
}
-ipmi_ret_t closeBlob(ManagerInterface* mgr, const uint8_t* reqBuf, uint8_t*,
- size_t* dataLen)
+Resp closeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
struct BmcBlobCloseTx request;
- std::memcpy(&request, reqBuf, sizeof(request));
- (*dataLen) = 0;
+ if (data.size() < sizeof(request))
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+ std::memcpy(&request, data.data(), sizeof(request));
/* Attempt to close. */
if (!mgr->close(request.sessionId))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(std::vector<uint8_t>{});
}
-ipmi_ret_t deleteBlob(ManagerInterface* mgr, const uint8_t* reqBuf, uint8_t*,
- size_t* dataLen)
+Resp deleteBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
- auto request = reinterpret_cast<const struct BmcBlobDeleteTx*>(reqBuf);
- (*dataLen) = 0;
-
- std::string path =
- stringFromBuffer(reinterpret_cast<const char*>(request + 1),
- requestLen - sizeof(*request));
+ std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobDeleteTx)));
if (path.empty())
{
- return IPMI_CC_REQ_DATA_LEN_INVALID;
+ return ipmi::responseReqDataLenInvalid();
}
/* Attempt to delete. */
if (!mgr->deleteBlob(path))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(std::vector<uint8_t>{});
}
-static ipmi_ret_t returnStatBlob(BlobMeta* meta, uint8_t* replyCmdBuf,
- size_t* dataLen)
+static Resp returnStatBlob(BlobMeta* meta)
{
struct BmcBlobStatRx reply;
reply.crc = 0;
@@ -201,91 +176,85 @@
reply.size = meta->size;
reply.metadataLen = meta->metadata.size();
- std::memcpy(replyCmdBuf, &reply, sizeof(reply));
+ std::vector<uint8_t> output(sizeof(BmcBlobStatRx), 0);
+ std::memcpy(output.data(), &reply, sizeof(reply));
- /* If there is metadata, copy it over. */
+ /* If there is metadata, insert it to output. */
if (!meta->metadata.empty())
{
- uint8_t* metadata = &replyCmdBuf[sizeof(reply)];
- std::memcpy(metadata, meta->metadata.data(), reply.metadataLen);
+ output.insert(output.end(), meta->metadata.begin(),
+ meta->metadata.end());
}
-
- (*dataLen) = sizeof(reply) + reply.metadataLen;
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(output);
}
-ipmi_ret_t statBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp statBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
- auto request = reinterpret_cast<const struct BmcBlobStatTx*>(reqBuf);
- (*dataLen) = 0;
-
- std::string path =
- stringFromBuffer(reinterpret_cast<const char*>(request + 1),
- requestLen - sizeof(*request));
+ std::string path = stringFromBuffer(data.subspan(sizeof(BmcBlobStatTx)));
if (path.empty())
{
- return IPMI_CC_REQ_DATA_LEN_INVALID;
+ return ipmi::responseReqDataLenInvalid();
}
/* Attempt to stat. */
BlobMeta meta;
if (!mgr->stat(path, &meta))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return returnStatBlob(&meta, replyCmdBuf, dataLen);
+ return returnStatBlob(&meta);
}
-ipmi_ret_t sessionStatBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp sessionStatBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
struct BmcBlobSessionStatTx request;
- std::memcpy(&request, reqBuf, sizeof(request));
- (*dataLen) = 0;
+ if (data.size() < sizeof(request))
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+ std::memcpy(&request, data.data(), sizeof(request));
/* Attempt to stat. */
BlobMeta meta;
if (!mgr->stat(request.sessionId, &meta))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return returnStatBlob(&meta, replyCmdBuf, dataLen);
+ return returnStatBlob(&meta);
}
-ipmi_ret_t commitBlob(ManagerInterface* mgr, const uint8_t* reqBuf, uint8_t*,
- size_t* dataLen)
+Resp commitBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
- auto request = reinterpret_cast<const struct BmcBlobCommitTx*>(reqBuf);
- (*dataLen) = 0;
+ auto request = reinterpret_cast<const struct BmcBlobCommitTx*>(data.data());
/* Sanity check the commitDataLen */
- if (request->commitDataLen > (requestLen - sizeof(struct BmcBlobCommitTx)))
+ if (request->commitDataLen > (data.size() - sizeof(struct BmcBlobCommitTx)))
{
- return IPMI_CC_REQ_DATA_LEN_INVALID;
+ return ipmi::responseReqDataLenInvalid();
}
- std::vector<uint8_t> data(request->commitDataLen);
- std::memcpy(data.data(), request + 1, request->commitDataLen);
+ data = data.subspan(sizeof(struct BmcBlobCommitTx), request->commitDataLen);
- if (!mgr->commit(request->sessionId, data))
+ if (!mgr->commit(request->sessionId,
+ std::vector<uint8_t>(data.begin(), data.end())))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(std::vector<uint8_t>{});
}
-ipmi_ret_t readBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp readBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
struct BmcBlobReadTx request;
- std::memcpy(&request, reqBuf, sizeof(request));
+ if (data.size() < sizeof(request))
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+ std::memcpy(&request, data.data(), sizeof(request));
/* TODO(venture): Verify requestedSize can fit in a returned IPMI packet.
*/
@@ -297,64 +266,53 @@
* of data.
* If there was data returned, copy into the reply buffer.
*/
- (*dataLen) = sizeof(struct BmcBlobReadRx);
+ std::vector<uint8_t> output(sizeof(BmcBlobReadRx), 0);
if (!result.empty())
{
- uint8_t* output = &replyCmdBuf[sizeof(struct BmcBlobReadRx)];
- std::memcpy(output, result.data(), result.size());
-
- (*dataLen) = sizeof(struct BmcBlobReadRx) + result.size();
+ output.insert(output.end(), result.begin(), result.end());
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(output);
}
-ipmi_ret_t writeBlob(ManagerInterface* mgr, const uint8_t* reqBuf, uint8_t*,
- size_t* dataLen)
+Resp writeBlob(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
- auto request = reinterpret_cast<const struct BmcBlobWriteTx*>(reqBuf);
- (*dataLen) = 0;
-
- uint32_t size = requestLen - sizeof(struct BmcBlobWriteTx);
- std::vector<uint8_t> data(size);
-
- std::memcpy(data.data(), request + 1, size);
+ auto request = reinterpret_cast<const struct BmcBlobWriteTx*>(data.data());
+ data = data.subspan(sizeof(struct BmcBlobWriteTx));
/* Attempt to write the bytes. */
- if (!mgr->write(request->sessionId, request->offset, data))
+ if (!mgr->write(request->sessionId, request->offset,
+ std::vector<uint8_t>(data.begin(), data.end())))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(std::vector<uint8_t>{});
}
-ipmi_ret_t writeMeta(ManagerInterface* mgr, const uint8_t* reqBuf, uint8_t*,
- size_t* dataLen)
+Resp writeMeta(ManagerInterface* mgr, std::span<const uint8_t> data)
{
- size_t requestLen = (*dataLen);
struct BmcBlobWriteMetaTx request;
- (*dataLen) = 0;
+ if (data.size() < sizeof(request))
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
/* Copy over the request. */
- std::memcpy(&request, reqBuf, sizeof(request));
-
- /* Determine number of bytes of metadata to write. */
- uint32_t size = requestLen - sizeof(request);
+ std::memcpy(&request, data.data(), sizeof(request));
/* Nothing really else to validate, we just copy those bytes. */
- std::vector<uint8_t> data(size);
- std::memcpy(data.data(), &reqBuf[sizeof(request)], size);
+ data = data.subspan(sizeof(struct BmcBlobWriteMetaTx));
/* Attempt to write the bytes. */
- if (!mgr->writeMeta(request.sessionId, request.offset, data))
+ if (!mgr->writeMeta(request.sessionId, request.offset,
+ std::vector<uint8_t>(data.begin(), data.end())))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
- return IPMI_CC_OK;
+ return ipmi::responseSuccess(std::vector<uint8_t>{});
}
} // namespace blobs
diff --git a/ipmi.hpp b/ipmi.hpp
index 318498b..51a9d79 100644
--- a/ipmi.hpp
+++ b/ipmi.hpp
@@ -5,15 +5,19 @@
#include <ipmid/api.h>
#include <blobs-ipmid/blobs.hpp>
+#include <ipmid/api-types.hpp>
+#include <span>
#include <string>
+#include <vector>
namespace blobs
{
+using Resp = ipmi::RspType<std::vector<uint8_t>>;
+
/* Used by bmcBlobGetCount */
struct BmcBlobCountTx
{
- uint8_t cmd; /* bmcBlobGetCount */
} __attribute__((packed));
struct BmcBlobCountRx
@@ -25,7 +29,6 @@
/* Used by bmcBlobEnumerate */
struct BmcBlobEnumerateTx
{
- uint8_t cmd; /* bmcBlobEnumerate */
uint16_t crc;
uint32_t blobIdx;
} __attribute__((packed));
@@ -38,7 +41,6 @@
/* Used by bmcBlobOpen */
struct BmcBlobOpenTx
{
- uint8_t cmd; /* bmcBlobOpen */
uint16_t crc;
uint16_t flags;
} __attribute__((packed));
@@ -52,7 +54,6 @@
/* Used by bmcBlobClose */
struct BmcBlobCloseTx
{
- uint8_t cmd; /* bmcBlobClose */
uint16_t crc;
uint16_t sessionId; /* Returned from BmcBlobOpen. */
} __attribute__((packed));
@@ -60,14 +61,12 @@
/* Used by bmcBlobDelete */
struct BmcBlobDeleteTx
{
- uint8_t cmd; /* bmcBlobDelete */
uint16_t crc;
} __attribute__((packed));
/* Used by bmcBlobStat */
struct BmcBlobStatTx
{
- uint8_t cmd; /* bmcBlobStat */
uint16_t crc;
} __attribute__((packed));
@@ -82,7 +81,6 @@
/* Used by bmcBlobSessionStat */
struct BmcBlobSessionStatTx
{
- uint8_t cmd; /* bmcBlobSessionStat */
uint16_t crc;
uint16_t sessionId;
} __attribute__((packed));
@@ -90,7 +88,6 @@
/* Used by bmcBlobCommit */
struct BmcBlobCommitTx
{
- uint8_t cmd; /* bmcBlobCommit */
uint16_t crc;
uint16_t sessionId;
uint8_t commitDataLen;
@@ -99,7 +96,6 @@
/* Used by bmcBlobRead */
struct BmcBlobReadTx
{
- uint8_t cmd; /* bmcBlobRead */
uint16_t crc;
uint16_t sessionId;
uint32_t offset; /* The byte sequence start, 0-based. */
@@ -114,7 +110,6 @@
/* Used by bmcBlobWrite */
struct BmcBlobWriteTx
{
- uint8_t cmd; /* bmcBlobWrite */
uint16_t crc;
uint16_t sessionId;
uint32_t offset; /* The byte sequence start, 0-based. */
@@ -123,7 +118,6 @@
/* Used by bmcBlobWriteMeta */
struct BmcBlobWriteMetaTx
{
- uint8_t cmd; /* bmcBlobWriteMeta */
uint16_t crc;
uint16_t sessionId; /* Returned from BmcBlobOpen. */
uint32_t offset; /* The byte sequence start, 0-based. */
@@ -142,17 +136,15 @@
* Given a pointer into an IPMI request buffer and the length of the remaining
* buffer, builds a string. This does no string validation w.r.t content.
*
- * @param[in] start - the start of the expected string.
- * @param[in] length - the number of bytes remaining in the buffer.
+ * @param[in] data - Buffer containing the string.
* @return the string if valid otherwise an empty string.
*/
-std::string stringFromBuffer(const char* start, size_t length);
+std::string stringFromBuffer(std::span<const uint8_t> data);
/**
* Writes out a BmcBlobCountRx structure and returns IPMI_OK.
*/
-ipmi_ret_t getBlobCount(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp getBlobCount(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Writes out a BmcBlobEnumerateRx in response to a BmcBlobEnumerateTx
@@ -162,61 +154,51 @@
* It will also return failure if the response buffer is of an invalid
* length.
*/
-ipmi_ret_t enumerateBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp enumerateBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to open the blobId specified and associate with a session id.
*/
-ipmi_ret_t openBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp openBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to close the session specified.
*/
-ipmi_ret_t closeBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp closeBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to delete the blobId specified.
*/
-ipmi_ret_t deleteBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp deleteBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to retrieve the Stat for the blobId specified.
*/
-ipmi_ret_t statBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp statBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to retrieve the Stat for the session specified.
*/
-ipmi_ret_t sessionStatBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp sessionStatBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempts to commit the data in the blob.
*/
-ipmi_ret_t commitBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp commitBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempt to read data from the blob.
*/
-ipmi_ret_t readBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp readBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempt to write data to the blob.
*/
-ipmi_ret_t writeBlob(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp writeBlob(ManagerInterface* mgr, std::span<const uint8_t> data);
/**
* Attempt to write metadata to the blob.
*/
-ipmi_ret_t writeMeta(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp writeMeta(ManagerInterface* mgr, std::span<const uint8_t> data);
} // namespace blobs
diff --git a/main.cpp b/main.cpp
index e90969b..d3179f3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -24,11 +24,14 @@
#include <ipmid/api.h>
#include <cstdio>
+#include <ipmid/api-types.hpp>
+#include <ipmid/handler.hpp>
#include <ipmid/iana.hpp>
#include <ipmid/oemopenbmc.hpp>
#include <ipmid/oemrouter.hpp>
#include <memory>
#include <phosphor-logging/log.hpp>
+#include <span>
namespace blobs
{
@@ -39,13 +42,16 @@
void setupBlobGlobalHandler()
{
- oem::Router* oemRouter = oem::mutableRouter();
std::fprintf(stderr,
"Registering OEM:[%#08X], Cmd:[%#04X] for Blob Commands\n",
oem::obmcOemNumber, oem::Cmd::blobTransferCmd);
- oemRouter->registerHandler(oem::obmcOemNumber, oem::Cmd::blobTransferCmd,
- handleBlobCommand);
+ ipmi::registerOemHandler(
+ ipmi::prioOemBase, oem::obmcOemNumber, oem::Cmd::blobTransferCmd,
+ ::ipmi::Privilege::User,
+ [](ipmi::Context::ptr, uint8_t cmd, const std::vector<uint8_t>& data) {
+ return handleBlobCommand(cmd, data);
+ });
/* Install handlers. */
try
diff --git a/process.cpp b/process.cpp
index 2481fa2..46ffea5 100644
--- a/process.cpp
+++ b/process.cpp
@@ -20,7 +20,10 @@
#include <cstring>
#include <ipmiblob/crc.hpp>
+#include <ipmid/api-types.hpp>
+#include <span>
#include <unordered_map>
+#include <utility>
#include <vector>
namespace blobs
@@ -29,7 +32,6 @@
/* Used by all commands with data. */
struct BmcRx
{
- uint8_t cmd;
uint16_t crc;
uint8_t data; /* one byte minimum of data. */
} __attribute__((packed));
@@ -48,29 +50,29 @@
{BlobOEMCommands::bmcBlobWriteMeta, writeMeta},
};
-IpmiBlobHandler validateBlobCommand(const uint8_t* reqBuf,
- uint8_t* /*replyCmdBuf*/, size_t* dataLen,
- ipmi_ret_t* code)
+IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data)
{
- size_t requestLength = (*dataLen);
+ size_t requestLength = data.size();
/* We know dataLen is at least 1 already */
- auto command = static_cast<BlobOEMCommands>(reqBuf[0]);
+ auto command = static_cast<BlobOEMCommands>(cmd);
/* Validate it's at least well-formed. */
if (!validateRequestLength(command, requestLength))
{
- *code = IPMI_CC_REQ_DATA_LEN_INVALID;
- return nullptr;
+ return [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseReqDataLenInvalid();
+ };
}
/* If there is a payload. */
- if (requestLength > sizeof(uint8_t))
+ if (requestLength > sizeof(cmd))
{
/* Verify the request includes: command, crc16, data */
if (requestLength < sizeof(struct BmcRx))
{
- *code = IPMI_CC_REQ_DATA_LEN_INVALID;
- return nullptr;
+ return [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseReqDataLenInvalid();
+ };
}
/* We don't include the command byte at offset 0 as part of the crc
@@ -81,44 +83,58 @@
/* We start after the command byte. */
std::vector<uint8_t> bytes(requestBodyLen);
- /* It likely has a well-formed payload. */
- struct BmcRx request;
- std::memcpy(&request, reqBuf, sizeof(request));
- uint16_t crcValue = request.crc;
+ /* It likely has a well-formed payload.
+ * Get the first two bytes of the request for crc.
+ */
+ uint16_t crc;
+ if (data.size() < sizeof(crc))
+ {
+ return [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseReqDataLenInvalid();
+ };
+ }
+ std::memcpy(&crc, data.data(), sizeof(crc));
- /* Set the in-place CRC to zero. */
- std::memcpy(bytes.data(), &reqBuf[3], requestBodyLen);
+ /* Set the in-place CRC to zero.
+ * Remove the first two bytes for crc and get the reset of the request.
+ */
+ data = data.subspan(sizeof(crc));
/* Crc expected but didn't match. */
- if (crcValue != ipmiblob::generateCrc(bytes))
+ if (crc != ipmiblob::generateCrc(
+ std::vector<uint8_t>(data.begin(), data.end())))
{
- *code = IPMI_CC_UNSPECIFIED_ERROR;
- return nullptr;
- }
+ return [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseUnspecifiedError();
+ };
+ };
}
/* Grab the corresponding handler for the command. */
auto found = handlers.find(command);
if (found == handlers.end())
{
- *code = IPMI_CC_INVALID_FIELD_REQUEST;
- return nullptr;
+ return [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseInvalidFieldRequest();
+ };
}
return found->second;
}
-ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
- const uint8_t* reqBuf, uint8_t* replyCmdBuf,
- size_t* dataLen)
+Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
+ std::span<const uint8_t> data)
{
- ipmi_ret_t result = cmd(mgr, reqBuf, replyCmdBuf, dataLen);
- if (result != IPMI_CC_OK)
+ Resp result = cmd(mgr, data);
+ if (std::get<0>(result) != ipmi::ccSuccess)
{
return result;
}
- size_t replyLength = (*dataLen);
+ std::vector<uint8_t>& response = std::get<0>(
+ // std::variant<std::vector<uint8_t>>
+ *std::get<1>(result));
+ size_t replyLength = response.size();
/* The command, whatever it was, returned success. */
if (replyLength == 0)
@@ -131,42 +147,30 @@
*/
if (replyLength < (sizeof(uint16_t)))
{
- return IPMI_CC_UNSPECIFIED_ERROR;
+ return ipmi::responseUnspecifiedError();
}
/* The command, whatever it was, replied, so let's set the CRC. */
- std::vector<std::uint8_t> crcBuffer(replyCmdBuf + sizeof(uint16_t),
- replyCmdBuf + replyLength);
+ std::span<const uint8_t> responseView = response;
+ responseView = responseView.subspan(sizeof(uint16_t));
+ std::vector<std::uint8_t> crcBuffer(responseView.begin(),
+ responseView.end());
/* Copy the CRC into place. */
uint16_t crcValue = ipmiblob::generateCrc(crcBuffer);
- std::memcpy(replyCmdBuf, &crcValue, sizeof(crcValue));
+ if (response.size() < sizeof(crcValue))
+ {
+ return ipmi::responseReqDataLenInvalid();
+ }
+ std::memcpy(response.data(), &crcValue, sizeof(crcValue));
return result;
}
-ipmi_ret_t handleBlobCommand(ipmi_cmd_t, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)
+Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data)
{
- /* It's holding at least a sub-command. The OEN is trimmed from the bytes
- * before this is called.
- */
- if ((*dataLen) < 1)
- {
- return IPMI_CC_REQ_DATA_LEN_INVALID;
- }
-
/* on failure rc is set to the corresponding IPMI error. */
- ipmi_ret_t rc = IPMI_CC_OK;
- IpmiBlobHandler command =
- validateBlobCommand(reqBuf, replyCmdBuf, dataLen, &rc);
- if (command == nullptr)
- {
- (*dataLen) = 0;
- return rc;
- }
-
- return processBlobCommand(command, getBlobManager(), reqBuf, replyCmdBuf,
- dataLen);
+ return processBlobCommand(validateBlobCommand(cmd, data), getBlobManager(),
+ data);
}
} // namespace blobs
diff --git a/process.hpp b/process.hpp
index da0031c..6b89413 100644
--- a/process.hpp
+++ b/process.hpp
@@ -1,30 +1,30 @@
#pragma once
+#include "ipmi.hpp"
#include "manager.hpp"
#include <ipmid/api.h>
#include <functional>
+#include <ipmid/api-types.hpp>
+#include <span>
+#include <utility>
+#include <vector>
namespace blobs
{
using IpmiBlobHandler =
- std::function<ipmi_ret_t(ManagerInterface* mgr, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen)>;
+ std::function<Resp(ManagerInterface* mgr, std::span<const uint8_t> data)>;
/**
* Validate the IPMI request and determine routing.
*
- * @param[in] reqBuf - a pointer to the ipmi request packet buffer.
- * @param[in,out] replyCmdBuf - a pointer to the ipmi reply packet buffer.
- * @param[in,out] dataLen - initially the request length, set to reply length
- * on return.
- * @param[out] code - set to the IPMI error on failure, otherwise unset.
- * @return the ipmi command handler, or nullptr on failure.
+ * @param[in] cmd Requested command
+ * @param[in] data Requested data
+ * @return the ipmi command handler, or nullopt on failure.
*/
-IpmiBlobHandler validateBlobCommand(const uint8_t* reqBuf, uint8_t* replyCmdBuf,
- size_t* dataLen, ipmi_ret_t* code);
+IpmiBlobHandler validateBlobCommand(uint8_t cmd, std::span<const uint8_t> data);
/**
* Call the IPMI command and process the result, including running the CRC
@@ -32,20 +32,16 @@
*
* @param[in] cmd - a funtion pointer to the ipmi command to process.
* @param[in] mgr - a pointer to the manager interface.
- * @param[in] reqBuf - a pointer to the ipmi request packet buffer.
- * @param[in,out] replyCmdBuf - a pointer to the ipmi reply packet buffer.
- * @param[in,out] dataLen - initially the request length, set to reply length
- * on return.
+ * @param[in] data - Requested data.
+ * @param[in,out] maxSize - Maximum ipmi reply size
* @return the ipmi command result.
*/
-ipmi_ret_t processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
- const uint8_t* reqBuf, uint8_t* replyCmdBuf,
- size_t* dataLen);
+Resp processBlobCommand(IpmiBlobHandler cmd, ManagerInterface* mgr,
+ std::span<const uint8_t> data);
/**
* Given an IPMI command, request buffer, and reply buffer, validate the request
* and call processBlobCommand.
*/
-ipmi_ret_t handleBlobCommand(ipmi_cmd_t cmd, const uint8_t* reqBuf,
- uint8_t* replyCmdBuf, size_t* dataLen);
+Resp handleBlobCommand(uint8_t cmd, std::vector<uint8_t> data);
} // namespace blobs
diff --git a/test/helper.cpp b/test/helper.cpp
new file mode 100644
index 0000000..73e19aa
--- /dev/null
+++ b/test/helper.cpp
@@ -0,0 +1,32 @@
+#include "helper.hpp"
+
+#include "ipmi.hpp"
+
+#include <ipmid/api-types.hpp>
+#include <optional>
+#include <span>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace blobs
+{
+std::vector<std::uint8_t>
+ validateReply(ipmi::RspType<std::vector<uint8_t>> reply, bool hasData)
+{
+ // Reply is in the form of
+ // std::tuple<ipmi::Cc, std::optional<std::tuple<RetTypes...>>>
+ EXPECT_EQ(::ipmi::ccSuccess, std::get<0>(reply));
+
+ auto actualReply = std::get<1>(reply);
+ EXPECT_TRUE(actualReply.has_value());
+
+ auto data = std::get<0>(*actualReply);
+ EXPECT_EQ(hasData, !data.empty());
+
+ return hasData ? data : std::vector<uint8_t>{};
+}
+
+} // namespace blobs
diff --git a/test/helper.hpp b/test/helper.hpp
new file mode 100644
index 0000000..8d33f5c
--- /dev/null
+++ b/test/helper.hpp
@@ -0,0 +1,15 @@
+#include <ipmid/api-types.hpp>
+#include <optional>
+#include <span>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace blobs
+{
+std::vector<std::uint8_t>
+ validateReply(ipmi::RspType<std::vector<uint8_t>> reply,
+ bool hasData = true);
+} // namespace blobs
diff --git a/test/ipmi_close_unittest.cpp b/test/ipmi_close_unittest.cpp
index af2e03e..d4bcb41 100644
--- a/test/ipmi_close_unittest.cpp
+++ b/test/ipmi_close_unittest.cpp
@@ -11,10 +11,6 @@
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobCloseTest, ManagerRejectsCloseReturnsFailure)
{
// The session manager returned failure to close, which we need to pass on.
@@ -22,21 +18,18 @@
ManagerMock mgr;
uint16_t sessionId = 0x54;
size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request;
struct BmcBlobCloseTx req;
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobClose);
req.crc = 0;
req.sessionId = sessionId;
dataLen = sizeof(req);
-
- std::memcpy(request, &req, sizeof(req));
+ request.resize(dataLen);
+ std::memcpy(request.data(), &req, dataLen);
EXPECT_CALL(mgr, close(sessionId)).WillOnce(Return(false));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- closeBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), closeBlob(&mgr, request));
}
TEST(BlobCloseTest, BlobClosedReturnsSuccess)
@@ -46,19 +39,18 @@
ManagerMock mgr;
uint16_t sessionId = 0x54;
size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request;
struct BmcBlobCloseTx req;
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobClose);
req.crc = 0;
req.sessionId = sessionId;
dataLen = sizeof(req);
-
- std::memcpy(request, &req, sizeof(req));
+ request.resize(dataLen);
+ std::memcpy(request.data(), &req, dataLen);
EXPECT_CALL(mgr, close(sessionId)).WillOnce(Return(true));
- EXPECT_EQ(IPMI_CC_OK, closeBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ closeBlob(&mgr, request));
}
} // namespace blobs
diff --git a/test/ipmi_commit_unittest.cpp b/test/ipmi_commit_unittest.cpp
index d4b9c58..6cc8223 100644
--- a/test/ipmi_commit_unittest.cpp
+++ b/test/ipmi_commit_unittest.cpp
@@ -12,31 +12,22 @@
using ::testing::ElementsAreArray;
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobCommitTest, InvalidCommitDataLengthReturnsFailure)
{
// The commit command supports an optional commit blob. This test verifies
// we sanity check the length of that blob.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
-
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
- req->crc = 0;
- req->sessionId = 0x54;
- req->commitDataLen =
+ std::vector<uint8_t> request;
+ struct BmcBlobCommitTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.commitDataLen =
1; // It's one byte, but that's more than the packet size.
- dataLen = sizeof(struct BmcBlobCommitTx);
-
- EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
- commitBlob(&mgr, request, reply, &dataLen));
+ request.resize(sizeof(struct BmcBlobCommitTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+ EXPECT_EQ(ipmi::responseReqDataLenInvalid(), commitBlob(&mgr, request));
}
TEST(BlobCommitTest, ValidCommitNoDataHandlerRejectsReturnsFailure)
@@ -44,22 +35,17 @@
// The commit packet is valid and the manager's commit call returns failure.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobCommitTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.commitDataLen = 0;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
- req->crc = 0;
- req->sessionId = 0x54;
- req->commitDataLen = 0;
+ request.resize(sizeof(struct BmcBlobCommitTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
- dataLen = sizeof(struct BmcBlobCommitTx);
-
- EXPECT_CALL(mgr, commit(req->sessionId, _)).WillOnce(Return(false));
-
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- commitBlob(&mgr, request, reply, &dataLen));
+ EXPECT_CALL(mgr, commit(req.sessionId, _)).WillOnce(Return(false));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), commitBlob(&mgr, request));
}
TEST(BlobCommitTest, ValidCommitNoDataHandlerAcceptsReturnsSuccess)
@@ -67,21 +53,18 @@
// Commit called with no data and everything returns success.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobCommitTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.commitDataLen = 0;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
- req->crc = 0;
- req->sessionId = 0x54;
- req->commitDataLen = 0;
+ request.resize(sizeof(struct BmcBlobCommitTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+ EXPECT_CALL(mgr, commit(req.sessionId, _)).WillOnce(Return(true));
- dataLen = sizeof(struct BmcBlobCommitTx);
-
- EXPECT_CALL(mgr, commit(req->sessionId, _)).WillOnce(Return(true));
-
- EXPECT_EQ(IPMI_CC_OK, commitBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ commitBlob(&mgr, request));
}
TEST(BlobCommitTest, ValidCommitWithDataHandlerAcceptsReturnsSuccess)
@@ -89,26 +72,21 @@
// Commit called with extra data and everything returns success.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobCommitTx*>(request);
+ std::vector<uint8_t> request;
+ std::array<uint8_t, 4> expectedBlob = {0x25, 0x33, 0x45, 0x67};
+ struct BmcBlobCommitTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.commitDataLen = sizeof(expectedBlob);
- uint8_t expectedBlob[4] = {0x25, 0x33, 0x45, 0x67};
+ request.resize(sizeof(struct BmcBlobCommitTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobCommitTx));
+ request.insert(request.end(), expectedBlob.begin(), expectedBlob.end());
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobCommit);
- req->crc = 0;
- req->sessionId = 0x54;
- req->commitDataLen = sizeof(expectedBlob);
- std::memcpy(req + 1, &expectedBlob[0], sizeof(expectedBlob));
-
- dataLen = sizeof(struct BmcBlobCommitTx) + sizeof(expectedBlob);
-
- EXPECT_CALL(mgr,
- commit(req->sessionId,
- ElementsAreArray(expectedBlob, sizeof(expectedBlob))))
+ EXPECT_CALL(mgr, commit(req.sessionId, ElementsAreArray(expectedBlob)))
.WillOnce(Return(true));
- EXPECT_EQ(IPMI_CC_OK, commitBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ commitBlob(&mgr, request));
}
} // namespace blobs
diff --git a/test/ipmi_delete_unittest.cpp b/test/ipmi_delete_unittest.cpp
index 3336b2d..cb1401a 100644
--- a/test/ipmi_delete_unittest.cpp
+++ b/test/ipmi_delete_unittest.cpp
@@ -12,79 +12,58 @@
using ::testing::Return;
using ::testing::StrEq;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobDeleteTest, InvalidRequestLengthReturnsFailure)
{
// There is a minimum blobId length of one character, this test verifies
// we check that.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobDeleteTx req;
+ req.crc = 0;
std::string blobId = "abc";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
- req->crc = 0;
- // length() doesn't include the nul-terminator.
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
+ request.resize(sizeof(struct BmcBlobDeleteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
- dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length();
-
- EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
- deleteBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseReqDataLenInvalid(), deleteBlob(&mgr, request));
}
TEST(BlobDeleteTest, RequestRejectedReturnsFailure)
{
// The blobId is rejected for any reason.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobDeleteTx req;
+ req.crc = 0;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
- req->crc = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
- dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length() + 1;
+ request.resize(sizeof(struct BmcBlobDeleteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
EXPECT_CALL(mgr, deleteBlob(StrEq(blobId))).WillOnce(Return(false));
-
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- deleteBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), deleteBlob(&mgr, request));
}
TEST(BlobDeleteTest, BlobDeleteReturnsOk)
{
// The boring case where the blobId is deleted.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobDeleteTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobDeleteTx req;
+ req.crc = 0;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobDelete);
- req->crc = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
- dataLen = sizeof(struct BmcBlobDeleteTx) + blobId.length() + 1;
+ request.resize(sizeof(struct BmcBlobDeleteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobDeleteTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
EXPECT_CALL(mgr, deleteBlob(StrEq(blobId))).WillOnce(Return(true));
- EXPECT_EQ(IPMI_CC_OK, deleteBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ deleteBlob(&mgr, request));
}
} // namespace blobs
diff --git a/test/ipmi_enumerate_unittest.cpp b/test/ipmi_enumerate_unittest.cpp
index edea82b..87752ea 100644
--- a/test/ipmi_enumerate_unittest.cpp
+++ b/test/ipmi_enumerate_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -11,28 +12,21 @@
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobEnumerateTest, VerifyIfRequestByIdInvalidReturnsFailure)
{
// This tests to verify that if the index is invalid, it'll return failure.
ManagerMock mgr;
- size_t dataLen;
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request;
struct BmcBlobEnumerateTx req;
- uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate);
req.blobIdx = 0;
- dataLen = sizeof(struct BmcBlobEnumerateTx);
+
+ request.resize(sizeof(struct BmcBlobEnumerateTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobEnumerateTx));
EXPECT_CALL(mgr, getBlobId(req.blobIdx)).WillOnce(Return(""));
-
- EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST,
- enumerateBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseInvalidFieldRequest(),
+ enumerateBlob(&mgr, request));
}
TEST(BlobEnumerateTest, BoringRequestByIdAndReceive)
@@ -41,26 +35,23 @@
// will return the blobId.
ManagerMock mgr;
- size_t dataLen;
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request;
struct BmcBlobEnumerateTx req;
- struct BmcBlobEnumerateRx* rep;
- uint8_t* request = reinterpret_cast<uint8_t*>(&req);
+ req.blobIdx = 0;
std::string blobId = "/asdf";
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobEnumerate);
- req.blobIdx = 0;
- dataLen = sizeof(struct BmcBlobEnumerateTx);
+ request.resize(sizeof(struct BmcBlobEnumerateTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobEnumerateTx));
EXPECT_CALL(mgr, getBlobId(req.blobIdx)).WillOnce(Return(blobId));
- EXPECT_EQ(IPMI_CC_OK, enumerateBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(enumerateBlob(&mgr, request));
// We're expecting this as a response.
// blobId.length + 1 + sizeof(uint16_t);
- EXPECT_EQ(blobId.length() + 1 + sizeof(uint16_t), dataLen);
-
- rep = reinterpret_cast<struct BmcBlobEnumerateRx*>(reply);
- EXPECT_EQ(0, std::memcmp(rep + 1, blobId.c_str(), blobId.length() + 1));
+ EXPECT_EQ(blobId.length() + 1 + sizeof(uint16_t), result.size());
+ EXPECT_EQ(blobId,
+ // Remove crc and nul-terminator.
+ std::string(result.begin() + sizeof(uint16_t), result.end() - 1));
}
} // namespace blobs
diff --git a/test/ipmi_getcount_unittest.cpp b/test/ipmi_getcount_unittest.cpp
index 34fc33d..dc1202d 100644
--- a/test/ipmi_getcount_unittest.cpp
+++ b/test/ipmi_getcount_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -11,10 +12,6 @@
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
// the request here is only the subcommand byte and therefore there's no invalid
// length check, etc to handle within the method.
@@ -24,24 +21,17 @@
// return that there are 0 blobs.
ManagerMock mgr;
- size_t dataLen;
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- struct BmcBlobCountTx req;
struct BmcBlobCountRx rep;
- uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
- dataLen = sizeof(req);
rep.crc = 0;
rep.blobCount = 0;
EXPECT_CALL(mgr, buildBlobList()).WillOnce(Return(0));
- EXPECT_EQ(IPMI_CC_OK, getBlobCount(&mgr, request, reply, &dataLen));
+ auto result = validateReply(getBlobCount(&mgr, {}));
- EXPECT_EQ(sizeof(rep), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+ EXPECT_EQ(sizeof(rep), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
}
TEST(BlobCountTest, ReturnsTwoBlobs)
@@ -50,23 +40,16 @@
// blobs will return that it found two blobs.
ManagerMock mgr;
- size_t dataLen;
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- struct BmcBlobCountTx req;
struct BmcBlobCountRx rep;
- uint8_t* request = reinterpret_cast<uint8_t*>(&req);
-
- req.cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
- dataLen = sizeof(req);
rep.crc = 0;
rep.blobCount = 2;
EXPECT_CALL(mgr, buildBlobList()).WillOnce(Return(2));
- EXPECT_EQ(IPMI_CC_OK, getBlobCount(&mgr, request, reply, &dataLen));
+ auto result = validateReply(getBlobCount(&mgr, {}));
- EXPECT_EQ(sizeof(rep), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+ EXPECT_EQ(sizeof(rep), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
}
} // namespace blobs
diff --git a/test/ipmi_open_unittest.cpp b/test/ipmi_open_unittest.cpp
index 5b18631..b938cbe 100644
--- a/test/ipmi_open_unittest.cpp
+++ b/test/ipmi_open_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -15,59 +16,44 @@
using ::testing::Return;
using ::testing::StrEq;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobOpenTest, InvalidRequestLengthReturnsFailure)
{
// There is a minimum blobId length of one character, this test verifies
// we check that.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+ std::vector<uint8_t> request;
+ BmcBlobOpenTx req;
std::string blobId = "abc";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
- req->crc = 0;
- req->flags = 0;
- // length() doesn't include the nul-terminator.
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
+ req.crc = 0;
+ req.flags = 0;
- dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length();
+ // Missintg the nul-terminator.
+ request.resize(sizeof(struct BmcBlobOpenTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
- EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
- openBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseReqDataLenInvalid(), openBlob(&mgr, request));
}
TEST(BlobOpenTest, RequestRejectedReturnsFailure)
{
// The blobId is rejected for any reason.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+ std::vector<uint8_t> request;
+ BmcBlobOpenTx req;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
- req->crc = 0;
- req->flags = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
+ req.crc = 0;
+ req.flags = 0;
+ request.resize(sizeof(struct BmcBlobOpenTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
- dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
+ EXPECT_CALL(mgr, open(req.flags, StrEq(blobId), _)).WillOnce(Return(false));
- EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), _))
- .WillOnce(Return(false));
-
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- openBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), openBlob(&mgr, request));
}
TEST(BlobOpenTest, BlobOpenReturnsOk)
@@ -75,35 +61,32 @@
// The boring case where the blobId opens.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobOpenTx*>(request);
+ std::vector<uint8_t> request;
+ BmcBlobOpenTx req;
struct BmcBlobOpenRx rep;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobOpen);
- req->crc = 0;
- req->flags = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
+ req.crc = 0;
+ req.flags = 0;
+ request.resize(sizeof(struct BmcBlobOpenTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobOpenTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
- dataLen = sizeof(struct BmcBlobOpenTx) + blobId.length() + 1;
uint16_t returnedSession = 0x54;
- EXPECT_CALL(mgr, open(req->flags, StrEq(blobId), NotNull()))
+ EXPECT_CALL(mgr, open(req.flags, StrEq(blobId), NotNull()))
.WillOnce(Invoke([&](uint16_t, const std::string&, uint16_t* session) {
(*session) = returnedSession;
return true;
}));
- EXPECT_EQ(IPMI_CC_OK, openBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(openBlob(&mgr, request));
rep.crc = 0;
rep.sessionId = returnedSession;
- EXPECT_EQ(sizeof(rep), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+ EXPECT_EQ(sizeof(rep), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
}
} // namespace blobs
diff --git a/test/ipmi_read_unittest.cpp b/test/ipmi_read_unittest.cpp
index 8d1b55f..80e1cbc 100644
--- a/test/ipmi_read_unittest.cpp
+++ b/test/ipmi_read_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -11,64 +12,50 @@
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobReadTest, ManagerReturnsNoData)
{
// Verify that if no data is returned the IPMI command reply has no
// payload. The manager, in all failures, will just return 0 bytes.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobReadTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobReadTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobRead);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
- req->requestedSize = 0x10;
-
- dataLen = sizeof(struct BmcBlobReadTx);
-
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
+ req.requestedSize = 0x10;
+ request.resize(sizeof(struct BmcBlobReadTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobReadTx));
std::vector<uint8_t> data;
- EXPECT_CALL(mgr, read(req->sessionId, req->offset, req->requestedSize))
+ EXPECT_CALL(mgr, read(req.sessionId, req.offset, req.requestedSize))
.WillOnce(Return(data));
- EXPECT_EQ(IPMI_CC_OK, readBlob(&mgr, request, reply, &dataLen));
- EXPECT_EQ(sizeof(struct BmcBlobReadRx), dataLen);
+ auto result = validateReply(readBlob(&mgr, request));
+ EXPECT_EQ(sizeof(struct BmcBlobReadRx), result.size());
}
TEST(BlobReadTest, ManagerReturnsData)
{
// Verify that if data is returned, it's placed in the expected location.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobReadTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobReadTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobRead);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
- req->requestedSize = 0x10;
-
- dataLen = sizeof(struct BmcBlobReadTx);
-
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
+ req.requestedSize = 0x10;
+ request.resize(sizeof(struct BmcBlobReadTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobReadTx));
std::vector<uint8_t> data = {0x02, 0x03, 0x05, 0x06};
- EXPECT_CALL(mgr, read(req->sessionId, req->offset, req->requestedSize))
+ EXPECT_CALL(mgr, read(req.sessionId, req.offset, req.requestedSize))
.WillOnce(Return(data));
- EXPECT_EQ(IPMI_CC_OK, readBlob(&mgr, request, reply, &dataLen));
- EXPECT_EQ(sizeof(struct BmcBlobReadRx) + data.size(), dataLen);
- EXPECT_EQ(0, std::memcmp(&reply[sizeof(struct BmcBlobReadRx)], data.data(),
+ auto result = validateReply(readBlob(&mgr, request));
+ EXPECT_EQ(sizeof(struct BmcBlobReadRx) + data.size(), result.size());
+ EXPECT_EQ(0, std::memcmp(&result[sizeof(struct BmcBlobReadRx)], data.data(),
data.size()));
}
diff --git a/test/ipmi_sessionstat_unittest.cpp b/test/ipmi_sessionstat_unittest.cpp
index 4bf1125..3278f25 100644
--- a/test/ipmi_sessionstat_unittest.cpp
+++ b/test/ipmi_sessionstat_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -23,22 +24,19 @@
// If the session ID is invalid, the request must fail.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
- req->crc = 0;
- req->sessionId = 0x54;
+ std::vector<uint8_t> request;
+ struct BmcBlobSessionStatTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
- dataLen = sizeof(struct BmcBlobSessionStatTx);
+ request.resize(sizeof(struct BmcBlobSessionStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
EXPECT_CALL(mgr,
- stat(Matcher<uint16_t>(req->sessionId), Matcher<BlobMeta*>(_)))
+ stat(Matcher<uint16_t>(req.sessionId), Matcher<BlobMeta*>(_)))
.WillOnce(Return(false));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- sessionStatBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), sessionStatBlob(&mgr, request));
}
TEST(BlobSessionStatTest, RequestSucceedsNoMetadata)
@@ -46,15 +44,13 @@
// Stat request succeeeds but there were no metadata bytes.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
- req->crc = 0;
- req->sessionId = 0x54;
+ std::vector<uint8_t> request;
+ struct BmcBlobSessionStatTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
- dataLen = sizeof(struct BmcBlobSessionStatTx);
+ request.resize(sizeof(struct BmcBlobSessionStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
struct BmcBlobStatRx rep;
rep.crc = 0x00;
@@ -65,7 +61,7 @@
uint16_t blobState = rep.blobState;
uint32_t size = rep.size;
- EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req->sessionId),
+ EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req.sessionId),
Matcher<BlobMeta*>(NotNull())))
.WillOnce(Invoke([&](uint16_t, BlobMeta* meta) {
meta->blobState = blobState;
@@ -73,10 +69,10 @@
return true;
}));
- EXPECT_EQ(IPMI_CC_OK, sessionStatBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(sessionStatBlob(&mgr, request));
- EXPECT_EQ(sizeof(rep), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+ EXPECT_EQ(sizeof(rep), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
}
TEST(BlobSessionStatTest, RequestSucceedsWithMetadata)
@@ -84,15 +80,13 @@
// Stat request succeeds and there were metadata bytes.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobSessionStatTx*>(request);
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobSessionStat);
- req->crc = 0;
- req->sessionId = 0x54;
+ std::vector<uint8_t> request;
+ struct BmcBlobSessionStatTx req;
+ req.crc = 0;
+ req.sessionId = 0x54;
- dataLen = sizeof(struct BmcBlobSessionStatTx);
+ request.resize(sizeof(struct BmcBlobSessionStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobSessionStatTx));
BlobMeta lmeta;
lmeta.blobState = 0x01;
@@ -108,18 +102,18 @@
rep.size = lmeta.size;
rep.metadataLen = lmeta.metadata.size();
- EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req->sessionId),
+ EXPECT_CALL(mgr, stat(Matcher<uint16_t>(req.sessionId),
Matcher<BlobMeta*>(NotNull())))
.WillOnce(Invoke([&](uint16_t, BlobMeta* meta) {
(*meta) = lmeta;
return true;
}));
- EXPECT_EQ(IPMI_CC_OK, sessionStatBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(sessionStatBlob(&mgr, request));
- EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
- EXPECT_EQ(0, std::memcmp(reply + sizeof(rep), lmeta.metadata.data(),
+ EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
+ EXPECT_EQ(0, std::memcmp(result.data() + sizeof(rep), lmeta.metadata.data(),
lmeta.metadata.size()));
}
} // namespace blobs
diff --git a/test/ipmi_stat_unittest.cpp b/test/ipmi_stat_unittest.cpp
index 6d4d7b2..ab091ad 100644
--- a/test/ipmi_stat_unittest.cpp
+++ b/test/ipmi_stat_unittest.cpp
@@ -1,3 +1,4 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
@@ -24,23 +25,18 @@
{
// There is a minimum blobId length of one character, this test verifies
// we check that.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobStatTx req;
std::string blobId = "abc";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
- req->crc = 0;
- // length() doesn't include the nul-terminator.
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
+ req.crc = 0;
+ request.resize(sizeof(struct BmcBlobStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+ // Do not include the nul-terminator
+ request.insert(request.end(), blobId.begin(), blobId.end());
- dataLen = sizeof(struct BmcBlobStatTx) + blobId.length();
-
- EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID,
- statBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseReqDataLenInvalid(), statBlob(&mgr, request));
}
TEST(BlobStatTest, RequestRejectedReturnsFailure)
@@ -48,26 +44,21 @@
// The blobId is rejected for any reason.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobStatTx req;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
- req->crc = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
- dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+ req.crc = 0;
+ request.resize(sizeof(struct BmcBlobStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
EXPECT_CALL(mgr, stat(Matcher<const std::string&>(StrEq(blobId)),
Matcher<BlobMeta*>(_)))
.WillOnce(Return(false));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- statBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), statBlob(&mgr, request));
}
TEST(BlobStatTest, RequestSucceedsNoMetadata)
@@ -75,19 +66,15 @@
// Stat request succeeeds but there were no metadata bytes.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobStatTx req;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
- req->crc = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
- dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+ req.crc = 0;
+ request.resize(sizeof(struct BmcBlobStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
struct BmcBlobStatRx rep;
rep.crc = 0x00;
@@ -106,10 +93,10 @@
return true;
}));
- EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(statBlob(&mgr, request));
- EXPECT_EQ(sizeof(rep), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
+ EXPECT_EQ(sizeof(rep), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
}
TEST(BlobStatTest, RequestSucceedsWithMetadata)
@@ -117,19 +104,15 @@
// Stat request succeeds and there were metadata bytes.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobStatTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobStatTx req;
std::string blobId = "a";
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobStat);
- req->crc = 0;
- // length() doesn't include the nul-terminator, request buff is initialized
- // to 0s
- std::memcpy(req + 1, blobId.c_str(), blobId.length());
-
- dataLen = sizeof(struct BmcBlobStatTx) + blobId.length() + 1;
+ req.crc = 0;
+ request.resize(sizeof(struct BmcBlobStatTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobStatTx));
+ request.insert(request.end(), blobId.begin(), blobId.end());
+ request.emplace_back('\0');
BlobMeta lmeta;
lmeta.blobState = 0x01;
@@ -152,11 +135,11 @@
return true;
}));
- EXPECT_EQ(IPMI_CC_OK, statBlob(&mgr, request, reply, &dataLen));
+ auto result = validateReply(statBlob(&mgr, request));
- EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), dataLen);
- EXPECT_EQ(0, std::memcmp(reply, &rep, sizeof(rep)));
- EXPECT_EQ(0, std::memcmp(reply + sizeof(rep), lmeta.metadata.data(),
+ EXPECT_EQ(sizeof(rep) + lmeta.metadata.size(), result.size());
+ EXPECT_EQ(0, std::memcmp(result.data(), &rep, sizeof(rep)));
+ EXPECT_EQ(0, std::memcmp(result.data() + sizeof(rep), lmeta.metadata.data(),
lmeta.metadata.size()));
}
} // namespace blobs
diff --git a/test/ipmi_unittest.cpp b/test/ipmi_unittest.cpp
index 8f27ed7..ed2f026 100644
--- a/test/ipmi_unittest.cpp
+++ b/test/ipmi_unittest.cpp
@@ -14,47 +14,37 @@
TEST(StringInputTest, NullPointerInput)
{
// The method should verify it did receive a non-null input pointer.
-
- EXPECT_STREQ("", stringFromBuffer(NULL, 5).c_str());
+ EXPECT_STREQ("", stringFromBuffer({}).c_str());
}
TEST(StringInputTest, ZeroBytesInput)
{
// Verify that if the input length is 0 that it'll return the empty string.
-
- const char* request = "asdf";
- EXPECT_STREQ("", stringFromBuffer(request, 0).c_str());
+ const std::string request = "asdf";
+ EXPECT_STREQ("", stringFromBuffer(
+ std::vector<uint8_t>(request.begin(), request.end()))
+ .c_str());
}
TEST(StringInputTest, NulTerminatorNotFound)
{
// Verify that if there isn't a nul-terminator found in an otherwise valid
// string, it'll return the emptry string.
-
- char request[MAX_IPMI_BUFFER];
- std::memset(request, 'a', sizeof(request));
- EXPECT_STREQ("", stringFromBuffer(request, sizeof(request)).c_str());
-}
-
-TEST(StringInputTest, TwoNulsFound)
-{
- // Verify it makes you use the entire data region for the string.
- char request[MAX_IPMI_BUFFER];
- request[0] = 'a';
- request[1] = 0;
- std::memset(&request[2], 'b', sizeof(request) - 2);
- request[MAX_IPMI_BUFFER - 1] = 0;
-
- // This case has two strings, and the last character is a nul-terminator.
- EXPECT_STREQ("", stringFromBuffer(request, sizeof(request)).c_str());
+ std::array<char, MAX_IPMI_BUFFER> request;
+ std::memset(request.data(), 'a', sizeof(request));
+ EXPECT_STREQ("", stringFromBuffer(
+ std::vector<uint8_t>(request.begin(), request.end()))
+ .c_str());
}
TEST(StringInputTest, NulTerminatorFound)
{
// Verify that if it's provided a valid nul-terminated string, it'll
// return it.
-
- const char* request = "asdf";
- EXPECT_STREQ("asdf", stringFromBuffer(request, 5).c_str());
+ std::string request = "asdf";
+ request.push_back('\0');
+ EXPECT_STREQ("asdf", stringFromBuffer(std::vector<uint8_t>(request.begin(),
+ request.end()))
+ .c_str());
}
} // namespace blobs
diff --git a/test/ipmi_write_unittest.cpp b/test/ipmi_write_unittest.cpp
index 229ebd3..12cf1bc 100644
--- a/test/ipmi_write_unittest.cpp
+++ b/test/ipmi_write_unittest.cpp
@@ -1,47 +1,38 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
#include <cstring>
#include <gtest/gtest.h>
-
namespace blobs
{
using ::testing::ElementsAreArray;
using ::testing::Return;
-// ipmid.hpp isn't installed where we can grab it and this value is per BMC
-// SoC.
-#define MAX_IPMI_BUFFER 64
-
TEST(BlobWriteTest, ManagerReturnsFailureReturnsFailure)
{
// This verifies a failure from the manager is passed back.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobWriteTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+ request.resize(sizeof(struct BmcBlobWriteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
- dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
- EXPECT_CALL(mgr,
- write(req->sessionId, req->offset,
- ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+ EXPECT_CALL(
+ mgr, write(req.sessionId, req.offset, ElementsAreArray(expectedBytes)))
.WillOnce(Return(false));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- writeBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), writeBlob(&mgr, request));
}
TEST(BlobWriteTest, ManagerReturnsTrueWriteSucceeds)
@@ -49,26 +40,24 @@
// The case where everything works.
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobWriteTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+ request.resize(sizeof(struct BmcBlobWriteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
- dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
- EXPECT_CALL(mgr,
- write(req->sessionId, req->offset,
- ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+ EXPECT_CALL(
+ mgr, write(req.sessionId, req.offset, ElementsAreArray(expectedBytes)))
.WillOnce(Return(true));
- EXPECT_EQ(IPMI_CC_OK, writeBlob(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ writeBlob(&mgr, request));
}
} // namespace blobs
diff --git a/test/ipmi_writemeta_unittest.cpp b/test/ipmi_writemeta_unittest.cpp
index dd9e742..bc8669d 100644
--- a/test/ipmi_writemeta_unittest.cpp
+++ b/test/ipmi_writemeta_unittest.cpp
@@ -17,57 +17,49 @@
TEST(BlobWriteMetaTest, ManagerReturnsFailureReturnsFailure)
{
// This verifies a failure from the manager is passed back.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobWriteMetaTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobWriteMetaTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+ request.resize(sizeof(struct BmcBlobWriteMetaTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteMetaTx));
- dataLen = sizeof(struct BmcBlobWriteMetaTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
- EXPECT_CALL(
- mgr, writeMeta(req->sessionId, req->offset,
- ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+ EXPECT_CALL(mgr, writeMeta(req.sessionId, req.offset,
+ ElementsAreArray(expectedBytes)))
.WillOnce(Return(false));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- writeMeta(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), writeMeta(&mgr, request));
}
TEST(BlobWriteMetaTest, ManagerReturnsTrueWriteSucceeds)
{
// The case where everything works.
-
ManagerMock mgr;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
- auto req = reinterpret_cast<struct BmcBlobWriteMetaTx*>(request);
+ std::vector<uint8_t> request;
+ struct BmcBlobWriteMetaTx req;
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0;
- req->sessionId = 0x54;
- req->offset = 0x100;
+ req.crc = 0;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
+ request.resize(sizeof(struct BmcBlobWriteMetaTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteMetaTx));
- dataLen = sizeof(struct BmcBlobWriteMetaTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
- EXPECT_CALL(
- mgr, writeMeta(req->sessionId, req->offset,
- ElementsAreArray(expectedBytes, sizeof(expectedBytes))))
+ EXPECT_CALL(mgr, writeMeta(req.sessionId, req.offset,
+ ElementsAreArray(expectedBytes)))
.WillOnce(Return(true));
- EXPECT_EQ(IPMI_CC_OK, writeMeta(&mgr, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>{}),
+ writeMeta(&mgr, request));
}
} // namespace blobs
diff --git a/test/meson.build b/test/meson.build
index db240b3..b5bdd99 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -37,6 +37,7 @@
executable(
t.underscorify(),
t + '.cpp',
+ 'helper.cpp',
implicit_include_directories: false,
dependencies: [blob_manager_dep, gtest, gmock]))
endforeach
diff --git a/test/process_unittest.cpp b/test/process_unittest.cpp
index b72fe9a..02014d4 100644
--- a/test/process_unittest.cpp
+++ b/test/process_unittest.cpp
@@ -1,9 +1,11 @@
+#include "helper.hpp"
#include "ipmi.hpp"
#include "manager_mock.hpp"
#include "process.hpp"
#include <cstring>
#include <ipmiblob/test/crc_mock.hpp>
+#include <span>
#include <gtest/gtest.h>
@@ -12,6 +14,7 @@
#define MAX_IPMI_BUFFER 64
using ::testing::_;
+using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Return;
using ::testing::StrictMock;
@@ -36,15 +39,11 @@
EXPECT_FALSE(lhs == nullptr);
EXPECT_FALSE(rhs == nullptr);
- ipmi_ret_t (*const* lPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
- size_t*) =
- lhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
- size_t*)>();
+ Resp (*const* lPtr)(ManagerInterface*, std::span<const uint8_t>) =
+ lhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
- ipmi_ret_t (*const* rPtr)(ManagerInterface*, const uint8_t*, uint8_t*,
- size_t*) =
- rhs.target<ipmi_ret_t (*)(ManagerInterface*, const uint8_t*, uint8_t*,
- size_t*)>();
+ Resp (*const* rPtr)(ManagerInterface*, std::span<const uint8_t>) =
+ rhs.target<Resp (*)(ManagerInterface*, std::span<const uint8_t>)>();
EXPECT_TRUE(lPtr);
EXPECT_TRUE(rPtr);
@@ -67,34 +66,20 @@
TEST_F(ValidateBlobCommandTest, InvalidCommandReturnsFailure)
{
// Verify we handle an invalid command.
-
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
- request[0] = 0xff; // There is no command 0xff.
- dataLen = sizeof(uint8_t); // There is no payload for CRC.
- ipmi_ret_t rc;
-
- EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
- EXPECT_EQ(IPMI_CC_INVALID_FIELD_REQUEST, rc);
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
+ // There is no command 0xff.
+ IpmiBlobHandler handler = validateBlobCommand(0xff, request);
+ EXPECT_EQ(ipmi::responseInvalidFieldRequest(), handler(nullptr, {}));
}
TEST_F(ValidateBlobCommandTest, ValidCommandWithoutPayload)
{
// Verify we handle a valid command that doesn't have a payload.
-
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
- request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
- dataLen = sizeof(uint8_t); // There is no payload for CRC.
- ipmi_ret_t rc;
-
- IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
- EXPECT_FALSE(res == nullptr);
- EqualFunctions(getBlobCount, res);
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
+ IpmiBlobHandler handler = validateBlobCommand(
+ static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
+ EXPECT_FALSE(handler == nullptr);
+ EqualFunctions(getBlobCount, handler);
}
TEST_F(ValidateBlobCommandTest, WithPayloadMinimumLengthIs3VerifyChecks)
@@ -102,76 +87,61 @@
// Verify that if there's a payload, it's at least one command byte and
// two bytes for the crc16 and then one data byte.
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
- request[0] = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount);
- dataLen = sizeof(uint8_t) + sizeof(uint16_t);
+ std::vector<uint8_t> request(sizeof(uint16_t));
// There is a payload, but there are insufficient bytes.
- ipmi_ret_t rc;
- EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
- EXPECT_EQ(IPMI_CC_REQ_DATA_LEN_INVALID, rc);
+ IpmiBlobHandler handler = validateBlobCommand(
+ static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobGetCount), request);
+ EXPECT_EQ(ipmi::responseReqDataLenInvalid(), handler(nullptr, {}));
}
TEST_F(ValidateBlobCommandTest, WithPayloadAndInvalidCrc)
{
// Verify that the CRC is checked, and failure is reported.
+ std::vector<uint8_t> request;
+ BmcBlobWriteTx req;
+ req.crc = 0x34;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
- auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0x34;
- req->sessionId = 0x54;
- req->offset = 0x100;
-
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
-
- dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.resize(sizeof(struct BmcBlobWriteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
// skip over cmd and crc.
- std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
+ std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
+ request.end());
EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x1234));
- ipmi_ret_t rc;
-
- EXPECT_EQ(nullptr, validateBlobCommand(request, reply, &dataLen, &rc));
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR, rc);
+ IpmiBlobHandler handler = validateBlobCommand(
+ static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
+ EXPECT_EQ(ipmi::responseUnspecifiedError(), handler(nullptr, {}));
}
TEST_F(ValidateBlobCommandTest, WithPayloadAndValidCrc)
{
// Verify the CRC is checked and if it matches, return the handler.
+ std::vector<uint8_t> request;
+ BmcBlobWriteTx req;
+ req.crc = 0x3412;
+ req.sessionId = 0x54;
+ req.offset = 0x100;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
-
- auto req = reinterpret_cast<struct BmcBlobWriteTx*>(request);
- req->cmd = static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite);
- req->crc = 0x3412;
- req->sessionId = 0x54;
- req->offset = 0x100;
-
- uint8_t expectedBytes[2] = {0x66, 0x67};
- std::memcpy(req + 1, &expectedBytes[0], sizeof(expectedBytes));
-
- dataLen = sizeof(struct BmcBlobWriteTx) + sizeof(expectedBytes);
+ std::array<uint8_t, 2> expectedBytes = {0x66, 0x67};
+ request.resize(sizeof(struct BmcBlobWriteTx));
+ std::memcpy(request.data(), &req, sizeof(struct BmcBlobWriteTx));
+ request.insert(request.end(), expectedBytes.begin(), expectedBytes.end());
// skip over cmd and crc.
- std::vector<std::uint8_t> bytes(&request[3], request + dataLen);
+ std::vector<uint8_t> bytes(request.begin() + sizeof(req.crc),
+ request.end());
EXPECT_CALL(crcMock, generateCrc(Eq(bytes))).WillOnce(Return(0x3412));
- ipmi_ret_t rc;
-
- IpmiBlobHandler res = validateBlobCommand(request, reply, &dataLen, &rc);
- EXPECT_FALSE(res == nullptr);
- EqualFunctions(writeBlob, res);
+ IpmiBlobHandler handler = validateBlobCommand(
+ static_cast<std::uint8_t>(BlobOEMCommands::bmcBlobWrite), request);
+ EXPECT_FALSE(handler == nullptr);
+ EqualFunctions(writeBlob, handler);
}
class ProcessBlobCommandTest : public ::testing::Test
@@ -191,17 +161,14 @@
// noticed and returned.
StrictMock<ManagerMock> manager;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
- IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
- size_t*) { return IPMI_CC_INVALID; };
+ IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseInvalidCommand();
+ };
- dataLen = sizeof(request);
-
- EXPECT_EQ(IPMI_CC_INVALID,
- processBlobCommand(h, &manager, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseInvalidCommand(),
+ processBlobCommand(h, &manager, request));
}
TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithNoPayload)
@@ -210,20 +177,14 @@
// it doesn't try to compute a CRC.
StrictMock<ManagerMock> manager;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
- IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
- size_t* dataLen) {
- (*dataLen) = 0;
- return IPMI_CC_OK;
+ IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseSuccess(std::vector<uint8_t>());
};
- dataLen = sizeof(request);
-
- EXPECT_EQ(IPMI_CC_OK,
- processBlobCommand(h, &manager, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseSuccess(std::vector<uint8_t>()),
+ processBlobCommand(h, &manager, request));
}
TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithInvalidPayloadLength)
@@ -232,20 +193,14 @@
// read), this returns 1.
StrictMock<ManagerMock> manager;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
- IpmiBlobHandler h = [](ManagerInterface*, const uint8_t*, uint8_t*,
- size_t* dataLen) {
- (*dataLen) = sizeof(uint8_t);
- return IPMI_CC_OK;
+ IpmiBlobHandler h = [](ManagerInterface*, std::span<const uint8_t>) {
+ return ipmi::responseSuccess(std::vector<uint8_t>(1));
};
- dataLen = sizeof(request);
-
- EXPECT_EQ(IPMI_CC_UNSPECIFIED_ERROR,
- processBlobCommand(h, &manager, request, reply, &dataLen));
+ EXPECT_EQ(ipmi::responseUnspecifiedError(),
+ processBlobCommand(h, &manager, request));
}
TEST_F(ProcessBlobCommandTest, CommandReturnsOkWithValidPayloadLength)
@@ -254,27 +209,22 @@
// payload of 3 bytes and the crc code is called to process the payload.
StrictMock<ManagerMock> manager;
- size_t dataLen;
- uint8_t request[MAX_IPMI_BUFFER] = {0};
- uint8_t reply[MAX_IPMI_BUFFER] = {0};
+ std::vector<uint8_t> request(MAX_IPMI_BUFFER - 1);
uint32_t payloadLen = sizeof(uint16_t) + sizeof(uint8_t);
- IpmiBlobHandler h = [payloadLen](ManagerInterface*, const uint8_t*,
- uint8_t* replyCmdBuf, size_t* dataLen) {
- (*dataLen) = payloadLen;
- replyCmdBuf[2] = 0x56;
- return IPMI_CC_OK;
+ IpmiBlobHandler h = [payloadLen](ManagerInterface*,
+ std::span<const uint8_t>) {
+ std::vector<uint8_t> output(payloadLen, 0);
+ output[2] = 0x56;
+ return ipmi::responseSuccess(output);
};
- dataLen = sizeof(request);
-
EXPECT_CALL(crcMock, generateCrc(_)).WillOnce(Return(0x3412));
- EXPECT_EQ(IPMI_CC_OK,
- processBlobCommand(h, &manager, request, reply, &dataLen));
- EXPECT_EQ(dataLen, payloadLen);
+ auto result = validateReply(processBlobCommand(h, &manager, request));
- uint8_t expectedBytes[3] = {0x12, 0x34, 0x56};
- EXPECT_EQ(0, std::memcmp(expectedBytes, reply, sizeof(expectedBytes)));
+ EXPECT_EQ(result.size(), payloadLen);
+ EXPECT_THAT(result, ElementsAre(0x12, 0x34, 0x56));
}
+
} // namespace blobs