pldmtool: PDR: add parsers

Add parsers for FRU record set and entity association type PDRs.

Tested: Following is an example output:

pldmtool platform GetPDR -d 6

FRU Record Set
Parsed Response Msg:
nextRecordHandle: 7
responseCount: 20
recordHandle: 6
PDRHeaderVersion: 1
PDRType: 20
recordChangeNumber: 0
dataLength: 10

PLDMTerminusHandle: 0
FRURecordSetIdentifier: 4
entityType: Chassis front panel board (control panel)
entityInstanceNumber: 2
containerID: 1

pldmtool platform GetPDR -d 10

Entity Association
Parsed Response Msg:
nextRecordHandle: 0
responseCount: 56
recordHandle: 10
PDRHeaderVersion: 1
PDRType: 15
recordChangeNumber: 0
dataLength: 46

containerID: 1
associationType: Physical

containerEntityType: System Board
containerEntityInstanceNumber: 1
containerEntityContainerID: 0
containedEntityCount: 6

containedEntityType[1]: Chassis front panel board (control panel)
containedEntityInstanceNumber[1]: 1
containedEntityContainerID[1]: 1

containedEntityType[2]: Chassis front panel board (control panel)
containedEntityInstanceNumber[2]: 2
containedEntityContainerID[2]: 1

containedEntityType[3]: Management Controller
containedEntityInstanceNumber[3]: 1
containedEntityContainerID[3]: 1

containedEntityType[4]: 208
containedEntityInstanceNumber[4]: 1
containedEntityContainerID[4]: 1

containedEntityType[5]: Power converter
containedEntityInstanceNumber[5]: 1
containedEntityContainerID[5]: 1

Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Change-Id: I475976982b7e105680f6539b7f3a706aaea444e3
diff --git a/libpldm/platform.h b/libpldm/platform.h
index ba0854c..82c2b28 100644
--- a/libpldm/platform.h
+++ b/libpldm/platform.h
@@ -9,6 +9,7 @@
 #include <stdint.h>
 
 #include "base.h"
+#include "pdr.h"
 
 /* Maximum size for request */
 #define PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES 19
@@ -174,6 +175,18 @@
 	uint16_t length;
 } __attribute__((packed));
 
