Make Send Command feature more flexible
The sendOemCommand command, used to send NCSI_CMD_SEND_CMD payloads,
is hardcoded to only send one command.
Update the sendOemCommand function to allow the sub-operation to be
passed as a command line argument. This is done by prepending the
sub-operation byte to the front of the Send Cmd payload.
Doing this allows sub-operations without any payload bytes to be
called. For example "-o 0a", where the sub-operation for Send Cmd is
the 0x0a value.
Tested:
Sent 'ncsi-netlink -x 3 -p 0 -c 0 -o 50000001572100' and confirmed
the 0x50 byte worked the same way as the original hard-coded value.
Sent 'ncsi-netlink -x 3 -p 0 -c 0 -o 0a' and confirmed the 0x0a
sub-operation functioned on the submitters SUT.
Change-Id: I20f093fd8296f549fce03dc5729b8e5fedcab313
Signed-off-by: Johnathan Mantey <johnathanx.mantey@intel.com>
diff --git a/src/argument.cpp b/src/argument.cpp
index 0c49b11..6bc40bc 100644
--- a/src/argument.cpp
+++ b/src/argument.cpp
@@ -66,18 +66,29 @@
void ArgumentParser::usage(char** argv)
{
std::cerr << "Usage: " << argv[0] << " [options]\n";
- std::cerr << "Options:\n";
- std::cerr << " --help Print this menu.\n";
- std::cerr << " --info=<info> Retrieve info about NCSI topology.\n";
- std::cerr << " --set=<set> Set a specific package/channel.\n";
std::cerr
- << " --clear=<clear> Clear all the settings on the interface.\n";
- std::cerr
- << " --oem-payload=<hex data> Send an OEM command with payload.\n";
- std::cerr << " --package=<package> Specify a package.\n";
- std::cerr << " --channel=<channel> Specify a channel.\n";
- std::cerr << " --index=<device index> Specify device ifindex.\n";
- std::cerr << std::flush;
+ << "Options:\n"
+ " --help | -h Print this menu.\n"
+ " --index=<device index> | -x <device index> Specify device ifindex.\n"
+ " --package=<package> | -p <package> Specify a package.\n"
+ " --channel=<channel> | -c <channel> Specify a channel.\n"
+ " --info | -i Retrieve info about NCSI topology.\n"
+ " --set | -s Set a specific package/channel.\n"
+ " --clear | -r Clear all the settings on the interface.\n"
+ " --oem-payload=<hex data...> | -o <hex data...> Send an OEM command with payload.\n"
+ "\n"
+ "Example commands:\n"
+ " 1) Retrieve topology information:\n"
+ " ncsi-netlink -x 3 -p 0 -i\n"
+ " 2) Set preferred package\n"
+ " ncsi-netlink -x 3 -p 0 -s\n"
+ " 3) Set preferred channel\n"
+ " ncsi-netlink -x 3 -p 0 -c 1 -s\n"
+ " 4) Clear preferred channel\n"
+ " ncsi-netlink -x 3 -p 0 -r\n"
+ " 5) Send NCSI Command\n"
+ " ncsi-netlink -x 3 -p 0 -c 0 -o 50000001572100\n"
+ "\n";
}
const option ArgumentParser::options[] = {
@@ -92,7 +103,7 @@
{0, 0, 0, 0},
};
-const char* ArgumentParser::optionStr = "i:s:r:o:p:c:x:h?";
+const char* ArgumentParser::optionStr = "irsx:o:p:c:h?";
const std::string ArgumentParser::trueString = "true";
const std::string ArgumentParser::emptyString = "";
diff --git a/src/ncsi_netlink_main.cpp b/src/ncsi_netlink_main.cpp
index 5f65777..7808ef7 100644
--- a/src/ncsi_netlink_main.cpp
+++ b/src/ncsi_netlink_main.cpp
@@ -37,6 +37,7 @@
int packageInt{};
int channelInt{};
int indexInt{};
+ int operationInt{DEFAULT_VALUE};
// Parse out interface argument.
auto ifIndex = (options)["index"];
@@ -97,7 +98,11 @@
exitWithError("Payload invalid: specify two hex digits per byte.",
argv);
- // Parse the payload string (e.g. "000001572100") to byte data
+ // Parse the payload string (e.g. "50000001572100") to byte data
+ // The first two characters (i.e. "50") represent the Send Cmd Operation
+ // All remaining pairs, interpreted in hex radix, represent the command
+ // payload
+ int sendCmdSelect{};
for (unsigned int i = 1; i < payloadStr.size(); i += 2)
{
byte[0] = payloadStr[i - 1];
@@ -105,15 +110,23 @@
try
{
- payload.push_back(stoi(byte, nullptr, 16));
+ sendCmdSelect = stoi(byte, nullptr, 16);
}
catch (const std::exception& e)
{
exitWithError("Payload invalid.", argv);
}
+ if (i == 1)
+ {
+ operationInt = sendCmdSelect;
+ }
+ else
+ {
+ payload.push_back(sendCmdSelect);
+ }
}
- if (payload.empty())
+ if (operationInt == DEFAULT_VALUE)
{
exitWithError("No payload specified.", argv);
}
@@ -124,7 +137,7 @@
}
return ncsi::sendOemCommand(
- indexInt, packageInt, channelInt,
+ indexInt, packageInt, channelInt, operationInt,
std::span<const unsigned char>(payload.begin(), payload.end()));
}
else if ((options)["set"] == "true")
diff --git a/src/ncsi_util.cpp b/src/ncsi_util.cpp
index c739d6f..826d7de 100644
--- a/src/ncsi_util.cpp
+++ b/src/ncsi_util.cpp
@@ -30,7 +30,7 @@
return ret;
}
stdplus::IntToStr<16, uint8_t> its;
- auto oit = ret.append(c.size() * 3 - 1);
+ auto oit = ret.append(c.size() * 3);
auto cit = c.begin();
oit = its(oit, *cit++, 2);
for (; cit != c.end(); ++cit)
@@ -38,6 +38,7 @@
*oit++ = ' ';
oit = its(oit, *cit, 2);
}
+ *oit = 0;
return ret;
}
@@ -66,14 +67,14 @@
Command(Command&&) = default;
Command& operator=(Command&&) = default;
Command(
- int c, int nc = DEFAULT_VALUE,
+ int ncsiCmd, int operation = DEFAULT_VALUE,
std::span<const unsigned char> p = std::span<const unsigned char>()) :
- cmd(c),
- ncsi_cmd(nc), payload(p)
+ ncsi_cmd(ncsiCmd),
+ operation(operation), payload(p)
{}
- int cmd;
int ncsi_cmd;
+ int operation;
std::span<const unsigned char> payload;
};
@@ -300,11 +301,12 @@
return -ENOMEM;
}
- auto msgHdr = genlmsg_put(msg.get(), 0, 0, driverID, 0, flags, cmd.cmd, 0);
+ auto msgHdr = genlmsg_put(msg.get(), NL_AUTO_PORT, NL_AUTO_SEQ, driverID, 0,
+ flags, cmd.ncsi_cmd, 0);
if (!msgHdr)
{
lg2::error("Unable to add the netlink headers , COMMAND : {COMMAND}",
- "COMMAND", cmd.cmd);
+ "COMMAND", cmd.ncsi_cmd);
return -ENOMEM;
}
@@ -343,7 +345,7 @@
return ret;
}
- if (cmd.ncsi_cmd != DEFAULT_VALUE)
+ if (cmd.operation != DEFAULT_VALUE)
{
std::vector<unsigned char> pl(sizeof(NCSIPacketHeader) +
cmd.payload.size());
@@ -352,7 +354,7 @@
std::copy(cmd.payload.begin(), cmd.payload.end(),
pl.begin() + sizeof(NCSIPacketHeader));
- hdr->type = cmd.ncsi_cmd;
+ hdr->type = cmd.operation;
hdr->length = htons(cmd.payload.size());
ret = nla_put(msg.get(), ncsi_nl_attrs::NCSI_ATTR_DATA, pl.size(),
@@ -398,11 +400,9 @@
} // namespace internal
-int sendOemCommand(int ifindex, int package, int channel,
+int sendOemCommand(int ifindex, int package, int channel, int operation,
std::span<const unsigned char> payload)
{
- constexpr auto cmd = 0x50;
-
lg2::debug("Send OEM Command, CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, "
"INTERFACE_INDEX: {INTERFACE_INDEX}",
"CHANNEL", lg2::hex, channel, "PACKAGE", lg2::hex, package,
@@ -414,7 +414,8 @@
return internal::applyCmd(
ifindex,
- internal::Command(ncsi_nl_commands::NCSI_CMD_SEND_CMD, cmd, payload),
+ internal::Command(ncsi_nl_commands::NCSI_CMD_SEND_CMD, operation,
+ payload),
package, channel, NONE, internal::sendCallBack);
}
diff --git a/src/ncsi_util.hpp b/src/ncsi_util.hpp
index eaa076d..750f0f1 100644
--- a/src/ncsi_util.hpp
+++ b/src/ncsi_util.hpp
@@ -20,10 +20,11 @@
* @param[in] ifindex - Interface Index.
* @param[in] package - NCSI Package.
* @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.
*/
-int sendOemCommand(int ifindex, int package, int channel,
+int sendOemCommand(int ifindex, int package, int channel, int opcode,
std::span<const unsigned char> payload);
/* @brief This function will ask underlying NCSI driver