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