ipmi: start implementing flashVerifyCheck

Change-Id: I811693d9e736d273d2df9e65f7c5de7efd1d884c
Signed-off-by: Patrick Venture <venture@google.com>
diff --git a/configure.ac b/configure.ac
index 12763e4..d565472 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,10 @@
 AS_IF([test "x$HASH_PATH" == "x"], [HASH_PATH="/tmp/bmc.sig"])
 AC_DEFINE_UNQUOTED([HASH_PATH], ["$HASH_PATH"], [The path for the hash file.])
 
+AC_ARG_VAR(STATUS_PATH, [The path for the verification status file.])
+AS_IF([test "x$STATUS_PATH" == "x"], [STATUS_PATH="/tmp/bmc.verify"])
+AC_DEFINE_UNQUOTED([STATUS_PATH], ["$STATUS_PATH"], [The path for the verification status file.])
+
 # Create configured output
 AC_CONFIG_FILES([Makefile test/Makefile])
 AC_OUTPUT
diff --git a/flash-ipmi.cpp b/flash-ipmi.cpp
index dda9580..00fa027 100644
--- a/flash-ipmi.cpp
+++ b/flash-ipmi.cpp
@@ -196,3 +196,9 @@
     /* TODO: implement. */
     return false;
 }
+
+VerifyCheckResponse FlashUpdate::checkVerify()
+{
+    /* TODO: implement. */
+    return VerifyCheckResponse::other;
+}
diff --git a/flash-ipmi.hpp b/flash-ipmi.hpp
index 2d7dcaa..4a13edb 100644
--- a/flash-ipmi.hpp
+++ b/flash-ipmi.hpp
@@ -10,6 +10,18 @@
 #define SUBCMD_SZ sizeof(uint8_t)
 
 /*
+ * These are the codes we return over IPMI when the host checks for the status
+ * of the asynchronous verification call.
+ */
+enum VerifyCheckResponse
+{
+    running = 0x00,
+    success = 0x01,
+    failed = 0x02,
+    other = 0x03,
+};
+
+/*
  * flashStartTransfer -- starts file upload.
  * flashDataBlock -- adds data to image file.
  * flashDataFinish -- closes the file.
@@ -145,14 +157,23 @@
      * @return true if aborted, false if unable or failed.
      */
     virtual bool abortUpdate() = 0;
+
+    /**
+     * Check if the verification result is available and return.
+     *
+     * @return the verification response.
+     */
+    virtual VerifyCheckResponse checkVerify() = 0;
 };
 
 class FlashUpdate : public UpdateInterface
 {
   public:
-    FlashUpdate(const std::string& stagingPath, const std::string& hash = "") :
-        flashLength(0), flashFd(nullptr), tmpPath(stagingPath), hashLength(0),
-        hashFd(nullptr), hashPath(hash){};
+    FlashUpdate(const std::string& stagingPath, const std::string& verifyPath,
+                const std::string& hash = "") :
+        flashLength(0),
+        flashFd(nullptr), tmpPath(stagingPath), hashLength(0), hashFd(nullptr),
+        hashPath(hash), verifyPath(verifyPath){};
     ~FlashUpdate();
 
     FlashUpdate(const FlashUpdate&) = default;
@@ -170,6 +191,7 @@
 
     bool startDataVerification() override;
     bool abortUpdate() override;
+    VerifyCheckResponse checkVerify() override;
 
   private:
     /**
@@ -219,4 +241,7 @@
      * process uses a separate signature.
      */
     const std::string hashPath;
+
+    /* The path to read the status of the signature verification. */
+    const std::string verifyPath;
 };
diff --git a/ipmi.cpp b/ipmi.cpp
index 50269b0..3c43aa7 100644
--- a/ipmi.cpp
+++ b/ipmi.cpp
@@ -32,6 +32,7 @@
             {FlashSubCmds::flashHashFinish, hashFinish},
             {FlashSubCmds::flashDataVerify, dataVerify},
             {FlashSubCmds::flashAbort, abortUpdate},
+            {FlashSubCmds::flashVerifyCheck, checkVerify},
         };
 
     auto results = subHandlers.find(command);
@@ -210,3 +211,12 @@
     (*dataLen) = 1;
     return IPMI_CC_OK;
 }
+
+ipmi_ret_t checkVerify(UpdateInterface* updater, const uint8_t* reqBuf,
+                       uint8_t* replyBuf, size_t* dataLen)
+{
+    auto value = updater->checkVerify();
+    replyBuf[0] = static_cast<uint8_t>(value);
+    (*dataLen) = 1;
+    return IPMI_CC_OK;
+}
diff --git a/ipmi.hpp b/ipmi.hpp
index 7fc27b4..bc457c0 100644
--- a/ipmi.hpp
+++ b/ipmi.hpp
@@ -130,3 +130,16 @@
  */
 ipmi_ret_t abortUpdate(UpdateInterface* updater, const uint8_t* reqBuf,
                        uint8_t* replyBuf, size_t* dataLen);
