libpldmresponder: implement handler for GetPDR

This commit implements the GetPDR command as defined in DSP0248 v1.1.1.
Multipart PDR transfers are still not implemented.

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: Ic520a914e8228b723521151f4ba1eed947179047
diff --git a/libpldmresponder/Makefile.am b/libpldmresponder/Makefile.am
index 948898f..a73252c 100644
--- a/libpldmresponder/Makefile.am
+++ b/libpldmresponder/Makefile.am
@@ -7,8 +7,8 @@
 	effecters.cpp \
 	pdr.cpp \
 	bios_parser.cpp \
-	bios.cpp
-
+	bios.cpp \
+	platform.cpp
 libpldmresponder_la_LIBADD = \
 	../libpldm/libpldm.la \
 	$(CODE_COVERAGE_LIBS)
diff --git a/libpldmresponder/meson.build b/libpldmresponder/meson.build
index c63685c..45dff73 100644
--- a/libpldmresponder/meson.build
+++ b/libpldmresponder/meson.build
@@ -13,6 +13,7 @@
   'pdr.cpp',
   'effecters.cpp',
   'utils.cpp',
+  'platform.cpp',
   '../registration.cpp'
 ]
 
diff --git a/libpldmresponder/platform.cpp b/libpldmresponder/platform.cpp
new file mode 100644
index 0000000..5fa14c8
--- /dev/null
+++ b/libpldmresponder/platform.cpp
@@ -0,0 +1,87 @@
+#include "config.h"
+
+#include "platform.hpp"
+
+#include "pdr.hpp"
+
+#include <exception>
+#include <phosphor-logging/log.hpp>
+
+namespace pldm
+{
+
+namespace responder
+{
+
+using namespace phosphor::logging;
+
+Response getPDR(const pldm_msg* request, size_t payloadLength)
+{
+    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES, 0);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+
+    if (payloadLength != PLDM_GET_PDR_REQ_BYTES)
+    {
+        encode_get_pdr_resp(request->hdr.instance_id, PLDM_ERROR_INVALID_LENGTH,
+                            0, 0, 0, 0, nullptr, 0, responsePtr);
+        return response;
+    }
+
+    uint32_t recordHandle{};
+    uint32_t dataTransferHandle{};
+    uint8_t transferOpFlag{};
+    uint16_t reqSizeBytes{};
+    uint16_t recordChangeNum{};
+
+    decode_get_pdr_req(request, payloadLength, &recordHandle,
+                       &dataTransferHandle, &transferOpFlag, &reqSizeBytes,
+                       &recordChangeNum);
+
+    uint32_t nextRecordHandle{};
+    uint16_t respSizeBytes{};
+    uint8_t* recordData = nullptr;
+    try
+    {
+        pdr::Repo& pdrRepo = pdr::get(PDR_JSONS_DIR);
+        nextRecordHandle = pdrRepo.getNextRecordHandle(recordHandle);
+        pdr::Entry e;
+        if (reqSizeBytes)
+        {
+            e = pdrRepo.at(recordHandle);
+            respSizeBytes = e.size();
+            if (respSizeBytes > reqSizeBytes)
+            {
+                respSizeBytes = reqSizeBytes;
+            }
+            recordData = e.data();
+        }
+        response.resize(sizeof(pldm_msg_hdr) + PLDM_GET_PDR_MIN_RESP_BYTES +
+                            respSizeBytes,
+                        0);
+        responsePtr = reinterpret_cast<pldm_msg*>(response.data());
+        encode_get_pdr_resp(request->hdr.instance_id, PLDM_SUCCESS,
+                            nextRecordHandle, 0, PLDM_START, respSizeBytes,
+                            recordData, 0, responsePtr);
+    }
+    catch (const std::out_of_range& e)
+    {
+        encode_get_pdr_resp(request->hdr.instance_id,
+                            PLDM_PLATFORM_INVALID_RECORD_HANDLE,
+                            nextRecordHandle, 0, PLDM_START, respSizeBytes,
+                            recordData, 0, responsePtr);
+        return response;
+    }
+    catch (const std::exception& e)
+    {
+        log<level::ERR>("Error accessing PDR", entry("HANDLE=%d", recordHandle),
+                        entry("ERROR=%s", e.what()));
+        encode_get_pdr_resp(request->hdr.instance_id, PLDM_ERROR,
+                            nextRecordHandle, 0, PLDM_START, respSizeBytes,
+                            recordData, 0, responsePtr);
+        return response;
+    }
+    return response;
+}
+
+} // namespace responder
+} // namespace pldm
diff --git a/libpldmresponder/platform.hpp b/libpldmresponder/platform.hpp
new file mode 100644
index 0000000..253d786
--- /dev/null
+++ b/libpldmresponder/platform.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "libpldm/platform.h"
+
+namespace pldm
+{
+
+using Response = std::vector<uint8_t>;
+
+namespace responder
+{
+
+/** @brief Handler for GetPDR
+ *
+ *  @param[in] request - Request message payload
+ *  @param[in] payloadLength - Request payload length
+ *  @param[out] Response - Response message written here
+ */
+Response getPDR(const pldm_msg* request, size_t payloadLength);
+
+} // namespace responder
+} // namespace pldm