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