pdr: Introduce remote_container_id and associated APIs

We have a concept of a Primary PDR repository and merging the PDRs from
a remote PLDM endpoint (DSP0248 section 7: PDRs support functions).

The main functions of the PLDM discovery Agent (DSP0248 section 14)
(assuming a PLDM terminus like BMC) is maintaining a primary PDR
repository, adding/deleting/updating the PDRs to form a complete system
model. And to do so this API (pldm_entity_node_get_remote_container_id)
will help us update the container id field of the PDR obtained by the
remote PLDM terminus.

Change-Id: I249e627a1e05ee6d9644f3f93f326e47256d914a
Signed-off-by: Archana Kakani <archana.kakani@ibm.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2abe408..6f66f63 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@
 
 1. Add encode/decode pldmMessagePollEvent data
 2. README: Add a section on working with libpldm
+3. pdr: Introduce remote_container_id and associated APIs
 
 ### Changed
 
diff --git a/include/libpldm/pdr.h b/include/libpldm/pdr.h
index 5443fba..6a72028 100644
--- a/include/libpldm/pdr.h
+++ b/include/libpldm/pdr.h
@@ -280,6 +280,15 @@
  */
 pldm_entity pldm_entity_extract(pldm_entity_node *node);
 
+/** @brief Extract remote container id from the pldm_entity_node
+ *
+ *  @param[in] entity         - pointer to existing entity
+ *
+ *  @param[out] cid           -  remote container id
+ */
+int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
+					     uint16_t *cid);
+
 /** @brief Destroy entity association tree
  *
  *  @param[in] tree - opaque pointer acting as a handle to the tree
@@ -362,7 +371,6 @@
  *  @param[in] tree - pointer to entity association tree
  *  @param[in/out] entity - entity type and instance id set on input, container
  *                 id set on output
- *
  *  @return pldm_entity_node* pointer to entity if found, NULL otherwise
  */
 pldm_entity_node *
diff --git a/src/pdr.c b/src/pdr.c
index 68342ef..ff4fbd1 100644
--- a/src/pdr.c
+++ b/src/pdr.c
@@ -5,6 +5,7 @@
 #include <endian.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 typedef struct pldm_pdr_record {
 	uint32_t record_handle;
@@ -373,6 +374,7 @@
 typedef struct pldm_entity_node {
 	pldm_entity entity;
 	pldm_entity parent;
+	uint16_t remote_container_id;
 	pldm_entity_node *first_child;
 	pldm_entity_node *next_sibling;
 	uint8_t association_type;
@@ -394,6 +396,18 @@
 	return node->entity;
 }
 
+LIBPLDM_ABI_TESTING
+int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
+					     uint16_t *cid)
+{
+	if (!entity) {
+		return -EINVAL;
+	}
+
+	*cid = entity->remote_container_id;
+	return 0;
+}
+
 LIBPLDM_ABI_STABLE
 pldm_entity_association_tree *pldm_entity_association_tree_init(void)
 {
@@ -458,12 +472,14 @@
 	node->entity.entity_instance_num =
 		entity_instance_number != 0xFFFF ? entity_instance_number : 1;
 	node->association_type = association_type;
+	node->remote_container_id = 0;
 
 	if (tree->root == NULL) {
 		assert(parent == NULL);
 		tree->root = node;
 		/* container_id 0 here indicates this is the top-most entry */
 		node->entity.entity_container_id = 0;
+		node->remote_container_id = node->entity.entity_container_id;
 	} else if (parent != NULL && parent->first_child == NULL) {
 		parent->first_child = node;
 		node->parent = parent->entity;
@@ -487,6 +503,7 @@
 		node->next_sibling = next;
 		node->entity.entity_container_id =
 			prev->entity.entity_container_id;
+		node->remote_container_id = entity->entity_container_id;
 	}
 	entity->entity_instance_num = node->entity.entity_instance_num;
 	entity->entity_container_id = node->entity.entity_container_id;
@@ -776,13 +793,21 @@
 void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
 			     pldm_entity_node **node)
 {
+	bool is_entity_container_id;
+	bool is_entity_instance_num;
+	bool is_type;
+
 	if (tree_node == NULL) {
 		return;
 	}
 
-	if (tree_node->entity.entity_type == entity.entity_type &&
-	    tree_node->entity.entity_instance_num ==
-		    entity.entity_instance_num) {
+	is_type = tree_node->entity.entity_type == entity.entity_type;
+	is_entity_instance_num = tree_node->entity.entity_instance_num ==
+				 entity.entity_instance_num;
+	is_entity_container_id = tree_node->entity.entity_container_id ==
+				 entity.entity_container_id;
+
+	if (is_type && is_entity_instance_num && is_entity_container_id) {
 		*node = tree_node;
 		return;
 	}
@@ -910,7 +935,6 @@
 		*out = node;
 		return;
 	}
-
 	entity_association_tree_find(node->next_sibling, entity, out);
 	entity_association_tree_find(node->first_child, entity, out);
 }
@@ -937,6 +961,7 @@
 	(*new_node)->parent = org_node->parent;
 	(*new_node)->entity = org_node->entity;
 	(*new_node)->association_type = org_node->association_type;
+	(*new_node)->remote_container_id = org_node->remote_container_id;
 	(*new_node)->first_child = NULL;
 	(*new_node)->next_sibling = NULL;
 	entity_association_tree_copy(org_node->first_child,