blob: 55350a8db9c45699593ce0043b37852ba0ac957c [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include "pdr.h"
2#include "platform.h"
3#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05304#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <stdlib.h>
6#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06007#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308
9typedef struct pldm_pdr_record {
10 uint32_t record_handle;
11 uint32_t size;
12 uint8_t *data;
13 struct pldm_pdr_record *next;
14 bool is_remote;
15 uint16_t terminus_handle;
16} pldm_pdr_record;
17
18typedef struct pldm_pdr {
19 uint32_t record_count;
20 uint32_t size;
21 pldm_pdr_record *first;
22 pldm_pdr_record *last;
23} pldm_pdr;
24
25static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
26 const pldm_pdr_record *record)
27{
28 assert(repo != NULL);
29 assert(record != NULL);
30
31 if (record == repo->last) {
32 return 0;
33 }
34 return record->next->record_handle;
35}
36
37static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
38{
39 assert(repo != NULL);
40 assert(record != NULL);
41
42 if (repo->first == NULL) {
43 assert(repo->last == NULL);
44 repo->first = record;
45 repo->last = record;
46 } else {
47 repo->last->next = record;
48 repo->last = record;
49 }
50 repo->size += record->size;
51 ++repo->record_count;
52}
53
54static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
55{
56 assert(repo != NULL);
57 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093058 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093059 assert(last_used_hdl != UINT32_MAX);
60
61 return last_used_hdl + 1;
62}
63
64static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
65 const uint8_t *data, uint32_t size,
66 uint32_t record_handle, bool is_remote,
67 uint16_t terminus_handle)
68{
69 assert(repo != NULL);
70 assert(size != 0);
71
72 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
73 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093074 record->record_handle = record_handle == 0 ?
75 get_new_record_handle(repo) :
76 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093077 record->size = size;
78 record->is_remote = is_remote;
79 record->terminus_handle = terminus_handle;
80 if (data != NULL) {
81 record->data = malloc(size);
82 assert(record->data != NULL);
83 memcpy(record->data, data, size);
84 /* If record handle is 0, that is an indication for this API to
85 * compute a new handle. For that reason, the computed handle
86 * needs to be populated in the PDR header. For a case where the
87 * caller supplied the record handle, it would exist in the
88 * header already.
89 */
90 if (!record_handle) {
91 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093092 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093093 hdr->record_handle = htole32(record->record_handle);
94 }
95 }
96 record->next = NULL;
97
98 return record;
99}
100
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930101LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
103 uint32_t record_handle, bool is_remote,
104 uint16_t terminus_handle)
105{
106 assert(size != 0);
107 assert(data != NULL);
108
109 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930110 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111 add_record(repo, record);
112
113 return record->record_handle;
114}
115
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930116LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930117pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118{
119 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
120 assert(repo != NULL);
121 repo->record_count = 0;
122 repo->size = 0;
123 repo->first = NULL;
124 repo->last = NULL;
125
126 return repo;
127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130void pldm_pdr_destroy(pldm_pdr *repo)
131{
132 assert(repo != NULL);
133
134 pldm_pdr_record *record = repo->first;
135 while (record != NULL) {
136 pldm_pdr_record *next = record->next;
137 if (record->data) {
138 free(record->data);
139 record->data = NULL;
140 }
141 free(record);
142 record = next;
143 }
144 free(repo);
145}
146
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930147LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
149 uint32_t record_handle,
150 uint8_t **data, uint32_t *size,
151 uint32_t *next_record_handle)
152{
153 assert(repo != NULL);
154 assert(data != NULL);
155 assert(size != NULL);
156 assert(next_record_handle != NULL);
157
158 if (!record_handle && (repo->first != NULL)) {
159 record_handle = repo->first->record_handle;
160 }
161 pldm_pdr_record *record = repo->first;
162 while (record != NULL) {
163 if (record->record_handle == record_handle) {
164 *size = record->size;
165 *data = record->data;
166 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930167 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168 return record;
169 }
170 record = record->next;
171 }
172
173 *size = 0;
174 *next_record_handle = 0;
175 return NULL;
176}
177
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930178LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179const pldm_pdr_record *
180pldm_pdr_get_next_record(const pldm_pdr *repo,
181 const pldm_pdr_record *curr_record, uint8_t **data,
182 uint32_t *size, uint32_t *next_record_handle)
183{
184 assert(repo != NULL);
185 assert(curr_record != NULL);
186 assert(data != NULL);
187 assert(size != NULL);
188 assert(next_record_handle != NULL);
189
190 if (curr_record == repo->last) {
191 *data = NULL;
192 *size = 0;
193 *next_record_handle = get_next_record_handle(repo, curr_record);
194 return NULL;
195 }
196
197 *next_record_handle = get_next_record_handle(repo, curr_record->next);
198 *data = curr_record->next->data;
199 *size = curr_record->next->size;
200 return curr_record->next;
201}
202
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930203LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204const pldm_pdr_record *
205pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
206 const pldm_pdr_record *curr_record, uint8_t **data,
207 uint32_t *size)
208{
209 assert(repo != NULL);
210
211 pldm_pdr_record *record = repo->first;
212 if (curr_record != NULL) {
213 record = curr_record->next;
214 }
215 while (record != NULL) {
216 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
217 if (hdr->type == pdr_type) {
218 if (data && size) {
219 *size = record->size;
220 *data = record->data;
221 }
222 return record;
223 }
224 record = record->next;
225 }
226
227 if (size) {
228 *size = 0;
229 }
230 return NULL;
231}
232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930233LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930234uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
235{
236 assert(repo != NULL);
237
238 return repo->record_count;
239}
240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930242uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
243{
244 assert(repo != NULL);
245
246 return repo->size;
247}
248
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930249LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930250uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
251 const pldm_pdr_record *record)
252{
253 assert(repo != NULL);
254 assert(record != NULL);
255
256 return record->record_handle;
257}
258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930259LIBPLDM_ABI_STABLE
260bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930261{
262 assert(record != NULL);
263
264 return record->is_remote;
265}
266
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930267LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
269 uint16_t fru_rsi, uint16_t entity_type,
270 uint16_t entity_instance_num,
271 uint16_t container_id,
272 uint32_t bmc_record_handle)
273{
274 uint32_t size = sizeof(struct pldm_pdr_hdr) +
275 sizeof(struct pldm_pdr_fru_record_set);
276 uint8_t data[size];
277
278 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
279 hdr->version = 1;
280 hdr->record_handle = bmc_record_handle;
281 hdr->type = PLDM_PDR_FRU_RECORD_SET;
282 hdr->record_change_num = 0;
283 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
284 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930285 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
286 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930287 fru->terminus_handle = htole16(terminus_handle);
288 fru->fru_rsi = htole16(fru_rsi);
289 fru->entity_type = htole16(entity_type);
290 fru->entity_instance_num = htole16(entity_instance_num);
291 fru->container_id = htole16(container_id);
292
293 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
294 terminus_handle);
295}
296
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930297LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930299 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
300 uint16_t *entity_type, uint16_t *entity_instance_num,
301 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302{
303 assert(terminus_handle != NULL);
304 assert(entity_type != NULL);
305 assert(entity_instance_num != NULL);
306 assert(container_id != NULL);
307
308 uint8_t *data = NULL;
309 uint32_t size = 0;
310 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930311 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312 while (curr_record != NULL) {
313 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 (struct pldm_pdr_fru_record_set
315 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316 if (fru->fru_rsi == htole16(fru_rsi)) {
317 *terminus_handle = le16toh(fru->terminus_handle);
318 *entity_type = le16toh(fru->entity_type);
319 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 *container_id = le16toh(fru->container_id);
322 return curr_record;
323 }
324 data = NULL;
325 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930326 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
327 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328 }
329
330 *terminus_handle = 0;
331 *entity_type = 0;
332 *entity_instance_num = 0;
333 *container_id = 0;
334
335 return NULL;
336}
337
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930338LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930339/* NOLINTNEXTLINE(readability-identifier-naming) */
340void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
341 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930343 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344 uint32_t size = 0;
345 const pldm_pdr_record *record;
346 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930347 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348
349 do {
350 if (record != NULL) {
351 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930354 (struct pldm_terminus_locator_type_mctp_eid *)
355 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930356 if (pdr->terminus_handle == terminus_handle &&
357 pdr->tid == tid && value->eid == tl_eid) {
358 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 break;
360 }
361 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930362 record = pldm_pdr_find_record_by_type(repo,
363 PLDM_TERMINUS_LOCATOR_PDR,
364 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 } while (record);
366}
367
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500368static bool pldm_record_handle_in_range(uint32_t record_handle,
369 uint32_t first_record_handle,
370 uint32_t last_record_handle)
371{
372 return record_handle >= first_record_handle &&
373 record_handle <= last_record_handle;
374}
375
376LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500377int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500378 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500379 uint8_t child_index, uint32_t range_exclude_start_handle,
380 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500381{
382 pldm_pdr_record *record;
383 if (!repo) {
384 return -EINVAL;
385 }
386
387 for (record = repo->first; record; record = record->next) {
388 bool is_container_entity_instance_number;
389 struct pldm_pdr_entity_association *pdr;
390 bool is_container_entity_type;
391 struct pldm_entity *child;
392 struct pldm_pdr_hdr *hdr;
393 bool in_range;
394
395 // pldm_pdr_add() takes only uint8_t* data as an argument.
396 // The expectation here is the pldm_pdr_hdr is the first field of the record data
397 hdr = (struct pldm_pdr_hdr *)record->data;
398 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
399 continue;
400 }
401 in_range = pldm_record_handle_in_range(
402 record->record_handle, range_exclude_start_handle,
403 range_exclude_end_handle);
404 if (in_range) {
405 continue;
406 }
407
408 // this cast is valid with respect to alignment because
409 // struct pldm_pdr_hdr is declared with __attribute__((packed))
410 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500411 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500412 continue;
413 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500414
415 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500416 is_container_entity_type = pdr->container.entity_type ==
417 entity_type;
418 is_container_entity_instance_number =
419 pdr->container.entity_instance_num == entity_instance;
420 if (is_container_entity_type &&
421 is_container_entity_instance_number) {
422 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500423 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500424 }
425 }
426 return -ENOKEY;
427}
428
Andrew Jeffery9c766792022-08-10 23:12:49 +0930429typedef struct pldm_entity_association_tree {
430 pldm_entity_node *root;
431 uint16_t last_used_container_id;
432} pldm_entity_association_tree;
433
434typedef struct pldm_entity_node {
435 pldm_entity entity;
436 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600437 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930438 pldm_entity_node *first_child;
439 pldm_entity_node *next_sibling;
440 uint8_t association_type;
441} pldm_entity_node;
442
443static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
444{
445 assert(tree != NULL);
446 assert(tree->last_used_container_id != UINT16_MAX);
447
448 return ++tree->last_used_container_id;
449}
450
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930451LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452pldm_entity pldm_entity_extract(pldm_entity_node *node)
453{
454 assert(node != NULL);
455
456 return node->entity;
457}
458
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600459LIBPLDM_ABI_TESTING
460int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
461 uint16_t *cid)
462{
463 if (!entity) {
464 return -EINVAL;
465 }
466
467 *cid = entity->remote_container_id;
468 return 0;
469}
470
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930471LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930472pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930473{
474 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930475 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476 assert(tree != NULL);
477 tree->root = NULL;
478 tree->last_used_container_id = 0;
479
480 return tree;
481}
482
483static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
484 uint16_t entity_type)
485{
486 assert(start != NULL);
487
488 /* Insert after the the last node that matches the input entity type, or
489 * at the end if no such match occurrs
490 */
491 while (start->next_sibling != NULL) {
492 uint16_t this_type = start->entity.entity_type;
493 pldm_entity_node *next = start->next_sibling;
494 if (this_type == entity_type &&
495 (this_type != next->entity.entity_type)) {
496 break;
497 }
498 start = start->next_sibling;
499 }
500
501 return start;
502}
503
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930504LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930505pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930506 pldm_entity_association_tree *tree, pldm_entity *entity,
507 uint16_t entity_instance_number, pldm_entity_node *parent,
508 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930509{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500510 return pldm_entity_association_tree_add_entity(tree, entity,
511 entity_instance_number,
512 parent, association_type,
513 false, true, 0xFFFF);
514}
515
516LIBPLDM_ABI_TESTING
517pldm_entity_node *pldm_entity_association_tree_add_entity(
518 pldm_entity_association_tree *tree, pldm_entity *entity,
519 uint16_t entity_instance_number, pldm_entity_node *parent,
520 uint8_t association_type, bool is_remote, bool is_update_container_id,
521 uint16_t container_id)
522{
523 if ((!tree) || (!entity)) {
524 return NULL;
525 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930526
527 if (entity_instance_number != 0xFFFF && parent != NULL) {
528 pldm_entity node;
529 node.entity_type = entity->entity_type;
530 node.entity_instance_num = entity_instance_number;
531 if (pldm_is_current_parent_child(parent, &node)) {
532 return NULL;
533 }
534 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500535 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
536 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
537 return NULL;
538 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930539 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500540 if (!node) {
541 return NULL;
542 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543 node->first_child = NULL;
544 node->next_sibling = NULL;
545 node->parent.entity_type = 0;
546 node->parent.entity_instance_num = 0;
547 node->parent.entity_container_id = 0;
548 node->entity.entity_type = entity->entity_type;
549 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930550 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600552 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930553 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500554 if (parent != NULL) {
555 free(node);
556 return NULL;
557 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 tree->root = node;
559 /* container_id 0 here indicates this is the top-most entry */
560 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600561 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 } else if (parent != NULL && parent->first_child == NULL) {
563 parent->first_child = node;
564 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500565
566 if (is_remote) {
567 node->remote_container_id = entity->entity_container_id;
568 }
569 if (is_update_container_id) {
570 if (container_id != 0xFFFF) {
571 node->entity.entity_container_id = container_id;
572 } else {
573 node->entity.entity_container_id =
574 next_container_id(tree);
575 }
576 } else {
577 node->entity.entity_container_id =
578 entity->entity_container_id;
579 }
580
581 if (!is_remote) {
582 node->remote_container_id =
583 node->entity.entity_container_id;
584 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930585 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930586 pldm_entity_node *start = parent == NULL ? tree->root :
587 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930589 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500590 if (!prev) {
591 free(node);
592 return NULL;
593 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594 pldm_entity_node *next = prev->next_sibling;
595 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500596 if (prev->entity.entity_instance_num == UINT16_MAX) {
597 free(node);
598 return NULL;
599 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930601 entity_instance_number != 0xFFFF ?
602 entity_instance_number :
603 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604 }
605 prev->next_sibling = node;
606 node->parent = prev->parent;
607 node->next_sibling = next;
608 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930609 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600610 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 }
612 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500613 if (is_update_container_id) {
614 entity->entity_container_id = node->entity.entity_container_id;
615 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 return node;
617}
618
619static void get_num_nodes(pldm_entity_node *node, size_t *num)
620{
621 if (node == NULL) {
622 return;
623 }
624
625 ++(*num);
626 get_num_nodes(node->next_sibling, num);
627 get_num_nodes(node->first_child, num);
628}
629
630static void entity_association_tree_visit(pldm_entity_node *node,
631 pldm_entity *entities, size_t *index)
632{
633 if (node == NULL) {
634 return;
635 }
636
637 pldm_entity *entity = &entities[*index];
638 ++(*index);
639 entity->entity_type = node->entity.entity_type;
640 entity->entity_instance_num = node->entity.entity_instance_num;
641 entity->entity_container_id = node->entity.entity_container_id;
642
643 entity_association_tree_visit(node->next_sibling, entities, index);
644 entity_association_tree_visit(node->first_child, entities, index);
645}
646
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930647LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
649 pldm_entity **entities, size_t *size)
650{
651 assert(tree != NULL);
652
653 *size = 0;
654 if (tree->root == NULL) {
655 return;
656 }
657
658 get_num_nodes(tree->root, size);
659 *entities = malloc(*size * sizeof(pldm_entity));
660 size_t index = 0;
661 entity_association_tree_visit(tree->root, *entities, &index);
662}
663
664static void entity_association_tree_destroy(pldm_entity_node *node)
665{
666 if (node == NULL) {
667 return;
668 }
669
670 entity_association_tree_destroy(node->next_sibling);
671 entity_association_tree_destroy(node->first_child);
672 free(node);
673}
674
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930675LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930676void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
677{
678 assert(tree != NULL);
679
680 entity_association_tree_destroy(tree->root);
681 free(tree);
682}
683
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930684LIBPLDM_ABI_STABLE
685bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686{
687 assert(node != NULL);
688
689 return node->first_child != NULL;
690}
691
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930692LIBPLDM_ABI_STABLE
693pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694{
695 assert(node != NULL);
696
697 return node->parent;
698}
699
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930700LIBPLDM_ABI_STABLE
701bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702{
703 assert(node != NULL);
704
705 if (node->parent.entity_type == 0 &&
706 node->parent.entity_instance_num == 0 &&
707 node->parent.entity_container_id == 0) {
708 return false;
709 }
710
711 return true;
712}
713
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930714LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930715uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
716 uint8_t association_type)
717{
718 assert(node != NULL);
719 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
720 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
721
722 size_t count = 0;
723 pldm_entity_node *curr = node->first_child;
724 while (curr != NULL) {
725 if (curr->association_type == association_type) {
726 ++count;
727 }
728 curr = curr->next_sibling;
729 }
730
731 assert(count < UINT8_MAX);
732 return count;
733}
734
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930735LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
737{
738 assert(parent != NULL);
739 assert(node != NULL);
740
741 pldm_entity_node *curr = parent->first_child;
742 while (curr != NULL) {
743 if (node->entity_type == curr->entity.entity_type &&
744 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930745 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930746 return true;
747 }
748 curr = curr->next_sibling;
749 }
750
751 return false;
752}
753
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500754static void entity_association_pdr_add_children(
755 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
756 uint8_t contained_count, uint8_t association_type, bool is_remote,
757 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758{
759 uint8_t pdr[size];
760 uint8_t *start = pdr;
761
762 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
763 hdr->version = 1;
764 hdr->record_handle = 0;
765 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
766 hdr->record_change_num = 0;
767 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
768 start += sizeof(struct pldm_pdr_hdr);
769
770 uint16_t *container_id = (uint16_t *)start;
771 *container_id = htole16(curr->first_child->entity.entity_container_id);
772 start += sizeof(uint16_t);
773 *start = association_type;
774 start += sizeof(uint8_t);
775
776 pldm_entity *entity = (pldm_entity *)start;
777 entity->entity_type = htole16(curr->entity.entity_type);
778 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
779 entity->entity_container_id = htole16(curr->entity.entity_container_id);
780 start += sizeof(pldm_entity);
781
782 *start = contained_count;
783 start += sizeof(uint8_t);
784
785 pldm_entity_node *node = curr->first_child;
786 while (node != NULL) {
787 if (node->association_type == association_type) {
788 pldm_entity *entity = (pldm_entity *)start;
789 entity->entity_type = htole16(node->entity.entity_type);
790 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930791 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930792 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930793 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930794 start += sizeof(pldm_entity);
795 }
796 node = node->next_sibling;
797 }
798
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500799 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
800 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930801}
802
803static void entity_association_pdr_add_entry(pldm_entity_node *curr,
804 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500805 uint16_t terminus_handle,
806 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930807{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930808 uint8_t num_logical_children = pldm_entity_get_num_children(
809 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
810 uint8_t num_physical_children = pldm_entity_get_num_children(
811 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812
813 if (num_logical_children) {
814 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
816 sizeof(uint8_t) + sizeof(pldm_entity) +
817 sizeof(uint8_t) +
818 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930819 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930820 curr, repo, logical_pdr_size, num_logical_children,
821 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500822 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823 }
824
825 if (num_physical_children) {
826 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930827 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
828 sizeof(uint8_t) + sizeof(pldm_entity) +
829 sizeof(uint8_t) +
830 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930831 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930832 curr, repo, physical_pdr_size, num_physical_children,
833 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500834 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930835 }
836}
837
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930838LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930839bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
840{
841 if (entities == NULL || num_entities == 0) {
842 return true;
843 }
844 size_t i = 0;
845 while (i < num_entities) {
846 if ((*entities + i)->entity_type == entity.entity_type) {
847 return true;
848 }
849 i++;
850 }
851 return false;
852}
853
854static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
855 pldm_entity **entities,
856 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500857 uint16_t terminus_handle,
858 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859{
860 if (curr == NULL) {
861 return;
862 }
863 bool to_add = true;
864 to_add = is_present(curr->entity, entities, num_entities);
865 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500866 entity_association_pdr_add_entry(
867 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868 }
869 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500870 num_entities, is_remote, terminus_handle,
871 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500873 num_entities, is_remote, terminus_handle,
874 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930875}
876
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930877LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
879 pldm_pdr *repo, bool is_remote,
880 uint16_t terminus_handle)
881{
882 assert(tree != NULL);
883 assert(repo != NULL);
884
885 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500886 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887}
888
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930889LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930891 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
892 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893{
894 assert(repo != NULL);
895
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500896 pldm_entity_association_pdr_add_from_node_with_record_handle(
897 node, repo, entities, num_entities, is_remote, terminus_handle,
898 0);
899}
900
901LIBPLDM_ABI_TESTING
902int pldm_entity_association_pdr_add_from_node_with_record_handle(
903 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
904 size_t num_entities, bool is_remote, uint16_t terminus_handle,
905 uint32_t record_handle)
906{
907 if (!node || !repo || !entities) {
908 return -EINVAL;
909 }
910
Andrew Jeffery9c766792022-08-10 23:12:49 +0930911 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500912 is_remote, terminus_handle, record_handle);
913
914 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915}
916
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930917LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
919 pldm_entity_node **node)
920{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600921 bool is_entity_container_id;
922 bool is_entity_instance_num;
923 bool is_type;
924
Andrew Jeffery9c766792022-08-10 23:12:49 +0930925 if (tree_node == NULL) {
926 return;
927 }
928
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600929 is_type = tree_node->entity.entity_type == entity.entity_type;
930 is_entity_instance_num = tree_node->entity.entity_instance_num ==
931 entity.entity_instance_num;
932 is_entity_container_id = tree_node->entity.entity_container_id ==
933 entity.entity_container_id;
934
935 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930936 *node = tree_node;
937 return;
938 }
939
940 find_entity_ref_in_tree(tree_node->first_child, entity, node);
941 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
942}
943
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930944LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
946 pldm_entity entity, pldm_entity_node **node)
947{
948 assert(tree != NULL);
949 find_entity_ref_in_tree(tree->root, entity, node);
950}
951
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930952LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
954 uint16_t terminus_handle)
955{
956 assert(repo != NULL);
957 bool removed = false;
958
959 pldm_pdr_record *record = repo->first;
960 pldm_pdr_record *prev = NULL;
961 while (record != NULL) {
962 pldm_pdr_record *next = record->next;
963 if (record->terminus_handle == terminus_handle) {
964 if (repo->first == record) {
965 repo->first = next;
966 } else {
967 prev->next = next;
968 }
969 if (repo->last == record) {
970 repo->last = prev;
971 }
972 if (record->data) {
973 free(record->data);
974 }
975 --repo->record_count;
976 repo->size -= record->size;
977 free(record);
978 removed = true;
979 } else {
980 prev = record;
981 }
982 record = next;
983 }
984
985 if (removed == true) {
986 record = repo->first;
987 uint32_t record_handle = 0;
988 while (record != NULL) {
989 record->record_handle = ++record_handle;
990 if (record->data != NULL) {
991 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930992 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930994 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995 }
996 record = record->next;
997 }
998 }
999}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000
1001LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1003{
1004 assert(repo != NULL);
1005 bool removed = false;
1006
1007 pldm_pdr_record *record = repo->first;
1008 pldm_pdr_record *prev = NULL;
1009 while (record != NULL) {
1010 pldm_pdr_record *next = record->next;
1011 if (record->is_remote == true) {
1012 if (repo->first == record) {
1013 repo->first = next;
1014 } else {
1015 prev->next = next;
1016 }
1017 if (repo->last == record) {
1018 repo->last = prev;
1019 }
1020 if (record->data) {
1021 free(record->data);
1022 }
1023 --repo->record_count;
1024 repo->size -= record->size;
1025 free(record);
1026 removed = true;
1027 } else {
1028 prev = record;
1029 }
1030 record = next;
1031 }
1032
1033 if (removed == true) {
1034 record = repo->first;
1035 uint32_t record_handle = 0;
1036 while (record != NULL) {
1037 record->record_handle = ++record_handle;
1038 if (record->data != NULL) {
1039 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301042 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043 }
1044 record = record->next;
1045 }
1046 }
1047}
1048
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001049LIBPLDM_ABI_TESTING
1050pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1051 uint32_t first, uint32_t last)
1052{
1053 pldm_pdr_record *record = NULL;
1054 pldm_pdr_record *curr;
1055
1056 if (!repo) {
1057 return NULL;
1058 }
1059 for (curr = repo->first; curr; curr = curr->next) {
1060 if (first > curr->record_handle || last < curr->record_handle) {
1061 continue;
1062 }
1063 if (!record || curr->record_handle > record->record_handle) {
1064 record = curr;
1065 }
1066 }
1067
1068 return record;
1069}
1070
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001071static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1072 pldm_entity *entity,
1073 pldm_entity_node **out,
1074 bool is_remote)
1075{
1076 assert(out != NULL && *out == NULL);
1077 if (node == NULL) {
1078 return;
1079 }
1080 bool is_entity_type;
1081 bool is_entity_instance_num;
1082
1083 is_entity_type = node->entity.entity_type == entity->entity_type;
1084 is_entity_instance_num = node->entity.entity_instance_num ==
1085 entity->entity_instance_num;
1086
1087 if (!is_remote ||
1088 node->remote_container_id == entity->entity_container_id) {
1089 if (is_entity_type && is_entity_instance_num) {
1090 entity->entity_container_id =
1091 node->entity.entity_container_id;
1092 *out = node;
1093 return;
1094 }
1095 }
1096 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1097 is_remote);
1098 entity_association_tree_find_if_remote(node->first_child, entity, out,
1099 is_remote);
1100}
1101
1102LIBPLDM_ABI_TESTING
1103pldm_entity_node *
1104pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1105 pldm_entity *entity, bool is_remote)
1106{
1107 if (!tree || !entity) {
1108 return NULL;
1109 }
1110 pldm_entity_node *node = NULL;
1111 entity_association_tree_find_if_remote(tree->root, entity, &node,
1112 is_remote);
1113 return node;
1114}
1115
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301116LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301117void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1118 pldm_entity_node **out)
1119{
1120 if (node == NULL) {
1121 return;
1122 }
1123
1124 if (node->entity.entity_type == entity->entity_type &&
1125 node->entity.entity_instance_num == entity->entity_instance_num) {
1126 entity->entity_container_id = node->entity.entity_container_id;
1127 *out = node;
1128 return;
1129 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301130 entity_association_tree_find(node->next_sibling, entity, out);
1131 entity_association_tree_find(node->first_child, entity, out);
1132}
1133
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301134LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135pldm_entity_node *
1136pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1137 pldm_entity *entity)
1138{
1139 assert(tree != NULL);
1140
1141 pldm_entity_node *node = NULL;
1142 entity_association_tree_find(tree->root, entity, &node);
1143 return node;
1144}
1145
1146static void entity_association_tree_copy(pldm_entity_node *org_node,
1147 pldm_entity_node **new_node)
1148{
1149 if (org_node == NULL) {
1150 return;
1151 }
1152 *new_node = malloc(sizeof(pldm_entity_node));
1153 (*new_node)->parent = org_node->parent;
1154 (*new_node)->entity = org_node->entity;
1155 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001156 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157 (*new_node)->first_child = NULL;
1158 (*new_node)->next_sibling = NULL;
1159 entity_association_tree_copy(org_node->first_child,
1160 &((*new_node)->first_child));
1161 entity_association_tree_copy(org_node->next_sibling,
1162 &((*new_node)->next_sibling));
1163}
1164
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301165LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301167 pldm_entity_association_tree *org_tree,
1168 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169{
1170 new_tree->last_used_container_id = org_tree->last_used_container_id;
1171 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1172}
1173
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301174LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301175void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301176 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301177{
1178 assert(tree != NULL);
1179 entity_association_tree_destroy(tree->root);
1180 tree->last_used_container_id = 0;
1181 tree->root = NULL;
1182}
1183
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301184LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301185bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1186{
1187 return ((tree->root == NULL) ? true : false);
1188}
1189
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301190LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301191void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1192 size_t *num_entities,
1193 pldm_entity **entities)
1194{
1195 assert(pdr != NULL);
1196 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301197 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198
1199 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1200 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1201
1202 const uint8_t *start = (uint8_t *)pdr;
1203 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301204 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205 start += sizeof(struct pldm_pdr_hdr);
1206 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301207 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208 *num_entities = entity_association_pdr->num_children + 1;
1209 assert(*num_entities >= 2);
1210 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1211 assert(*entities != NULL);
1212 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301213 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 end);
1215 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301216 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301218 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301219 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301220 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221 pldm_entity *curr_entity = entity_association_pdr->children;
1222 size_t i = 1;
1223 while (i < *num_entities) {
1224 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301225 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301227 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301229 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230 ++curr_entity;
1231 ++i;
1232 }
1233}