blob: 232dd89f498b43fa6f2d099f4727e1032f958d96 [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>
7
8typedef struct pldm_pdr_record {
9 uint32_t record_handle;
10 uint32_t size;
11 uint8_t *data;
12 struct pldm_pdr_record *next;
13 bool is_remote;
14 uint16_t terminus_handle;
15} pldm_pdr_record;
16
17typedef struct pldm_pdr {
18 uint32_t record_count;
19 uint32_t size;
20 pldm_pdr_record *first;
21 pldm_pdr_record *last;
22} pldm_pdr;
23
24static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
25 const pldm_pdr_record *record)
26{
27 assert(repo != NULL);
28 assert(record != NULL);
29
30 if (record == repo->last) {
31 return 0;
32 }
33 return record->next->record_handle;
34}
35
36static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
37{
38 assert(repo != NULL);
39 assert(record != NULL);
40
41 if (repo->first == NULL) {
42 assert(repo->last == NULL);
43 repo->first = record;
44 repo->last = record;
45 } else {
46 repo->last->next = record;
47 repo->last = record;
48 }
49 repo->size += record->size;
50 ++repo->record_count;
51}
52
53static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
54{
55 assert(repo != NULL);
56 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093057 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093058 assert(last_used_hdl != UINT32_MAX);
59
60 return last_used_hdl + 1;
61}
62
63static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
64 const uint8_t *data, uint32_t size,
65 uint32_t record_handle, bool is_remote,
66 uint16_t terminus_handle)
67{
68 assert(repo != NULL);
69 assert(size != 0);
70
71 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
72 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093073 record->record_handle = record_handle == 0 ?
74 get_new_record_handle(repo) :
75 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093076 record->size = size;
77 record->is_remote = is_remote;
78 record->terminus_handle = terminus_handle;
79 if (data != NULL) {
80 record->data = malloc(size);
81 assert(record->data != NULL);
82 memcpy(record->data, data, size);
83 /* If record handle is 0, that is an indication for this API to
84 * compute a new handle. For that reason, the computed handle
85 * needs to be populated in the PDR header. For a case where the
86 * caller supplied the record handle, it would exist in the
87 * header already.
88 */
89 if (!record_handle) {
90 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093091 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093092 hdr->record_handle = htole32(record->record_handle);
93 }
94 }
95 record->next = NULL;
96
97 return record;
98}
99
100uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
101 uint32_t record_handle, bool is_remote,
102 uint16_t terminus_handle)
103{
104 assert(size != 0);
105 assert(data != NULL);
106
107 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930108 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109 add_record(repo, record);
110
111 return record->record_handle;
112}
113
Andrew Jeffery319304f2023-04-05 13:53:18 +0930114pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930115{
116 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
117 assert(repo != NULL);
118 repo->record_count = 0;
119 repo->size = 0;
120 repo->first = NULL;
121 repo->last = NULL;
122
123 return repo;
124}
125
126void pldm_pdr_destroy(pldm_pdr *repo)
127{
128 assert(repo != NULL);
129
130 pldm_pdr_record *record = repo->first;
131 while (record != NULL) {
132 pldm_pdr_record *next = record->next;
133 if (record->data) {
134 free(record->data);
135 record->data = NULL;
136 }
137 free(record);
138 record = next;
139 }
140 free(repo);
141}
142
143const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
144 uint32_t record_handle,
145 uint8_t **data, uint32_t *size,
146 uint32_t *next_record_handle)
147{
148 assert(repo != NULL);
149 assert(data != NULL);
150 assert(size != NULL);
151 assert(next_record_handle != NULL);
152
153 if (!record_handle && (repo->first != NULL)) {
154 record_handle = repo->first->record_handle;
155 }
156 pldm_pdr_record *record = repo->first;
157 while (record != NULL) {
158 if (record->record_handle == record_handle) {
159 *size = record->size;
160 *data = record->data;
161 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930162 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930163 return record;
164 }
165 record = record->next;
166 }
167
168 *size = 0;
169 *next_record_handle = 0;
170 return NULL;
171}
172
173const pldm_pdr_record *
174pldm_pdr_get_next_record(const pldm_pdr *repo,
175 const pldm_pdr_record *curr_record, uint8_t **data,
176 uint32_t *size, uint32_t *next_record_handle)
177{
178 assert(repo != NULL);
179 assert(curr_record != NULL);
180 assert(data != NULL);
181 assert(size != NULL);
182 assert(next_record_handle != NULL);
183
184 if (curr_record == repo->last) {
185 *data = NULL;
186 *size = 0;
187 *next_record_handle = get_next_record_handle(repo, curr_record);
188 return NULL;
189 }
190
191 *next_record_handle = get_next_record_handle(repo, curr_record->next);
192 *data = curr_record->next->data;
193 *size = curr_record->next->size;
194 return curr_record->next;
195}
196
197const pldm_pdr_record *
198pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
199 const pldm_pdr_record *curr_record, uint8_t **data,
200 uint32_t *size)
201{
202 assert(repo != NULL);
203
204 pldm_pdr_record *record = repo->first;
205 if (curr_record != NULL) {
206 record = curr_record->next;
207 }
208 while (record != NULL) {
209 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
210 if (hdr->type == pdr_type) {
211 if (data && size) {
212 *size = record->size;
213 *data = record->data;
214 }
215 return record;
216 }
217 record = record->next;
218 }
219
220 if (size) {
221 *size = 0;
222 }
223 return NULL;
224}
225
226uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
227{
228 assert(repo != NULL);
229
230 return repo->record_count;
231}
232
233uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
234{
235 assert(repo != NULL);
236
237 return repo->size;
238}
239
240uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
241 const pldm_pdr_record *record)
242{
243 assert(repo != NULL);
244 assert(record != NULL);
245
246 return record->record_handle;
247}
248
249inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
250{
251 assert(record != NULL);
252
253 return record->is_remote;
254}
255
256uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
257 uint16_t fru_rsi, uint16_t entity_type,
258 uint16_t entity_instance_num,
259 uint16_t container_id,
260 uint32_t bmc_record_handle)
261{
262 uint32_t size = sizeof(struct pldm_pdr_hdr) +
263 sizeof(struct pldm_pdr_fru_record_set);
264 uint8_t data[size];
265
266 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
267 hdr->version = 1;
268 hdr->record_handle = bmc_record_handle;
269 hdr->type = PLDM_PDR_FRU_RECORD_SET;
270 hdr->record_change_num = 0;
271 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
272 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930273 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
274 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930275 fru->terminus_handle = htole16(terminus_handle);
276 fru->fru_rsi = htole16(fru_rsi);
277 fru->entity_type = htole16(entity_type);
278 fru->entity_instance_num = htole16(entity_instance_num);
279 fru->container_id = htole16(container_id);
280
281 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
282 terminus_handle);
283}
284
285const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930286 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
287 uint16_t *entity_type, uint16_t *entity_instance_num,
288 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930289{
290 assert(terminus_handle != NULL);
291 assert(entity_type != NULL);
292 assert(entity_instance_num != NULL);
293 assert(container_id != NULL);
294
295 uint8_t *data = NULL;
296 uint32_t size = 0;
297 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930298 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299 while (curr_record != NULL) {
300 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930301 (struct pldm_pdr_fru_record_set
302 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303 if (fru->fru_rsi == htole16(fru_rsi)) {
304 *terminus_handle = le16toh(fru->terminus_handle);
305 *entity_type = le16toh(fru->entity_type);
306 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930307 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308 *container_id = le16toh(fru->container_id);
309 return curr_record;
310 }
311 data = NULL;
312 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930313 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
314 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930315 }
316
317 *terminus_handle = 0;
318 *entity_type = 0;
319 *entity_instance_num = 0;
320 *container_id = 0;
321
322 return NULL;
323}
324
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930325/* NOLINTNEXTLINE(readability-identifier-naming) */
326void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
327 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930329 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930330 uint32_t size = 0;
331 const pldm_pdr_record *record;
332 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930333 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334
335 do {
336 if (record != NULL) {
337 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930338 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930340 (struct pldm_terminus_locator_type_mctp_eid *)
341 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930342 if (pdr->terminus_handle == terminus_handle &&
343 pdr->tid == tid && value->eid == tl_eid) {
344 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345 break;
346 }
347 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 record = pldm_pdr_find_record_by_type(repo,
349 PLDM_TERMINUS_LOCATOR_PDR,
350 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 } while (record);
352}
353
354typedef struct pldm_entity_association_tree {
355 pldm_entity_node *root;
356 uint16_t last_used_container_id;
357} pldm_entity_association_tree;
358
359typedef struct pldm_entity_node {
360 pldm_entity entity;
361 pldm_entity parent;
362 pldm_entity_node *first_child;
363 pldm_entity_node *next_sibling;
364 uint8_t association_type;
365} pldm_entity_node;
366
367static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
368{
369 assert(tree != NULL);
370 assert(tree->last_used_container_id != UINT16_MAX);
371
372 return ++tree->last_used_container_id;
373}
374
375pldm_entity pldm_entity_extract(pldm_entity_node *node)
376{
377 assert(node != NULL);
378
379 return node->entity;
380}
381
Andrew Jeffery319304f2023-04-05 13:53:18 +0930382pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383{
384 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930385 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930386 assert(tree != NULL);
387 tree->root = NULL;
388 tree->last_used_container_id = 0;
389
390 return tree;
391}
392
393static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
394 uint16_t entity_type)
395{
396 assert(start != NULL);
397
398 /* Insert after the the last node that matches the input entity type, or
399 * at the end if no such match occurrs
400 */
401 while (start->next_sibling != NULL) {
402 uint16_t this_type = start->entity.entity_type;
403 pldm_entity_node *next = start->next_sibling;
404 if (this_type == entity_type &&
405 (this_type != next->entity.entity_type)) {
406 break;
407 }
408 start = start->next_sibling;
409 }
410
411 return start;
412}
413
414pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930415 pldm_entity_association_tree *tree, pldm_entity *entity,
416 uint16_t entity_instance_number, pldm_entity_node *parent,
417 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930418{
419 assert(tree != NULL);
420 assert(entity != NULL);
421
422 if (entity_instance_number != 0xFFFF && parent != NULL) {
423 pldm_entity node;
424 node.entity_type = entity->entity_type;
425 node.entity_instance_num = entity_instance_number;
426 if (pldm_is_current_parent_child(parent, &node)) {
427 return NULL;
428 }
429 }
430
431 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
432 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
433 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
434 assert(node != NULL);
435 node->first_child = NULL;
436 node->next_sibling = NULL;
437 node->parent.entity_type = 0;
438 node->parent.entity_instance_num = 0;
439 node->parent.entity_container_id = 0;
440 node->entity.entity_type = entity->entity_type;
441 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930442 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443 node->association_type = association_type;
444
445 if (tree->root == NULL) {
446 assert(parent == NULL);
447 tree->root = node;
448 /* container_id 0 here indicates this is the top-most entry */
449 node->entity.entity_container_id = 0;
450 } else if (parent != NULL && parent->first_child == NULL) {
451 parent->first_child = node;
452 node->parent = parent->entity;
453 node->entity.entity_container_id = next_container_id(tree);
454 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930455 pldm_entity_node *start = parent == NULL ? tree->root :
456 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930457 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930458 find_insertion_at(start, entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459 assert(prev != NULL);
460 pldm_entity_node *next = prev->next_sibling;
461 if (prev->entity.entity_type == entity->entity_type) {
462 assert(prev->entity.entity_instance_num != UINT16_MAX);
463 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930464 entity_instance_number != 0xFFFF ?
465 entity_instance_number :
466 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930467 }
468 prev->next_sibling = node;
469 node->parent = prev->parent;
470 node->next_sibling = next;
471 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930472 prev->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930473 }
474 entity->entity_instance_num = node->entity.entity_instance_num;
475 entity->entity_container_id = node->entity.entity_container_id;
476
477 return node;
478}
479
480static void get_num_nodes(pldm_entity_node *node, size_t *num)
481{
482 if (node == NULL) {
483 return;
484 }
485
486 ++(*num);
487 get_num_nodes(node->next_sibling, num);
488 get_num_nodes(node->first_child, num);
489}
490
491static void entity_association_tree_visit(pldm_entity_node *node,
492 pldm_entity *entities, size_t *index)
493{
494 if (node == NULL) {
495 return;
496 }
497
498 pldm_entity *entity = &entities[*index];
499 ++(*index);
500 entity->entity_type = node->entity.entity_type;
501 entity->entity_instance_num = node->entity.entity_instance_num;
502 entity->entity_container_id = node->entity.entity_container_id;
503
504 entity_association_tree_visit(node->next_sibling, entities, index);
505 entity_association_tree_visit(node->first_child, entities, index);
506}
507
508void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
509 pldm_entity **entities, size_t *size)
510{
511 assert(tree != NULL);
512
513 *size = 0;
514 if (tree->root == NULL) {
515 return;
516 }
517
518 get_num_nodes(tree->root, size);
519 *entities = malloc(*size * sizeof(pldm_entity));
520 size_t index = 0;
521 entity_association_tree_visit(tree->root, *entities, &index);
522}
523
524static void entity_association_tree_destroy(pldm_entity_node *node)
525{
526 if (node == NULL) {
527 return;
528 }
529
530 entity_association_tree_destroy(node->next_sibling);
531 entity_association_tree_destroy(node->first_child);
532 free(node);
533}
534
535void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
536{
537 assert(tree != NULL);
538
539 entity_association_tree_destroy(tree->root);
540 free(tree);
541}
542
543inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
544{
545 assert(node != NULL);
546
547 return node->first_child != NULL;
548}
549
550inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
551{
552 assert(node != NULL);
553
554 return node->parent;
555}
556
557inline bool pldm_entity_is_exist_parent(pldm_entity_node *node)
558{
559 assert(node != NULL);
560
561 if (node->parent.entity_type == 0 &&
562 node->parent.entity_instance_num == 0 &&
563 node->parent.entity_container_id == 0) {
564 return false;
565 }
566
567 return true;
568}
569
570uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
571 uint8_t association_type)
572{
573 assert(node != NULL);
574 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
575 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
576
577 size_t count = 0;
578 pldm_entity_node *curr = node->first_child;
579 while (curr != NULL) {
580 if (curr->association_type == association_type) {
581 ++count;
582 }
583 curr = curr->next_sibling;
584 }
585
586 assert(count < UINT8_MAX);
587 return count;
588}
589
590bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
591{
592 assert(parent != NULL);
593 assert(node != NULL);
594
595 pldm_entity_node *curr = parent->first_child;
596 while (curr != NULL) {
597 if (node->entity_type == curr->entity.entity_type &&
598 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930599 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600 return true;
601 }
602 curr = curr->next_sibling;
603 }
604
605 return false;
606}
607
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930608static void entity_association_pdr_add_children(pldm_entity_node *curr,
609 pldm_pdr *repo, uint16_t size,
610 uint8_t contained_count,
611 uint8_t association_type,
612 bool is_remote,
613 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614{
615 uint8_t pdr[size];
616 uint8_t *start = pdr;
617
618 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
619 hdr->version = 1;
620 hdr->record_handle = 0;
621 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
622 hdr->record_change_num = 0;
623 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
624 start += sizeof(struct pldm_pdr_hdr);
625
626 uint16_t *container_id = (uint16_t *)start;
627 *container_id = htole16(curr->first_child->entity.entity_container_id);
628 start += sizeof(uint16_t);
629 *start = association_type;
630 start += sizeof(uint8_t);
631
632 pldm_entity *entity = (pldm_entity *)start;
633 entity->entity_type = htole16(curr->entity.entity_type);
634 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
635 entity->entity_container_id = htole16(curr->entity.entity_container_id);
636 start += sizeof(pldm_entity);
637
638 *start = contained_count;
639 start += sizeof(uint8_t);
640
641 pldm_entity_node *node = curr->first_child;
642 while (node != NULL) {
643 if (node->association_type == association_type) {
644 pldm_entity *entity = (pldm_entity *)start;
645 entity->entity_type = htole16(node->entity.entity_type);
646 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930647 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930649 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930650 start += sizeof(pldm_entity);
651 }
652 node = node->next_sibling;
653 }
654
655 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
656}
657
658static void entity_association_pdr_add_entry(pldm_entity_node *curr,
659 pldm_pdr *repo, bool is_remote,
660 uint16_t terminus_handle)
661{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930662 uint8_t num_logical_children = pldm_entity_get_num_children(
663 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
664 uint8_t num_physical_children = pldm_entity_get_num_children(
665 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666
667 if (num_logical_children) {
668 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930669 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
670 sizeof(uint8_t) + sizeof(pldm_entity) +
671 sizeof(uint8_t) +
672 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930673 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930674 curr, repo, logical_pdr_size, num_logical_children,
675 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
676 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677 }
678
679 if (num_physical_children) {
680 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930681 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
682 sizeof(uint8_t) + sizeof(pldm_entity) +
683 sizeof(uint8_t) +
684 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930685 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930686 curr, repo, physical_pdr_size, num_physical_children,
687 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
688 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930689 }
690}
691
692bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
693{
694 if (entities == NULL || num_entities == 0) {
695 return true;
696 }
697 size_t i = 0;
698 while (i < num_entities) {
699 if ((*entities + i)->entity_type == entity.entity_type) {
700 return true;
701 }
702 i++;
703 }
704 return false;
705}
706
707static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
708 pldm_entity **entities,
709 size_t num_entities, bool is_remote,
710 uint16_t terminus_handle)
711{
712 if (curr == NULL) {
713 return;
714 }
715 bool to_add = true;
716 to_add = is_present(curr->entity, entities, num_entities);
717 if (to_add) {
718 entity_association_pdr_add_entry(curr, repo, is_remote,
719 terminus_handle);
720 }
721 entity_association_pdr_add(curr->next_sibling, repo, entities,
722 num_entities, is_remote, terminus_handle);
723 entity_association_pdr_add(curr->first_child, repo, entities,
724 num_entities, is_remote, terminus_handle);
725}
726
727void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
728 pldm_pdr *repo, bool is_remote,
729 uint16_t terminus_handle)
730{
731 assert(tree != NULL);
732 assert(repo != NULL);
733
734 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
735 terminus_handle);
736}
737
738void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930739 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
740 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741{
742 assert(repo != NULL);
743
744 entity_association_pdr_add(node, repo, entities, num_entities,
745 is_remote, terminus_handle);
746}
747
748void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
749 pldm_entity_node **node)
750{
751 if (tree_node == NULL) {
752 return;
753 }
754
755 if (tree_node->entity.entity_type == entity.entity_type &&
756 tree_node->entity.entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930757 entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758 *node = tree_node;
759 return;
760 }
761
762 find_entity_ref_in_tree(tree_node->first_child, entity, node);
763 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
764}
765
766void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
767 pldm_entity entity, pldm_entity_node **node)
768{
769 assert(tree != NULL);
770 find_entity_ref_in_tree(tree->root, entity, node);
771}
772
773void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
774 uint16_t terminus_handle)
775{
776 assert(repo != NULL);
777 bool removed = false;
778
779 pldm_pdr_record *record = repo->first;
780 pldm_pdr_record *prev = NULL;
781 while (record != NULL) {
782 pldm_pdr_record *next = record->next;
783 if (record->terminus_handle == terminus_handle) {
784 if (repo->first == record) {
785 repo->first = next;
786 } else {
787 prev->next = next;
788 }
789 if (repo->last == record) {
790 repo->last = prev;
791 }
792 if (record->data) {
793 free(record->data);
794 }
795 --repo->record_count;
796 repo->size -= record->size;
797 free(record);
798 removed = true;
799 } else {
800 prev = record;
801 }
802 record = next;
803 }
804
805 if (removed == true) {
806 record = repo->first;
807 uint32_t record_handle = 0;
808 while (record != NULL) {
809 record->record_handle = ++record_handle;
810 if (record->data != NULL) {
811 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930812 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930814 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815 }
816 record = record->next;
817 }
818 }
819}
820void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
821{
822 assert(repo != NULL);
823 bool removed = false;
824
825 pldm_pdr_record *record = repo->first;
826 pldm_pdr_record *prev = NULL;
827 while (record != NULL) {
828 pldm_pdr_record *next = record->next;
829 if (record->is_remote == true) {
830 if (repo->first == record) {
831 repo->first = next;
832 } else {
833 prev->next = next;
834 }
835 if (repo->last == record) {
836 repo->last = prev;
837 }
838 if (record->data) {
839 free(record->data);
840 }
841 --repo->record_count;
842 repo->size -= record->size;
843 free(record);
844 removed = true;
845 } else {
846 prev = record;
847 }
848 record = next;
849 }
850
851 if (removed == true) {
852 record = repo->first;
853 uint32_t record_handle = 0;
854 while (record != NULL) {
855 record->record_handle = ++record_handle;
856 if (record->data != NULL) {
857 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930858 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930860 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861 }
862 record = record->next;
863 }
864 }
865}
866
867void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
868 pldm_entity_node **out)
869{
870 if (node == NULL) {
871 return;
872 }
873
874 if (node->entity.entity_type == entity->entity_type &&
875 node->entity.entity_instance_num == entity->entity_instance_num) {
876 entity->entity_container_id = node->entity.entity_container_id;
877 *out = node;
878 return;
879 }
880
881 entity_association_tree_find(node->next_sibling, entity, out);
882 entity_association_tree_find(node->first_child, entity, out);
883}
884
885pldm_entity_node *
886pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
887 pldm_entity *entity)
888{
889 assert(tree != NULL);
890
891 pldm_entity_node *node = NULL;
892 entity_association_tree_find(tree->root, entity, &node);
893 return node;
894}
895
896static void entity_association_tree_copy(pldm_entity_node *org_node,
897 pldm_entity_node **new_node)
898{
899 if (org_node == NULL) {
900 return;
901 }
902 *new_node = malloc(sizeof(pldm_entity_node));
903 (*new_node)->parent = org_node->parent;
904 (*new_node)->entity = org_node->entity;
905 (*new_node)->association_type = org_node->association_type;
906 (*new_node)->first_child = NULL;
907 (*new_node)->next_sibling = NULL;
908 entity_association_tree_copy(org_node->first_child,
909 &((*new_node)->first_child));
910 entity_association_tree_copy(org_node->next_sibling,
911 &((*new_node)->next_sibling));
912}
913
914void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930915 pldm_entity_association_tree *org_tree,
916 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917{
918 new_tree->last_used_container_id = org_tree->last_used_container_id;
919 entity_association_tree_copy(org_tree->root, &(new_tree->root));
920}
921
922void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930923 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924{
925 assert(tree != NULL);
926 entity_association_tree_destroy(tree->root);
927 tree->last_used_container_id = 0;
928 tree->root = NULL;
929}
930
931bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
932{
933 return ((tree->root == NULL) ? true : false);
934}
935
936void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
937 size_t *num_entities,
938 pldm_entity **entities)
939{
940 assert(pdr != NULL);
941 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930942 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943
944 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
945 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
946
947 const uint8_t *start = (uint8_t *)pdr;
948 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930949 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 start += sizeof(struct pldm_pdr_hdr);
951 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930952 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953 *num_entities = entity_association_pdr->num_children + 1;
954 assert(*num_entities >= 2);
955 *entities = malloc(sizeof(pldm_entity) * *num_entities);
956 assert(*entities != NULL);
957 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930958 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959 end);
960 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930961 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930963 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930964 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930965 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930966 pldm_entity *curr_entity = entity_association_pdr->children;
967 size_t i = 1;
968 while (i < *num_entities) {
969 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930970 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930972 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930974 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975 ++curr_entity;
976 ++i;
977 }
978}