xref: /openbmc/libpldm/src/dsp/pdr.c (revision 5192e2e26f26ffbbf4256429ea5ae42237e011cc)
148761c62SAndrew Jeffery /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2860a43d9SAndrew Jeffery #include "compiler.h"
348761c62SAndrew Jeffery #include "msgbuf.h"
448761c62SAndrew Jeffery #include <libpldm/pdr.h>
548761c62SAndrew Jeffery #include <libpldm/platform.h>
648761c62SAndrew Jeffery 
748761c62SAndrew Jeffery #include <assert.h>
848761c62SAndrew Jeffery #include <endian.h>
99e566597SAndrew Jeffery #include <stdint.h>
1048761c62SAndrew Jeffery #include <stdlib.h>
1148761c62SAndrew Jeffery #include <string.h>
1248761c62SAndrew Jeffery #include <errno.h>
1348761c62SAndrew Jeffery 
1448761c62SAndrew Jeffery #define PDR_ENTITY_ASSOCIATION_MIN_SIZE                                        \
1548761c62SAndrew Jeffery 	(sizeof(struct pldm_pdr_hdr) +                                         \
1648761c62SAndrew Jeffery 	 sizeof(struct pldm_pdr_entity_association))
1748761c62SAndrew Jeffery 
188b53ad9dSVarsha Kaverappa #define PDR_FRU_RECORD_SET_MIN_SIZE                                            \
198b53ad9dSVarsha Kaverappa 	(sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
208b53ad9dSVarsha Kaverappa 
2148761c62SAndrew Jeffery typedef struct pldm_pdr_record {
2248761c62SAndrew Jeffery 	uint32_t record_handle;
2348761c62SAndrew Jeffery 	uint32_t size;
2448761c62SAndrew Jeffery 	uint8_t *data;
2548761c62SAndrew Jeffery 	struct pldm_pdr_record *next;
2648761c62SAndrew Jeffery 	bool is_remote;
2748761c62SAndrew Jeffery 	uint16_t terminus_handle;
2848761c62SAndrew Jeffery } pldm_pdr_record;
2948761c62SAndrew Jeffery 
3048761c62SAndrew Jeffery typedef struct pldm_pdr {
3148761c62SAndrew Jeffery 	uint32_t record_count;
3248761c62SAndrew Jeffery 	uint32_t size;
3348761c62SAndrew Jeffery 	pldm_pdr_record *first;
3448761c62SAndrew Jeffery 	pldm_pdr_record *last;
3548761c62SAndrew Jeffery } pldm_pdr;
3648761c62SAndrew Jeffery 
37890d37a3SAndrew Jeffery LIBPLDM_CC_NONNULL
3894e2d754SArchana Kakani static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
3994e2d754SArchana Kakani 						 pldm_pdr_record *record);
4094e2d754SArchana Kakani 
4194e2d754SArchana Kakani LIBPLDM_CC_NONNULL_ARGS(1, 2)
4294e2d754SArchana Kakani static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
4394e2d754SArchana Kakani 				  pldm_pdr_record *prev);
4494e2d754SArchana Kakani 
4594e2d754SArchana Kakani LIBPLDM_CC_NONNULL
get_next_record_handle(const pldm_pdr * repo,const pldm_pdr_record * record)4648761c62SAndrew Jeffery static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
4748761c62SAndrew Jeffery 					      const pldm_pdr_record *record)
4848761c62SAndrew Jeffery {
4948761c62SAndrew Jeffery 	if (record == repo->last) {
5048761c62SAndrew Jeffery 		return 0;
5148761c62SAndrew Jeffery 	}
5248761c62SAndrew Jeffery 	return record->next->record_handle;
5348761c62SAndrew Jeffery }
5448761c62SAndrew Jeffery 
5548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_add(pldm_pdr * repo,const uint8_t * data,uint32_t size,bool is_remote,uint16_t terminus_handle,uint32_t * record_handle)56fae3641dSAndrew Jeffery int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
5748761c62SAndrew Jeffery 		 bool is_remote, uint16_t terminus_handle,
5848761c62SAndrew Jeffery 		 uint32_t *record_handle)
5948761c62SAndrew Jeffery {
608b53ad9dSVarsha Kaverappa 	uint32_t curr = 0;
6148761c62SAndrew Jeffery 
6248761c62SAndrew Jeffery 	if (!repo || !data || !size) {
6348761c62SAndrew Jeffery 		return -EINVAL;
6448761c62SAndrew Jeffery 	}
6548761c62SAndrew Jeffery 
6648761c62SAndrew Jeffery 	if (record_handle && *record_handle) {
6748761c62SAndrew Jeffery 		curr = *record_handle;
6848761c62SAndrew Jeffery 	} else if (repo->last) {
6948761c62SAndrew Jeffery 		curr = repo->last->record_handle;
7048761c62SAndrew Jeffery 		if (curr == UINT32_MAX) {
7148761c62SAndrew Jeffery 			return -EOVERFLOW;
7248761c62SAndrew Jeffery 		}
7348761c62SAndrew Jeffery 		curr += 1;
7448761c62SAndrew Jeffery 	} else {
7548761c62SAndrew Jeffery 		curr = 1;
7648761c62SAndrew Jeffery 	}
7748761c62SAndrew Jeffery 
7848761c62SAndrew Jeffery 	pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
7948761c62SAndrew Jeffery 	if (!record) {
8048761c62SAndrew Jeffery 		return -ENOMEM;
8148761c62SAndrew Jeffery 	}
8248761c62SAndrew Jeffery 
8348761c62SAndrew Jeffery 	if (data) {
8448761c62SAndrew Jeffery 		record->data = malloc(size);
8548761c62SAndrew Jeffery 		if (!record->data) {
8648761c62SAndrew Jeffery 			free(record);
8748761c62SAndrew Jeffery 			return -ENOMEM;
8848761c62SAndrew Jeffery 		}
8948761c62SAndrew Jeffery 		memcpy(record->data, data, size);
9048761c62SAndrew Jeffery 	}
9148761c62SAndrew Jeffery 
9248761c62SAndrew Jeffery 	record->size = size;
9348761c62SAndrew Jeffery 	record->is_remote = is_remote;
9448761c62SAndrew Jeffery 	record->terminus_handle = terminus_handle;
9548761c62SAndrew Jeffery 	record->record_handle = curr;
9648761c62SAndrew Jeffery 
9748761c62SAndrew Jeffery 	if (record_handle && !*record_handle && data) {
9848761c62SAndrew Jeffery 		/* If record handle is 0, that is an indication for this API to
9948761c62SAndrew Jeffery 		 * compute a new handle. For that reason, the computed handle
10048761c62SAndrew Jeffery 		 * needs to be populated in the PDR header. For a case where the
10148761c62SAndrew Jeffery 		 * caller supplied the record handle, it would exist in the
10248761c62SAndrew Jeffery 		 * header already.
10348761c62SAndrew Jeffery 		 */
10448761c62SAndrew Jeffery 		struct pldm_pdr_hdr *hdr = (void *)record->data;
10548761c62SAndrew Jeffery 		hdr->record_handle = htole32(record->record_handle);
10648761c62SAndrew Jeffery 	}
10748761c62SAndrew Jeffery 
10848761c62SAndrew Jeffery 	record->next = NULL;
10948761c62SAndrew Jeffery 
11048761c62SAndrew Jeffery 	assert(!repo->first == !repo->last);
11148761c62SAndrew Jeffery 	if (repo->first == NULL) {
11248761c62SAndrew Jeffery 		repo->first = record;
11348761c62SAndrew Jeffery 		repo->last = record;
11448761c62SAndrew Jeffery 	} else {
11548761c62SAndrew Jeffery 		repo->last->next = record;
11648761c62SAndrew Jeffery 		repo->last = record;
11748761c62SAndrew Jeffery 	}
11848761c62SAndrew Jeffery 
11948761c62SAndrew Jeffery 	repo->size += record->size;
12048761c62SAndrew Jeffery 	++repo->record_count;
12148761c62SAndrew Jeffery 
12248761c62SAndrew Jeffery 	if (record_handle) {
12348761c62SAndrew Jeffery 		*record_handle = record->record_handle;
12448761c62SAndrew Jeffery 	}
12548761c62SAndrew Jeffery 
12648761c62SAndrew Jeffery 	return 0;
12748761c62SAndrew Jeffery }
12848761c62SAndrew Jeffery 
12948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_init(void)13048761c62SAndrew Jeffery pldm_pdr *pldm_pdr_init(void)
13148761c62SAndrew Jeffery {
13248761c62SAndrew Jeffery 	pldm_pdr *repo = malloc(sizeof(pldm_pdr));
13348761c62SAndrew Jeffery 	if (!repo) {
13448761c62SAndrew Jeffery 		return NULL;
13548761c62SAndrew Jeffery 	}
13648761c62SAndrew Jeffery 	repo->record_count = 0;
13748761c62SAndrew Jeffery 	repo->size = 0;
13848761c62SAndrew Jeffery 	repo->first = NULL;
13948761c62SAndrew Jeffery 	repo->last = NULL;
14048761c62SAndrew Jeffery 
14148761c62SAndrew Jeffery 	return repo;
14248761c62SAndrew Jeffery }
14348761c62SAndrew Jeffery 
14448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_destroy(pldm_pdr * repo)14548761c62SAndrew Jeffery void pldm_pdr_destroy(pldm_pdr *repo)
14648761c62SAndrew Jeffery {
14748761c62SAndrew Jeffery 	if (!repo) {
14848761c62SAndrew Jeffery 		return;
14948761c62SAndrew Jeffery 	}
15048761c62SAndrew Jeffery 
15148761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
15248761c62SAndrew Jeffery 	while (record != NULL) {
15348761c62SAndrew Jeffery 		pldm_pdr_record *next = record->next;
15448761c62SAndrew Jeffery 		if (record->data) {
15548761c62SAndrew Jeffery 			free(record->data);
15648761c62SAndrew Jeffery 			record->data = NULL;
15748761c62SAndrew Jeffery 		}
15848761c62SAndrew Jeffery 		free(record);
15948761c62SAndrew Jeffery 		record = next;
16048761c62SAndrew Jeffery 	}
16148761c62SAndrew Jeffery 	free(repo);
16248761c62SAndrew Jeffery }
16348761c62SAndrew Jeffery 
16448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_find_record(const pldm_pdr * repo,uint32_t record_handle,uint8_t ** data,uint32_t * size,uint32_t * next_record_handle)16548761c62SAndrew Jeffery const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
16648761c62SAndrew Jeffery 					    uint32_t record_handle,
16748761c62SAndrew Jeffery 					    uint8_t **data, uint32_t *size,
16848761c62SAndrew Jeffery 					    uint32_t *next_record_handle)
16948761c62SAndrew Jeffery {
17048761c62SAndrew Jeffery 	if (!repo || !data || !size || !next_record_handle) {
17148761c62SAndrew Jeffery 		return NULL;
17248761c62SAndrew Jeffery 	}
17348761c62SAndrew Jeffery 
17448761c62SAndrew Jeffery 	if (!record_handle && (repo->first != NULL)) {
17548761c62SAndrew Jeffery 		record_handle = repo->first->record_handle;
17648761c62SAndrew Jeffery 	}
17748761c62SAndrew Jeffery 
17848761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
17948761c62SAndrew Jeffery 	while (record != NULL) {
18048761c62SAndrew Jeffery 		if (record->record_handle == record_handle) {
18148761c62SAndrew Jeffery 			*size = record->size;
18248761c62SAndrew Jeffery 			*data = record->data;
18348761c62SAndrew Jeffery 			*next_record_handle =
18448761c62SAndrew Jeffery 				get_next_record_handle(repo, record);
18548761c62SAndrew Jeffery 			return record;
18648761c62SAndrew Jeffery 		}
18748761c62SAndrew Jeffery 		record = record->next;
18848761c62SAndrew Jeffery 	}
18948761c62SAndrew Jeffery 
19048761c62SAndrew Jeffery 	*size = 0;
19148761c62SAndrew Jeffery 	*next_record_handle = 0;
19248761c62SAndrew Jeffery 	return NULL;
19348761c62SAndrew Jeffery }
19448761c62SAndrew Jeffery 
19548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
19648761c62SAndrew Jeffery 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)19748761c62SAndrew Jeffery pldm_pdr_get_next_record(const pldm_pdr *repo,
19848761c62SAndrew Jeffery 			 const pldm_pdr_record *curr_record, uint8_t **data,
19948761c62SAndrew Jeffery 			 uint32_t *size, uint32_t *next_record_handle)
20048761c62SAndrew Jeffery {
20148761c62SAndrew Jeffery 	if (!repo || !curr_record || !data || !size || !next_record_handle) {
20248761c62SAndrew Jeffery 		return NULL;
20348761c62SAndrew Jeffery 	}
20448761c62SAndrew Jeffery 
20548761c62SAndrew Jeffery 	if (curr_record == repo->last) {
20648761c62SAndrew Jeffery 		*data = NULL;
20748761c62SAndrew Jeffery 		*size = 0;
20848761c62SAndrew Jeffery 		*next_record_handle = get_next_record_handle(repo, curr_record);
20948761c62SAndrew Jeffery 		return NULL;
21048761c62SAndrew Jeffery 	}
21148761c62SAndrew Jeffery 
21248761c62SAndrew Jeffery 	*next_record_handle = get_next_record_handle(repo, curr_record->next);
21348761c62SAndrew Jeffery 	*data = curr_record->next->data;
21448761c62SAndrew Jeffery 	*size = curr_record->next->size;
21548761c62SAndrew Jeffery 	return curr_record->next;
21648761c62SAndrew Jeffery }
21748761c62SAndrew Jeffery 
21848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
21948761c62SAndrew Jeffery 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)22048761c62SAndrew Jeffery pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
22148761c62SAndrew Jeffery 			     const pldm_pdr_record *curr_record, uint8_t **data,
22248761c62SAndrew Jeffery 			     uint32_t *size)
22348761c62SAndrew Jeffery {
22448761c62SAndrew Jeffery 	if (!repo) {
22548761c62SAndrew Jeffery 		return NULL;
22648761c62SAndrew Jeffery 	}
22748761c62SAndrew Jeffery 
22848761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
22948761c62SAndrew Jeffery 	if (curr_record != NULL) {
23048761c62SAndrew Jeffery 		record = curr_record->next;
23148761c62SAndrew Jeffery 	}
23248761c62SAndrew Jeffery 	while (record != NULL) {
23348761c62SAndrew Jeffery 		struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
23448761c62SAndrew Jeffery 		if (hdr->type == pdr_type) {
23548761c62SAndrew Jeffery 			if (data && size) {
23648761c62SAndrew Jeffery 				*size = record->size;
23748761c62SAndrew Jeffery 				*data = record->data;
23848761c62SAndrew Jeffery 			}
23948761c62SAndrew Jeffery 			return record;
24048761c62SAndrew Jeffery 		}
24148761c62SAndrew Jeffery 		record = record->next;
24248761c62SAndrew Jeffery 	}
24348761c62SAndrew Jeffery 
24448761c62SAndrew Jeffery 	if (size) {
24548761c62SAndrew Jeffery 		*size = 0;
24648761c62SAndrew Jeffery 	}
24748761c62SAndrew Jeffery 	return NULL;
24848761c62SAndrew Jeffery }
24948761c62SAndrew Jeffery 
25048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_get_record_count(const pldm_pdr * repo)25148761c62SAndrew Jeffery uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
25248761c62SAndrew Jeffery {
25348761c62SAndrew Jeffery 	assert(repo != NULL);
25448761c62SAndrew Jeffery 
25548761c62SAndrew Jeffery 	return repo->record_count;
25648761c62SAndrew Jeffery }
25748761c62SAndrew Jeffery 
25848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_get_repo_size(const pldm_pdr * repo)25948761c62SAndrew Jeffery uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
26048761c62SAndrew Jeffery {
26148761c62SAndrew Jeffery 	assert(repo != NULL);
26248761c62SAndrew Jeffery 
26348761c62SAndrew Jeffery 	return repo->size;
26448761c62SAndrew Jeffery }
26548761c62SAndrew Jeffery 
26648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_get_record_handle(const pldm_pdr * repo LIBPLDM_CC_UNUSED,const pldm_pdr_record * record)267860a43d9SAndrew Jeffery uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
26848761c62SAndrew Jeffery 				    const pldm_pdr_record *record)
26948761c62SAndrew Jeffery {
27048761c62SAndrew Jeffery 	assert(repo != NULL);
27148761c62SAndrew Jeffery 	assert(record != NULL);
27248761c62SAndrew Jeffery 
27348761c62SAndrew Jeffery 	return record->record_handle;
27448761c62SAndrew Jeffery }
27548761c62SAndrew Jeffery 
276274732fcSPavithra Barithaya LIBPLDM_ABI_TESTING
pldm_pdr_get_terminus_handle(const pldm_pdr * repo LIBPLDM_CC_UNUSED,const pldm_pdr_record * record)277860a43d9SAndrew Jeffery uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
278274732fcSPavithra Barithaya 				      const pldm_pdr_record *record)
279274732fcSPavithra Barithaya {
280274732fcSPavithra Barithaya 	assert(repo != NULL);
281274732fcSPavithra Barithaya 	assert(record != NULL);
282274732fcSPavithra Barithaya 
283274732fcSPavithra Barithaya 	return record->terminus_handle;
284274732fcSPavithra Barithaya }
285274732fcSPavithra Barithaya 
28648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_record_is_remote(const pldm_pdr_record * record)28748761c62SAndrew Jeffery bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
28848761c62SAndrew Jeffery {
28948761c62SAndrew Jeffery 	assert(record != NULL);
29048761c62SAndrew Jeffery 
29148761c62SAndrew Jeffery 	return record->is_remote;
29248761c62SAndrew Jeffery }
29348761c62SAndrew Jeffery 
29448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)295e7f55113SAndrew Jeffery int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
29648761c62SAndrew Jeffery 				uint16_t fru_rsi, uint16_t entity_type,
29748761c62SAndrew Jeffery 				uint16_t entity_instance_num,
29848761c62SAndrew Jeffery 				uint16_t container_id,
29948761c62SAndrew Jeffery 				uint32_t *bmc_record_handle)
30048761c62SAndrew Jeffery {
30148761c62SAndrew Jeffery 	if (!repo || !bmc_record_handle) {
30248761c62SAndrew Jeffery 		return -EINVAL;
30348761c62SAndrew Jeffery 	}
30448761c62SAndrew Jeffery 
3055c49f162SAndrew Jeffery 	uint8_t data[sizeof(struct pldm_pdr_hdr) +
3065c49f162SAndrew Jeffery 		     sizeof(struct pldm_pdr_fru_record_set)];
30748761c62SAndrew Jeffery 
30848761c62SAndrew Jeffery 	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
30948761c62SAndrew Jeffery 	hdr->version = 1;
31048761c62SAndrew Jeffery 	hdr->record_handle = *bmc_record_handle;
31148761c62SAndrew Jeffery 	hdr->type = PLDM_PDR_FRU_RECORD_SET;
31248761c62SAndrew Jeffery 	hdr->record_change_num = 0;
31348761c62SAndrew Jeffery 	hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
31448761c62SAndrew Jeffery 	struct pldm_pdr_fru_record_set *fru =
31548761c62SAndrew Jeffery 		(struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
31648761c62SAndrew Jeffery 						   sizeof(struct pldm_pdr_hdr));
31748761c62SAndrew Jeffery 	fru->terminus_handle = htole16(terminus_handle);
31848761c62SAndrew Jeffery 	fru->fru_rsi = htole16(fru_rsi);
31948761c62SAndrew Jeffery 	fru->entity_type = htole16(entity_type);
32048761c62SAndrew Jeffery 	fru->entity_instance_num = htole16(entity_instance_num);
32148761c62SAndrew Jeffery 	fru->container_id = htole16(container_id);
32248761c62SAndrew Jeffery 
3235c49f162SAndrew Jeffery 	return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
32448761c62SAndrew Jeffery 			    bmc_record_handle);
32548761c62SAndrew Jeffery }
32648761c62SAndrew Jeffery 
32748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
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)32848761c62SAndrew Jeffery const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
32948761c62SAndrew Jeffery 	const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
33048761c62SAndrew Jeffery 	uint16_t *entity_type, uint16_t *entity_instance_num,
33148761c62SAndrew Jeffery 	uint16_t *container_id)
33248761c62SAndrew Jeffery {
33348761c62SAndrew Jeffery 	if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
33448761c62SAndrew Jeffery 	    !container_id) {
33548761c62SAndrew Jeffery 		return NULL;
33648761c62SAndrew Jeffery 	}
33748761c62SAndrew Jeffery 
33848761c62SAndrew Jeffery 	uint8_t *data = NULL;
33948761c62SAndrew Jeffery 	uint32_t size = 0;
34048761c62SAndrew Jeffery 	const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
34148761c62SAndrew Jeffery 		repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
34248761c62SAndrew Jeffery 	while (curr_record != NULL) {
34348761c62SAndrew Jeffery 		struct pldm_pdr_fru_record_set *fru =
34448761c62SAndrew Jeffery 			(struct pldm_pdr_fru_record_set
34548761c62SAndrew Jeffery 				 *)(data + sizeof(struct pldm_pdr_hdr));
34648761c62SAndrew Jeffery 		if (fru->fru_rsi == htole16(fru_rsi)) {
34748761c62SAndrew Jeffery 			*terminus_handle = le16toh(fru->terminus_handle);
34848761c62SAndrew Jeffery 			*entity_type = le16toh(fru->entity_type);
34948761c62SAndrew Jeffery 			*entity_instance_num =
35048761c62SAndrew Jeffery 				le16toh(fru->entity_instance_num);
35148761c62SAndrew Jeffery 			*container_id = le16toh(fru->container_id);
35248761c62SAndrew Jeffery 			return curr_record;
35348761c62SAndrew Jeffery 		}
35448761c62SAndrew Jeffery 		data = NULL;
35548761c62SAndrew Jeffery 		curr_record = pldm_pdr_find_record_by_type(
35648761c62SAndrew Jeffery 			repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
35748761c62SAndrew Jeffery 			&size);
35848761c62SAndrew Jeffery 	}
35948761c62SAndrew Jeffery 
36048761c62SAndrew Jeffery 	*terminus_handle = 0;
36148761c62SAndrew Jeffery 	*entity_type = 0;
36248761c62SAndrew Jeffery 	*entity_instance_num = 0;
36348761c62SAndrew Jeffery 	*container_id = 0;
36448761c62SAndrew Jeffery 
36548761c62SAndrew Jeffery 	return NULL;
36648761c62SAndrew Jeffery }
36748761c62SAndrew Jeffery 
36848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
36948761c62SAndrew Jeffery /* NOLINTNEXTLINE(readability-identifier-naming) */
pldm_pdr_update_TL_pdr(const pldm_pdr * repo,uint16_t terminus_handle,uint8_t tid,uint8_t tl_eid,bool valid_bit)37048761c62SAndrew Jeffery void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
37148761c62SAndrew Jeffery 			    uint8_t tid, uint8_t tl_eid, bool valid_bit)
37248761c62SAndrew Jeffery {
37348761c62SAndrew Jeffery 	uint8_t *out_data = NULL;
37448761c62SAndrew Jeffery 	uint32_t size = 0;
37548761c62SAndrew Jeffery 	const pldm_pdr_record *record;
37648761c62SAndrew Jeffery 	record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
37748761c62SAndrew Jeffery 					      NULL, &out_data, &size);
37848761c62SAndrew Jeffery 
37948761c62SAndrew Jeffery 	do {
38048761c62SAndrew Jeffery 		if (record != NULL) {
38148761c62SAndrew Jeffery 			struct pldm_terminus_locator_pdr *pdr =
38248761c62SAndrew Jeffery 				(struct pldm_terminus_locator_pdr *)out_data;
38348761c62SAndrew Jeffery 			struct pldm_terminus_locator_type_mctp_eid *value =
38448761c62SAndrew Jeffery 				(struct pldm_terminus_locator_type_mctp_eid *)
38548761c62SAndrew Jeffery 					pdr->terminus_locator_value;
38648761c62SAndrew Jeffery 			if (pdr->terminus_handle == terminus_handle &&
38748761c62SAndrew Jeffery 			    pdr->tid == tid && value->eid == tl_eid) {
38848761c62SAndrew Jeffery 				pdr->validity = valid_bit;
38948761c62SAndrew Jeffery 				break;
39048761c62SAndrew Jeffery 			}
39148761c62SAndrew Jeffery 		}
39248761c62SAndrew Jeffery 		record = pldm_pdr_find_record_by_type(repo,
39348761c62SAndrew Jeffery 						      PLDM_TERMINUS_LOCATOR_PDR,
39448761c62SAndrew Jeffery 						      record, &out_data, &size);
39548761c62SAndrew Jeffery 	} while (record);
39648761c62SAndrew Jeffery }
39748761c62SAndrew Jeffery 
pldm_record_handle_in_range(uint32_t record_handle,uint32_t first_record_handle,uint32_t last_record_handle)39848761c62SAndrew Jeffery static bool pldm_record_handle_in_range(uint32_t record_handle,
39948761c62SAndrew Jeffery 					uint32_t first_record_handle,
40048761c62SAndrew Jeffery 					uint32_t last_record_handle)
40148761c62SAndrew Jeffery {
40248761c62SAndrew Jeffery 	return record_handle >= first_record_handle &&
40348761c62SAndrew Jeffery 	       record_handle <= last_record_handle;
40448761c62SAndrew Jeffery }
40548761c62SAndrew Jeffery 
40648761c62SAndrew Jeffery LIBPLDM_ABI_TESTING
pldm_pdr_find_child_container_id_index_range_exclude(const pldm_pdr * repo,uint16_t entity_type,uint16_t entity_instance,uint8_t child_index,uint32_t range_exclude_start_handle,uint32_t range_exclude_end_handle,uint16_t * container_id)40748761c62SAndrew Jeffery int pldm_pdr_find_child_container_id_index_range_exclude(
40848761c62SAndrew Jeffery 	const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
40948761c62SAndrew Jeffery 	uint8_t child_index, uint32_t range_exclude_start_handle,
41048761c62SAndrew Jeffery 	uint32_t range_exclude_end_handle, uint16_t *container_id)
41148761c62SAndrew Jeffery {
41248761c62SAndrew Jeffery 	pldm_pdr_record *record;
41348761c62SAndrew Jeffery 	if (!repo) {
41448761c62SAndrew Jeffery 		return -EINVAL;
41548761c62SAndrew Jeffery 	}
41648761c62SAndrew Jeffery 
41748761c62SAndrew Jeffery 	for (record = repo->first; record; record = record->next) {
41848761c62SAndrew Jeffery 		bool is_container_entity_instance_number;
41948761c62SAndrew Jeffery 		struct pldm_pdr_entity_association *pdr;
42048761c62SAndrew Jeffery 		bool is_container_entity_type;
42148761c62SAndrew Jeffery 		struct pldm_entity *child;
42248761c62SAndrew Jeffery 		struct pldm_pdr_hdr *hdr;
42348761c62SAndrew Jeffery 		bool in_range;
42448761c62SAndrew Jeffery 
42548761c62SAndrew Jeffery 		// pldm_pdr_add() takes only uint8_t* data as an argument.
42648761c62SAndrew Jeffery 		// The expectation here is the pldm_pdr_hdr is the first field of the record data
42748761c62SAndrew Jeffery 		hdr = (struct pldm_pdr_hdr *)record->data;
42848761c62SAndrew Jeffery 		if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
42948761c62SAndrew Jeffery 			continue;
43048761c62SAndrew Jeffery 		}
43148761c62SAndrew Jeffery 		in_range = pldm_record_handle_in_range(
43248761c62SAndrew Jeffery 			record->record_handle, range_exclude_start_handle,
43348761c62SAndrew Jeffery 			range_exclude_end_handle);
43448761c62SAndrew Jeffery 		if (in_range) {
43548761c62SAndrew Jeffery 			continue;
43648761c62SAndrew Jeffery 		}
43748761c62SAndrew Jeffery 
43848761c62SAndrew Jeffery 		// this cast is valid with respect to alignment because
43948761c62SAndrew Jeffery 		// struct pldm_pdr_hdr is declared with __attribute__((packed))
44048761c62SAndrew Jeffery 		pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
44148761c62SAndrew Jeffery 		if (child_index >= pdr->num_children) {
44248761c62SAndrew Jeffery 			continue;
44348761c62SAndrew Jeffery 		}
44448761c62SAndrew Jeffery 
44548761c62SAndrew Jeffery 		child = (&pdr->children[child_index]);
44648761c62SAndrew Jeffery 		is_container_entity_type = pdr->container.entity_type ==
44748761c62SAndrew Jeffery 					   entity_type;
44848761c62SAndrew Jeffery 		is_container_entity_instance_number =
44948761c62SAndrew Jeffery 			pdr->container.entity_instance_num == entity_instance;
45048761c62SAndrew Jeffery 		if (is_container_entity_type &&
45148761c62SAndrew Jeffery 		    is_container_entity_instance_number) {
45248761c62SAndrew Jeffery 			*container_id = le16toh(child->entity_container_id);
45348761c62SAndrew Jeffery 			return 0;
45448761c62SAndrew Jeffery 		}
45548761c62SAndrew Jeffery 	}
456ae05d5e5SMatt Johnston 	return -ENOENT;
45748761c62SAndrew Jeffery }
45848761c62SAndrew Jeffery 
459*5192e2e2SPavithra Barithaya LIBPLDM_ABI_TESTING
460*5192e2e2SPavithra Barithaya int pldm_pdr_delete_by_record_handle(pldm_pdr *repo, uint32_t record_handle,
461*5192e2e2SPavithra Barithaya 				     bool is_remote)
462*5192e2e2SPavithra Barithaya {
463*5192e2e2SPavithra Barithaya 	pldm_pdr_record *record;
464*5192e2e2SPavithra Barithaya 	pldm_pdr_record *prev = NULL;
465*5192e2e2SPavithra Barithaya 	int rc = 0;
466*5192e2e2SPavithra Barithaya 	uint16_t rec_handle = 0;
467*5192e2e2SPavithra Barithaya 
468*5192e2e2SPavithra Barithaya 	if (!repo) {
469*5192e2e2SPavithra Barithaya 		return -EINVAL;
470*5192e2e2SPavithra Barithaya 	}
471*5192e2e2SPavithra Barithaya 	record = repo->first;
472*5192e2e2SPavithra Barithaya 
473*5192e2e2SPavithra Barithaya 	while (record != NULL) {
pldm_entity_extract(pldm_entity_node * node)474*5192e2e2SPavithra Barithaya 		struct pldm_msgbuf _buf;
475*5192e2e2SPavithra Barithaya 		struct pldm_msgbuf *buf = &_buf;
476*5192e2e2SPavithra Barithaya 		rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
477*5192e2e2SPavithra Barithaya 					    record->data, record->size);
478*5192e2e2SPavithra Barithaya 
479*5192e2e2SPavithra Barithaya 		if (rc) {
480*5192e2e2SPavithra Barithaya 			return rc;
481*5192e2e2SPavithra Barithaya 		}
482*5192e2e2SPavithra Barithaya 		if ((rc = pldm_msgbuf_extract(buf, rec_handle))) {
pldm_entity_node_get_remote_container_id(const pldm_entity_node * entity)483*5192e2e2SPavithra Barithaya 			return rc;
484*5192e2e2SPavithra Barithaya 		}
485*5192e2e2SPavithra Barithaya 		if (record->is_remote == is_remote &&
486*5192e2e2SPavithra Barithaya 		    rec_handle == record_handle) {
487*5192e2e2SPavithra Barithaya 			prev = pldm_pdr_get_prev_record(repo, record);
488*5192e2e2SPavithra Barithaya 			return pldm_pdr_remove_record(repo, record, prev);
489*5192e2e2SPavithra Barithaya 		}
490*5192e2e2SPavithra Barithaya 		rc = pldm_msgbuf_destroy(buf);
pldm_entity_association_tree_init(void)491*5192e2e2SPavithra Barithaya 		if (rc) {
492*5192e2e2SPavithra Barithaya 			return rc;
493*5192e2e2SPavithra Barithaya 		}
494*5192e2e2SPavithra Barithaya 		record = record->next;
495*5192e2e2SPavithra Barithaya 	}
496*5192e2e2SPavithra Barithaya 	return -ENOENT;
497*5192e2e2SPavithra Barithaya }
498*5192e2e2SPavithra Barithaya 
49948761c62SAndrew Jeffery typedef struct pldm_entity_association_tree {
50048761c62SAndrew Jeffery 	pldm_entity_node *root;
50148761c62SAndrew Jeffery 	uint16_t last_used_container_id;
50248761c62SAndrew Jeffery } pldm_entity_association_tree;
50348761c62SAndrew Jeffery 
50448761c62SAndrew Jeffery typedef struct pldm_entity_node {
find_insertion_at(pldm_entity_node * start,uint16_t entity_type)50548761c62SAndrew Jeffery 	pldm_entity entity;
50648761c62SAndrew Jeffery 	pldm_entity parent;
50748761c62SAndrew Jeffery 	uint16_t remote_container_id;
50848761c62SAndrew Jeffery 	pldm_entity_node *first_child;
50948761c62SAndrew Jeffery 	pldm_entity_node *next_sibling;
51048761c62SAndrew Jeffery 	uint8_t association_type;
51148761c62SAndrew Jeffery } pldm_entity_node;
51248761c62SAndrew Jeffery 
51348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
51448761c62SAndrew Jeffery pldm_entity pldm_entity_extract(pldm_entity_node *node)
51548761c62SAndrew Jeffery {
51648761c62SAndrew Jeffery 	assert(node != NULL);
51748761c62SAndrew Jeffery 
51848761c62SAndrew Jeffery 	return node->entity;
51948761c62SAndrew Jeffery }
52048761c62SAndrew Jeffery 
52148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
52248761c62SAndrew Jeffery uint16_t
52348761c62SAndrew Jeffery pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
52448761c62SAndrew Jeffery {
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)52548761c62SAndrew Jeffery 	assert(entity != NULL);
52648761c62SAndrew Jeffery 
52748761c62SAndrew Jeffery 	return entity->remote_container_id;
52848761c62SAndrew Jeffery }
52948761c62SAndrew Jeffery 
53048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
53148761c62SAndrew Jeffery pldm_entity_association_tree *pldm_entity_association_tree_init(void)
53248761c62SAndrew Jeffery {
53348761c62SAndrew Jeffery 	pldm_entity_association_tree *tree =
53448761c62SAndrew Jeffery 		malloc(sizeof(pldm_entity_association_tree));
53548761c62SAndrew Jeffery 	if (!tree) {
53648761c62SAndrew Jeffery 		return NULL;
pldm_entity_association_tree_add_entity(pldm_entity_association_tree * tree,pldm_entity * entity,uint16_t entity_instance_number,pldm_entity_node * parent,uint8_t association_type,bool is_remote,bool is_update_container_id,uint16_t container_id)53748761c62SAndrew Jeffery 	}
53848761c62SAndrew Jeffery 	tree->root = NULL;
53948761c62SAndrew Jeffery 	tree->last_used_container_id = 0;
54048761c62SAndrew Jeffery 
54148761c62SAndrew Jeffery 	return tree;
54248761c62SAndrew Jeffery }
54348761c62SAndrew Jeffery 
544890d37a3SAndrew Jeffery LIBPLDM_CC_NONNULL
54548761c62SAndrew Jeffery static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
54648761c62SAndrew Jeffery 					   uint16_t entity_type)
54748761c62SAndrew Jeffery {
54848761c62SAndrew Jeffery 	/* Insert after the the last node that matches the input entity type, or
5499e3a5d45SManojkiran Eda 	 * at the end if no such match occurs
55048761c62SAndrew Jeffery 	 */
55148761c62SAndrew Jeffery 	while (start->next_sibling != NULL) {
55248761c62SAndrew Jeffery 		uint16_t this_type = start->entity.entity_type;
55348761c62SAndrew Jeffery 		pldm_entity_node *next = start->next_sibling;
55448761c62SAndrew Jeffery 		if (this_type == entity_type &&
55548761c62SAndrew Jeffery 		    (this_type != next->entity.entity_type)) {
55648761c62SAndrew Jeffery 			break;
55748761c62SAndrew Jeffery 		}
55848761c62SAndrew Jeffery 		start = start->next_sibling;
55948761c62SAndrew Jeffery 	}
56048761c62SAndrew Jeffery 
56148761c62SAndrew Jeffery 	return start;
56248761c62SAndrew Jeffery }
56348761c62SAndrew Jeffery 
56448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
56548761c62SAndrew Jeffery pldm_entity_node *pldm_entity_association_tree_add(
56648761c62SAndrew Jeffery 	pldm_entity_association_tree *tree, pldm_entity *entity,
56748761c62SAndrew Jeffery 	uint16_t entity_instance_number, pldm_entity_node *parent,
56848761c62SAndrew Jeffery 	uint8_t association_type)
56948761c62SAndrew Jeffery {
57048761c62SAndrew Jeffery 	return pldm_entity_association_tree_add_entity(tree, entity,
57148761c62SAndrew Jeffery 						       entity_instance_number,
57248761c62SAndrew Jeffery 						       parent, association_type,
57348761c62SAndrew Jeffery 						       false, true, 0xffff);
57448761c62SAndrew Jeffery }
57548761c62SAndrew Jeffery 
57648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
57748761c62SAndrew Jeffery pldm_entity_node *pldm_entity_association_tree_add_entity(
57848761c62SAndrew Jeffery 	pldm_entity_association_tree *tree, pldm_entity *entity,
57948761c62SAndrew Jeffery 	uint16_t entity_instance_number, pldm_entity_node *parent,
58048761c62SAndrew Jeffery 	uint8_t association_type, bool is_remote, bool is_update_container_id,
58148761c62SAndrew Jeffery 	uint16_t container_id)
58248761c62SAndrew Jeffery {
58348761c62SAndrew Jeffery 	if ((!tree) || (!entity)) {
58448761c62SAndrew Jeffery 		return NULL;
58548761c62SAndrew Jeffery 	}
58648761c62SAndrew Jeffery 
58748761c62SAndrew Jeffery 	if (entity_instance_number != 0xffff && parent != NULL) {
58848761c62SAndrew Jeffery 		pldm_entity node;
58948761c62SAndrew Jeffery 		node.entity_type = entity->entity_type;
59048761c62SAndrew Jeffery 		node.entity_instance_num = entity_instance_number;
59148761c62SAndrew Jeffery 		if (pldm_is_current_parent_child(parent, &node)) {
59248761c62SAndrew Jeffery 			return NULL;
59348761c62SAndrew Jeffery 		}
59448761c62SAndrew Jeffery 	}
59548761c62SAndrew Jeffery 	if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
59648761c62SAndrew Jeffery 	    association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
59748761c62SAndrew Jeffery 		return NULL;
59848761c62SAndrew Jeffery 	}
59948761c62SAndrew Jeffery 	pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
60048761c62SAndrew Jeffery 	if (!node) {
60148761c62SAndrew Jeffery 		return NULL;
60248761c62SAndrew Jeffery 	}
60348761c62SAndrew Jeffery 	node->first_child = NULL;
60448761c62SAndrew Jeffery 	node->next_sibling = NULL;
60548761c62SAndrew Jeffery 	node->parent.entity_type = 0;
60648761c62SAndrew Jeffery 	node->parent.entity_instance_num = 0;
60748761c62SAndrew Jeffery 	node->parent.entity_container_id = 0;
60848761c62SAndrew Jeffery 	node->entity.entity_type = entity->entity_type;
60948761c62SAndrew Jeffery 	node->entity.entity_instance_num =
61048761c62SAndrew Jeffery 		entity_instance_number != 0xffff ? entity_instance_number : 1;
61148761c62SAndrew Jeffery 	node->association_type = association_type;
61248761c62SAndrew Jeffery 	node->remote_container_id = 0;
61348761c62SAndrew Jeffery 	if (tree->root == NULL) {
61448761c62SAndrew Jeffery 		if (parent != NULL) {
61548761c62SAndrew Jeffery 			free(node);
61648761c62SAndrew Jeffery 			return NULL;
61748761c62SAndrew Jeffery 		}
61848761c62SAndrew Jeffery 		tree->root = node;
61948761c62SAndrew Jeffery 		/* container_id 0 here indicates this is the top-most entry */
62048761c62SAndrew Jeffery 		node->entity.entity_container_id = 0;
62148761c62SAndrew Jeffery 		node->remote_container_id = node->entity.entity_container_id;
62248761c62SAndrew Jeffery 	} else if (parent != NULL && parent->first_child == NULL) {
62348761c62SAndrew Jeffery 		/* Ensure next_container_id() will yield a valid ID */
62448761c62SAndrew Jeffery 		if (tree->last_used_container_id == UINT16_MAX) {
62548761c62SAndrew Jeffery 			free(node);
62648761c62SAndrew Jeffery 			return NULL;
62748761c62SAndrew Jeffery 		}
62848761c62SAndrew Jeffery 
62948761c62SAndrew Jeffery 		parent->first_child = node;
63048761c62SAndrew Jeffery 		node->parent = parent->entity;
63148761c62SAndrew Jeffery 
63248761c62SAndrew Jeffery 		if (is_remote) {
63348761c62SAndrew Jeffery 			node->remote_container_id = entity->entity_container_id;
63448761c62SAndrew Jeffery 		}
63548761c62SAndrew Jeffery 		if (is_update_container_id) {
63648761c62SAndrew Jeffery 			if (container_id != 0xffff) {
63748761c62SAndrew Jeffery 				node->entity.entity_container_id = container_id;
63848761c62SAndrew Jeffery 			} else {
63905507773SAndrew Jeffery 				/* We will have returned above */
64005507773SAndrew Jeffery 				assert(tree->last_used_container_id !=
64105507773SAndrew Jeffery 				       UINT16_MAX);
64248761c62SAndrew Jeffery 				node->entity.entity_container_id =
64305507773SAndrew Jeffery 					++tree->last_used_container_id;
64448761c62SAndrew Jeffery 			}
64548761c62SAndrew Jeffery 		} else {
64648761c62SAndrew Jeffery 			node->entity.entity_container_id =
64748761c62SAndrew Jeffery 				entity->entity_container_id;
get_num_nodes(pldm_entity_node * node,size_t * num)64848761c62SAndrew Jeffery 		}
64948761c62SAndrew Jeffery 
65048761c62SAndrew Jeffery 		if (!is_remote) {
65148761c62SAndrew Jeffery 			node->remote_container_id =
65248761c62SAndrew Jeffery 				node->entity.entity_container_id;
65348761c62SAndrew Jeffery 		}
65448761c62SAndrew Jeffery 	} else {
65548761c62SAndrew Jeffery 		pldm_entity_node *start = parent == NULL ? tree->root :
65648761c62SAndrew Jeffery 							   parent->first_child;
65748761c62SAndrew Jeffery 		pldm_entity_node *prev =
65848761c62SAndrew Jeffery 			find_insertion_at(start, entity->entity_type);
entity_association_tree_visit(pldm_entity_node * node,pldm_entity * entities,size_t * index)65948761c62SAndrew Jeffery 		if (!prev) {
66048761c62SAndrew Jeffery 			free(node);
66148761c62SAndrew Jeffery 			return NULL;
66248761c62SAndrew Jeffery 		}
66348761c62SAndrew Jeffery 		pldm_entity_node *next = prev->next_sibling;
66448761c62SAndrew Jeffery 		if (prev->entity.entity_type == entity->entity_type) {
66548761c62SAndrew Jeffery 			if (prev->entity.entity_instance_num == UINT16_MAX) {
66648761c62SAndrew Jeffery 				free(node);
66748761c62SAndrew Jeffery 				return NULL;
66848761c62SAndrew Jeffery 			}
66948761c62SAndrew Jeffery 			node->entity.entity_instance_num =
67048761c62SAndrew Jeffery 				entity_instance_number != 0xffff ?
67148761c62SAndrew Jeffery 					entity_instance_number :
67248761c62SAndrew Jeffery 					prev->entity.entity_instance_num + 1;
67348761c62SAndrew Jeffery 		}
67448761c62SAndrew Jeffery 		prev->next_sibling = node;
67548761c62SAndrew Jeffery 		node->parent = prev->parent;
67648761c62SAndrew Jeffery 		node->next_sibling = next;
pldm_entity_association_tree_visit(pldm_entity_association_tree * tree,pldm_entity ** entities,size_t * size)67748761c62SAndrew Jeffery 		node->entity.entity_container_id =
67848761c62SAndrew Jeffery 			prev->entity.entity_container_id;
67948761c62SAndrew Jeffery 		node->remote_container_id = entity->entity_container_id;
68048761c62SAndrew Jeffery 	}
68148761c62SAndrew Jeffery 	entity->entity_instance_num = node->entity.entity_instance_num;
68248761c62SAndrew Jeffery 	if (is_update_container_id) {
68348761c62SAndrew Jeffery 		entity->entity_container_id = node->entity.entity_container_id;
68448761c62SAndrew Jeffery 	}
68548761c62SAndrew Jeffery 	return node;
68648761c62SAndrew Jeffery }
68748761c62SAndrew Jeffery 
68848761c62SAndrew Jeffery static void get_num_nodes(pldm_entity_node *node, size_t *num)
68948761c62SAndrew Jeffery {
69048761c62SAndrew Jeffery 	if (node == NULL) {
69148761c62SAndrew Jeffery 		return;
69248761c62SAndrew Jeffery 	}
69348761c62SAndrew Jeffery 
69448761c62SAndrew Jeffery 	++(*num);
69548761c62SAndrew Jeffery 	get_num_nodes(node->next_sibling, num);
69648761c62SAndrew Jeffery 	get_num_nodes(node->first_child, num);
69748761c62SAndrew Jeffery }
entity_association_tree_destroy(pldm_entity_node * node)69848761c62SAndrew Jeffery 
69948761c62SAndrew Jeffery static void entity_association_tree_visit(pldm_entity_node *node,
70048761c62SAndrew Jeffery 					  pldm_entity *entities, size_t *index)
70148761c62SAndrew Jeffery {
70248761c62SAndrew Jeffery 	if (node == NULL) {
70348761c62SAndrew Jeffery 		return;
70448761c62SAndrew Jeffery 	}
70548761c62SAndrew Jeffery 
70648761c62SAndrew Jeffery 	pldm_entity *entity = &entities[*index];
70748761c62SAndrew Jeffery 	++(*index);
70848761c62SAndrew Jeffery 	entity->entity_type = node->entity.entity_type;
70948761c62SAndrew Jeffery 	entity->entity_instance_num = node->entity.entity_instance_num;
71048761c62SAndrew Jeffery 	entity->entity_container_id = node->entity.entity_container_id;
71148761c62SAndrew Jeffery 
71248761c62SAndrew Jeffery 	entity_association_tree_visit(node->next_sibling, entities, index);
71348761c62SAndrew Jeffery 	entity_association_tree_visit(node->first_child, entities, index);
71448761c62SAndrew Jeffery }
71548761c62SAndrew Jeffery 
71648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
71748761c62SAndrew Jeffery void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
71848761c62SAndrew Jeffery 					pldm_entity **entities, size_t *size)
71948761c62SAndrew Jeffery {
72048761c62SAndrew Jeffery 	if (!tree || !entities || !size) {
pldm_entity_is_node_parent(pldm_entity_node * node)72148761c62SAndrew Jeffery 		return;
72248761c62SAndrew Jeffery 	}
72348761c62SAndrew Jeffery 
72448761c62SAndrew Jeffery 	*size = 0;
72548761c62SAndrew Jeffery 	if (tree->root == NULL) {
72648761c62SAndrew Jeffery 		return;
72748761c62SAndrew Jeffery 	}
72848761c62SAndrew Jeffery 
pldm_entity_get_parent(pldm_entity_node * node)72948761c62SAndrew Jeffery 	get_num_nodes(tree->root, size);
73048761c62SAndrew Jeffery 	*entities = malloc(*size * sizeof(pldm_entity));
73148761c62SAndrew Jeffery 	if (!entities) {
73248761c62SAndrew Jeffery 		return;
73348761c62SAndrew Jeffery 	}
73448761c62SAndrew Jeffery 	size_t index = 0;
73548761c62SAndrew Jeffery 	entity_association_tree_visit(tree->root, *entities, &index);
73648761c62SAndrew Jeffery }
pldm_entity_is_exist_parent(pldm_entity_node * node)73748761c62SAndrew Jeffery 
73848761c62SAndrew Jeffery static void entity_association_tree_destroy(pldm_entity_node *node)
73948761c62SAndrew Jeffery {
74048761c62SAndrew Jeffery 	if (node == NULL) {
74148761c62SAndrew Jeffery 		return;
74248761c62SAndrew Jeffery 	}
74348761c62SAndrew Jeffery 
74448761c62SAndrew Jeffery 	entity_association_tree_destroy(node->next_sibling);
74548761c62SAndrew Jeffery 	entity_association_tree_destroy(node->first_child);
74648761c62SAndrew Jeffery 	free(node);
74748761c62SAndrew Jeffery }
74848761c62SAndrew Jeffery 
74948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
75048761c62SAndrew Jeffery void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
75148761c62SAndrew Jeffery {
75248761c62SAndrew Jeffery 	if (!tree) {
pldm_entity_get_num_children(pldm_entity_node * node,uint8_t association_type)75348761c62SAndrew Jeffery 		return;
75448761c62SAndrew Jeffery 	}
75548761c62SAndrew Jeffery 
75648761c62SAndrew Jeffery 	entity_association_tree_destroy(tree->root);
75748761c62SAndrew Jeffery 	free(tree);
75848761c62SAndrew Jeffery }
75948761c62SAndrew Jeffery 
76048761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
76148761c62SAndrew Jeffery bool pldm_entity_is_node_parent(pldm_entity_node *node)
76248761c62SAndrew Jeffery {
76348761c62SAndrew Jeffery 	assert(node != NULL);
76448761c62SAndrew Jeffery 
76548761c62SAndrew Jeffery 	return node->first_child != NULL;
76648761c62SAndrew Jeffery }
76748761c62SAndrew Jeffery 
76848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
76948761c62SAndrew Jeffery pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
77048761c62SAndrew Jeffery {
77148761c62SAndrew Jeffery 	assert(node != NULL);
77248761c62SAndrew Jeffery 
77348761c62SAndrew Jeffery 	return node->parent;
77448761c62SAndrew Jeffery }
77548761c62SAndrew Jeffery 
77648761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
77748761c62SAndrew Jeffery bool pldm_entity_is_exist_parent(pldm_entity_node *node)
77848761c62SAndrew Jeffery {
pldm_is_current_parent_child(pldm_entity_node * parent,pldm_entity * node)779890d37a3SAndrew Jeffery 	if (!node) {
780890d37a3SAndrew Jeffery 		return false;
781890d37a3SAndrew Jeffery 	}
78248761c62SAndrew Jeffery 
78348761c62SAndrew Jeffery 	if (node->parent.entity_type == 0 &&
78448761c62SAndrew Jeffery 	    node->parent.entity_instance_num == 0 &&
78548761c62SAndrew Jeffery 	    node->parent.entity_container_id == 0) {
78648761c62SAndrew Jeffery 		return false;
78748761c62SAndrew Jeffery 	}
78848761c62SAndrew Jeffery 
78948761c62SAndrew Jeffery 	return true;
79048761c62SAndrew Jeffery }
79148761c62SAndrew Jeffery 
79248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
79348761c62SAndrew Jeffery uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
79448761c62SAndrew Jeffery 				     uint8_t association_type)
79548761c62SAndrew Jeffery {
79648761c62SAndrew Jeffery 	if (!node) {
79748761c62SAndrew Jeffery 		return 0;
entity_association_pdr_add_children(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,uint32_t record_handle)79848761c62SAndrew Jeffery 	}
79948761c62SAndrew Jeffery 
80048761c62SAndrew Jeffery 	if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
80148761c62SAndrew Jeffery 	      association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
80248761c62SAndrew Jeffery 		return 0;
80348761c62SAndrew Jeffery 	}
80448761c62SAndrew Jeffery 
80548761c62SAndrew Jeffery 	size_t count = 0;
80648761c62SAndrew Jeffery 	pldm_entity_node *curr = node->first_child;
80748761c62SAndrew Jeffery 	while (curr != NULL) {
80848761c62SAndrew Jeffery 		if (curr->association_type == association_type) {
80948761c62SAndrew Jeffery 			++count;
81048761c62SAndrew Jeffery 		}
81148761c62SAndrew Jeffery 		curr = curr->next_sibling;
81248761c62SAndrew Jeffery 	}
81348761c62SAndrew Jeffery 
81448761c62SAndrew Jeffery 	assert(count < UINT8_MAX);
81548761c62SAndrew Jeffery 	return count < UINT8_MAX ? count : 0;
81648761c62SAndrew Jeffery }
81748761c62SAndrew Jeffery 
81848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
81948761c62SAndrew Jeffery bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
82048761c62SAndrew Jeffery {
82148761c62SAndrew Jeffery 	if (!parent || !node) {
82248761c62SAndrew Jeffery 		return false;
82348761c62SAndrew Jeffery 	}
82448761c62SAndrew Jeffery 
82548761c62SAndrew Jeffery 	pldm_entity_node *curr = parent->first_child;
82648761c62SAndrew Jeffery 	while (curr != NULL) {
82748761c62SAndrew Jeffery 		if (node->entity_type == curr->entity.entity_type &&
82848761c62SAndrew Jeffery 		    node->entity_instance_num ==
82948761c62SAndrew Jeffery 			    curr->entity.entity_instance_num) {
83048761c62SAndrew Jeffery 			return true;
83148761c62SAndrew Jeffery 		}
83248761c62SAndrew Jeffery 		curr = curr->next_sibling;
83348761c62SAndrew Jeffery 	}
83448761c62SAndrew Jeffery 
83548761c62SAndrew Jeffery 	return false;
83648761c62SAndrew Jeffery }
83748761c62SAndrew Jeffery 
838bc40dd5aSArchana Kakani static int64_t entity_association_pdr_add_children(
83948761c62SAndrew Jeffery 	pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
84048761c62SAndrew Jeffery 	uint8_t contained_count, uint8_t association_type, bool is_remote,
84148761c62SAndrew Jeffery 	uint16_t terminus_handle, uint32_t record_handle)
84248761c62SAndrew Jeffery {
8435c49f162SAndrew Jeffery 	uint8_t *start;
8445c49f162SAndrew Jeffery 	uint8_t *pdr;
845bc40dd5aSArchana Kakani 	int64_t rc;
8465c49f162SAndrew Jeffery 
8475c49f162SAndrew Jeffery 	pdr = calloc(1, size);
8485c49f162SAndrew Jeffery 	if (!pdr) {
8495c49f162SAndrew Jeffery 		return -ENOMEM;
8505c49f162SAndrew Jeffery 	}
8515c49f162SAndrew Jeffery 
8525c49f162SAndrew Jeffery 	start = pdr;
85348761c62SAndrew Jeffery 
85448761c62SAndrew Jeffery 	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
85548761c62SAndrew Jeffery 	hdr->version = 1;
85648761c62SAndrew Jeffery 	hdr->record_handle = record_handle;
entity_association_pdr_add_entry(pldm_entity_node * curr,pldm_pdr * repo,bool is_remote,uint16_t terminus_handle,uint32_t record_handle)85748761c62SAndrew Jeffery 	hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
85848761c62SAndrew Jeffery 	hdr->record_change_num = 0;
85948761c62SAndrew Jeffery 	hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
86048761c62SAndrew Jeffery 	start += sizeof(struct pldm_pdr_hdr);
86148761c62SAndrew Jeffery 
86248761c62SAndrew Jeffery 	uint16_t *container_id = (uint16_t *)start;
86348761c62SAndrew Jeffery 	*container_id = htole16(curr->first_child->entity.entity_container_id);
86448761c62SAndrew Jeffery 	start += sizeof(uint16_t);
86548761c62SAndrew Jeffery 	*start = association_type;
86648761c62SAndrew Jeffery 	start += sizeof(uint8_t);
86748761c62SAndrew Jeffery 
86848761c62SAndrew Jeffery 	pldm_entity *entity = (pldm_entity *)start;
86948761c62SAndrew Jeffery 	entity->entity_type = htole16(curr->entity.entity_type);
87048761c62SAndrew Jeffery 	entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
87148761c62SAndrew Jeffery 	entity->entity_container_id = htole16(curr->entity.entity_container_id);
87248761c62SAndrew Jeffery 	start += sizeof(pldm_entity);
87348761c62SAndrew Jeffery 
87448761c62SAndrew Jeffery 	*start = contained_count;
87548761c62SAndrew Jeffery 	start += sizeof(uint8_t);
87648761c62SAndrew Jeffery 
87748761c62SAndrew Jeffery 	pldm_entity_node *node = curr->first_child;
87848761c62SAndrew Jeffery 	while (node != NULL) {
87948761c62SAndrew Jeffery 		if (node->association_type == association_type) {
88048761c62SAndrew Jeffery 			pldm_entity *entity = (pldm_entity *)start;
88148761c62SAndrew Jeffery 			entity->entity_type = htole16(node->entity.entity_type);
88248761c62SAndrew Jeffery 			entity->entity_instance_num =
88348761c62SAndrew Jeffery 				htole16(node->entity.entity_instance_num);
88448761c62SAndrew Jeffery 			entity->entity_container_id =
88548761c62SAndrew Jeffery 				htole16(node->entity.entity_container_id);
88648761c62SAndrew Jeffery 			start += sizeof(pldm_entity);
88748761c62SAndrew Jeffery 		}
88848761c62SAndrew Jeffery 		node = node->next_sibling;
88948761c62SAndrew Jeffery 	}
89048761c62SAndrew Jeffery 
8915c49f162SAndrew Jeffery 	rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
89248761c62SAndrew Jeffery 			  &record_handle);
8935c49f162SAndrew Jeffery 	free(pdr);
894bc40dd5aSArchana Kakani 	return (rc < 0) ? rc : record_handle;
89548761c62SAndrew Jeffery }
89648761c62SAndrew Jeffery 
897bc40dd5aSArchana Kakani static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
89848761c62SAndrew Jeffery 						pldm_pdr *repo, bool is_remote,
89948761c62SAndrew Jeffery 						uint16_t terminus_handle,
90048761c62SAndrew Jeffery 						uint32_t record_handle)
is_present(pldm_entity entity,pldm_entity ** entities,size_t num_entities)90148761c62SAndrew Jeffery {
90248761c62SAndrew Jeffery 	uint8_t num_logical_children = pldm_entity_get_num_children(
90348761c62SAndrew Jeffery 		curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
90448761c62SAndrew Jeffery 	uint8_t num_physical_children = pldm_entity_get_num_children(
90548761c62SAndrew Jeffery 		curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
906bc40dd5aSArchana Kakani 	int64_t rc;
907bc40dd5aSArchana Kakani 
908bc40dd5aSArchana Kakani 	if (!num_logical_children && !num_physical_children) {
909bc40dd5aSArchana Kakani 		if (record_handle == 0) {
910bc40dd5aSArchana Kakani 			return -EINVAL;
911bc40dd5aSArchana Kakani 		}
912bc40dd5aSArchana Kakani 		return record_handle - 1;
913bc40dd5aSArchana Kakani 	}
91448761c62SAndrew Jeffery 
91548761c62SAndrew Jeffery 	if (num_logical_children) {
91648761c62SAndrew Jeffery 		uint16_t logical_pdr_size =
91748761c62SAndrew Jeffery 			sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
91848761c62SAndrew Jeffery 			sizeof(uint8_t) + sizeof(pldm_entity) +
91948761c62SAndrew Jeffery 			sizeof(uint8_t) +
92048761c62SAndrew Jeffery 			(num_logical_children * sizeof(pldm_entity));
92148761c62SAndrew Jeffery 		rc = entity_association_pdr_add_children(
92248761c62SAndrew Jeffery 			curr, repo, logical_pdr_size, num_logical_children,
92348761c62SAndrew Jeffery 			PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
92448761c62SAndrew Jeffery 			terminus_handle, record_handle);
92548761c62SAndrew Jeffery 		if (rc < 0) {
92648761c62SAndrew Jeffery 			return rc;
92748761c62SAndrew Jeffery 		}
928bc40dd5aSArchana Kakani 		if (num_physical_children) {
929bc40dd5aSArchana Kakani 			if (rc >= UINT32_MAX) {
930bc40dd5aSArchana Kakani 				return -EOVERFLOW;
931bc40dd5aSArchana Kakani 			}
932bc40dd5aSArchana Kakani 			record_handle = rc + 1;
933bc40dd5aSArchana Kakani 		}
93448761c62SAndrew Jeffery 	}
93548761c62SAndrew Jeffery 
93648761c62SAndrew Jeffery 	if (num_physical_children) {
93748761c62SAndrew Jeffery 		uint16_t physical_pdr_size =
93848761c62SAndrew Jeffery 			sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
93948761c62SAndrew Jeffery 			sizeof(uint8_t) + sizeof(pldm_entity) +
94048761c62SAndrew Jeffery 			sizeof(uint8_t) +
94148761c62SAndrew Jeffery 			(num_physical_children * sizeof(pldm_entity));
94248761c62SAndrew Jeffery 		rc = entity_association_pdr_add_children(
94348761c62SAndrew Jeffery 			curr, repo, physical_pdr_size, num_physical_children,
94448761c62SAndrew Jeffery 			PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
94548761c62SAndrew Jeffery 			terminus_handle, record_handle);
94648761c62SAndrew Jeffery 		if (rc < 0) {
94748761c62SAndrew Jeffery 			return rc;
94848761c62SAndrew Jeffery 		}
949bc40dd5aSArchana Kakani 		record_handle = rc;
95048761c62SAndrew Jeffery 	}
95148761c62SAndrew Jeffery 
952bc40dd5aSArchana Kakani 	return record_handle;
95348761c62SAndrew Jeffery }
95448761c62SAndrew Jeffery 
95548761c62SAndrew Jeffery static bool is_present(pldm_entity entity, pldm_entity **entities,
95648761c62SAndrew Jeffery 		       size_t num_entities)
95748761c62SAndrew Jeffery {
95848761c62SAndrew Jeffery 	if (entities == NULL || num_entities == 0) {
95948761c62SAndrew Jeffery 		return true;
96048761c62SAndrew Jeffery 	}
96148761c62SAndrew Jeffery 	size_t i = 0;
96248761c62SAndrew Jeffery 	while (i < num_entities) {
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)96348761c62SAndrew Jeffery 		if ((*entities + i)->entity_type == entity.entity_type) {
96448761c62SAndrew Jeffery 			return true;
96548761c62SAndrew Jeffery 		}
96648761c62SAndrew Jeffery 		i++;
96748761c62SAndrew Jeffery 	}
96848761c62SAndrew Jeffery 	return false;
96948761c62SAndrew Jeffery }
97048761c62SAndrew Jeffery 
971bc40dd5aSArchana Kakani static int64_t entity_association_pdr_add(pldm_entity_node *curr,
972bc40dd5aSArchana Kakani 					  pldm_pdr *repo,
pldm_entity_association_pdr_add_from_node_with_record_handle(pldm_entity_node * node,pldm_pdr * repo,pldm_entity ** entities,size_t num_entities,bool is_remote,uint16_t terminus_handle,uint32_t record_handle)97348761c62SAndrew Jeffery 					  pldm_entity **entities,
97448761c62SAndrew Jeffery 					  size_t num_entities, bool is_remote,
97548761c62SAndrew Jeffery 					  uint16_t terminus_handle,
97648761c62SAndrew Jeffery 					  uint32_t record_handle)
97748761c62SAndrew Jeffery {
978bc40dd5aSArchana Kakani 	int64_t rc;
97948761c62SAndrew Jeffery 
98048761c62SAndrew Jeffery 	if (curr == NULL) {
981bc40dd5aSArchana Kakani 		// entity_association_pdr_add function gets called
982bc40dd5aSArchana Kakani 		// recursively for the siblings and children of the
983bc40dd5aSArchana Kakani 		// entity. This causes NULL current entity node, and the
984bc40dd5aSArchana Kakani 		// record handle is returned
985bc40dd5aSArchana Kakani 		return record_handle;
98648761c62SAndrew Jeffery 	}
98748761c62SAndrew Jeffery 
98848761c62SAndrew Jeffery 	if (is_present(curr->entity, entities, num_entities)) {
98948761c62SAndrew Jeffery 		rc = entity_association_pdr_add_entry(
99048761c62SAndrew Jeffery 			curr, repo, is_remote, terminus_handle, record_handle);
991bc40dd5aSArchana Kakani 		if (rc < 0) {
99248761c62SAndrew Jeffery 			return rc;
99348761c62SAndrew Jeffery 		}
994bc40dd5aSArchana Kakani 		if (rc >= UINT32_MAX) {
995bc40dd5aSArchana Kakani 			return -EOVERFLOW;
996bc40dd5aSArchana Kakani 		}
997bc40dd5aSArchana Kakani 		record_handle = rc + 1;
99848761c62SAndrew Jeffery 	}
99948761c62SAndrew Jeffery 
100048761c62SAndrew Jeffery 	rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
100148761c62SAndrew Jeffery 					num_entities, is_remote,
100248761c62SAndrew Jeffery 					terminus_handle, record_handle);
1003bc40dd5aSArchana Kakani 	if (rc < 0) {
100448761c62SAndrew Jeffery 		return rc;
100548761c62SAndrew Jeffery 	}
1006bc40dd5aSArchana Kakani 	// entity_association_pdr_add return record handle in success
1007bc40dd5aSArchana Kakani 	// case. If the pdr gets added to the repo, new record handle
1008bc40dd5aSArchana Kakani 	// will be returned. Below check confirms if the pdr is added
1009bc40dd5aSArchana Kakani 	// to the repo and increments the record handle
1010bc40dd5aSArchana Kakani 	if (record_handle != rc) {
1011bc40dd5aSArchana Kakani 		if (rc >= UINT32_MAX) {
1012bc40dd5aSArchana Kakani 			return -EOVERFLOW;
1013bc40dd5aSArchana Kakani 		}
1014bc40dd5aSArchana Kakani 		record_handle = rc + 1;
1015bc40dd5aSArchana Kakani 	}
101648761c62SAndrew Jeffery 
1017bc40dd5aSArchana Kakani 	rc = entity_association_pdr_add(curr->first_child, repo, entities,
101848761c62SAndrew Jeffery 					num_entities, is_remote,
101948761c62SAndrew Jeffery 					terminus_handle, record_handle);
1020bc40dd5aSArchana Kakani 	return rc;
102148761c62SAndrew Jeffery }
102248761c62SAndrew Jeffery 
102348761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
1024d72ea4b8SAndrew Jeffery int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr * repo,uint16_t terminus_handle)102548761c62SAndrew Jeffery 				    pldm_pdr *repo, bool is_remote,
102648761c62SAndrew Jeffery 				    uint16_t terminus_handle)
102748761c62SAndrew Jeffery {
102848761c62SAndrew Jeffery 	if (!tree || !repo) {
102948761c62SAndrew Jeffery 		return 0;
103048761c62SAndrew Jeffery 	}
1031bc40dd5aSArchana Kakani 	int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
1032bc40dd5aSArchana Kakani 						is_remote, terminus_handle, 0);
1033bc40dd5aSArchana Kakani 	assert(rc >= INT_MIN);
1034bc40dd5aSArchana Kakani 	return (rc < 0) ? (int)rc : 0;
103548761c62SAndrew Jeffery }
103648761c62SAndrew Jeffery 
103748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
1038aa49b71fSAndrew Jeffery int pldm_entity_association_pdr_add_from_node(
103948761c62SAndrew Jeffery 	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
104048761c62SAndrew Jeffery 	size_t num_entities, bool is_remote, uint16_t terminus_handle)
104148761c62SAndrew Jeffery {
104248761c62SAndrew Jeffery 	return pldm_entity_association_pdr_add_from_node_with_record_handle(
104348761c62SAndrew Jeffery 		node, repo, entities, num_entities, is_remote, terminus_handle,
104448761c62SAndrew Jeffery 		0);
104548761c62SAndrew Jeffery }
104648761c62SAndrew Jeffery 
104748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
104848761c62SAndrew Jeffery int pldm_entity_association_pdr_add_from_node_with_record_handle(
104948761c62SAndrew Jeffery 	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
105048761c62SAndrew Jeffery 	size_t num_entities, bool is_remote, uint16_t terminus_handle,
105148761c62SAndrew Jeffery 	uint32_t record_handle)
105248761c62SAndrew Jeffery {
105348761c62SAndrew Jeffery 	if (!node || !repo || !entities) {
105448761c62SAndrew Jeffery 		return -EINVAL;
105548761c62SAndrew Jeffery 	}
105648761c62SAndrew Jeffery 
1057bc40dd5aSArchana Kakani 	int64_t rc = entity_association_pdr_add(node, repo, entities,
1058bc40dd5aSArchana Kakani 						num_entities, is_remote,
1059bc40dd5aSArchana Kakani 						terminus_handle, record_handle);
1060bc40dd5aSArchana Kakani 
1061bc40dd5aSArchana Kakani 	assert(rc >= INT_MIN);
1062bc40dd5aSArchana Kakani 	return (rc < 0) ? (int)rc : 0;
106348761c62SAndrew Jeffery }
106448761c62SAndrew Jeffery 
106548761c62SAndrew Jeffery static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
106648761c62SAndrew Jeffery 				    pldm_entity entity, pldm_entity_node **node)
106748761c62SAndrew Jeffery {
106848761c62SAndrew Jeffery 	bool is_entity_container_id;
106948761c62SAndrew Jeffery 	bool is_entity_instance_num;
107048761c62SAndrew Jeffery 	bool is_type;
107148761c62SAndrew Jeffery 
107248761c62SAndrew Jeffery 	if (tree_node == NULL) {
107348761c62SAndrew Jeffery 		return;
107448761c62SAndrew Jeffery 	}
107548761c62SAndrew Jeffery 
107648761c62SAndrew Jeffery 	is_type = tree_node->entity.entity_type == entity.entity_type;
pldm_pdr_remove_remote_pdrs(pldm_pdr * repo)107748761c62SAndrew Jeffery 	is_entity_instance_num = tree_node->entity.entity_instance_num ==
107848761c62SAndrew Jeffery 				 entity.entity_instance_num;
107948761c62SAndrew Jeffery 	is_entity_container_id = tree_node->entity.entity_container_id ==
108048761c62SAndrew Jeffery 				 entity.entity_container_id;
108148761c62SAndrew Jeffery 
108248761c62SAndrew Jeffery 	if (is_type && is_entity_instance_num && is_entity_container_id) {
108348761c62SAndrew Jeffery 		*node = tree_node;
108448761c62SAndrew Jeffery 		return;
108548761c62SAndrew Jeffery 	}
108648761c62SAndrew Jeffery 
108748761c62SAndrew Jeffery 	find_entity_ref_in_tree(tree_node->first_child, entity, node);
108848761c62SAndrew Jeffery 	find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
108948761c62SAndrew Jeffery }
109048761c62SAndrew Jeffery 
109148761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
109248761c62SAndrew Jeffery void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
109348761c62SAndrew Jeffery 				  pldm_entity entity, pldm_entity_node **node)
109448761c62SAndrew Jeffery {
109548761c62SAndrew Jeffery 	if (!tree || !node) {
109648761c62SAndrew Jeffery 		return;
109748761c62SAndrew Jeffery 	}
109848761c62SAndrew Jeffery 
109948761c62SAndrew Jeffery 	find_entity_ref_in_tree(tree->root, entity, node);
110048761c62SAndrew Jeffery }
110148761c62SAndrew Jeffery 
110248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
110348761c62SAndrew Jeffery void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
110448761c62SAndrew Jeffery 					     uint16_t terminus_handle)
110548761c62SAndrew Jeffery {
110648761c62SAndrew Jeffery 	if (!repo) {
110748761c62SAndrew Jeffery 		return;
110848761c62SAndrew Jeffery 	}
110948761c62SAndrew Jeffery 
111048761c62SAndrew Jeffery 	bool removed = false;
111148761c62SAndrew Jeffery 
111248761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
111348761c62SAndrew Jeffery 	pldm_pdr_record *prev = NULL;
111448761c62SAndrew Jeffery 	while (record != NULL) {
111548761c62SAndrew Jeffery 		pldm_pdr_record *next = record->next;
111648761c62SAndrew Jeffery 		if (record->terminus_handle == terminus_handle) {
111748761c62SAndrew Jeffery 			if (repo->first == record) {
111848761c62SAndrew Jeffery 				repo->first = next;
111948761c62SAndrew Jeffery 			} else {
112048761c62SAndrew Jeffery 				prev->next = next;
112148761c62SAndrew Jeffery 			}
112248761c62SAndrew Jeffery 			if (repo->last == record) {
112348761c62SAndrew Jeffery 				repo->last = prev;
112448761c62SAndrew Jeffery 			}
112548761c62SAndrew Jeffery 			if (record->data) {
112648761c62SAndrew Jeffery 				free(record->data);
112748761c62SAndrew Jeffery 			}
pldm_pdr_find_last_in_range(const pldm_pdr * repo,uint32_t first,uint32_t last)112848761c62SAndrew Jeffery 			--repo->record_count;
112948761c62SAndrew Jeffery 			repo->size -= record->size;
113048761c62SAndrew Jeffery 			free(record);
113148761c62SAndrew Jeffery 			removed = true;
113248761c62SAndrew Jeffery 		} else {
113348761c62SAndrew Jeffery 			prev = record;
113448761c62SAndrew Jeffery 		}
113548761c62SAndrew Jeffery 		record = next;
113648761c62SAndrew Jeffery 	}
113748761c62SAndrew Jeffery 
113848761c62SAndrew Jeffery 	if (removed == true) {
113948761c62SAndrew Jeffery 		record = repo->first;
114048761c62SAndrew Jeffery 		uint32_t record_handle = 0;
114148761c62SAndrew Jeffery 		while (record != NULL) {
114248761c62SAndrew Jeffery 			record->record_handle = ++record_handle;
114348761c62SAndrew Jeffery 			if (record->data != NULL) {
114448761c62SAndrew Jeffery 				struct pldm_pdr_hdr *hdr =
114548761c62SAndrew Jeffery 					(struct pldm_pdr_hdr *)(record->data);
114648761c62SAndrew Jeffery 				hdr->record_handle =
114748761c62SAndrew Jeffery 					htole32(record->record_handle);
114848761c62SAndrew Jeffery 			}
entity_association_tree_find_if_remote(pldm_entity_node * node,pldm_entity * entity,pldm_entity_node ** out,bool is_remote)114948761c62SAndrew Jeffery 			record = record->next;
115048761c62SAndrew Jeffery 		}
115148761c62SAndrew Jeffery 	}
115248761c62SAndrew Jeffery }
115348761c62SAndrew Jeffery 
115448761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
115548761c62SAndrew Jeffery void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
115648761c62SAndrew Jeffery {
115748761c62SAndrew Jeffery 	if (!repo) {
115848761c62SAndrew Jeffery 		return;
115948761c62SAndrew Jeffery 	}
116048761c62SAndrew Jeffery 
116148761c62SAndrew Jeffery 	bool removed = false;
116248761c62SAndrew Jeffery 
116348761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
116448761c62SAndrew Jeffery 	pldm_pdr_record *prev = NULL;
116548761c62SAndrew Jeffery 	while (record != NULL) {
116648761c62SAndrew Jeffery 		pldm_pdr_record *next = record->next;
116748761c62SAndrew Jeffery 		if (record->is_remote == true) {
116848761c62SAndrew Jeffery 			if (repo->first == record) {
116948761c62SAndrew Jeffery 				repo->first = next;
117048761c62SAndrew Jeffery 			} else {
117148761c62SAndrew Jeffery 				prev->next = next;
117248761c62SAndrew Jeffery 			}
117348761c62SAndrew Jeffery 			if (repo->last == record) {
117448761c62SAndrew Jeffery 				repo->last = prev;
117548761c62SAndrew Jeffery 			}
117648761c62SAndrew Jeffery 			if (record->data) {
117748761c62SAndrew Jeffery 				free(record->data);
117848761c62SAndrew Jeffery 			}
117948761c62SAndrew Jeffery 			--repo->record_count;
pldm_entity_association_tree_find_with_locality(pldm_entity_association_tree * tree,pldm_entity * entity,bool is_remote)118048761c62SAndrew Jeffery 			repo->size -= record->size;
118148761c62SAndrew Jeffery 			free(record);
118248761c62SAndrew Jeffery 			removed = true;
118348761c62SAndrew Jeffery 		} else {
118448761c62SAndrew Jeffery 			prev = record;
118548761c62SAndrew Jeffery 		}
118648761c62SAndrew Jeffery 		record = next;
118748761c62SAndrew Jeffery 	}
118848761c62SAndrew Jeffery 
118948761c62SAndrew Jeffery 	if (removed == true) {
119048761c62SAndrew Jeffery 		record = repo->first;
119148761c62SAndrew Jeffery 		uint32_t record_handle = 0;
entity_association_tree_find(pldm_entity_node * node,pldm_entity * entity,pldm_entity_node ** out)119248761c62SAndrew Jeffery 		while (record != NULL) {
119348761c62SAndrew Jeffery 			record->record_handle = ++record_handle;
119448761c62SAndrew Jeffery 			if (record->data != NULL) {
119548761c62SAndrew Jeffery 				struct pldm_pdr_hdr *hdr =
119648761c62SAndrew Jeffery 					(struct pldm_pdr_hdr *)(record->data);
119748761c62SAndrew Jeffery 				hdr->record_handle =
119848761c62SAndrew Jeffery 					htole32(record->record_handle);
119948761c62SAndrew Jeffery 			}
120048761c62SAndrew Jeffery 			record = record->next;
120148761c62SAndrew Jeffery 		}
120248761c62SAndrew Jeffery 	}
120348761c62SAndrew Jeffery }
120448761c62SAndrew Jeffery 
120548761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
120648761c62SAndrew Jeffery pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
120748761c62SAndrew Jeffery 					     uint32_t first, uint32_t last)
120848761c62SAndrew Jeffery {
120948761c62SAndrew Jeffery 	pldm_pdr_record *record = NULL;
121048761c62SAndrew Jeffery 	pldm_pdr_record *curr;
121148761c62SAndrew Jeffery 
pldm_entity_association_tree_find(pldm_entity_association_tree * tree,pldm_entity * entity)121248761c62SAndrew Jeffery 	if (!repo) {
121348761c62SAndrew Jeffery 		return NULL;
121448761c62SAndrew Jeffery 	}
121548761c62SAndrew Jeffery 	for (curr = repo->first; curr; curr = curr->next) {
121648761c62SAndrew Jeffery 		if (first > curr->record_handle || last < curr->record_handle) {
121748761c62SAndrew Jeffery 			continue;
121848761c62SAndrew Jeffery 		}
121948761c62SAndrew Jeffery 		if (!record || curr->record_handle > record->record_handle) {
122048761c62SAndrew Jeffery 			record = curr;
122148761c62SAndrew Jeffery 		}
122248761c62SAndrew Jeffery 	}
122348761c62SAndrew Jeffery 
entity_association_tree_copy(pldm_entity_node * org_node,pldm_entity_node ** new_node)122448761c62SAndrew Jeffery 	return record;
122548761c62SAndrew Jeffery }
122648761c62SAndrew Jeffery 
122748761c62SAndrew Jeffery static void entity_association_tree_find_if_remote(pldm_entity_node *node,
122848761c62SAndrew Jeffery 						   pldm_entity *entity,
122948761c62SAndrew Jeffery 						   pldm_entity_node **out,
123048761c62SAndrew Jeffery 						   bool is_remote)
123148761c62SAndrew Jeffery {
123248761c62SAndrew Jeffery 	if (node == NULL) {
123348761c62SAndrew Jeffery 		return;
123448761c62SAndrew Jeffery 	}
123548761c62SAndrew Jeffery 	bool is_entity_type;
123648761c62SAndrew Jeffery 	bool is_entity_instance_num;
123748761c62SAndrew Jeffery 
123848761c62SAndrew Jeffery 	is_entity_type = node->entity.entity_type == entity->entity_type;
123948761c62SAndrew Jeffery 	is_entity_instance_num = node->entity.entity_instance_num ==
124048761c62SAndrew Jeffery 				 entity->entity_instance_num;
124148761c62SAndrew Jeffery 
124248761c62SAndrew Jeffery 	if (!is_remote ||
124348761c62SAndrew Jeffery 	    node->remote_container_id == entity->entity_container_id) {
124448761c62SAndrew Jeffery 		if (is_entity_type && is_entity_instance_num) {
124548761c62SAndrew Jeffery 			entity->entity_container_id =
124648761c62SAndrew Jeffery 				node->entity.entity_container_id;
124748761c62SAndrew Jeffery 			*out = node;
124848761c62SAndrew Jeffery 			return;
124948761c62SAndrew Jeffery 		}
125048761c62SAndrew Jeffery 	}
125148761c62SAndrew Jeffery 	entity_association_tree_find_if_remote(node->next_sibling, entity, out,
125248761c62SAndrew Jeffery 					       is_remote);
125348761c62SAndrew Jeffery 	entity_association_tree_find_if_remote(node->first_child, entity, out,
125448761c62SAndrew Jeffery 					       is_remote);
125548761c62SAndrew Jeffery }
125648761c62SAndrew Jeffery 
125748761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
125848761c62SAndrew Jeffery pldm_entity_node *pldm_entity_association_tree_find_with_locality(
125948761c62SAndrew Jeffery 	pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
126048761c62SAndrew Jeffery {
126148761c62SAndrew Jeffery 	if (!tree || !entity) {
126248761c62SAndrew Jeffery 		return NULL;
126348761c62SAndrew Jeffery 	}
126448761c62SAndrew Jeffery 	pldm_entity_node *node = NULL;
126548761c62SAndrew Jeffery 	entity_association_tree_find_if_remote(tree->root, entity, &node,
126648761c62SAndrew Jeffery 					       is_remote);
pldm_entity_association_tree_copy_root(pldm_entity_association_tree * org_tree,pldm_entity_association_tree * new_tree)126748761c62SAndrew Jeffery 	return node;
126848761c62SAndrew Jeffery }
126948761c62SAndrew Jeffery 
127048761c62SAndrew Jeffery static void entity_association_tree_find(pldm_entity_node *node,
127148761c62SAndrew Jeffery 					 pldm_entity *entity,
127248761c62SAndrew Jeffery 					 pldm_entity_node **out)
127348761c62SAndrew Jeffery {
127448761c62SAndrew Jeffery 	if (node == NULL) {
127548761c62SAndrew Jeffery 		return;
127648761c62SAndrew Jeffery 	}
127748761c62SAndrew Jeffery 
127848761c62SAndrew Jeffery 	if (node->entity.entity_type == entity->entity_type &&
pldm_entity_association_tree_copy_root_check(pldm_entity_association_tree * org_tree,pldm_entity_association_tree * new_tree)127948761c62SAndrew Jeffery 	    node->entity.entity_instance_num == entity->entity_instance_num) {
128048761c62SAndrew Jeffery 		entity->entity_container_id = node->entity.entity_container_id;
128148761c62SAndrew Jeffery 		*out = node;
128248761c62SAndrew Jeffery 		return;
128348761c62SAndrew Jeffery 	}
128448761c62SAndrew Jeffery 	entity_association_tree_find(node->next_sibling, entity, out);
128548761c62SAndrew Jeffery 	entity_association_tree_find(node->first_child, entity, out);
128648761c62SAndrew Jeffery }
128748761c62SAndrew Jeffery 
128848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
128948761c62SAndrew Jeffery pldm_entity_node *
129048761c62SAndrew Jeffery pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
129148761c62SAndrew Jeffery 				  pldm_entity *entity)
pldm_entity_association_tree_destroy_root(pldm_entity_association_tree * tree)129248761c62SAndrew Jeffery {
129348761c62SAndrew Jeffery 	if (!tree || !entity) {
129448761c62SAndrew Jeffery 		return NULL;
129548761c62SAndrew Jeffery 	}
129648761c62SAndrew Jeffery 
129748761c62SAndrew Jeffery 	pldm_entity_node *node = NULL;
129848761c62SAndrew Jeffery 	entity_association_tree_find(tree->root, entity, &node);
129948761c62SAndrew Jeffery 	return node;
130048761c62SAndrew Jeffery }
130148761c62SAndrew Jeffery 
130260582150SAndrew Jeffery static int entity_association_tree_copy(pldm_entity_node *org_node,
130348761c62SAndrew Jeffery 					pldm_entity_node **new_node)
130448761c62SAndrew Jeffery {
pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree * tree)130560582150SAndrew Jeffery 	int rc;
130660582150SAndrew Jeffery 
130748761c62SAndrew Jeffery 	if (org_node == NULL) {
130860582150SAndrew Jeffery 		return 0;
130948761c62SAndrew Jeffery 	}
131060582150SAndrew Jeffery 
pldm_entity_association_pdr_extract(const uint8_t * pdr,uint16_t pdr_len,size_t * num_entities,pldm_entity ** entities)131148761c62SAndrew Jeffery 	*new_node = malloc(sizeof(pldm_entity_node));
131260582150SAndrew Jeffery 	if (!*new_node) {
131360582150SAndrew Jeffery 		return -ENOMEM;
131460582150SAndrew Jeffery 	}
131560582150SAndrew Jeffery 
131648761c62SAndrew Jeffery 	(*new_node)->parent = org_node->parent;
131748761c62SAndrew Jeffery 	(*new_node)->entity = org_node->entity;
131848761c62SAndrew Jeffery 	(*new_node)->association_type = org_node->association_type;
131948761c62SAndrew Jeffery 	(*new_node)->remote_container_id = org_node->remote_container_id;
132048761c62SAndrew Jeffery 	(*new_node)->first_child = NULL;
132148761c62SAndrew Jeffery 	(*new_node)->next_sibling = NULL;
132260582150SAndrew Jeffery 
132360582150SAndrew Jeffery 	rc = entity_association_tree_copy(org_node->first_child,
132448761c62SAndrew Jeffery 					  &((*new_node)->first_child));
132560582150SAndrew Jeffery 	if (rc) {
132660582150SAndrew Jeffery 		goto cleanup;
132748761c62SAndrew Jeffery 	}
132848761c62SAndrew Jeffery 
132960582150SAndrew Jeffery 	rc = entity_association_tree_copy(org_node->next_sibling,
133060582150SAndrew Jeffery 					  &((*new_node)->next_sibling));
133160582150SAndrew Jeffery 	if (rc) {
133260582150SAndrew Jeffery 		entity_association_tree_destroy((*new_node)->first_child);
133360582150SAndrew Jeffery 		goto cleanup;
133460582150SAndrew Jeffery 	}
133560582150SAndrew Jeffery 
133660582150SAndrew Jeffery 	return 0;
133760582150SAndrew Jeffery 
133860582150SAndrew Jeffery cleanup:
133960582150SAndrew Jeffery 	free(*new_node);
134060582150SAndrew Jeffery 	*new_node = NULL;
134160582150SAndrew Jeffery 	return rc;
134260582150SAndrew Jeffery }
134360582150SAndrew Jeffery 
134436324f6bSAndrew Jeffery LIBPLDM_ABI_DEPRECATED_UNSAFE
134548761c62SAndrew Jeffery void pldm_entity_association_tree_copy_root(
134648761c62SAndrew Jeffery 	pldm_entity_association_tree *org_tree,
134748761c62SAndrew Jeffery 	pldm_entity_association_tree *new_tree)
134848761c62SAndrew Jeffery {
134948761c62SAndrew Jeffery 	assert(org_tree != NULL);
135048761c62SAndrew Jeffery 	assert(new_tree != NULL);
135148761c62SAndrew Jeffery 
135248761c62SAndrew Jeffery 	new_tree->last_used_container_id = org_tree->last_used_container_id;
135348761c62SAndrew Jeffery 	entity_association_tree_copy(org_tree->root, &(new_tree->root));
135448761c62SAndrew Jeffery }
135548761c62SAndrew Jeffery 
135660582150SAndrew Jeffery LIBPLDM_ABI_TESTING
135760582150SAndrew Jeffery int pldm_entity_association_tree_copy_root_check(
135860582150SAndrew Jeffery 	pldm_entity_association_tree *org_tree,
135960582150SAndrew Jeffery 	pldm_entity_association_tree *new_tree)
136060582150SAndrew Jeffery {
136160582150SAndrew Jeffery 	if (!org_tree || !new_tree) {
136260582150SAndrew Jeffery 		return -EINVAL;
136360582150SAndrew Jeffery 	}
136460582150SAndrew Jeffery 
136560582150SAndrew Jeffery 	new_tree->last_used_container_id = org_tree->last_used_container_id;
136660582150SAndrew Jeffery 	return entity_association_tree_copy(org_tree->root, &(new_tree->root));
136760582150SAndrew Jeffery }
136860582150SAndrew Jeffery 
136948761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
137048761c62SAndrew Jeffery void pldm_entity_association_tree_destroy_root(
137148761c62SAndrew Jeffery 	pldm_entity_association_tree *tree)
137248761c62SAndrew Jeffery {
137348761c62SAndrew Jeffery 	if (!tree) {
137448761c62SAndrew Jeffery 		return;
137548761c62SAndrew Jeffery 	}
137648761c62SAndrew Jeffery 
137748761c62SAndrew Jeffery 	entity_association_tree_destroy(tree->root);
137848761c62SAndrew Jeffery 	tree->last_used_container_id = 0;
137948761c62SAndrew Jeffery 	tree->root = NULL;
138048761c62SAndrew Jeffery }
138148761c62SAndrew Jeffery 
138248761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
138348761c62SAndrew Jeffery bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
138448761c62SAndrew Jeffery {
138548761c62SAndrew Jeffery 	return ((tree->root == NULL) ? true : false);
138648761c62SAndrew Jeffery }
138748761c62SAndrew Jeffery 
138848761c62SAndrew Jeffery LIBPLDM_ABI_STABLE
pldm_pdr_replace_record(pldm_pdr * repo,pldm_pdr_record * record,pldm_pdr_record * prev,pldm_pdr_record * new_record)138948761c62SAndrew Jeffery void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
139048761c62SAndrew Jeffery 					 size_t *num_entities,
139148761c62SAndrew Jeffery 					 pldm_entity **entities)
139248761c62SAndrew Jeffery {
139348761c62SAndrew Jeffery 	if (!pdr || !num_entities || !entities) {
139448761c62SAndrew Jeffery 		return;
139548761c62SAndrew Jeffery 	}
139648761c62SAndrew Jeffery 	if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
139748761c62SAndrew Jeffery 		return;
139848761c62SAndrew Jeffery 	}
139948761c62SAndrew Jeffery 
140048761c62SAndrew Jeffery 	struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
140148761c62SAndrew Jeffery 	if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
140248761c62SAndrew Jeffery 		return;
140348761c62SAndrew Jeffery 	}
140448761c62SAndrew Jeffery 
140548761c62SAndrew Jeffery 	const uint8_t *start = (uint8_t *)pdr;
14069e566597SAndrew Jeffery 
14079e566597SAndrew Jeffery 	if (UINTPTR_MAX - (uintptr_t)start <
14089e566597SAndrew Jeffery 	    (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
14099e566597SAndrew Jeffery 		return;
14109e566597SAndrew Jeffery 	}
14119e566597SAndrew Jeffery 
14129e566597SAndrew Jeffery 	if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
14139e566597SAndrew Jeffery 		return;
14149e566597SAndrew Jeffery 	}
14159e566597SAndrew Jeffery 
14169e566597SAndrew Jeffery 	const uint8_t *end =
141748761c62SAndrew Jeffery 		start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
141848761c62SAndrew Jeffery 	start += sizeof(struct pldm_pdr_hdr);
14199e566597SAndrew Jeffery 
14209e566597SAndrew Jeffery 	if ((uintptr_t)end - (uintptr_t)start <
14219e566597SAndrew Jeffery 	    sizeof(struct pldm_pdr_entity_association)) {
14229e566597SAndrew Jeffery 		return;
14239e566597SAndrew Jeffery 	}
1424bc40dd5aSArchana Kakani 
142548761c62SAndrew Jeffery 	struct pldm_pdr_entity_association *entity_association_pdr =
142648761c62SAndrew Jeffery 		(struct pldm_pdr_entity_association *)start;
14279e566597SAndrew Jeffery 
1428bc40dd5aSArchana Kakani 	size_t l_num_entities = entity_association_pdr->num_children;
1429bc40dd5aSArchana Kakani 
1430bc40dd5aSArchana Kakani 	if (l_num_entities == 0) {
14319e566597SAndrew Jeffery 		return;
14329e566597SAndrew Jeffery 	}
14338f33a1dcSAndrew Jeffery 
1434bc40dd5aSArchana Kakani 	if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1435bc40dd5aSArchana Kakani 	    l_num_entities) {
143648761c62SAndrew Jeffery 		return;
143748761c62SAndrew Jeffery 	}
14389e566597SAndrew Jeffery 
1439bc40dd5aSArchana Kakani 	if (l_num_entities >= (size_t)UINT8_MAX) {
14409e566597SAndrew Jeffery 		return;
14419e566597SAndrew Jeffery 	}
14429e566597SAndrew Jeffery 
1443bc40dd5aSArchana Kakani 	l_num_entities++;
1444bc40dd5aSArchana Kakani 
14459e566597SAndrew Jeffery 	pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
144648761c62SAndrew Jeffery 	if (!l_entities) {
144748761c62SAndrew Jeffery 		return;
144848761c62SAndrew Jeffery 	}
144948761c62SAndrew Jeffery 	l_entities[0].entity_type =
145048761c62SAndrew Jeffery 		le16toh(entity_association_pdr->container.entity_type);
145148761c62SAndrew Jeffery 	l_entities[0].entity_instance_num =
145248761c62SAndrew Jeffery 		le16toh(entity_association_pdr->container.entity_instance_num);
145348761c62SAndrew Jeffery 	l_entities[0].entity_container_id =
145448761c62SAndrew Jeffery 		le16toh(entity_association_pdr->container.entity_container_id);
145548761c62SAndrew Jeffery 	pldm_entity *curr_entity = entity_association_pdr->children;
145648761c62SAndrew Jeffery 	for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
145748761c62SAndrew Jeffery 		l_entities[i].entity_type = le16toh(curr_entity->entity_type);
145848761c62SAndrew Jeffery 		l_entities[i].entity_instance_num =
145948761c62SAndrew Jeffery 			le16toh(curr_entity->entity_instance_num);
146048761c62SAndrew Jeffery 		l_entities[i].entity_container_id =
146148761c62SAndrew Jeffery 			le16toh(curr_entity->entity_container_id);
146248761c62SAndrew Jeffery 	}
146348761c62SAndrew Jeffery 
146448761c62SAndrew Jeffery 	*num_entities = l_num_entities;
146548761c62SAndrew Jeffery 	*entities = l_entities;
146648761c62SAndrew Jeffery }
146748761c62SAndrew Jeffery 
14689e3a5d45SManojkiran Eda /* Find the position of record in pldm_pdr repo and place new_record in
146948761c62SAndrew Jeffery  * the same position.
147048761c62SAndrew Jeffery  */
1471890d37a3SAndrew Jeffery LIBPLDM_CC_NONNULL
147248761c62SAndrew Jeffery static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
147348761c62SAndrew Jeffery 				   pldm_pdr_record *prev,
147448761c62SAndrew Jeffery 				   pldm_pdr_record *new_record)
147548761c62SAndrew Jeffery {
147648761c62SAndrew Jeffery 	if (repo->size < record->size) {
147748761c62SAndrew Jeffery 		return -EOVERFLOW;
147848761c62SAndrew Jeffery 	}
147948761c62SAndrew Jeffery 
148048761c62SAndrew Jeffery 	if (repo->size + new_record->size < new_record->size) {
148148761c62SAndrew Jeffery 		return -EOVERFLOW;
148248761c62SAndrew Jeffery 	}
148348761c62SAndrew Jeffery 
148448761c62SAndrew Jeffery 	if (repo->first == record) {
148548761c62SAndrew Jeffery 		repo->first = new_record;
148648761c62SAndrew Jeffery 	} else {
148748761c62SAndrew Jeffery 		prev->next = new_record;
148848761c62SAndrew Jeffery 	}
148948761c62SAndrew Jeffery 	new_record->next = record->next;
149048761c62SAndrew Jeffery 
149148761c62SAndrew Jeffery 	if (repo->last == record) {
149248761c62SAndrew Jeffery 		repo->last = new_record;
149348761c62SAndrew Jeffery 	}
149448761c62SAndrew Jeffery 
149548761c62SAndrew Jeffery 	repo->size = (repo->size - record->size) + new_record->size;
149648761c62SAndrew Jeffery 	return 0;
149748761c62SAndrew Jeffery }
149848761c62SAndrew Jeffery 
149948761c62SAndrew Jeffery /* Insert a new record to pldm_pdr repo to a position that comes after
150048761c62SAndrew Jeffery  * pldm_pdr_record record.
150148761c62SAndrew Jeffery  */
1502890d37a3SAndrew Jeffery LIBPLDM_CC_NONNULL
150348761c62SAndrew Jeffery static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
150448761c62SAndrew Jeffery 				  pldm_pdr_record *new_record)
150548761c62SAndrew Jeffery {
150648761c62SAndrew Jeffery 	if (repo->size + new_record->size < new_record->size) {
150748761c62SAndrew Jeffery 		return -EOVERFLOW;
150848761c62SAndrew Jeffery 	}
150948761c62SAndrew Jeffery 
151048761c62SAndrew Jeffery 	if (repo->record_count == UINT32_MAX) {
151148761c62SAndrew Jeffery 		return -EOVERFLOW;
151248761c62SAndrew Jeffery 	}
151348761c62SAndrew Jeffery 
151448761c62SAndrew Jeffery 	new_record->next = record->next;
151548761c62SAndrew Jeffery 	record->next = new_record;
151648761c62SAndrew Jeffery 
151748761c62SAndrew Jeffery 	if (repo->last == record) {
151848761c62SAndrew Jeffery 		repo->last = new_record;
151948761c62SAndrew Jeffery 	}
152048761c62SAndrew Jeffery 
152148761c62SAndrew Jeffery 	repo->size = repo->size + new_record->size;
152248761c62SAndrew Jeffery 	++repo->record_count;
152348761c62SAndrew Jeffery 	return 0;
152448761c62SAndrew Jeffery }
152548761c62SAndrew Jeffery 
152648761c62SAndrew Jeffery /* Find the position of PDR when its record handle is known
152748761c62SAndrew Jeffery  */
1528890d37a3SAndrew Jeffery LIBPLDM_CC_NONNULL
152948761c62SAndrew Jeffery static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
153048761c62SAndrew Jeffery 					   pldm_pdr_record **prev,
153148761c62SAndrew Jeffery 					   uint32_t record_handle)
153248761c62SAndrew Jeffery {
153348761c62SAndrew Jeffery 	while (*record != NULL) {
153448761c62SAndrew Jeffery 		if ((*record)->record_handle == record_handle) {
153548761c62SAndrew Jeffery 			return true;
153648761c62SAndrew Jeffery 		}
153748761c62SAndrew Jeffery 		*prev = *record;
153848761c62SAndrew Jeffery 		*record = (*record)->next;
153948761c62SAndrew Jeffery 	}
154048761c62SAndrew Jeffery 	return false;
154148761c62SAndrew Jeffery }
154248761c62SAndrew Jeffery 
154348761c62SAndrew Jeffery LIBPLDM_ABI_TESTING
154448761c62SAndrew Jeffery int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
154548761c62SAndrew Jeffery 	pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
154648761c62SAndrew Jeffery {
154748761c62SAndrew Jeffery 	if (!repo || !entity) {
154848761c62SAndrew Jeffery 		return -EINVAL;
154948761c62SAndrew Jeffery 	}
155048761c62SAndrew Jeffery 
155148761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
155248761c62SAndrew Jeffery 	pldm_pdr_record *prev = repo->first;
155348761c62SAndrew Jeffery 	int rc = 0;
155448761c62SAndrew Jeffery 	uint16_t header_length = 0;
155548761c62SAndrew Jeffery 	uint8_t num_children = 0;
155648761c62SAndrew Jeffery 	struct pldm_msgbuf _src;
155748761c62SAndrew Jeffery 	struct pldm_msgbuf *src = &_src;
155848761c62SAndrew Jeffery 	struct pldm_msgbuf _dst;
155948761c62SAndrew Jeffery 	struct pldm_msgbuf *dst = &_dst;
156048761c62SAndrew Jeffery 
156148761c62SAndrew Jeffery 	pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
156248761c62SAndrew Jeffery 
156348761c62SAndrew Jeffery 	if (!record) {
156448761c62SAndrew Jeffery 		return -EINVAL;
156548761c62SAndrew Jeffery 	}
156648761c62SAndrew Jeffery 	// Initialize msg buffer for record and record->data
156748761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
156848761c62SAndrew Jeffery 				    record->data, record->size);
156948761c62SAndrew Jeffery 	if (rc) {
157048761c62SAndrew Jeffery 		return rc;
157148761c62SAndrew Jeffery 	}
157248761c62SAndrew Jeffery 
157348761c62SAndrew Jeffery 	// check if adding another entity to record causes overflow before
157448761c62SAndrew Jeffery 	// allocating memory for new_record.
157548761c62SAndrew Jeffery 	if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
157648761c62SAndrew Jeffery 		return -EOVERFLOW;
157748761c62SAndrew Jeffery 	}
157848761c62SAndrew Jeffery 	pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
157948761c62SAndrew Jeffery 	if (!new_record) {
158048761c62SAndrew Jeffery 		return -ENOMEM;
158148761c62SAndrew Jeffery 	}
158248761c62SAndrew Jeffery 
158348761c62SAndrew Jeffery 	new_record->data = malloc(record->size + sizeof(pldm_entity));
158448761c62SAndrew Jeffery 	if (!new_record->data) {
158548761c62SAndrew Jeffery 		rc = -ENOMEM;
158648761c62SAndrew Jeffery 		goto cleanup_new_record;
158748761c62SAndrew Jeffery 	}
158848761c62SAndrew Jeffery 
158948761c62SAndrew Jeffery 	new_record->record_handle = record->record_handle;
159048761c62SAndrew Jeffery 	new_record->size = record->size + sizeof(struct pldm_entity);
159148761c62SAndrew Jeffery 	new_record->is_remote = record->is_remote;
159248761c62SAndrew Jeffery 
159348761c62SAndrew Jeffery 	// Initialize new PDR record with data from original PDR record.
159448761c62SAndrew Jeffery 	// Start with adding the header of original PDR
159548761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
159648761c62SAndrew Jeffery 				    new_record->data, new_record->size);
159748761c62SAndrew Jeffery 	if (rc) {
159848761c62SAndrew Jeffery 		goto cleanup_new_record_data;
pldm_entity_association_pdr_create_new(pldm_pdr * repo,uint32_t pdr_record_handle,pldm_entity * parent,pldm_entity * entity,uint32_t * entity_record_handle)159948761c62SAndrew Jeffery 	}
160048761c62SAndrew Jeffery 
160148761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
160248761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
160348761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
160448761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
160548761c62SAndrew Jeffery 	// extract the header length from record and increment size with
160648761c62SAndrew Jeffery 	// size of pldm_entity before inserting the value into new_record.
160748761c62SAndrew Jeffery 	rc = pldm_msgbuf_extract(src, header_length);
160848761c62SAndrew Jeffery 	if (rc) {
160948761c62SAndrew Jeffery 		goto cleanup_new_record_data;
161048761c62SAndrew Jeffery 	}
161148761c62SAndrew Jeffery 	static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
161248761c62SAndrew Jeffery 		      "Fix the following bounds check.");
161348761c62SAndrew Jeffery 	if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
161448761c62SAndrew Jeffery 		rc = -EOVERFLOW;
161548761c62SAndrew Jeffery 		goto cleanup_new_record_data;
161648761c62SAndrew Jeffery 	}
161748761c62SAndrew Jeffery 	header_length += sizeof(pldm_entity);
161848761c62SAndrew Jeffery 	pldm_msgbuf_insert(dst, header_length);
161948761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, container_id);
162048761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint8_t, association_type);
162148761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
162248761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
162348761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
162448761c62SAndrew Jeffery 	// extract value of number of children from record and increment it
162548761c62SAndrew Jeffery 	// by 1 before insert the value to new record.
162648761c62SAndrew Jeffery 	rc = pldm_msgbuf_extract(src, num_children);
162748761c62SAndrew Jeffery 	if (rc) {
162848761c62SAndrew Jeffery 		goto cleanup_new_record_data;
162948761c62SAndrew Jeffery 	}
163048761c62SAndrew Jeffery 	if (num_children == UINT8_MAX) {
163148761c62SAndrew Jeffery 		rc = -EOVERFLOW;
163248761c62SAndrew Jeffery 		goto cleanup_new_record_data;
163348761c62SAndrew Jeffery 	}
163448761c62SAndrew Jeffery 	num_children += 1;
163548761c62SAndrew Jeffery 	pldm_msgbuf_insert(dst, num_children);
163648761c62SAndrew Jeffery 	//Add all children of original PDR to new PDR
163748761c62SAndrew Jeffery 	for (int i = 0; i < num_children - 1; i++) {
163848761c62SAndrew Jeffery 		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
163948761c62SAndrew Jeffery 		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
164048761c62SAndrew Jeffery 		pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
164148761c62SAndrew Jeffery 	}
164248761c62SAndrew Jeffery 
164348761c62SAndrew Jeffery 	// Add new contained entity as a child of new PDR
164448761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(src);
164548761c62SAndrew Jeffery 	if (rc) {
164648761c62SAndrew Jeffery 		goto cleanup_new_record_data;
164748761c62SAndrew Jeffery 	}
164848761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
164948761c62SAndrew Jeffery 				    sizeof(struct pldm_entity));
165048761c62SAndrew Jeffery 	if (rc) {
165148761c62SAndrew Jeffery 		goto cleanup_new_record_data;
165248761c62SAndrew Jeffery 	}
165348761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
165448761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
165548761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
165648761c62SAndrew Jeffery 
165748761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(src);
165848761c62SAndrew Jeffery 	if (rc) {
165948761c62SAndrew Jeffery 		goto cleanup_new_record_data;
166048761c62SAndrew Jeffery 	}
166148761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(dst);
166248761c62SAndrew Jeffery 	if (rc) {
166348761c62SAndrew Jeffery 		goto cleanup_new_record_data;
166448761c62SAndrew Jeffery 	}
166548761c62SAndrew Jeffery 
166648761c62SAndrew Jeffery 	rc = pldm_pdr_replace_record(repo, record, prev, new_record);
166748761c62SAndrew Jeffery 	if (rc) {
166848761c62SAndrew Jeffery 		goto cleanup_new_record_data;
166948761c62SAndrew Jeffery 	}
167048761c62SAndrew Jeffery 
167148761c62SAndrew Jeffery 	free(record->data);
167248761c62SAndrew Jeffery 	free(record);
167348761c62SAndrew Jeffery 	return rc;
167448761c62SAndrew Jeffery cleanup_new_record_data:
167548761c62SAndrew Jeffery 	free(new_record->data);
167648761c62SAndrew Jeffery cleanup_new_record:
167748761c62SAndrew Jeffery 	free(new_record);
167848761c62SAndrew Jeffery 	return rc;
167948761c62SAndrew Jeffery }
168048761c62SAndrew Jeffery 
168148761c62SAndrew Jeffery LIBPLDM_ABI_TESTING
168248761c62SAndrew Jeffery int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
168348761c62SAndrew Jeffery 					   uint32_t pdr_record_handle,
168448761c62SAndrew Jeffery 					   pldm_entity *parent,
168548761c62SAndrew Jeffery 					   pldm_entity *entity,
168648761c62SAndrew Jeffery 					   uint32_t *entity_record_handle)
168748761c62SAndrew Jeffery {
168848761c62SAndrew Jeffery 	if (!repo || !parent || !entity || !entity_record_handle) {
168948761c62SAndrew Jeffery 		return -EINVAL;
169048761c62SAndrew Jeffery 	}
169148761c62SAndrew Jeffery 
169248761c62SAndrew Jeffery 	if (pdr_record_handle == UINT32_MAX) {
169348761c62SAndrew Jeffery 		return -EOVERFLOW;
169448761c62SAndrew Jeffery 	}
169548761c62SAndrew Jeffery 
169648761c62SAndrew Jeffery 	bool pdr_added = false;
169748761c62SAndrew Jeffery 	uint16_t new_pdr_size;
169848761c62SAndrew Jeffery 	uint16_t container_id = 0;
1699b31e4c6cSVarsha Kaverappa 	void *container_id_addr;
170048761c62SAndrew Jeffery 	struct pldm_msgbuf _dst;
170148761c62SAndrew Jeffery 	struct pldm_msgbuf *dst = &_dst;
170248761c62SAndrew Jeffery 	struct pldm_msgbuf _src_p;
170348761c62SAndrew Jeffery 	struct pldm_msgbuf *src_p = &_src_p;
170448761c62SAndrew Jeffery 	struct pldm_msgbuf _src_c;
170548761c62SAndrew Jeffery 	struct pldm_msgbuf *src_c = &_src_c;
170648761c62SAndrew Jeffery 	int rc = 0;
170748761c62SAndrew Jeffery 
170848761c62SAndrew Jeffery 	pldm_pdr_record *prev = repo->first;
170948761c62SAndrew Jeffery 	pldm_pdr_record *record = repo->first;
171048761c62SAndrew Jeffery 	pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
171148761c62SAndrew Jeffery 						   pdr_record_handle);
171248761c62SAndrew Jeffery 	if (!pdr_added) {
171348761c62SAndrew Jeffery 		return -ENOENT;
171448761c62SAndrew Jeffery 	}
171548761c62SAndrew Jeffery 
171648761c62SAndrew Jeffery 	static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
171748761c62SAndrew Jeffery 		      "Truncation ahead");
171848761c62SAndrew Jeffery 	new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
171948761c62SAndrew Jeffery 	pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
172048761c62SAndrew Jeffery 	if (!new_record) {
172148761c62SAndrew Jeffery 		return -ENOMEM;
172248761c62SAndrew Jeffery 	}
172348761c62SAndrew Jeffery 
172448761c62SAndrew Jeffery 	new_record->data = malloc(new_pdr_size);
172548761c62SAndrew Jeffery 	if (!new_record->data) {
172648761c62SAndrew Jeffery 		rc = -ENOMEM;
172748761c62SAndrew Jeffery 		goto cleanup_new_record;
172848761c62SAndrew Jeffery 	}
172948761c62SAndrew Jeffery 
173048761c62SAndrew Jeffery 	// Initialise new PDR to be added with the header, size and handle.
173148761c62SAndrew Jeffery 	// Set the position of new PDR
173248761c62SAndrew Jeffery 	*entity_record_handle = pdr_record_handle + 1;
173348761c62SAndrew Jeffery 	new_record->record_handle = *entity_record_handle;
173448761c62SAndrew Jeffery 	new_record->size = new_pdr_size;
173548761c62SAndrew Jeffery 	new_record->is_remote = false;
173648761c62SAndrew Jeffery 
173748761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
pldm_entity_cmp(const struct pldm_entity * l,const struct pldm_entity * r)173848761c62SAndrew Jeffery 				    new_record->data, new_record->size);
173948761c62SAndrew Jeffery 	if (rc) {
174048761c62SAndrew Jeffery 		goto cleanup_new_record_data;
174148761c62SAndrew Jeffery 	}
174248761c62SAndrew Jeffery 
174348761c62SAndrew Jeffery 	// header record handle
174448761c62SAndrew Jeffery 	pldm_msgbuf_insert(dst, *entity_record_handle);
174548761c62SAndrew Jeffery 	// header version
174648761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint8(dst, 1);
174748761c62SAndrew Jeffery 	// header type
174848761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
174948761c62SAndrew Jeffery 	// header change number
pldm_entity_association_find_record_handle_by_entity(pldm_pdr * repo,pldm_entity * entity,bool is_remote,uint32_t * record_handle)175048761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint16(dst, 0);
175148761c62SAndrew Jeffery 	// header length
175248761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint16(dst,
175348761c62SAndrew Jeffery 				  (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
175448761c62SAndrew Jeffery 
175548761c62SAndrew Jeffery 	// Data for new PDR is obtained from parent PDR and new contained entity
175648761c62SAndrew Jeffery 	// is added as the child
175748761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
175848761c62SAndrew Jeffery 				    sizeof(*parent));
175948761c62SAndrew Jeffery 	if (rc) {
176048761c62SAndrew Jeffery 		goto cleanup_new_record_data;
176148761c62SAndrew Jeffery 	}
176248761c62SAndrew Jeffery 
176348761c62SAndrew Jeffery 	rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
176448761c62SAndrew Jeffery 				    sizeof(*entity));
176548761c62SAndrew Jeffery 	if (rc) {
176648761c62SAndrew Jeffery 		goto cleanup_new_record_data;
176748761c62SAndrew Jeffery 	}
176848761c62SAndrew Jeffery 
1769b31e4c6cSVarsha Kaverappa 	container_id_addr = NULL;
177048761c62SAndrew Jeffery 	// extract pointer for container ID and save the address
177148761c62SAndrew Jeffery 	rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
177248761c62SAndrew Jeffery 				       (void **)&container_id_addr);
177348761c62SAndrew Jeffery 	if (rc) {
177448761c62SAndrew Jeffery 		goto cleanup_new_record_data;
177548761c62SAndrew Jeffery 	}
1776b31e4c6cSVarsha Kaverappa 	assert(container_id_addr);
177748761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
177848761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
177948761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
178048761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
178148761c62SAndrew Jeffery 	// number of children
178248761c62SAndrew Jeffery 	pldm_msgbuf_insert_uint8(dst, 1);
178348761c62SAndrew Jeffery 
178448761c62SAndrew Jeffery 	// Add new entity as child
178548761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
178648761c62SAndrew Jeffery 	pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
178748761c62SAndrew Jeffery 	// Extract and insert child entity container ID and add same value to
178848761c62SAndrew Jeffery 	// container ID of entity
178948761c62SAndrew Jeffery 	pldm_msgbuf_extract(src_c, container_id);
179048761c62SAndrew Jeffery 	pldm_msgbuf_insert(dst, container_id);
179148761c62SAndrew Jeffery 	container_id = htole16(container_id);
179248761c62SAndrew Jeffery 	memcpy(container_id_addr, &container_id, sizeof(uint16_t));
179348761c62SAndrew Jeffery 
179448761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(dst);
179548761c62SAndrew Jeffery 	if (rc) {
179648761c62SAndrew Jeffery 		goto cleanup_new_record_data;
179748761c62SAndrew Jeffery 	}
179848761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(src_p);
179948761c62SAndrew Jeffery 	if (rc) {
180048761c62SAndrew Jeffery 		goto cleanup_new_record_data;
180148761c62SAndrew Jeffery 	}
180248761c62SAndrew Jeffery 	rc = pldm_msgbuf_destroy(src_c);
180348761c62SAndrew Jeffery 	if (rc) {
180448761c62SAndrew Jeffery 		goto cleanup_new_record_data;
180548761c62SAndrew Jeffery 	}
180648761c62SAndrew Jeffery 
180748761c62SAndrew Jeffery 	rc = pldm_pdr_insert_record(repo, record, new_record);
pldm_entity_association_pdr_remove_contained_entity(pldm_pdr * repo,pldm_entity * entity,bool is_remote,uint32_t * pdr_record_handle)180848761c62SAndrew Jeffery 	if (rc) {
180948761c62SAndrew Jeffery 		goto cleanup_new_record_data;
181048761c62SAndrew Jeffery 	}
181148761c62SAndrew Jeffery 
181248761c62SAndrew Jeffery 	return rc;
181348761c62SAndrew Jeffery cleanup_new_record_data:
181448761c62SAndrew Jeffery 	free(new_record->data);
181548761c62SAndrew Jeffery cleanup_new_record:
181648761c62SAndrew Jeffery 	free(new_record);
181748761c62SAndrew Jeffery 	return rc;
181848761c62SAndrew Jeffery }
1819b31e4c6cSVarsha Kaverappa 
1820b31e4c6cSVarsha Kaverappa LIBPLDM_CC_NONNULL
1821b31e4c6cSVarsha Kaverappa static bool pldm_entity_cmp(const struct pldm_entity *l,
1822b31e4c6cSVarsha Kaverappa 			    const struct pldm_entity *r)
1823b31e4c6cSVarsha Kaverappa {
1824b31e4c6cSVarsha Kaverappa 	return l->entity_type == r->entity_type &&
1825b31e4c6cSVarsha Kaverappa 	       l->entity_instance_num == r->entity_instance_num &&
1826b31e4c6cSVarsha Kaverappa 	       l->entity_container_id == r->entity_container_id;
1827b31e4c6cSVarsha Kaverappa }
1828b31e4c6cSVarsha Kaverappa 
1829b31e4c6cSVarsha Kaverappa /* Find record handle of a PDR record from PDR repo and
1830b31e4c6cSVarsha Kaverappa  * entity
1831b31e4c6cSVarsha Kaverappa  */
1832b31e4c6cSVarsha Kaverappa LIBPLDM_CC_NONNULL
1833b31e4c6cSVarsha Kaverappa static int pldm_entity_association_find_record_handle_by_entity(
1834b31e4c6cSVarsha Kaverappa 	pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1835b31e4c6cSVarsha Kaverappa 	uint32_t *record_handle)
1836b31e4c6cSVarsha Kaverappa {
1837b31e4c6cSVarsha Kaverappa 	uint8_t num_children = 0;
1838b31e4c6cSVarsha Kaverappa 	uint8_t hdr_type = 0;
1839b31e4c6cSVarsha Kaverappa 	int rc = 0;
1840b31e4c6cSVarsha Kaverappa 	size_t skip_data_size = 0;
1841b31e4c6cSVarsha Kaverappa 	pldm_pdr_record *record = repo->first;
1842b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf _dst;
1843b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf *dst = &_dst;
1844b31e4c6cSVarsha Kaverappa 
1845b31e4c6cSVarsha Kaverappa 	while (record != NULL) {
1846b31e4c6cSVarsha Kaverappa 		rc = pldm_msgbuf_init_errno(dst,
1847b31e4c6cSVarsha Kaverappa 					    PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1848b31e4c6cSVarsha Kaverappa 					    record->data, record->size);
1849b31e4c6cSVarsha Kaverappa 		if (rc) {
1850b31e4c6cSVarsha Kaverappa 			return rc;
1851b31e4c6cSVarsha Kaverappa 		}
1852b31e4c6cSVarsha Kaverappa 		skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1853b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1854b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_extract(dst, hdr_type);
1855b31e4c6cSVarsha Kaverappa 		if (record->is_remote != is_remote ||
1856b31e4c6cSVarsha Kaverappa 		    hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1857b31e4c6cSVarsha Kaverappa 			goto cleanup;
1858b31e4c6cSVarsha Kaverappa 		}
1859b31e4c6cSVarsha Kaverappa 		skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1860b31e4c6cSVarsha Kaverappa 				 sizeof(uint16_t) + sizeof(uint8_t) +
1861b31e4c6cSVarsha Kaverappa 				 sizeof(struct pldm_entity);
1862b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1863b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_extract(dst, num_children);
1864b31e4c6cSVarsha Kaverappa 		for (int i = 0; i < num_children; ++i) {
1865b31e4c6cSVarsha Kaverappa 			struct pldm_entity e;
1866b31e4c6cSVarsha Kaverappa 
1867b31e4c6cSVarsha Kaverappa 			if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1868b31e4c6cSVarsha Kaverappa 			    (rc = pldm_msgbuf_extract(dst,
1869b31e4c6cSVarsha Kaverappa 						      e.entity_instance_num)) ||
1870b31e4c6cSVarsha Kaverappa 			    (rc = pldm_msgbuf_extract(dst,
1871b31e4c6cSVarsha Kaverappa 						      e.entity_container_id))) {
1872b31e4c6cSVarsha Kaverappa 				return rc;
1873b31e4c6cSVarsha Kaverappa 			}
1874b31e4c6cSVarsha Kaverappa 
1875b31e4c6cSVarsha Kaverappa 			if (pldm_entity_cmp(entity, &e)) {
1876b31e4c6cSVarsha Kaverappa 				*record_handle = record->record_handle;
1877b31e4c6cSVarsha Kaverappa 				return 0;
1878b31e4c6cSVarsha Kaverappa 			}
1879b31e4c6cSVarsha Kaverappa 		}
1880b31e4c6cSVarsha Kaverappa 	cleanup:
1881b31e4c6cSVarsha Kaverappa 		rc = pldm_msgbuf_destroy(dst);
1882b31e4c6cSVarsha Kaverappa 		if (rc) {
1883b31e4c6cSVarsha Kaverappa 			return rc;
1884b31e4c6cSVarsha Kaverappa 		}
1885b31e4c6cSVarsha Kaverappa 		record = record->next;
1886b31e4c6cSVarsha Kaverappa 	}
1887b31e4c6cSVarsha Kaverappa 	return 0;
1888b31e4c6cSVarsha Kaverappa }
1889b31e4c6cSVarsha Kaverappa 
1890b31e4c6cSVarsha Kaverappa LIBPLDM_ABI_TESTING
1891b31e4c6cSVarsha Kaverappa int pldm_entity_association_pdr_remove_contained_entity(
1892b31e4c6cSVarsha Kaverappa 	pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1893b31e4c6cSVarsha Kaverappa 	uint32_t *pdr_record_handle)
1894b31e4c6cSVarsha Kaverappa {
1895b31e4c6cSVarsha Kaverappa 	uint16_t header_length = 0;
1896b31e4c6cSVarsha Kaverappa 	uint8_t num_children = 0;
1897b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf _src;
1898b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf *src = &_src;
1899b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf _dst;
1900b31e4c6cSVarsha Kaverappa 	struct pldm_msgbuf *dst = &_dst;
1901b31e4c6cSVarsha Kaverappa 	int rc;
1902b31e4c6cSVarsha Kaverappa 	pldm_pdr_record *record;
1903b31e4c6cSVarsha Kaverappa 	pldm_pdr_record *prev;
1904b31e4c6cSVarsha Kaverappa 
1905b31e4c6cSVarsha Kaverappa 	if (!repo || !entity || !pdr_record_handle) {
1906b31e4c6cSVarsha Kaverappa 		return -EINVAL;
1907b31e4c6cSVarsha Kaverappa 	}
1908b31e4c6cSVarsha Kaverappa 	record = repo->first;
1909b31e4c6cSVarsha Kaverappa 	prev = repo->first;
1910b31e4c6cSVarsha Kaverappa 
1911b31e4c6cSVarsha Kaverappa 	rc = pldm_entity_association_find_record_handle_by_entity(
1912b31e4c6cSVarsha Kaverappa 		repo, entity, is_remote, pdr_record_handle);
1913b31e4c6cSVarsha Kaverappa 	if (rc) {
1914b31e4c6cSVarsha Kaverappa 		return rc;
1915b31e4c6cSVarsha Kaverappa 	}
1916b31e4c6cSVarsha Kaverappa 	pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
1917b31e4c6cSVarsha Kaverappa 	if (!record) {
1918b31e4c6cSVarsha Kaverappa 		return -EINVAL;
1919b31e4c6cSVarsha Kaverappa 	}
1920b31e4c6cSVarsha Kaverappa 	// Initialize msg buffer for record and record->data
1921b31e4c6cSVarsha Kaverappa 	rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1922b31e4c6cSVarsha Kaverappa 				    record->data, record->size);
1923b31e4c6cSVarsha Kaverappa 	if (rc) {
1924b31e4c6cSVarsha Kaverappa 		return rc;
1925b31e4c6cSVarsha Kaverappa 	}
1926b31e4c6cSVarsha Kaverappa 	// check if removing an entity from record causes overflow before
1927b31e4c6cSVarsha Kaverappa 	// allocating memory for new_record.
1928b31e4c6cSVarsha Kaverappa 	if (record->size < sizeof(pldm_entity)) {
1929b31e4c6cSVarsha Kaverappa 		return -EOVERFLOW;
1930b31e4c6cSVarsha Kaverappa 	}
1931b31e4c6cSVarsha Kaverappa 	pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1932b31e4c6cSVarsha Kaverappa 	if (!new_record) {
1933b31e4c6cSVarsha Kaverappa 		return -ENOMEM;
1934b31e4c6cSVarsha Kaverappa 	}
1935b31e4c6cSVarsha Kaverappa 	new_record->data = malloc(record->size - sizeof(pldm_entity));
1936b31e4c6cSVarsha Kaverappa 	if (!new_record->data) {
1937b31e4c6cSVarsha Kaverappa 		rc = -ENOMEM;
1938b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record;
1939b31e4c6cSVarsha Kaverappa 	}
1940b31e4c6cSVarsha Kaverappa 	new_record->record_handle = record->record_handle;
1941b31e4c6cSVarsha Kaverappa 	new_record->size = record->size - sizeof(struct pldm_entity);
1942b31e4c6cSVarsha Kaverappa 	new_record->is_remote = record->is_remote;
1943b31e4c6cSVarsha Kaverappa 
1944b31e4c6cSVarsha Kaverappa 	// Initialize new PDR record with data from original PDR record.
1945b31e4c6cSVarsha Kaverappa 	// Start with adding the header of original PDR
194694e2d754SArchana Kakani 	rc = pldm_msgbuf_init_errno(
pldm_pdr_get_prev_record(pldm_pdr * repo,pldm_pdr_record * record)194794e2d754SArchana Kakani 		dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
1948b31e4c6cSVarsha Kaverappa 		new_record->data, new_record->size);
1949b31e4c6cSVarsha Kaverappa 	if (rc) {
1950b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1951b31e4c6cSVarsha Kaverappa 	}
1952b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1953b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1954b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1955b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1956b31e4c6cSVarsha Kaverappa 	// extract the header length from record and decrement size with
1957b31e4c6cSVarsha Kaverappa 	// size of pldm_entity before inserting the value into new_record.
1958b31e4c6cSVarsha Kaverappa 	rc = pldm_msgbuf_extract(src, header_length);
1959b31e4c6cSVarsha Kaverappa 	if (rc) {
1960b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1961b31e4c6cSVarsha Kaverappa 	}
1962b31e4c6cSVarsha Kaverappa 	if (header_length < sizeof(pldm_entity)) {
1963b31e4c6cSVarsha Kaverappa 		rc = -EOVERFLOW;
1964b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1965b31e4c6cSVarsha Kaverappa 	}
is_prev_record_present(pldm_pdr * repo,pldm_pdr_record * record)1966b31e4c6cSVarsha Kaverappa 	header_length -= sizeof(pldm_entity);
1967b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_insert(dst, header_length);
1968b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1969b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1970b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1971b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1972b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1973b31e4c6cSVarsha Kaverappa 	// extract value of number of children from record and decrement it
1974b31e4c6cSVarsha Kaverappa 	// by 1 before insert the value to new record.
1975b31e4c6cSVarsha Kaverappa 	rc = pldm_msgbuf_extract(src, num_children);
1976b31e4c6cSVarsha Kaverappa 	if (rc) {
1977b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1978b31e4c6cSVarsha Kaverappa 	}
1979b31e4c6cSVarsha Kaverappa 	if (num_children == 1) {
pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record * record,uint16_t rsi)198094e2d754SArchana Kakani 		// This is the last child which is getting removed so we need to delete the Entity Association PDR.
198194e2d754SArchana Kakani 		pldm_pdr_remove_record(repo, record,
198294e2d754SArchana Kakani 				       pldm_pdr_get_prev_record(repo, record));
1983b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1984b31e4c6cSVarsha Kaverappa 	} else if (num_children < 1) {
1985b31e4c6cSVarsha Kaverappa 		rc = -EOVERFLOW;
1986b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
1987b31e4c6cSVarsha Kaverappa 	}
1988b31e4c6cSVarsha Kaverappa 	num_children -= 1;
1989b31e4c6cSVarsha Kaverappa 	pldm_msgbuf_insert(dst, num_children);
1990b31e4c6cSVarsha Kaverappa 	//Add all children of original PDR to new PDR
1991b31e4c6cSVarsha Kaverappa 	for (int i = 0; i < num_children + 1; ++i) {
1992b31e4c6cSVarsha Kaverappa 		struct pldm_entity e;
1993b31e4c6cSVarsha Kaverappa 
1994b31e4c6cSVarsha Kaverappa 		if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
1995b31e4c6cSVarsha Kaverappa 		    (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
1996b31e4c6cSVarsha Kaverappa 		    (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
1997b31e4c6cSVarsha Kaverappa 			goto cleanup_new_record_data;
1998b31e4c6cSVarsha Kaverappa 		}
1999b31e4c6cSVarsha Kaverappa 
2000b31e4c6cSVarsha Kaverappa 		if (pldm_entity_cmp(entity, &e)) {
2001b31e4c6cSVarsha Kaverappa 			continue;
2002b31e4c6cSVarsha Kaverappa 		}
2003b31e4c6cSVarsha Kaverappa 
2004b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_insert(dst, e.entity_type);
2005b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_insert(dst, e.entity_instance_num);
2006b31e4c6cSVarsha Kaverappa 		pldm_msgbuf_insert(dst, e.entity_container_id);
2007b31e4c6cSVarsha Kaverappa 	}
2008b31e4c6cSVarsha Kaverappa 
pldm_pdr_remove_record(pldm_pdr * repo,pldm_pdr_record * record,pldm_pdr_record * prev)2009b31e4c6cSVarsha Kaverappa 	if ((rc = pldm_msgbuf_destroy(src)) ||
2010b31e4c6cSVarsha Kaverappa 	    (rc = pldm_msgbuf_destroy(dst)) ||
2011b31e4c6cSVarsha Kaverappa 	    (rc = pldm_pdr_replace_record(repo, record, prev, new_record))) {
2012b31e4c6cSVarsha Kaverappa 		goto cleanup_new_record_data;
2013b31e4c6cSVarsha Kaverappa 	}
2014b31e4c6cSVarsha Kaverappa 
2015b31e4c6cSVarsha Kaverappa 	free(record->data);
2016b31e4c6cSVarsha Kaverappa 	free(record);
2017b31e4c6cSVarsha Kaverappa 	return rc;
2018b31e4c6cSVarsha Kaverappa 
2019b31e4c6cSVarsha Kaverappa cleanup_new_record_data:
2020b31e4c6cSVarsha Kaverappa 	free(new_record->data);
2021b31e4c6cSVarsha Kaverappa cleanup_new_record:
2022b31e4c6cSVarsha Kaverappa 	free(new_record);
2023b31e4c6cSVarsha Kaverappa 	return rc;
2024b31e4c6cSVarsha Kaverappa }
20258b53ad9dSVarsha Kaverappa 
20268b53ad9dSVarsha Kaverappa /* API to find the PDR record that is previous to a given PLDM PDR
20278b53ad9dSVarsha Kaverappa  * record in a given PLDM PDR repository
20288b53ad9dSVarsha Kaverappa  */
20298b53ad9dSVarsha Kaverappa LIBPLDM_CC_NONNULL
20308b53ad9dSVarsha Kaverappa static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
20318b53ad9dSVarsha Kaverappa 						 pldm_pdr_record *record)
20328b53ad9dSVarsha Kaverappa {
20338b53ad9dSVarsha Kaverappa 	pldm_pdr_record *prev = NULL;
20348b53ad9dSVarsha Kaverappa 	pldm_pdr_record *curr = repo->first;
20358b53ad9dSVarsha Kaverappa 
20368b53ad9dSVarsha Kaverappa 	while (curr != NULL) {
20378b53ad9dSVarsha Kaverappa 		if (curr->record_handle == record->record_handle) {
20388b53ad9dSVarsha Kaverappa 			break;
20398b53ad9dSVarsha Kaverappa 		}
20408b53ad9dSVarsha Kaverappa 		prev = curr;
20418b53ad9dSVarsha Kaverappa 		curr = curr->next;
20428b53ad9dSVarsha Kaverappa 	}
20438b53ad9dSVarsha Kaverappa 	return prev;
pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr * repo,uint16_t fru_rsi,bool is_remote,uint32_t * record_handle)20448b53ad9dSVarsha Kaverappa }
20458b53ad9dSVarsha Kaverappa 
20468b53ad9dSVarsha Kaverappa /* API to check if a PLDM PDR record is present in a PLDM PDR repository
20478b53ad9dSVarsha Kaverappa  */
20488b53ad9dSVarsha Kaverappa LIBPLDM_CC_NONNULL
20498b53ad9dSVarsha Kaverappa static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
20508b53ad9dSVarsha Kaverappa {
20518b53ad9dSVarsha Kaverappa 	if (repo->first == record) {
20528b53ad9dSVarsha Kaverappa 		return true;
20538b53ad9dSVarsha Kaverappa 	}
20548b53ad9dSVarsha Kaverappa 
20558b53ad9dSVarsha Kaverappa 	return pldm_pdr_get_prev_record(repo, record) != NULL;
20568b53ad9dSVarsha Kaverappa }
20578b53ad9dSVarsha Kaverappa 
20588b53ad9dSVarsha Kaverappa /* API to check if FRU RSI of record matches the given record set identifier.
20598b53ad9dSVarsha Kaverappa  * Returns 1 if the provided FRU record matches the provided record set identifier,
20608b53ad9dSVarsha Kaverappa  * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
20618b53ad9dSVarsha Kaverappa  */
20628b53ad9dSVarsha Kaverappa LIBPLDM_CC_NONNULL
20638b53ad9dSVarsha Kaverappa static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
20648b53ad9dSVarsha Kaverappa 					   uint16_t rsi)
20658b53ad9dSVarsha Kaverappa {
20668b53ad9dSVarsha Kaverappa 	uint16_t record_fru_rsi = 0;
20678b53ad9dSVarsha Kaverappa 	uint8_t *skip_data = NULL;
20688b53ad9dSVarsha Kaverappa 	uint8_t skip_data_size = 0;
20698b53ad9dSVarsha Kaverappa 	struct pldm_msgbuf _dst;
20708b53ad9dSVarsha Kaverappa 	struct pldm_msgbuf *dst = &_dst;
20718b53ad9dSVarsha Kaverappa 	int rc = 0;
20728b53ad9dSVarsha Kaverappa 
20738b53ad9dSVarsha Kaverappa 	rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
20748b53ad9dSVarsha Kaverappa 				    record->data, record->size);
20758b53ad9dSVarsha Kaverappa 	if (rc) {
20768b53ad9dSVarsha Kaverappa 		return rc;
20778b53ad9dSVarsha Kaverappa 	}
20788b53ad9dSVarsha Kaverappa 	skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
20798b53ad9dSVarsha Kaverappa 	pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
20808b53ad9dSVarsha Kaverappa 	pldm_msgbuf_extract(dst, record_fru_rsi);
20818b53ad9dSVarsha Kaverappa 
20828b53ad9dSVarsha Kaverappa 	rc = pldm_msgbuf_destroy(dst);
20838b53ad9dSVarsha Kaverappa 	if (rc) {
20848b53ad9dSVarsha Kaverappa 		return rc;
20858b53ad9dSVarsha Kaverappa 	}
20868b53ad9dSVarsha Kaverappa 	return record_fru_rsi == rsi;
20878b53ad9dSVarsha Kaverappa }
20888b53ad9dSVarsha Kaverappa 
20898b53ad9dSVarsha Kaverappa /* API to remove PLDM PDR record from a PLDM PDR repository
20908b53ad9dSVarsha Kaverappa  */
20918b53ad9dSVarsha Kaverappa LIBPLDM_CC_NONNULL_ARGS(1, 2)
20928b53ad9dSVarsha Kaverappa static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
20938b53ad9dSVarsha Kaverappa 				  pldm_pdr_record *prev)
20948b53ad9dSVarsha Kaverappa {
20958b53ad9dSVarsha Kaverappa 	if (!is_prev_record_present(repo, record)) {
20968b53ad9dSVarsha Kaverappa 		return -EINVAL;
20978b53ad9dSVarsha Kaverappa 	}
20988b53ad9dSVarsha Kaverappa 
20998b53ad9dSVarsha Kaverappa 	assert(repo->size >= record->size);
21008b53ad9dSVarsha Kaverappa 	if (repo->size < record->size) {
21018b53ad9dSVarsha Kaverappa 		return -EOVERFLOW;
21028b53ad9dSVarsha Kaverappa 	}
21038b53ad9dSVarsha Kaverappa 
21048b53ad9dSVarsha Kaverappa 	if (repo->first == record) {
21058b53ad9dSVarsha Kaverappa 		repo->first = record->next;
21068b53ad9dSVarsha Kaverappa 	} else {
21078b53ad9dSVarsha Kaverappa 		if (prev != NULL) {
21088b53ad9dSVarsha Kaverappa 			prev->next = record->next;
21098b53ad9dSVarsha Kaverappa 		}
21108b53ad9dSVarsha Kaverappa 	}
21118b53ad9dSVarsha Kaverappa 
21128b53ad9dSVarsha Kaverappa 	if (repo->last == record) {
21138b53ad9dSVarsha Kaverappa 		repo->last = prev;
21148b53ad9dSVarsha Kaverappa 		if (prev != NULL) {
21158b53ad9dSVarsha Kaverappa 			prev->next = NULL;
21168b53ad9dSVarsha Kaverappa 		}
21178b53ad9dSVarsha Kaverappa 	}
21188b53ad9dSVarsha Kaverappa 	repo->record_count -= 1;
21198b53ad9dSVarsha Kaverappa 	repo->size -= record->size;
21208b53ad9dSVarsha Kaverappa 	free(record->data);
21218b53ad9dSVarsha Kaverappa 	free(record);
21228b53ad9dSVarsha Kaverappa 
21238b53ad9dSVarsha Kaverappa 	return 0;
21248b53ad9dSVarsha Kaverappa }
21258b53ad9dSVarsha Kaverappa 
21268b53ad9dSVarsha Kaverappa LIBPLDM_ABI_TESTING
21278b53ad9dSVarsha Kaverappa int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
21288b53ad9dSVarsha Kaverappa 					  bool is_remote,
21298b53ad9dSVarsha Kaverappa 					  uint32_t *record_handle)
21308b53ad9dSVarsha Kaverappa {
21318b53ad9dSVarsha Kaverappa 	pldm_pdr_record *record;
21328b53ad9dSVarsha Kaverappa 	pldm_pdr_record *prev = NULL;
21338b53ad9dSVarsha Kaverappa 	size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
21348b53ad9dSVarsha Kaverappa 	uint8_t hdr_type = 0;
21358b53ad9dSVarsha Kaverappa 	int rc = 0;
21368b53ad9dSVarsha Kaverappa 	int match;
21378b53ad9dSVarsha Kaverappa 
21388b53ad9dSVarsha Kaverappa 	if (!repo || !record_handle) {
21398b53ad9dSVarsha Kaverappa 		return -EINVAL;
21408b53ad9dSVarsha Kaverappa 	}
21418b53ad9dSVarsha Kaverappa 	record = repo->first;
21428b53ad9dSVarsha Kaverappa 
21438b53ad9dSVarsha Kaverappa 	while (record != NULL) {
21448b53ad9dSVarsha Kaverappa 		struct pldm_msgbuf _buf;
21458b53ad9dSVarsha Kaverappa 		struct pldm_msgbuf *buf = &_buf;
21468b53ad9dSVarsha Kaverappa 		rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
21478b53ad9dSVarsha Kaverappa 					    record->data, record->size);
21488b53ad9dSVarsha Kaverappa 		if (rc) {
21498b53ad9dSVarsha Kaverappa 			return rc;
21508b53ad9dSVarsha Kaverappa 		}
21518b53ad9dSVarsha Kaverappa 		pldm_msgbuf_span_required(buf, skip_data_size, NULL);
21528b53ad9dSVarsha Kaverappa 		if ((rc = pldm_msgbuf_extract(buf, hdr_type))) {
21538b53ad9dSVarsha Kaverappa 			return rc;
21548b53ad9dSVarsha Kaverappa 		}
21558b53ad9dSVarsha Kaverappa 		if (record->is_remote != is_remote ||
21568b53ad9dSVarsha Kaverappa 		    hdr_type != PLDM_PDR_FRU_RECORD_SET) {
21578b53ad9dSVarsha Kaverappa 			goto cleanup;
21588b53ad9dSVarsha Kaverappa 		}
21598b53ad9dSVarsha Kaverappa 		match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
21608b53ad9dSVarsha Kaverappa 		if (match < 0) {
21618b53ad9dSVarsha Kaverappa 			return match;
21628b53ad9dSVarsha Kaverappa 		}
21638b53ad9dSVarsha Kaverappa 		if (match) {
21648b53ad9dSVarsha Kaverappa 			*record_handle = record->record_handle;
21658b53ad9dSVarsha Kaverappa 			prev = pldm_pdr_get_prev_record(repo, record);
21668b53ad9dSVarsha Kaverappa 			return pldm_pdr_remove_record(repo, record, prev);
21678b53ad9dSVarsha Kaverappa 		}
21688b53ad9dSVarsha Kaverappa 	cleanup:
21698b53ad9dSVarsha Kaverappa 		rc = pldm_msgbuf_destroy(buf);
21708b53ad9dSVarsha Kaverappa 		if (rc) {
21718b53ad9dSVarsha Kaverappa 			return rc;
21728b53ad9dSVarsha Kaverappa 		}
21738b53ad9dSVarsha Kaverappa 		record = record->next;
21748b53ad9dSVarsha Kaverappa 	}
21758b53ad9dSVarsha Kaverappa 	return rc;
21768b53ad9dSVarsha Kaverappa }
2177