pldmtool : File table parsing

This commit implements parsing of the file attribute
table by issuing the GetFileTable command with the
-t option which specifies the pldm file table type.

Tested:
 ./pldmtool oem-ibm -h
oem type command
Usage: ./pldmtool oem-ibm [OPTIONS] SUBCOMMAND

Options:
  -h,--help                   Print this help message and exit

Subcommands:
  GetAlertStatus              get alert status descriptor
  GetFileTable                get file table

./pldmtool oem-ibm GetFileTable
Request Message:
08 01 80 3f 01 00 00 00 00 01 00
Success in creating the socket : RC = 3
Success in connecting to socket : RC = 0
Success in sending message type as pldm to mctp : RC = 0
Write to socket successful : RC = 11
Total length:71
Shutdown Socket successful :  RC = 0
Response Message:
08 01 00 3f 01 00 00 00 00 00 05 00 00 00 00 0a 00 50 48 59 50 2d 4e 56 52 41 4d 00 b0 10 01 01 00 00 00 01 00 00 00 10 00 50 48 59 50 2d 4e 56 52 41 4d 2d 43 4b 53 55 4d 10 00 00 00 04 00 00 00 00 00 87 55 62 3e
FileHandle[0]:0
  FileNameLength[0]:10
  FileName[0]:PHYP-NVRAM
  FileSize[0]:17870848
  FileTraits[0]:1
FileHandle[1]:1
  FileNameLength[1]:16
  FileName[1]:PHYP-NVRAM-CKSUM
  FileSize[1]:16
  FileTraits[1]:4

Change-Id: I44de4dd33fee42df7cdc67eaaddf259ea83346ae
Signed-off-by: Pavithra Barithaya <pbaritha@in.ibm.com>
diff --git a/oem/ibm/libpldm/file_io.h b/oem/ibm/libpldm/file_io.h
index 38e50ca..2aa7bd4 100644
--- a/oem/ibm/libpldm/file_io.h
+++ b/oem/ibm/libpldm/file_io.h
@@ -178,6 +178,16 @@
 	uint8_t table_data[1];	       //!< Table Data
 } __attribute__((packed));
 
