Add support for sending NCSI command

Provide a means to send an OEM command to an NIC via NCSI netlink.
This may be invoked from a systemd Unit file to configure NIC
behavior.

Some NICs provide OEM commands to influence their behavior, for
example maintaining full speed even when the host is down instead
of negotiating a lower speed for power.

Signed-off-by: Eddie James <eajames@linux.ibm.com>
Change-Id: Id920b618422e8fbfc51984fbf932045bfb5e56e6
diff --git a/src/ncsi_netlink_main.cpp b/src/ncsi_netlink_main.cpp
index 9db624f..12d59be 100644
--- a/src/ncsi_netlink_main.cpp
+++ b/src/ncsi_netlink_main.cpp
@@ -18,6 +18,7 @@
 
 #include <iostream>
 #include <string>
+#include <vector>
 
 static void exitWithError(const char* err, char** argv)
 {
@@ -85,8 +86,47 @@
         channelInt = DEFAULT_VALUE;
     }
 
-    auto setCmd = (options)["set"];
-    if (setCmd == "true")
+    auto payloadStr = (options)["oem-payload"];
+    if (!payloadStr.empty())
+    {
+        std::string byte(2, '\0');
+        std::vector<unsigned char> payload;
+
+        if (payloadStr.size() % 2)
+            exitWithError("Payload invalid: specify two hex digits per byte.",
+                          argv);
+
+        // Parse the payload string (e.g. "000001572100") to byte data
+        for (unsigned int i = 1; i < payloadStr.size(); i += 2)
+        {
+            byte[0] = payloadStr[i - 1];
+            byte[1] = payloadStr[i];
+
+            try
+            {
+                payload.push_back(stoi(byte, nullptr, 16));
+            }
+            catch (const std::exception& e)
+            {
+                exitWithError("Payload invalid.", argv);
+            }
+        }
+
+        if (payload.empty())
+        {
+            exitWithError("No payload specified.", argv);
+        }
+
+        if (packageInt == DEFAULT_VALUE)
+        {
+            exitWithError("Package not specified.", argv);
+        }
+
+        return ncsi::sendOemCommand(
+            indexInt, packageInt, channelInt,
+            std::span<const unsigned char>(payload.begin(), payload.end()));
+    }
+    else if ((options)["set"] == "true")
     {
         // Can not perform set operation without package.
         if (packageInt == DEFAULT_VALUE)