oem-meta: Add file IO handler for getting Http boot certification

Support parsing read file IO for Http Boot command (type: 0x03) and
returning the Http boot certification stored in BMC.

Tested: Verified in yosemite4 platform.
- The HTTP boot certificate is parsed correctly if the file exists.

Change-Id: I4f35b408ac7547347f837620a0039c429a573e0f
Signed-off-by: Lora Lin <lora.lin.wiwynn@gmail.com>
Signed-off-by: Sora Su <baxiche@gmail.com>
diff --git a/oem/meta/libpldmresponder/file_io.cpp b/oem/meta/libpldmresponder/file_io.cpp
index ec82856..2293d43 100644
--- a/oem/meta/libpldmresponder/file_io.cpp
+++ b/oem/meta/libpldmresponder/file_io.cpp
@@ -1,6 +1,7 @@
 #include "file_io.hpp"
 
 #include "file_io_type_bios_version.hpp"
+#include "file_io_type_http_boot.hpp"
 #include "file_io_type_post_code.hpp"
 #include "file_io_type_power_control.hpp"
 
@@ -23,6 +24,8 @@
         case FileIOType::POWER_CONTROL:
             return std::make_unique<PowerControlHandler>(messageTid,
                                                          dBusHandler);
+        case FileIOType::HTTP_BOOT:
+            return std::make_unique<HttpBootHandler>();
         default:
             error("Get invalid file io type {FILEIOTYPE}", "FILEIOTYPE",
                   fileIOType);
