Add a IPMI blob handler for SMBIOS tables

smbios-mdr has dependencies on intel-ipmi-oem which makes BIOS sending
SMBIOS tables to BMC through VGA shared memory. For platforms without
intel-ipmi-oem, implement a IPMI blob hanler so that BIOS can send
SMBIOS tables through IPMI blob interfaces.

Test:
Unit tests for the IPMI blob handler.
Manual test that transfers SMBIOS tables to BMC through IPMI blob
interfaces on a platform host.

Signed-off-by: Jie Yang <jjy@google.com>
Change-Id: I9bc1ae7e9bfaa793e47e38fa19049f0f69355189
diff --git a/src/smbios-ipmi-blobs/handler.hpp b/src/smbios-ipmi-blobs/handler.hpp
new file mode 100644
index 0000000..d97618a
--- /dev/null
+++ b/src/smbios-ipmi-blobs/handler.hpp
@@ -0,0 +1,77 @@
+#pragma once
+
+#include <blobs-ipmid/blobs.hpp>
+
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace blobs
+{
+
+class SmbiosBlobHandler : public GenericBlobInterface
+{
+  public:
+    SmbiosBlobHandler() = default;
+    ~SmbiosBlobHandler() = default;
+    SmbiosBlobHandler(const SmbiosBlobHandler&) = delete;
+    SmbiosBlobHandler& operator=(const SmbiosBlobHandler&) = delete;
+    SmbiosBlobHandler(SmbiosBlobHandler&&) = default;
+    SmbiosBlobHandler& operator=(SmbiosBlobHandler&&) = default;
+
+    struct SmbiosBlob
+    {
+        SmbiosBlob(uint16_t id, const std::string& path, uint16_t flags) :
+            sessionId(id), blobId(path), state(0)
+        {
+            if (flags & blobs::OpenFlags::write)
+            {
+                state |= blobs::StateFlags::open_write;
+            }
+
+            /* Pre-allocate the buffer.capacity() with maxBufferSize */
+            buffer.reserve(maxBufferSize);
+        }
+
+        /* The blob handler session id. */
+        uint16_t sessionId;
+
+        /* The identifier for the blob */
+        std::string blobId;
+
+        /* The current state. */
+        uint16_t state;
+
+        /* The staging buffer. */
+        std::vector<uint8_t> buffer;
+    };
+
+    bool canHandleBlob(const std::string& path) override;
+    std::vector<std::string> getBlobIds() override;
+    bool deleteBlob(const std::string& path) override;
+    bool stat(const std::string& path, struct BlobMeta* meta) override;
+    bool open(uint16_t session, uint16_t flags,
+              const std::string& path) override;
+    std::vector<uint8_t> read(uint16_t session, uint32_t offset,
+                              uint32_t requestedSize) override;
+    bool write(uint16_t session, uint32_t offset,
+               const std::vector<uint8_t>& data) override;
+    bool writeMeta(uint16_t session, uint32_t offset,
+                   const std::vector<uint8_t>& data) override;
+    bool commit(uint16_t session, const std::vector<uint8_t>& data) override;
+    bool close(uint16_t session) override;
+    bool stat(uint16_t session, struct BlobMeta* meta) override;
+    bool expire(uint16_t session) override;
+
+  private:
+    static constexpr char blobId[] = "/smbios";
+
+    /* SMBIOS table storage size */
+    static constexpr uint32_t maxBufferSize = 64 * 1024;
+
+    /* The handler only allows one open blob. */
+    std::unique_ptr<SmbiosBlob> blobPtr = nullptr;
+};
+
+} // namespace blobs