ncsi: return command response from sendOemCommand
Rather than expecting the response to be handled from the command
callback, return it as the return value from sendOemCommand().
This addresses the todo in the sendOemCommand implementation.
Change-Id: I144128f50341d4ff7d8e248cb4dfa1427ead515b
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
diff --git a/src/ncsi_netlink_main.cpp b/src/ncsi_netlink_main.cpp
index d5c6fc5..3089b7c 100644
--- a/src/ncsi_netlink_main.cpp
+++ b/src/ncsi_netlink_main.cpp
@@ -17,6 +17,8 @@
#include "ncsi_util.hpp"
#include <phosphor-logging/lg2.hpp>
+#include <stdplus/numeric/str.hpp>
+#include <stdplus/str/buf.hpp>
#include <string>
#include <vector>
@@ -72,6 +74,26 @@
}
}
+static stdplus::StrBuf toHexStr(std::span<const uint8_t> c) noexcept
+{
+ stdplus::StrBuf ret;
+ if (c.empty())
+ {
+ return ret;
+ }
+ stdplus::IntToStr<16, uint8_t> its;
+ auto oit = ret.append(c.size() * 3);
+ auto cit = c.begin();
+ oit = its(oit, *cit++, 2);
+ for (; cit != c.end(); ++cit)
+ {
+ *oit++ = ' ';
+ oit = its(oit, *cit, 2);
+ }
+ *oit = 0;
+ return ret;
+}
+
int main(int argc, char** argv)
{
using namespace phosphor::network;
@@ -182,9 +204,21 @@
exitWithError("Package not specified.", argv);
}
- return interface.sendOemCommand(
- packageInt, channelInt, operationInt,
- std::span<const unsigned char>(payload.begin(), payload.end()));
+ if (!payload.empty())
+ {
+ lg2::debug("Payload: {PAYLOAD}", "PAYLOAD", toHexStr(payload));
+ }
+
+ auto cmd =
+ std::span<const unsigned char>(payload.begin(), payload.end());
+ auto resp =
+ interface.sendOemCommand(packageInt, channelInt, operationInt, cmd);
+ if (!resp)
+ {
+ return EXIT_FAILURE;
+ }
+ lg2::debug("Response {DATA_LEN} bytes: {DATA}", "DATA_LEN",
+ resp->size(), "DATA", toHexStr(*resp));
}
else if ((options)["set"] == "true")
{
diff --git a/src/ncsi_util.cpp b/src/ncsi_util.cpp
index 8c628aa..7a13590 100644
--- a/src/ncsi_util.cpp
+++ b/src/ncsi_util.cpp
@@ -6,8 +6,6 @@
#include <netlink/netlink.h>
#include <phosphor-logging/lg2.hpp>
-#include <stdplus/numeric/str.hpp>
-#include <stdplus/str/buf.hpp>
#include <vector>
@@ -20,26 +18,6 @@
using CallBack = int (*)(struct nl_msg* msg, void* arg);
-static stdplus::StrBuf toHexStr(std::span<const uint8_t> c) noexcept
-{
- stdplus::StrBuf ret;
- if (c.empty())
- {
- return ret;
- }
- stdplus::IntToStr<16, uint8_t> its;
- auto oit = ret.append(c.size() * 3);
- auto cit = c.begin();
- oit = its(oit, *cit++, 2);
- for (; cit != c.end(); ++cit)
- {
- *oit++ = ' ';
- oit = its(oit, *cit, 2);
- }
- *oit = 0;
- return ret;
-}
-
namespace internal
{
@@ -223,7 +201,12 @@
return static_cast<int>(NL_STOP);
};
-CallBack sendCallBack = [](struct nl_msg* msg, void*) {
+struct sendCallBackContext
+{
+ std::vector<unsigned char> msg;
+};
+
+CallBack sendCallBack = [](struct nl_msg* msg, void* arg) {
using namespace phosphor::network::ncsi;
auto nlh = nlmsg_hdr(msg);
struct nlattr* tb[NCSI_ATTR_MAX + 1] = {nullptr};
@@ -233,6 +216,14 @@
{NLA_FLAG, 0, 0}, {NLA_U32, 0, 0}, {NLA_U32, 0, 0},
};
+ if (arg == nullptr)
+ {
+ lg2::error("Internal error: invalid send callback context");
+ return -1;
+ }
+
+ struct sendCallBackContext* ctx = (struct sendCallBackContext*)arg;
+
auto ret = genlmsg_parse(nlh, 0, tb, NCSI_ATTR_MAX, ncsiPolicy);
if (ret)
{
@@ -250,10 +241,7 @@
unsigned char* data =
(unsigned char*)nla_data(tb[NCSI_ATTR_DATA]) + sizeof(NCSIPacketHeader);
- // Dump the response to stdout. Enhancement: option to save response data
- auto str = toHexStr(std::span<const unsigned char>(data, data_len));
- lg2::debug("Response {DATA_LEN} bytes: {DATA}", "DATA_LEN", data_len,
- "DATA", str);
+ ctx->msg.assign(data, data + data_len);
return static_cast<int>(NL_STOP);
};
@@ -411,23 +399,29 @@
return std::to_string(interface.ifindex);
}
-int Interface::sendOemCommand(int package, int channel, int operation,
+std::optional<std::vector<unsigned char>>
+ Interface::sendOemCommand(int package, int channel, int operation,
std::span<const unsigned char> payload)
{
lg2::debug("Send OEM Command, CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, "
"INTERFACE: {INTERFACE}",
"CHANNEL", lg2::hex, channel, "PACKAGE", lg2::hex, package,
"INTERFACE", this);
- if (!payload.empty())
- {
- lg2::debug("Payload: {PAYLOAD}", "PAYLOAD", toHexStr(payload));
- }
- return internal::applyCmd(
+ internal::sendCallBackContext ctx{};
+
+ int rc = internal::applyCmd(
*this,
internal::Command(ncsi_nl_commands::NCSI_CMD_SEND_CMD, operation,
payload),
- package, channel, NONE, internal::sendCallBack);
+ package, channel, NONE, internal::sendCallBack, &ctx);
+
+ if (rc < 0)
+ {
+ return {};
+ }
+
+ return ctx.msg;
}
int Interface::setChannel(int package, int channel)
diff --git a/src/ncsi_util.hpp b/src/ncsi_util.hpp
index 452c916..048bb71 100644
--- a/src/ncsi_util.hpp
+++ b/src/ncsi_util.hpp
@@ -42,6 +42,8 @@
struct Interface
{
+ using ncsiMessage = std::span<const unsigned char>;
+
/* @brief This function will ask underlying NCSI driver
* to send an OEM command (command type 0x50) with
* the specified payload as the OEM data.
@@ -51,10 +53,10 @@
* @param[in] channel - Channel number with in the package.
* @param[in] opcode - NCSI Send Command sub-operation
* @param[in] payload - OEM data to send.
- * @returns 0 on success and negative value for failure.
+ * @returns the NCSI response message to this command, or no value on error.
*/
- int sendOemCommand(int package, int channel, int opcode,
- std::span<const unsigned char> payload);
+ std::optional<std::vector<unsigned char>> sendOemCommand(
+ int package, int channel, int opcode, ncsiMessage payload);
/* @brief This function will ask underlying NCSI driver
* to set a specific package or package/channel