diff --git a/oem/meta/libpldmresponder/file_io_by_type.hpp b/oem/meta/libpldmresponder/file_io_by_type.hpp
index 1724514..7fee086 100644
--- a/oem/meta/libpldmresponder/file_io_by_type.hpp
+++ b/oem/meta/libpldmresponder/file_io_by_type.hpp
@@ -14,7 +14,8 @@
 {
     POST_CODE = 0x00,
     BIOS_VERSION = 0x01,
-    POWER_CONTROL = 0x02
+    POWER_CONTROL = 0x02,
+    HTTP_BOOT = 0x03
 };
 
 /**
diff --git a/oem/meta/libpldmresponder/file_io_type_http_boot.cpp b/oem/meta/libpldmresponder/file_io_type_http_boot.cpp
new file mode 100644
index 0000000..bd988c9
--- /dev/null
+++ b/oem/meta/libpldmresponder/file_io_type_http_boot.cpp
@@ -0,0 +1,182 @@
+#include "file_io_type_http_boot.hpp"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <phosphor-logging/lg2.hpp>
+
+#include <cstring>
+#include <fstream>
+#include <utility>
+
+PHOSPHOR_LOG2_USING;
+
+namespace pldm::responder::oem_meta
+{
+
+constexpr uint8_t HTTP_BOOT_ATTR_REQ_DATA_LEN = 0;
+
+static constexpr auto certificationfilepath = "/mnt/data/host/bios-rootcert";
+
+int HttpBootHandler::read(struct pldm_oem_meta_file_io_read_resp* data)
+{
+    if (data == nullptr)
+    {
+        error("Input data pointer is NULL");
+        return PLDM_ERROR;
+    }
+
+    int fd = -1;
+    struct stat sb;
+
+    if (access(certificationfilepath, F_OK) == -1)
+    {
+        error("Failed to find Http boot certification file");
+        goto noCertificationFile;
+    }
+
+    fd = open(certificationfilepath, O_RDONLY);
+    if (fd < 0)
+    {
+        error("Failed to open Http boot certification file");
+        goto noCertificationFile;
+    }
+
+    if (fstat(fd, &sb) == -1)
+    {
+        error("Failed to get Http boot certification file size");
+        goto noCertificationFile;
+    }
+
+    switch (data->option)
+    {
+        case PLDM_OEM_META_FILE_IO_READ_ATTR:
+        {
+            if (data->length != HTTP_BOOT_ATTR_REQ_DATA_LEN)
+            {
+                error(
+                    "Invalid request data length for http boot attribute, option={OPTION}, data size={SIZE}",
+                    "OPTION", data->option, "SIZE", data->length);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            if (sb.st_size == 0)
+            {
+                data->info.attr.size = 0;
+                data->info.attr.crc32 = 0;
+                close(fd);
+                return PLDM_SUCCESS;
+            }
+
+            uint8_t* buffer = (uint8_t*)malloc(sb.st_size);
+            if (buffer == nullptr)
+            {
+                error(
+                    "Failed to allocate buffer for http boot, length={LENGTH}",
+                    "LENGTH", sb.st_size);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            int ret = ::read(fd, buffer, sb.st_size);
+            if (ret < 0)
+            {
+                error("Failed to read all Http boot certification file");
+                free(buffer);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            uint32_t checksum = pldm_edac_crc32(buffer, sb.st_size);
+            free(buffer);
+
+            data->info.attr.size = sb.st_size;
+            data->info.attr.crc32 = checksum;
+            close(fd);
+            return PLDM_SUCCESS;
+        }
+        break;
+        case PLDM_OEM_META_FILE_IO_READ_DATA:
+        {
+            if (sb.st_size == 0)
+            {
+                data->length = 0;
+                data->info.data.transferFlag = PLDM_END;
+                data->info.data.offset = 0;
+                close(fd);
+                return PLDM_SUCCESS;
+            }
+
+            uint8_t transferFlag = data->info.data.transferFlag;
+            uint16_t offset = data->info.data.offset;
+
+            int ret = lseek(fd, offset, SEEK_SET);
+            if (ret < 0)
+            {
+                error(
+                    "Failed to lseek at offset={OFFSET} of length={LENGTH} on Http boot certification file",
+                    "OFFSET", offset, "LENGTH", data->length);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            if (offset + data->length >= sb.st_size)
+            {
+                transferFlag = PLDM_END;
+                data->length = sb.st_size - offset; // Revise length
+            }
+            else
+            {
+                transferFlag = PLDM_MIDDLE;
+            }
+
+            uint8_t* buffer = (uint8_t*)malloc(data->length);
+            if (buffer == nullptr)
+            {
+                error(
+                    "Failed to allocate buffer for http boot, length={LENGTH}",
+                    "LENGTH", data->length);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            ret = ::read(fd, buffer, data->length);
+            if (ret < 0)
+            {
+                error(
+                    "Failed to read file content at offset={OFFSET} of length={LENGTH} on Http boot certification file",
+                    "OFFSET", offset, "LENGTH", data->length);
+                free(buffer);
+                close(fd);
+                return PLDM_ERROR;
+            }
+
+            memcpy(pldm_oem_meta_file_io_read_resp_data(data), buffer,
+                   data->length);
+            free(buffer);
+
+            offset = offset + data->length;
+
+            data->info.data.transferFlag = transferFlag;
+            data->info.data.offset = offset;
+
+            close(fd);
+            return PLDM_SUCCESS;
+        }
+        break;
+        default:
+            error("Get invalid http boot option, option={OPTION}", "OPTION",
+                  data->option);
+            close(fd);
+            return PLDM_ERROR;
+    }
+
+noCertificationFile:
+    close(fd);
+    data->length = 0;
+    return PLDM_SUCCESS;
+}
+
+} // namespace pldm::responder::oem_meta
diff --git a/oem/meta/libpldmresponder/file_io_type_http_boot.hpp b/oem/meta/libpldmresponder/file_io_type_http_boot.hpp
new file mode 100644
index 0000000..cc908bd
--- /dev/null
+++ b/oem/meta/libpldmresponder/file_io_type_http_boot.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "file_io_by_type.hpp"
+
+#include <libpldm/oem/meta/file_io.h>
+
+namespace pldm::responder::oem_meta
+{
+/** @class PostCodeHandler
+ *
+ *  @brief Inherits and implements FileHandler. This class is used
+ *  to store incoming postcode
+ */
+class HttpBootHandler : public FileHandler
+{
+  public:
+    HttpBootHandler() = default;
+    HttpBootHandler(const HttpBootHandler&) = delete;
+    HttpBootHandler(HttpBootHandler&&) = delete;
+    HttpBootHandler& operator=(const HttpBootHandler&) = delete;
+    HttpBootHandler& operator=(HttpBootHandler&&) = delete;
+
+    ~HttpBootHandler() = default;
+
+    /** @brief Method to parse read file IO for Http Boot command (type: 0x03)
+     *         and returning the Http boot certification stored in BMC.
+     *  @param[in] data - eventData
+     *  @return  PLDM status code
+     */
+    int read(struct pldm_oem_meta_file_io_read_resp* data) override;
+};
+
+} // namespace pldm::responder::oem_meta
diff --git a/oem/meta/libpldmresponder/meson.build b/oem/meta/libpldmresponder/meson.build
index 33e2bc9..265f6f3 100644
--- a/oem/meta/libpldmresponder/meson.build
+++ b/oem/meta/libpldmresponder/meson.build
@@ -1,6 +1,7 @@
 oem_files += files(
     'file_io.cpp',
     'file_io_type_bios_version.cpp',
+    'file_io_type_http_boot.cpp',
     'file_io_type_post_code.cpp',
     'file_io_type_power_control.cpp',
 )