tools: starting burn_my_bmc host utility

burn_my_bmc is a host-run utility that in cooperation with the
phosphor-ipmi-flash library, attempts to send a BMC firmware image and
signature file to the BMC and trigger verification of said image.

The program's current design and use were tailored towards the legacy
OpenBMC image and not UBI.  Therefore, changes to support the UBI
process will get addressed as it all takes shape.

The overall process is:
1) Attempts to send firmware image over an interface.
2) Attempts to send signature file contents over an interface*.
3) Triggers a verification step.
4) Reboots the BMC**.

* The only interface in the initial version here is the blocktransfer
interface.  It's technically also possibly KCS.  It's sending the data
over the same communications channel as the normal IPMI packets.  A
later patchset will enable sending the data bytes over an LPC memory
region or the PCI P2A region.

** The 4th step is done by a separate call to the 'reboot' command.
The 'reboot' and 'ping' commands will come in a later patchset.

Change-Id: I62d725274e56c55ca414fa6c2a3eab6c500066ed
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/tools/libs/ipmitoolintf.c b/tools/libs/ipmitoolintf.c
new file mode 100644
index 0000000..b68d454
--- /dev/null
+++ b/tools/libs/ipmitoolintf.c
@@ -0,0 +1,65 @@
+#include "ipmitoolintf.h"
+
+#include <ipmitool/ipmi_intf.h>
+#include <string.h>
+
+extern struct ipmi_intf ipmi_open_intf;
+
+int ipmiSendCommand(const uint8_t* bytes, int length, struct IpmiResponse* resp)
+{
+    struct ipmi_intf* intf = &ipmi_open_intf;
+
+    /* The length needs to be at least two bytes [netfn][cmd] */
+    if (length < 2)
+    {
+        return -1;
+    }
+
+    uint8_t data[MAX_PIPELINE_BANDWIDTH];
+    struct ipmi_rq request;
+    memset(&data[0], 0, sizeof(data));
+    memset(&request, 0, sizeof(request));
+
+    ipmi_intf_session_set_timeout(intf, 15);
+    /* The retry here isn't used for the normal BT interface comms it appears.
+     * Only references found in sol and serial, and lan.
+     */
+    ipmi_intf_session_set_retry(intf, 1);
+
+    request.msg.netfn = bytes[0];
+    request.msg.lun = 0x00;
+    request.msg.cmd = bytes[1];
+    request.msg.data = &data[0];
+
+    /* Can you fit the request in the buffer? */
+    if ((length - 2) > sizeof(data))
+    {
+        return -1;
+    }
+
+    /* Skip beyond netfn and command. */
+    memcpy(request.msg.data, &bytes[2], length - 2);
+    request.msg.data_len = length - 2;
+
+    /* Actually send the command and check for a response. */
+    struct ipmi_rs* response = intf->sendrecv(intf, &request);
+    if (!response)
+    {
+        return -1;
+    }
+
+    /* If the caller wanted the response back. */
+    if (resp)
+    {
+        resp->ccode = response->ccode;
+        if (response->data_len <= sizeof(resp->data))
+        {
+            memcpy(resp->data, response->data, response->data_len);
+            resp->dataLen = response->data_len;
+            return 0;
+        }
+        /* TODO: deal with truncation... */
+    }
+
+    return 0;
+}