+
+/**
+ * Check on the status of the verification process.
+ *
+ * @param[in] updater - Pointer to Updater object.
+ * @param[in] reqBuf - the IPMI packet.
+ * @param[in] replyBuf - Pointer to buffer for any response.
+ * @param[in,out] dataLen - Initially reqBuf length, set to replyBuf
+ * length when done.
+ * @return corresponding IPMI return code.
+ */
+ipmi_ret_t checkVerify(UpdateInterface* updater, const uint8_t* reqBuf,
+                       uint8_t* replyBuf, size_t* dataLen);
diff --git a/main.cpp b/main.cpp
index 791cb22..5385348 100644
--- a/main.cpp
+++ b/main.cpp
@@ -25,6 +25,7 @@
 
 static constexpr auto stagingPath = STAGING_PATH;
 static constexpr auto hashPath = HASH_PATH;
+static constexpr auto statusPath = STATUS_PATH;
 
 /* TODO: Once OEM IPMI number placement is settled, point to that. */
 namespace oem
@@ -85,7 +86,8 @@
 
 void setupGlobalOemFlashControl()
 {
-    flashUpdateSingleton = std::make_unique<FlashUpdate>(stagingPath, hashPath);
+    flashUpdateSingleton =
+        std::make_unique<FlashUpdate>(stagingPath, statusPath, hashPath);
 
 #ifdef ENABLE_GOOGLE
     oem::Router* router = oem::mutableRouter();
diff --git a/test/Makefile.am b/test/Makefile.am
index bed24e6..26f3439 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -20,6 +20,7 @@
 	ipmi_abort_unittest \
 	ipmi_validate_unittest \
 	ipmi_command_unittest \
+	ipmi_verifycheck_unittest \
 	flash_start_unittest \
 	flash_flashdata_unittest \
 	flash_flashfinish_unittest \
@@ -59,6 +60,9 @@
 ipmi_command_unittest_SOURCES = ipmi_command_unittest.cpp
 ipmi_command_unittest_LDADD = $(top_builddir)/ipmi.o
 
+ipmi_verifycheck_unittest_SOURCES = ipmi_verifycheck_unittest.cpp
+ipmi_verifycheck_unittest_LDADD = $(top_builddir)/ipmi.o
+
 flash_start_unittest_SOURCES = flash_start_unittest.cpp
 flash_start_unittest_LDADD = $(top_builddir)/flash-ipmi.o $(SDBUSPLUS_LIBS)
 
diff --git a/test/flash_flashdata_unittest.cpp b/test/flash_flashdata_unittest.cpp
index df561ec..112565a 100644
--- a/test/flash_flashdata_unittest.cpp
+++ b/test/flash_flashdata_unittest.cpp
@@ -30,7 +30,7 @@
     // Verify that there is sanity checking.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     EXPECT_FALSE(updater.flashData(0, bytes));
 
     // Verify the file doesn't exist.
@@ -43,7 +43,7 @@
     // Verify that under normal usage it writes the bytes.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     updater.start(THIRTYTWO_MIB);
     EXPECT_TRUE(updater.flashData(0, bytes));
 
@@ -65,7 +65,7 @@
 
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     updater.start(THIRTYTWO_MIB);
     EXPECT_TRUE(updater.flashData(2, bytes));
 
diff --git a/test/flash_flashfinish_unittest.cpp b/test/flash_flashfinish_unittest.cpp
index bdddd5a..e160b29 100644
--- a/test/flash_flashfinish_unittest.cpp
+++ b/test/flash_flashfinish_unittest.cpp
@@ -30,7 +30,7 @@
     // Verify that there is sanity checking
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     EXPECT_FALSE(updater.flashFinish());
 
     // Verify the file doesn't exist.
@@ -43,7 +43,7 @@
     // Verify that under normal usage it closes the file.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     updater.start(THIRTYTWO_MIB);
     EXPECT_TRUE(updater.flashFinish());
 
@@ -59,7 +59,7 @@
     // be closed twice.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     updater.start(THIRTYTWO_MIB);
     EXPECT_TRUE(updater.flashFinish());
 
diff --git a/test/flash_hashdata_unittest.cpp b/test/flash_hashdata_unittest.cpp
index f9a3ffa..8d7be77 100644
--- a/test/flash_hashdata_unittest.cpp
+++ b/test/flash_hashdata_unittest.cpp
@@ -35,7 +35,7 @@
 
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_FALSE(updater.hashData(0, bytes));
 }
 
