Implement FRURecordTableMetadata and FRURecordTable command

This commit implements the GetFRURecordTableMetadata and GetFRURecordTable
in the PLDM specification DSP0257 for FRU data specification. The FRU table
is populated by the FRU handler class with the configs from the path
/usr/share/pldm/fru.

Tested:

On a Witherspoon system the Get FRURecordTableMetadata and FRURecordTable
command were executed and ensured the FRU table in the command response
matches with the D-Bus inventory properties.

Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I16d36df2834b65bfa5f69164d3a40eeac2c7f357
diff --git a/libpldmresponder/fru.cpp b/libpldmresponder/fru.cpp
index 096c4f7..01afde3 100644
--- a/libpldmresponder/fru.cpp
+++ b/libpldmresponder/fru.cpp
@@ -172,6 +172,60 @@
                 iter);
 }
 
+namespace fru
+{
+
+Response Handler::getFRURecordTableMetadata(const pldm_msg* request,
+                                            size_t /*payloadLength*/)
+{
+    constexpr uint8_t major = 0x01;
+    constexpr uint8_t minor = 0x00;
+    constexpr uint32_t maxSize = 0xFFFFFFFF;
+
+    Response response(sizeof(pldm_msg_hdr) +
+                          PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES,
+                      0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    auto rc = encode_get_fru_record_table_metadata_resp(
+        request->hdr.instance_id, PLDM_SUCCESS, major, minor, maxSize,
+        impl.size(), impl.numRSI(), impl.numRecords(), impl.checkSum(),
+        responsePtr);
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    return response;
+}
+
+Response Handler::getFRURecordTable(const pldm_msg* request,
+                                    size_t payloadLength)
+{
+    if (payloadLength != PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES)
+    {
+        return ccOnlyResponse(request, PLDM_ERROR_INVALID_LENGTH);
+    }
+
+    Response response(
+        sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES, 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    auto rc =
+        encode_get_fru_record_table_resp(request->hdr.instance_id, PLDM_SUCCESS,
+                                         0, PLDM_START_AND_END, responsePtr);
+    if (rc != PLDM_SUCCESS)
+    {
+        return ccOnlyResponse(request, rc);
+    }
+
+    impl.getFRUTable(response);
+
+    return response;
+}
+
+} // namespace fru
+
 } // namespace responder
 
 } // namespace pldm
diff --git a/libpldmresponder/fru.hpp b/libpldmresponder/fru.hpp
index 3f817fd..06411a8 100644
--- a/libpldmresponder/fru.hpp
+++ b/libpldmresponder/fru.hpp
@@ -121,6 +121,52 @@
                          const fru_parser::FruRecordInfos& recordInfos);
 };
 
+namespace fru
+{
+
+class Handler : public CmdHandler
+{
+
+  public:
+    Handler(const std::string configPath) : impl(configPath)
+    {
+        handlers.emplace(PLDM_GET_FRU_RECORD_TABLE_METADATA,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getFRURecordTableMetadata(
+                                 request, payloadLength);
+                         });
+
+        handlers.emplace(PLDM_GET_FRU_RECORD_TABLE,
+                         [this](const pldm_msg* request, size_t payloadLength) {
+                             return this->getFRURecordTable(request,
+                                                            payloadLength);
+                         });
+    }
+
+    FruImpl impl;
+
+    /** @brief Handler for Get FRURecordTableMetadata
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payloadLength - Request payload length
+     *
+     *  @return PLDM response message
+     */
+    Response getFRURecordTableMetadata(const pldm_msg* request,
+                                       size_t payloadLength);
+
+    /** @brief Handler for GetFRURecordTable
+     *
+     *  @param[in] request - Request message payload
+     *  @param[in] payloadLength - Request payload length
+     *
+     *  @return PLDM response message
+     */
+    Response getFRURecordTable(const pldm_msg* request, size_t payloadLength);
+};
+
+} // namespace fru
+
 } // namespace responder
 
 } // namespace pldm
diff --git a/meson.build b/meson.build
index 52af1d9..3a9977b 100644
--- a/meson.build
+++ b/meson.build
@@ -17,6 +17,7 @@
 conf_data.set_quoted('BIOS_JSONS_DIR', '/usr/share/pldm/bios')
 conf_data.set_quoted('BIOS_TABLES_DIR', '/var/lib/pldm/bios')
 conf_data.set_quoted('PDR_JSONS_DIR', '/usr/share/pldm/pdr')
+conf_data.set_quoted('FRU_JSONS_DIR', '/usr/share/pldm/fru')
 if get_option('oem-ibm').enabled()
   conf_data.set_quoted('FILE_TABLE_JSON', '/usr/share/pldm/fileTable.json')
   conf_data.set_quoted('LID_PERM_DIR', '/usr/share/host-fw')
diff --git a/pldmd.cpp b/pldmd.cpp
index 648ae6c..a13383d 100644
--- a/pldmd.cpp
+++ b/pldmd.cpp
@@ -2,6 +2,7 @@
 #include "invoker.hpp"
 #include "libpldmresponder/base.hpp"
 #include "libpldmresponder/bios.hpp"
+#include "libpldmresponder/fru.hpp"
 #include "libpldmresponder/platform.hpp"
 #include "utils.hpp"
 
@@ -148,6 +149,8 @@
     invoker.registerHandler(PLDM_BIOS, std::make_unique<bios::Handler>());
     invoker.registerHandler(PLDM_PLATFORM,
                             std::make_unique<platform::Handler>());
+    invoker.registerHandler(PLDM_FRU,
+                            std::make_unique<fru::Handler>(FRU_JSONS_DIR));
 
 #ifdef OEM_IBM
     invoker.registerHandler(PLDM_OEM, std::make_unique<oem_ibm::Handler>());