pdr: Add pldm_pdr_find_container_id_range_exclude() API

This API is necessary to find the container id of contained entity
which is not within the record handle ranges of the remote endpoint
PDRs.The remote endpoint has their own set of PDRs and have record
handle ranges defined.

Change-Id: If28325869d4c5c797c33bc4efd41bee16777a7aa
Signed-off-by: Pavithra Barithaya <pavithra.b@ibm.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/src/pdr.c b/src/pdr.c
index 0d6ce76..a78593c 100644
--- a/src/pdr.c
+++ b/src/pdr.c
@@ -365,6 +365,65 @@
 	} while (record);
 }
 
+static bool pldm_record_handle_in_range(uint32_t record_handle,
+					uint32_t first_record_handle,
+					uint32_t last_record_handle)
+{
+	return record_handle >= first_record_handle &&
+	       record_handle <= last_record_handle;
+}
+
+LIBPLDM_ABI_TESTING
+int pldm_pdr_find_container_id_range_exclude(
+	const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
+	uint32_t range_exclude_start_handle, uint32_t range_exclude_end_handle,
+	uint16_t *container_id)
+{
+	pldm_pdr_record *record;
+	if (!repo) {
+		return -EINVAL;
+	}
+
+	for (record = repo->first; record; record = record->next) {
+		bool is_container_entity_instance_number;
+		struct pldm_pdr_entity_association *pdr;
+		bool is_container_entity_type;
+		struct pldm_entity *child;
+		struct pldm_pdr_hdr *hdr;
+		bool in_range;
+
+		// pldm_pdr_add() takes only uint8_t* data as an argument.
+		// The expectation here is the pldm_pdr_hdr is the first field of the record data
+		hdr = (struct pldm_pdr_hdr *)record->data;
+		if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
+			continue;
+		}
+		in_range = pldm_record_handle_in_range(
+			record->record_handle, range_exclude_start_handle,
+			range_exclude_end_handle);
+		if (in_range) {
+			continue;
+		}
+
+		// this cast is valid with respect to alignment because
+		// struct pldm_pdr_hdr is declared with __attribute__((packed))
+		pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
+		if (pdr->num_children == 0) {
+			continue;
+		}
+		child = (&pdr->children[0]);
+		is_container_entity_type = pdr->container.entity_type ==
+					   entity_type;
+		is_container_entity_instance_number =
+			pdr->container.entity_instance_num == entity_instance;
+		if (is_container_entity_type &&
+		    is_container_entity_instance_number) {
+			*container_id = le16toh(child->entity_container_id);
+		}
+	}
+	return -ENOKEY;
+}
+
 typedef struct pldm_entity_association_tree {
 	pldm_entity_node *root;
 	uint16_t last_used_container_id;