libpldm: Migrate to subproject

Organize files in libpldm to make it a subproject

In the current state, libpldm is not readily consumable
as a subproject.This commit does all the necessary re-organisation
of the source code to make it work as a subproject.

There are no .c/.h files changes in this commit, only meson
changes and re-organising the code structure.

Signed-off-by: Manojkiran Eda <manojkiran.eda@gmail.com>
Change-Id: I20a71c0c972b1fd81fb359d604433618799102c6
diff --git a/src/pdr.c b/src/pdr.c
new file mode 100644
index 0000000..b057e3d
--- /dev/null
+++ b/src/pdr.c
@@ -0,0 +1,971 @@
+#include "pdr.h"
+#include "platform.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct pldm_pdr_record {
+	uint32_t record_handle;
+	uint32_t size;
+	uint8_t *data;
+	struct pldm_pdr_record *next;
+	bool is_remote;
+	uint16_t terminus_handle;
+} pldm_pdr_record;
+
+typedef struct pldm_pdr {
+	uint32_t record_count;
+	uint32_t size;
+	pldm_pdr_record *first;
+	pldm_pdr_record *last;
+} pldm_pdr;
+
+static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
+					      const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	if (record == repo->last) {
+		return 0;
+	}
+	return record->next->record_handle;
+}
+
+static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	if (repo->first == NULL) {
+		assert(repo->last == NULL);
+		repo->first = record;
+		repo->last = record;
+	} else {
+		repo->last->next = record;
+		repo->last = record;
+	}
+	repo->size += record->size;
+	++repo->record_count;
+}
+
+static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+	uint32_t last_used_hdl =
+	    repo->last != NULL ? repo->last->record_handle : 0;
+	assert(last_used_hdl != UINT32_MAX);
+
+	return last_used_hdl + 1;
+}
+
+static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
+					const uint8_t *data, uint32_t size,
+					uint32_t record_handle, bool is_remote,
+					uint16_t terminus_handle)
+{
+	assert(repo != NULL);
+	assert(size != 0);
+
+	pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
+	assert(record != NULL);
+	record->record_handle =
+	    record_handle == 0 ? get_new_record_handle(repo) : record_handle;
+	record->size = size;
+	record->is_remote = is_remote;
+	record->terminus_handle = terminus_handle;
+	if (data != NULL) {
+		record->data = malloc(size);
+		assert(record->data != NULL);
+		memcpy(record->data, data, size);
+		/* If record handle is 0, that is an indication for this API to
+		 * compute a new handle. For that reason, the computed handle
+		 * needs to be populated in the PDR header. For a case where the
+		 * caller supplied the record handle, it would exist in the
+		 * header already.
+		 */
+		if (!record_handle) {
+			struct pldm_pdr_hdr *hdr =
+			    (struct pldm_pdr_hdr *)(record->data);
+			hdr->record_handle = htole32(record->record_handle);
+		}
+	}
+	record->next = NULL;
+
+	return record;
+}
+
+uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
+		      uint32_t record_handle, bool is_remote,
+		      uint16_t terminus_handle)
+{
+	assert(size != 0);
+	assert(data != NULL);
+
+	pldm_pdr_record *record = make_new_record(
+	    repo, data, size, record_handle, is_remote, terminus_handle);
+	add_record(repo, record);
+
+	return record->record_handle;
+}
+
+pldm_pdr *pldm_pdr_init()
+{
+	pldm_pdr *repo = malloc(sizeof(pldm_pdr));
+	assert(repo != NULL);
+	repo->record_count = 0;
+	repo->size = 0;
+	repo->first = NULL;
+	repo->last = NULL;
+
+	return repo;
+}
+
+void pldm_pdr_destroy(pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->data) {
+			free(record->data);
+			record->data = NULL;
+		}
+		free(record);
+		record = next;
+	}
+	free(repo);
+}
+
+const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
+					    uint32_t record_handle,
+					    uint8_t **data, uint32_t *size,
+					    uint32_t *next_record_handle)
+{
+	assert(repo != NULL);
+	assert(data != NULL);
+	assert(size != NULL);
+	assert(next_record_handle != NULL);
+
+	if (!record_handle && (repo->first != NULL)) {
+		record_handle = repo->first->record_handle;
+	}
+	pldm_pdr_record *record = repo->first;
+	while (record != NULL) {
+		if (record->record_handle == record_handle) {
+			*size = record->size;
+			*data = record->data;
+			*next_record_handle =
+			    get_next_record_handle(repo, record);
+			return record;
+		}
+		record = record->next;
+	}
+
+	*size = 0;
+	*next_record_handle = 0;
+	return NULL;
+}
+
+const pldm_pdr_record *
+pldm_pdr_get_next_record(const pldm_pdr *repo,
+			 const pldm_pdr_record *curr_record, uint8_t **data,
+			 uint32_t *size, uint32_t *next_record_handle)
+{
+	assert(repo != NULL);
+	assert(curr_record != NULL);
+	assert(data != NULL);
+	assert(size != NULL);
+	assert(next_record_handle != NULL);
+
+	if (curr_record == repo->last) {
+		*data = NULL;
+		*size = 0;
+		*next_record_handle = get_next_record_handle(repo, curr_record);
+		return NULL;
+	}
+
+	*next_record_handle = get_next_record_handle(repo, curr_record->next);
+	*data = curr_record->next->data;
+	*size = curr_record->next->size;
+	return curr_record->next;
+}
+
+const pldm_pdr_record *
+pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
+			     const pldm_pdr_record *curr_record, uint8_t **data,
+			     uint32_t *size)
+{
+	assert(repo != NULL);
+
+	pldm_pdr_record *record = repo->first;
+	if (curr_record != NULL) {
+		record = curr_record->next;
+	}
+	while (record != NULL) {
+		struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
+		if (hdr->type == pdr_type) {
+			if (data && size) {
+				*size = record->size;
+				*data = record->data;
+			}
+			return record;
+		}
+		record = record->next;
+	}
+
+	if (size) {
+		*size = 0;
+	}
+	return NULL;
+}
+
+uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->record_count;
+}
+
+uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
+{
+	assert(repo != NULL);
+
+	return repo->size;
+}
+
+uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
+				    const pldm_pdr_record *record)
+{
+	assert(repo != NULL);
+	assert(record != NULL);
+
+	return record->record_handle;
+}
+
+inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
+{
+	assert(record != NULL);
+
+	return record->is_remote;
+}
+
+uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
+				     uint16_t fru_rsi, uint16_t entity_type,
+				     uint16_t entity_instance_num,
+				     uint16_t container_id,
+				     uint32_t bmc_record_handle)
+{
+	uint32_t size = sizeof(struct pldm_pdr_hdr) +
+			sizeof(struct pldm_pdr_fru_record_set);
+	uint8_t data[size];
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
+	hdr->version = 1;
+	hdr->record_handle = bmc_record_handle;
+	hdr->type = PLDM_PDR_FRU_RECORD_SET;
+	hdr->record_change_num = 0;
+	hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
+	struct pldm_pdr_fru_record_set *fru =
+	    (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
+					       sizeof(struct pldm_pdr_hdr));
+	fru->terminus_handle = htole16(terminus_handle);
+	fru->fru_rsi = htole16(fru_rsi);
+	fru->entity_type = htole16(entity_type);
+	fru->entity_instance_num = htole16(entity_instance_num);
+	fru->container_id = htole16(container_id);
+
+	return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
+			    terminus_handle);
+}
+
+const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
+    const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
+    uint16_t *entity_type, uint16_t *entity_instance_num,
+    uint16_t *container_id)
+{
+	assert(terminus_handle != NULL);
+	assert(entity_type != NULL);
+	assert(entity_instance_num != NULL);
+	assert(container_id != NULL);
+
+	uint8_t *data = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
+	    repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
+	while (curr_record != NULL) {
+		struct pldm_pdr_fru_record_set *fru =
+		    (struct pldm_pdr_fru_record_set
+			 *)(data + sizeof(struct pldm_pdr_hdr));
+		if (fru->fru_rsi == htole16(fru_rsi)) {
+			*terminus_handle = le16toh(fru->terminus_handle);
+			*entity_type = le16toh(fru->entity_type);
+			*entity_instance_num =
+			    le16toh(fru->entity_instance_num);
+			*container_id = le16toh(fru->container_id);
+			return curr_record;
+		}
+		data = NULL;
+		curr_record = pldm_pdr_find_record_by_type(
+		    repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
+	}
+
+	*terminus_handle = 0;
+	*entity_type = 0;
+	*entity_instance_num = 0;
+	*container_id = 0;
+
+	return NULL;
+}
+
+void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
+			    uint8_t tid, uint8_t tlEid, bool validBit)
+{
+	uint8_t *outData = NULL;
+	uint32_t size = 0;
+	const pldm_pdr_record *record;
+	record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
+					      NULL, &outData, &size);
+
+	do {
+		if (record != NULL) {
+			struct pldm_terminus_locator_pdr *pdr =
+			    (struct pldm_terminus_locator_pdr *)outData;
+			struct pldm_terminus_locator_type_mctp_eid *value =
+			    (struct pldm_terminus_locator_type_mctp_eid *)
+				pdr->terminus_locator_value;
+			if (pdr->terminus_handle == terminusHandle &&
+			    pdr->tid == tid && value->eid == tlEid) {
+				pdr->validity = validBit;
+				break;
+			}
+		}
+		record = pldm_pdr_find_record_by_type(
+		    repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size);
+	} while (record);
+}
+
+typedef struct pldm_entity_association_tree {
+	pldm_entity_node *root;
+	uint16_t last_used_container_id;
+} pldm_entity_association_tree;
+
+typedef struct pldm_entity_node {
+	pldm_entity entity;
+	pldm_entity parent;
+	pldm_entity_node *first_child;
+	pldm_entity_node *next_sibling;
+	uint8_t association_type;
+} pldm_entity_node;
+
+static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
+{
+	assert(tree != NULL);
+	assert(tree->last_used_container_id != UINT16_MAX);
+
+	return ++tree->last_used_container_id;
+}
+
+pldm_entity pldm_entity_extract(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->entity;
+}
+
+pldm_entity_association_tree *pldm_entity_association_tree_init()
+{
+	pldm_entity_association_tree *tree =
+	    malloc(sizeof(pldm_entity_association_tree));
+	assert(tree != NULL);
+	tree->root = NULL;
+	tree->last_used_container_id = 0;
+
+	return tree;
+}
+
+static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
+					   uint16_t entity_type)
+{
+	assert(start != NULL);
+
+	/* Insert after the the last node that matches the input entity type, or
+	 * at the end if no such match occurrs
+	 */
+	while (start->next_sibling != NULL) {
+		uint16_t this_type = start->entity.entity_type;
+		pldm_entity_node *next = start->next_sibling;
+		if (this_type == entity_type &&
+		    (this_type != next->entity.entity_type)) {
+			break;
+		}
+		start = start->next_sibling;
+	}
+
+	return start;
+}
+
+pldm_entity_node *pldm_entity_association_tree_add(
+    pldm_entity_association_tree *tree, pldm_entity *entity,
+    uint16_t entity_instance_number, pldm_entity_node *parent,
+    uint8_t association_type)
+{
+	assert(tree != NULL);
+	assert(entity != NULL);
+
+	if (entity_instance_number != 0xFFFF && parent != NULL) {
+		pldm_entity node;
+		node.entity_type = entity->entity_type;
+		node.entity_instance_num = entity_instance_number;
+		if (pldm_is_current_parent_child(parent, &node)) {
+			return NULL;
+		}
+	}
+
+	assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
+	       association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
+	pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
+	assert(node != NULL);
+	node->first_child = NULL;
+	node->next_sibling = NULL;
+	node->parent.entity_type = 0;
+	node->parent.entity_instance_num = 0;
+	node->parent.entity_container_id = 0;
+	node->entity.entity_type = entity->entity_type;
+	node->entity.entity_instance_num =
+	    entity_instance_number != 0xFFFF ? entity_instance_number : 1;
+	node->association_type = association_type;
+
+	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;
+	} else if (parent != NULL && parent->first_child == NULL) {
+		parent->first_child = node;
+		node->parent = parent->entity;
+		node->entity.entity_container_id = next_container_id(tree);
+	} else {
+		pldm_entity_node *start =
+		    parent == NULL ? tree->root : parent->first_child;
+		pldm_entity_node *prev =
+		    find_insertion_at(start, entity->entity_type);
+		assert(prev != NULL);
+		pldm_entity_node *next = prev->next_sibling;
+		if (prev->entity.entity_type == entity->entity_type) {
+			assert(prev->entity.entity_instance_num != UINT16_MAX);
+			node->entity.entity_instance_num =
+			    entity_instance_number != 0xFFFF
+				? entity_instance_number
+				: prev->entity.entity_instance_num + 1;
+		}
+		prev->next_sibling = node;
+		node->parent = prev->parent;
+		node->next_sibling = next;
+		node->entity.entity_container_id =
+		    prev->entity.entity_container_id;
+	}
+	entity->entity_instance_num = node->entity.entity_instance_num;
+	entity->entity_container_id = node->entity.entity_container_id;
+
+	return node;
+}
+
+static void get_num_nodes(pldm_entity_node *node, size_t *num)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	++(*num);
+	get_num_nodes(node->next_sibling, num);
+	get_num_nodes(node->first_child, num);
+}
+
+static void entity_association_tree_visit(pldm_entity_node *node,
+					  pldm_entity *entities, size_t *index)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	pldm_entity *entity = &entities[*index];
+	++(*index);
+	entity->entity_type = node->entity.entity_type;
+	entity->entity_instance_num = node->entity.entity_instance_num;
+	entity->entity_container_id = node->entity.entity_container_id;
+
+	entity_association_tree_visit(node->next_sibling, entities, index);
+	entity_association_tree_visit(node->first_child, entities, index);
+}
+
+void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
+					pldm_entity **entities, size_t *size)
+{
+	assert(tree != NULL);
+
+	*size = 0;
+	if (tree->root == NULL) {
+		return;
+	}
+
+	get_num_nodes(tree->root, size);
+	*entities = malloc(*size * sizeof(pldm_entity));
+	size_t index = 0;
+	entity_association_tree_visit(tree->root, *entities, &index);
+}
+
+static void entity_association_tree_destroy(pldm_entity_node *node)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	entity_association_tree_destroy(node->next_sibling);
+	entity_association_tree_destroy(node->first_child);
+	free(node);
+}
+
+void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
+{
+	assert(tree != NULL);
+
+	entity_association_tree_destroy(tree->root);
+	free(tree);
+}
+
+inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->first_child != NULL;
+}
+
+inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	return node->parent;
+}
+
+inline bool pldm_entity_is_exist_parent(pldm_entity_node *node)
+{
+	assert(node != NULL);
+
+	if (node->parent.entity_type == 0 &&
+	    node->parent.entity_instance_num == 0 &&
+	    node->parent.entity_container_id == 0) {
+		return false;
+	}
+
+	return true;
+}
+
+uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
+				     uint8_t association_type)
+{
+	assert(node != NULL);
+	assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
+	       association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
+
+	size_t count = 0;
+	pldm_entity_node *curr = node->first_child;
+	while (curr != NULL) {
+		if (curr->association_type == association_type) {
+			++count;
+		}
+		curr = curr->next_sibling;
+	}
+
+	assert(count < UINT8_MAX);
+	return count;
+}
+
+bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
+{
+	assert(parent != NULL);
+	assert(node != NULL);
+
+	pldm_entity_node *curr = parent->first_child;
+	while (curr != NULL) {
+		if (node->entity_type == curr->entity.entity_type &&
+		    node->entity_instance_num ==
+			curr->entity.entity_instance_num) {
+
+			return true;
+		}
+		curr = curr->next_sibling;
+	}
+
+	return false;
+}
+
+static void _entity_association_pdr_add_entry(pldm_entity_node *curr,
+					      pldm_pdr *repo, uint16_t size,
+					      uint8_t contained_count,
+					      uint8_t association_type,
+					      bool is_remote,
+					      uint16_t terminus_handle)
+{
+	uint8_t pdr[size];
+	uint8_t *start = pdr;
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
+	hdr->version = 1;
+	hdr->record_handle = 0;
+	hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
+	hdr->record_change_num = 0;
+	hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
+	start += sizeof(struct pldm_pdr_hdr);
+
+	uint16_t *container_id = (uint16_t *)start;
+	*container_id = htole16(curr->first_child->entity.entity_container_id);
+	start += sizeof(uint16_t);
+	*start = association_type;
+	start += sizeof(uint8_t);
+
+	pldm_entity *entity = (pldm_entity *)start;
+	entity->entity_type = htole16(curr->entity.entity_type);
+	entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
+	entity->entity_container_id = htole16(curr->entity.entity_container_id);
+	start += sizeof(pldm_entity);
+
+	*start = contained_count;
+	start += sizeof(uint8_t);
+
+	pldm_entity_node *node = curr->first_child;
+	while (node != NULL) {
+		if (node->association_type == association_type) {
+			pldm_entity *entity = (pldm_entity *)start;
+			entity->entity_type = htole16(node->entity.entity_type);
+			entity->entity_instance_num =
+			    htole16(node->entity.entity_instance_num);
+			entity->entity_container_id =
+			    htole16(node->entity.entity_container_id);
+			start += sizeof(pldm_entity);
+		}
+		node = node->next_sibling;
+	}
+
+	pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
+}
+
+static void entity_association_pdr_add_entry(pldm_entity_node *curr,
+					     pldm_pdr *repo, bool is_remote,
+					     uint16_t terminus_handle)
+{
+	uint8_t num_logical_children =
+	    pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
+	uint8_t num_physical_children =
+	    pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
+
+	if (num_logical_children) {
+		uint16_t logical_pdr_size =
+		    sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
+		    sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
+		    (num_logical_children * sizeof(pldm_entity));
+		_entity_association_pdr_add_entry(
+		    curr, repo, logical_pdr_size, num_logical_children,
+		    PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote, terminus_handle);
+	}
+
+	if (num_physical_children) {
+		uint16_t physical_pdr_size =
+		    sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
+		    sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
+		    (num_physical_children * sizeof(pldm_entity));
+		_entity_association_pdr_add_entry(
+		    curr, repo, physical_pdr_size, num_physical_children,
+		    PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
+		    terminus_handle);
+	}
+}
+
+bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
+{
+	if (entities == NULL || num_entities == 0) {
+		return true;
+	}
+	size_t i = 0;
+	while (i < num_entities) {
+		if ((*entities + i)->entity_type == entity.entity_type) {
+			return true;
+		}
+		i++;
+	}
+	return false;
+}
+
+static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
+				       pldm_entity **entities,
+				       size_t num_entities, bool is_remote,
+				       uint16_t terminus_handle)
+{
+	if (curr == NULL) {
+		return;
+	}
+	bool to_add = true;
+	to_add = is_present(curr->entity, entities, num_entities);
+	if (to_add) {
+		entity_association_pdr_add_entry(curr, repo, is_remote,
+						 terminus_handle);
+	}
+	entity_association_pdr_add(curr->next_sibling, repo, entities,
+				   num_entities, is_remote, terminus_handle);
+	entity_association_pdr_add(curr->first_child, repo, entities,
+				   num_entities, is_remote, terminus_handle);
+}
+
+void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
+				     pldm_pdr *repo, bool is_remote,
+				     uint16_t terminus_handle)
+{
+	assert(tree != NULL);
+	assert(repo != NULL);
+
+	entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
+				   terminus_handle);
+}
+
+void pldm_entity_association_pdr_add_from_node(
+    pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
+    size_t num_entities, bool is_remote, uint16_t terminus_handle)
+{
+	assert(repo != NULL);
+
+	entity_association_pdr_add(node, repo, entities, num_entities,
+				   is_remote, terminus_handle);
+}
+
+void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
+			     pldm_entity_node **node)
+{
+	if (tree_node == NULL) {
+		return;
+	}
+
+	if (tree_node->entity.entity_type == entity.entity_type &&
+	    tree_node->entity.entity_instance_num ==
+		entity.entity_instance_num) {
+		*node = tree_node;
+		return;
+	}
+
+	find_entity_ref_in_tree(tree_node->first_child, entity, node);
+	find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
+}
+
+void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
+				  pldm_entity entity, pldm_entity_node **node)
+{
+	assert(tree != NULL);
+	find_entity_ref_in_tree(tree->root, entity, node);
+}
+
+void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
+					     uint16_t terminus_handle)
+{
+	assert(repo != NULL);
+	bool removed = false;
+
+	pldm_pdr_record *record = repo->first;
+	pldm_pdr_record *prev = NULL;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->terminus_handle == terminus_handle) {
+			if (repo->first == record) {
+				repo->first = next;
+			} else {
+				prev->next = next;
+			}
+			if (repo->last == record) {
+				repo->last = prev;
+			}
+			if (record->data) {
+				free(record->data);
+			}
+			--repo->record_count;
+			repo->size -= record->size;
+			free(record);
+			removed = true;
+		} else {
+			prev = record;
+		}
+		record = next;
+	}
+
+	if (removed == true) {
+		record = repo->first;
+		uint32_t record_handle = 0;
+		while (record != NULL) {
+			record->record_handle = ++record_handle;
+			if (record->data != NULL) {
+				struct pldm_pdr_hdr *hdr =
+				    (struct pldm_pdr_hdr *)(record->data);
+				hdr->record_handle =
+				    htole32(record->record_handle);
+			}
+			record = record->next;
+		}
+	}
+}
+void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
+{
+	assert(repo != NULL);
+	bool removed = false;
+
+	pldm_pdr_record *record = repo->first;
+	pldm_pdr_record *prev = NULL;
+	while (record != NULL) {
+		pldm_pdr_record *next = record->next;
+		if (record->is_remote == true) {
+			if (repo->first == record) {
+				repo->first = next;
+			} else {
+				prev->next = next;
+			}
+			if (repo->last == record) {
+				repo->last = prev;
+			}
+			if (record->data) {
+				free(record->data);
+			}
+			--repo->record_count;
+			repo->size -= record->size;
+			free(record);
+			removed = true;
+		} else {
+			prev = record;
+		}
+		record = next;
+	}
+
+	if (removed == true) {
+		record = repo->first;
+		uint32_t record_handle = 0;
+		while (record != NULL) {
+			record->record_handle = ++record_handle;
+			if (record->data != NULL) {
+				struct pldm_pdr_hdr *hdr =
+				    (struct pldm_pdr_hdr *)(record->data);
+				hdr->record_handle =
+				    htole32(record->record_handle);
+			}
+			record = record->next;
+		}
+	}
+}
+
+void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
+				  pldm_entity_node **out)
+{
+	if (node == NULL) {
+		return;
+	}
+
+	if (node->entity.entity_type == entity->entity_type &&
+	    node->entity.entity_instance_num == entity->entity_instance_num) {
+		entity->entity_container_id = node->entity.entity_container_id;
+		*out = node;
+		return;
+	}
+
+	entity_association_tree_find(node->next_sibling, entity, out);
+	entity_association_tree_find(node->first_child, entity, out);
+}
+
+pldm_entity_node *
+pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
+				  pldm_entity *entity)
+{
+	assert(tree != NULL);
+
+	pldm_entity_node *node = NULL;
+	entity_association_tree_find(tree->root, entity, &node);
+	return node;
+}
+
+static void entity_association_tree_copy(pldm_entity_node *org_node,
+					 pldm_entity_node **new_node)
+{
+	if (org_node == NULL) {
+		return;
+	}
+	*new_node = malloc(sizeof(pldm_entity_node));
+	(*new_node)->parent = org_node->parent;
+	(*new_node)->entity = org_node->entity;
+	(*new_node)->association_type = org_node->association_type;
+	(*new_node)->first_child = NULL;
+	(*new_node)->next_sibling = NULL;
+	entity_association_tree_copy(org_node->first_child,
+				     &((*new_node)->first_child));
+	entity_association_tree_copy(org_node->next_sibling,
+				     &((*new_node)->next_sibling));
+}
+
+void pldm_entity_association_tree_copy_root(
+    pldm_entity_association_tree *org_tree,
+    pldm_entity_association_tree *new_tree)
+{
+	new_tree->last_used_container_id = org_tree->last_used_container_id;
+	entity_association_tree_copy(org_tree->root, &(new_tree->root));
+}
+
+void pldm_entity_association_tree_destroy_root(
+    pldm_entity_association_tree *tree)
+{
+	assert(tree != NULL);
+	entity_association_tree_destroy(tree->root);
+	tree->last_used_container_id = 0;
+	tree->root = NULL;
+}
+
+bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
+{
+	return ((tree->root == NULL) ? true : false);
+}
+
+void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
+					 size_t *num_entities,
+					 pldm_entity **entities)
+{
+	assert(pdr != NULL);
+	assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
+			      sizeof(struct pldm_pdr_entity_association));
+
+	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
+	assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
+
+	const uint8_t *start = (uint8_t *)pdr;
+	const uint8_t *end =
+	    start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
+	start += sizeof(struct pldm_pdr_hdr);
+	struct pldm_pdr_entity_association *entity_association_pdr =
+	    (struct pldm_pdr_entity_association *)start;
+	*num_entities = entity_association_pdr->num_children + 1;
+	assert(*num_entities >= 2);
+	*entities = malloc(sizeof(pldm_entity) * *num_entities);
+	assert(*entities != NULL);
+	assert(start + sizeof(struct pldm_pdr_entity_association) +
+		   sizeof(pldm_entity) * (*num_entities - 2) ==
+	       end);
+	(*entities)->entity_type =
+	    le16toh(entity_association_pdr->container.entity_type);
+	(*entities)->entity_instance_num =
+	    le16toh(entity_association_pdr->container.entity_instance_num);
+	(*entities)->entity_container_id =
+	    le16toh(entity_association_pdr->container.entity_container_id);
+	pldm_entity *curr_entity = entity_association_pdr->children;
+	size_t i = 1;
+	while (i < *num_entities) {
+		(*entities + i)->entity_type =
+		    le16toh(curr_entity->entity_type);
+		(*entities + i)->entity_instance_num =
+		    le16toh(curr_entity->entity_instance_num);
+		(*entities + i)->entity_container_id =
+		    le16toh(curr_entity->entity_container_id);
+		++curr_entity;
+		++i;
+	}
+}