+/** @struct pldm_file_attr_table_entry
+ *
+ * Structure representing File attribute table entry
+ */
+struct pldm_file_attr_table_entry {
+	uint32_t file_handle;		//!< File Handle
+	uint16_t file_name_length;	//!< File name length
+	uint8_t file_attr_table_nst[1]; //!< File name size traits
+} __attribute__((packed));
+
 /** @brief Decode GetFileTable command request data
  *
  *  @param[in] msg - Pointer to PLDM request message
diff --git a/pldmtool/meson.build b/pldmtool/meson.build
index 48f4c26..f6eda88 100644
--- a/pldmtool/meson.build
+++ b/pldmtool/meson.build
@@ -11,7 +11,7 @@
 
 if get_option('oem-ibm').enabled()
 sources += [
-    'oem/ibm/pldm_host_cmd.cpp'
+    'oem/ibm/pldm_oem_ibm.cpp',
   ]
 endif
 
diff --git a/pldmtool/oem/ibm/pldm_host_cmd.cpp b/pldmtool/oem/ibm/pldm_host_cmd.cpp
deleted file mode 100644
index 4f14e8c..0000000
--- a/pldmtool/oem/ibm/pldm_host_cmd.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-#include "pldm_host_cmd.hpp"
-
-#include "oem/ibm/libpldm/host.h"
-
-#include "../../pldm_cmd_helper.hpp"
-
-namespace pldmtool
-{
-
-namespace oem_ibm
-{
-namespace power_host
-{
-using namespace pldmtool::helper;
-
-std::vector<std::unique_ptr<CommandInterface>> commands;
-
-class GetAlertStatus : public CommandInterface
-{
-  public:
-    ~GetAlertStatus() = default;
-    GetAlertStatus() = delete;
-    GetAlertStatus(const GetAlertStatus&) = delete;
-    GetAlertStatus(GetAlertStatus&&) = default;
-    GetAlertStatus& operator=(const GetAlertStatus&) = delete;
-    GetAlertStatus& operator=(GetAlertStatus&&) = default;
-
-    explicit GetAlertStatus(const char* type, const char* name, CLI::App* app) :
-        CommandInterface(type, name, app)
-    {
-        app->add_option(
-               "-i, --id", versionId,
-               "Version of the command/response format. 0x00 for this format")
-            ->required();
-    }
-
-    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
-    {
-        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
-                                        PLDM_GET_ALERT_STATUS_REQ_BYTES);
-        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
-
-        auto rc = encode_get_alert_status_req(instanceId, versionId, request,
-                                              PLDM_GET_ALERT_STATUS_REQ_BYTES);
-        return {rc, requestMsg};
-    }
-
-    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
-    {
-        uint8_t completionCode = 0;
-        uint32_t rack_entry = 0;
-        uint32_t pri_cec_node = 0;
-        auto rc = decode_get_alert_status_resp(responsePtr, payloadLength,
-                                               &completionCode, &rack_entry,
-                                               &pri_cec_node);
-
-        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
-        {
-            std::cerr << "Response Message Error: "
-                      << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
-            return;
-        }
-
-        std::cout << "GetAlertStatus Success: " << std::endl;
-        std::cout << "rack entry: 0x" << std::setfill('0') << std::setw(8)
-                  << std::hex << (int)rack_entry << std::endl;
-        std::cout << "pri cec node: 0x" << std::setfill('0') << std::setw(8)
-                  << std::hex << (int)pri_cec_node << std::endl;
-    }
-
-  private:
-    uint8_t versionId;
-};
-
-void registerCommand(CLI::App& app)
-{
-    auto oem_ibm = app.add_subcommand("oem-ibm", "oem type command");
-    oem_ibm->require_subcommand(1);
-
-    auto getAlertStatus = oem_ibm->add_subcommand(
-        "GetAlertStatus", "get alert status descriptor");
-    commands.push_back(std::make_unique<GetAlertStatus>(
-        "oem_ibm", "getAlertStatus", getAlertStatus));
-}
-} // namespace power_host
-} // namespace oem_ibm
-} // namespace pldmtool
diff --git a/pldmtool/oem/ibm/pldm_oem_ibm.cpp b/pldmtool/oem/ibm/pldm_oem_ibm.cpp
new file mode 100644
index 0000000..2cea225
--- /dev/null
+++ b/pldmtool/oem/ibm/pldm_oem_ibm.cpp
@@ -0,0 +1,212 @@
+#include "pldm_oem_ibm.hpp"
+
+#include "oem/ibm/libpldm/file_io.h"
+#include "oem/ibm/libpldm/host.h"
+#include "pldm_types.h"
+
+#include "../../pldm_cmd_helper.hpp"
+
+#include <endian.h>
+
+#include <iostream>
+#include <string>
+namespace pldmtool
+{
+
+namespace oem_ibm
+{
+namespace
+{
+
+using namespace pldmtool::helper;
+
+std::vector<std::unique_ptr<CommandInterface>> commands;
+
+const std::map<const char*, pldm_fileio_table_type> pldmFileIOTableTypes{
+    {"AttributeTable", PLDM_FILE_ATTRIBUTE_TABLE},
+};
+
+constexpr uint8_t CHKSUM_PADDING = 8;
+
+} // namespace
+
+class GetAlertStatus : public CommandInterface
+{
+  public:
+    ~GetAlertStatus() = default;
+    GetAlertStatus() = delete;
+    GetAlertStatus(const GetAlertStatus&) = delete;
+    GetAlertStatus(GetAlertStatus&&) = default;
+    GetAlertStatus& operator=(const GetAlertStatus&) = delete;
+    GetAlertStatus& operator=(GetAlertStatus&&) = default;
+
+    explicit GetAlertStatus(const char* type, const char* name, CLI::App* app) :
+        CommandInterface(type, name, app)
+    {
+        app->add_option(
+               "-i, --id", versionId,
+               "Version of the command/response format. 0x00 for this format")
+            ->required();
+    }
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_ALERT_STATUS_REQ_BYTES);
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_alert_status_req(instanceId, versionId, request,
+                                              PLDM_GET_ALERT_STATUS_REQ_BYTES);
+        return {rc, requestMsg};
+    }
+
+    void parseResponseMsg(pldm_msg* responsePtr, size_t payloadLength) override
+    {
+        uint8_t completionCode = 0;
+        uint32_t rack_entry = 0;
+        uint32_t pri_cec_node = 0;
+        auto rc = decode_get_alert_status_resp(responsePtr, payloadLength,
+                                               &completionCode, &rack_entry,
+                                               &pri_cec_node);
+
+        if (rc != PLDM_SUCCESS || completionCode != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << "rc=" << rc << ",cc=" << (int)completionCode << "\n";
+            return;
+        }
+
+        std::cout << "GetAlertStatus Success: " << std::endl;
+        std::cout << "rack entry: 0x" << std::setfill('0') << std::setw(8)
+                  << std::hex << (int)rack_entry << std::endl;
+        std::cout << "pri cec node: 0x" << std::setfill('0') << std::setw(8)
+                  << std::hex << (int)pri_cec_node << std::endl;
+    }
+
+  private:
+    uint8_t versionId;
+};
+
+class GetFileTable : public CommandInterface
+{
+  public:
+    ~GetFileTable() = default;
+    GetFileTable() = delete;
+    GetFileTable(const GetFileTable&) = delete;
+    GetFileTable(GetFileTable&&) = default;
+    GetFileTable& operator=(const GetFileTable&) = delete;
+    GetFileTable& operator=(GetFileTable&&) = default;
+
+    using CommandInterface::CommandInterface;
+
+    std::pair<int, std::vector<uint8_t>> createRequestMsg() override
+    {
+
+        return {PLDM_ERROR, {}};
+    }
+
+    void parseResponseMsg(pldm_msg*, size_t) override
+    {}
+    void exec()
+    {
+        std::vector<uint8_t> requestMsg(sizeof(pldm_msg_hdr) +
+                                        PLDM_GET_FILE_TABLE_REQ_BYTES);
+
+        auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+        auto rc = encode_get_file_table_req(instanceId, 0, PLDM_GET_FIRSTPART,
+                                            0, request);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Request Message Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        std::vector<uint8_t> responseMsg;
+        rc = pldmSendRecv(requestMsg, responseMsg);
+        if (rc != PLDM_SUCCESS)
+        {
+            std::cerr << "PLDM: Communication Error, rc =" << rc << std::endl;
+            return;
+        }
+
+        uint8_t cc = 0;
+        uint8_t transferFlag = 0;
+        uint32_t nextTransferHandle = 0;
+        size_t fileTableDataLength = 0;
+        uint8_t table_data_start_offset;
+        auto responsePtr =
+            reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+        auto payloadLength = responseMsg.size() - sizeof(pldm_msg_hdr);
+
+        rc = decode_get_file_table_resp(
+            responsePtr, payloadLength, &cc, &nextTransferHandle, &transferFlag,
+            &table_data_start_offset, &fileTableDataLength);
+
+        if (rc != PLDM_SUCCESS || cc != PLDM_SUCCESS)
+        {
+            std::cerr << "Response Message Error: "
+                      << ", rc=" << rc << ", cc=" << (int)cc << std::endl;
+            return;
+        }
+
+        auto tableData = reinterpret_cast<uint8_t*>((responsePtr->payload) +
+                                                    table_data_start_offset);
+        printFileAttrTable(tableData, fileTableDataLength);
+    }
+
+    void printFileAttrTable(uint8_t* data, size_t length)
+    {
+        if (data == NULL || length == 0)
+        {
+            return;
+        }
+
+        auto startptr = data;
+        auto endptr = startptr + length - CHKSUM_PADDING;
+
+        while (startptr < endptr)
+        {
+            auto filetableData =
+                reinterpret_cast<pldm_file_attr_table_entry*>(startptr);
+            std::cout << "FileHandle:" << filetableData->file_handle
+                      << std::endl;
+            startptr += sizeof(filetableData->file_handle);
+
+            auto nameLength = filetableData->file_name_length;
+            std::cout << "  FileNameLength:" << nameLength << std::endl;
+            startptr += sizeof(filetableData->file_name_length);
+
+            std::cout << "  FileName:" << startptr << std::endl;
+            startptr += nameLength;
+
+            auto fileSize = *(reinterpret_cast<uint32_t*>(startptr));
+            std::cout << "  FileSize:" << le32toh(fileSize) << std::endl;
+            startptr += sizeof(fileSize);
+
+            auto fileTraits =
+                (*(reinterpret_cast<bitfield32_t*>(startptr))).value;
+            std::cout << "  FileTraits:" << le32toh(fileTraits) << std::endl;
+            startptr += sizeof(fileTraits);
+        }
+    }
+};
+
+void registerCommand(CLI::App& app)
+{
+    auto oem_ibm = app.add_subcommand("oem-ibm", "oem type command");
+    oem_ibm->require_subcommand(1);
+
+    auto getAlertStatus = oem_ibm->add_subcommand(
+        "GetAlertStatus", "get alert status descriptor");
+    commands.push_back(std::make_unique<GetAlertStatus>(
+        "oem_ibm", "getAlertStatus", getAlertStatus));
+
+    auto getFileTable =
+        oem_ibm->add_subcommand("GetFileTable", "get file table");
+
+    commands.push_back(std::make_unique<GetFileTable>("oem_ibm", "getFileTable",
+                                                      getFileTable));
+}
+} // namespace oem_ibm
+} // namespace pldmtool
diff --git a/pldmtool/oem/ibm/pldm_host_cmd.hpp b/pldmtool/oem/ibm/pldm_oem_ibm.hpp
similarity index 86%
rename from pldmtool/oem/ibm/pldm_host_cmd.hpp
rename to pldmtool/oem/ibm/pldm_oem_ibm.hpp
index d57ccd4..e2af83d 100644
--- a/pldmtool/oem/ibm/pldm_host_cmd.hpp
+++ b/pldmtool/oem/ibm/pldm_oem_ibm.hpp
@@ -7,13 +7,9 @@
 
 namespace oem_ibm
 {
-namespace power_host
-{
 
 void registerCommand(CLI::App& app);
 
-}
-
 } // namespace oem_ibm
 
 } // namespace pldmtool
diff --git a/pldmtool/pldmtool.cpp b/pldmtool/pldmtool.cpp
index 4b65b2a..f52c1e8 100644
--- a/pldmtool/pldmtool.cpp
+++ b/pldmtool/pldmtool.cpp
@@ -3,7 +3,7 @@
 #include "pldm_cmd_helper.hpp"
 #include "pldm_fru_cmd.hpp"
 #include "pldm_platform_cmd.hpp"
-#include "pldmtool/oem/ibm/pldm_host_cmd.hpp"
+#include "pldmtool/oem/ibm/pldm_oem_ibm.hpp"
 
 #include <CLI/CLI.hpp>
 
@@ -74,7 +74,7 @@
     pldmtool::fru::registerCommand(app);
 
 #ifdef OEM_IBM
-    pldmtool::oem_ibm::power_host::registerCommand(app);
+    pldmtool::oem_ibm::registerCommand(app);
 #endif
 
     CLI11_PARSE(app, argc, argv);