@@ -44,7 +44,7 @@
     // Verify the normal use case works.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_TRUE(updater.start(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.startHash(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.hashData(0, bytes));
@@ -67,7 +67,7 @@
 
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_TRUE(updater.start(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.startHash(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.hashData(2, bytes));
diff --git a/test/flash_hashfinish_unittest.cpp b/test/flash_hashfinish_unittest.cpp
index de785ae..12ff7a8 100644
--- a/test/flash_hashfinish_unittest.cpp
+++ b/test/flash_hashfinish_unittest.cpp
@@ -33,7 +33,7 @@
     // Verify that there is sanity checking
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_FALSE(updater.hashFinish());
 
     // Verify the file doesn't exist.
@@ -46,7 +46,7 @@
     // Verify that under normal usage it closes the file.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_TRUE(updater.start(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.startHash(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.hashFinish());
@@ -63,7 +63,7 @@
     // be closed twice.
     std::vector<uint8_t> bytes = {0xaa, 0x55};
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_TRUE(updater.start(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.startHash(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.hashFinish());
diff --git a/test/flash_hashstart_unittest.cpp b/test/flash_hashstart_unittest.cpp
index a3a1d9f..60f8df1 100644
--- a/test/flash_hashstart_unittest.cpp
+++ b/test/flash_hashstart_unittest.cpp
@@ -13,7 +13,7 @@
     std::string name = std::tmpnam(nullptr);
     std::string name2 = std::tmpnam(nullptr);
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_FALSE(updater.startHash(THIRTYTWO_MIB));
 
     (void)std::remove(name.c_str());
@@ -27,7 +27,7 @@
     std::string name = std::tmpnam(nullptr);
     std::string name2 = std::tmpnam(nullptr);
 
-    FlashUpdate updater(name, name2);
+    FlashUpdate updater(name, "", name2);
     EXPECT_TRUE(updater.start(THIRTYTWO_MIB));
     EXPECT_TRUE(updater.startHash(THIRTYTWO_MIB));
 
diff --git a/test/flash_start_unittest.cpp b/test/flash_start_unittest.cpp
index b287561..81c2d45 100644
--- a/test/flash_start_unittest.cpp
+++ b/test/flash_start_unittest.cpp
@@ -13,7 +13,7 @@
 
     std::string name = std::tmpnam(nullptr);
 
-    FlashUpdate updater(name);
+    FlashUpdate updater(name, "");
     updater.start(THIRTYTWO_MIB);
 
     auto file = std::fopen(name.c_str(), "r");
diff --git a/test/ipmi_verifycheck_unittest.cpp b/test/ipmi_verifycheck_unittest.cpp
new file mode 100644
index 0000000..f71155f
--- /dev/null
+++ b/test/ipmi_verifycheck_unittest.cpp
@@ -0,0 +1,32 @@
+#include "ipmi.hpp"
+
+#include "updater_mock.hpp"
+
+#include <gtest/gtest.h>
+
+using ::testing::Return;
+using ::testing::StrictMock;
+
+// ipmid.hpp isn't installed where we can grab it and this value is per BMC
+// SoC.
+#define MAX_IPMI_BUFFER 64
+
+TEST(IpmiCheckVerifyTest, CallPassedOn)
+{
+    // This IPMI handler just bundles the response.
+
+    StrictMock<UpdaterMock> updater;
+
+    size_t dataLen;
+    uint8_t request[MAX_IPMI_BUFFER] = {0};
+    uint8_t reply[MAX_IPMI_BUFFER] = {0};
+
+    dataLen = 1; // request is only the command.
+    request[0] = FlashSubCmds::flashVerifyCheck;
+
+    EXPECT_CALL(updater, checkVerify())
+        .WillOnce(Return(VerifyCheckResponse::running));
+    EXPECT_EQ(IPMI_CC_OK, checkVerify(&updater, request, reply, &dataLen));
+    EXPECT_EQ(sizeof(uint8_t), dataLen);
+    EXPECT_EQ(VerifyCheckResponse::running, reply[0]);
+}
diff --git a/test/updater_mock.hpp b/test/updater_mock.hpp
index 589df39..0fd6683 100644
--- a/test/updater_mock.hpp
+++ b/test/updater_mock.hpp
@@ -18,4 +18,5 @@
     MOCK_METHOD0(hashFinish, bool());
     MOCK_METHOD0(startDataVerification, bool());
     MOCK_METHOD0(abortUpdate, bool());
+    MOCK_METHOD0(checkVerify, VerifyCheckResponse());
 };