+/** @struct pldm_pdr_entity_association
+ *
+ *  Structure representing PLDM Entity Association PDR
+ */
+struct pldm_pdr_entity_association {
+	uint16_t container_id;
+	uint8_t association_type;
+	pldm_entity container;
+	uint8_t num_children;
+	pldm_entity children[1];
+} __attribute__((packed));
+
 /** @struct pldm_pdr_fru_record_set
  *
  *  Structure representing PLDM FRU record set PDR
diff --git a/tool/pldm_platform_cmd.cpp b/tool/pldm_platform_cmd.cpp
index 6d917fa..d2754ae 100644
--- a/tool/pldm_platform_cmd.cpp
+++ b/tool/pldm_platform_cmd.cpp
@@ -80,6 +80,95 @@
     }
 
   private:
+    const std::map<uint16_t, std::string> entityType = {
+        {64, "System Board"},
+        {137, "Management Controller"},
+        {69, "Chassis front panel board (control panel)"},
+        {123, "Power converter"},
+        {45, "System chassis (main enclosure)"},
+        {11521, "System (logical)"},
+    };
+
+    std::string getEntityName(uint8_t type)
+    {
+        try
+        {
+            return entityType.at(type);
+        }
+        catch (const std::out_of_range& e)
+        {
+            return std::to_string(static_cast<unsigned>(type)) + "(OEM)";
+        }
+    }
+
+    void printPDRFruRecordSet(uint8_t* data, size_t len)
+    {
+        if (data == NULL || len == 0)
+        {
+            return;
+        }
+
+        data += sizeof(pldm_pdr_hdr);
+        pldm_pdr_fru_record_set* pdr =
+            reinterpret_cast<pldm_pdr_fru_record_set*>(data);
+
+        std::cout << "PLDMTerminusHandle: " << pdr->terminus_handle
+                  << std::endl;
+        std::cout << "FRURecordSetIdentifier: " << pdr->fru_rsi << std::endl;
+        std::cout << "entityType: " << getEntityName(pdr->entity_type)
+                  << std::endl;
+        std::cout << "entityInstanceNumber: " << pdr->entity_instance_num
+                  << std::endl;
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+    }
+
+    void printPDREntityAssociation(uint8_t* data, size_t len)
+    {
+        const std::map<uint8_t, const char*> assocationType = {
+            {PLDM_ENTITY_ASSOCIAION_PHYSICAL, "Physical"},
+            {PLDM_ENTITY_ASSOCIAION_LOGICAL, "Logical"},
+        };
+
+        if (data == NULL || len == 0)
+        {
+            return;
+        }
+
+        data += sizeof(pldm_pdr_hdr);
+        pldm_pdr_entity_association* pdr =
+            reinterpret_cast<pldm_pdr_entity_association*>(data);
+
+        std::cout << "containerID: " << pdr->container_id << std::endl;
+        std::cout << "associationType: "
+                  << assocationType.at(pdr->association_type) << std::endl
+                  << std::endl;
+
+        std::cout << "containerEntityType: "
+                  << getEntityName(pdr->container.entity_type) << std::endl;
+        std::cout << "containerEntityInstanceNumber: "
+                  << pdr->container.entity_instance_num << std::endl;
+        std::cout << "containerEntityContainerID: "
+                  << pdr->container.entity_container_id << std::endl;
+
+        std::cout << "containedEntityCount: "
+                  << static_cast<unsigned>(pdr->num_children) << std::endl
+                  << std::endl;
+
+        auto child = reinterpret_cast<pldm_entity*>(&pdr->children[0]);
+        for (int i = 0; i < pdr->num_children; ++i)
+        {
+            std::cout << "containedEntityType[" << i + 1
+                      << "]: " << getEntityName(child->entity_type)
+                      << std::endl;
+            std::cout << "containedEntityInstanceNumber[" << i + 1
+                      << "]: " << child->entity_instance_num << std::endl;
+            std::cout << "containedEntityContainerID[" << i + 1
+                      << "]: " << child->entity_container_id << std::endl
+                      << std::endl;
+            ++child;
+        }
+    }
+
     void printPDR11(uint8_t* data, size_t len)
     {
         if (data == NULL || len == 0)
@@ -89,13 +178,6 @@
 
         struct pldm_state_effecter_pdr* pdr =
             (struct pldm_state_effecter_pdr*)data;
-        std::cout << "recordHandle: " << pdr->hdr.record_handle << std::endl;
-        std::cout << "PDRHeaderVersion: " << unsigned(pdr->hdr.version)
-                  << std::endl;
-        std::cout << "PDRType: " << unsigned(pdr->hdr.type) << std::endl;
-        std::cout << "recordChangeNumber: " << pdr->hdr.record_change_num
-                  << std::endl;
-        std::cout << "dataLength: " << pdr->hdr.length << std::endl;
         std::cout << "PLDMTerminusHandle: " << pdr->terminus_handle
                   << std::endl;
         std::cout << "effecterID: " << pdr->effecter_id << std::endl;
@@ -139,11 +221,25 @@
         std::cout << "responseCount: " << respCnt << std::endl;
 
         struct pldm_pdr_hdr* pdr = (struct pldm_pdr_hdr*)data;
+        std::cout << "recordHandle: " << pdr->record_handle << std::endl;
+        std::cout << "PDRHeaderVersion: " << unsigned(pdr->version)
+                  << std::endl;
+        std::cout << "PDRType: " << unsigned(pdr->type) << std::endl;
+        std::cout << "recordChangeNumber: " << pdr->record_change_num
+                  << std::endl;
+        std::cout << "dataLength: " << pdr->length << std::endl << std::endl;
+
         switch (pdr->type)
         {
             case PLDM_STATE_EFFECTER_PDR:
                 printPDR11(data, len);
                 break;
+            case PLDM_PDR_ENTITY_ASSOCIATION:
+                printPDREntityAssociation(data, len);
+                break;
+            case PLDM_PDR_FRU_RECORD_SET:
+                printPDRFruRecordSet(data, len);
+                break;
             default:
                 break;
         }