blob: 2fe9e7b2fb9c901ee3919d694734542c05a4a6d1 [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 =
57 repo->last != NULL ? repo->last->record_handle : 0;
58 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);
73 record->record_handle =
74 record_handle == 0 ? get_new_record_handle(repo) : record_handle;
75 record->size = size;
76 record->is_remote = is_remote;
77 record->terminus_handle = terminus_handle;
78 if (data != NULL) {
79 record->data = malloc(size);
80 assert(record->data != NULL);
81 memcpy(record->data, data, size);
82 /* If record handle is 0, that is an indication for this API to
83 * compute a new handle. For that reason, the computed handle
84 * needs to be populated in the PDR header. For a case where the
85 * caller supplied the record handle, it would exist in the
86 * header already.
87 */
88 if (!record_handle) {
89 struct pldm_pdr_hdr *hdr =
90 (struct pldm_pdr_hdr *)(record->data);
91 hdr->record_handle = htole32(record->record_handle);
92 }
93 }
94 record->next = NULL;
95
96 return record;
97}
98
99uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
100 uint32_t record_handle, bool is_remote,
101 uint16_t terminus_handle)
102{
103 assert(size != 0);
104 assert(data != NULL);
105
106 pldm_pdr_record *record = make_new_record(
107 repo, data, size, record_handle, is_remote, terminus_handle);
108 add_record(repo, record);
109
110 return record->record_handle;
111}
112
Andrew Jeffery319304f2023-04-05 13:53:18 +0930113pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114{
115 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
116 assert(repo != NULL);
117 repo->record_count = 0;
118 repo->size = 0;
119 repo->first = NULL;
120 repo->last = NULL;
121
122 return repo;
123}
124
125void pldm_pdr_destroy(pldm_pdr *repo)
126{
127 assert(repo != NULL);
128
129 pldm_pdr_record *record = repo->first;
130 while (record != NULL) {
131 pldm_pdr_record *next = record->next;
132 if (record->data) {
133 free(record->data);
134 record->data = NULL;
135 }
136 free(record);
137 record = next;
138 }
139 free(repo);
140}
141
142const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
143 uint32_t record_handle,
144 uint8_t **data, uint32_t *size,
145 uint32_t *next_record_handle)
146{
147 assert(repo != NULL);
148 assert(data != NULL);
149 assert(size != NULL);
150 assert(next_record_handle != NULL);
151
152 if (!record_handle && (repo->first != NULL)) {
153 record_handle = repo->first->record_handle;
154 }
155 pldm_pdr_record *record = repo->first;
156 while (record != NULL) {
157 if (record->record_handle == record_handle) {
158 *size = record->size;
159 *data = record->data;
160 *next_record_handle =
161 get_next_record_handle(repo, record);
162 return record;
163 }
164 record = record->next;
165 }
166
167 *size = 0;
168 *next_record_handle = 0;
169 return NULL;
170}
171
172const pldm_pdr_record *
173pldm_pdr_get_next_record(const pldm_pdr *repo,
174 const pldm_pdr_record *curr_record, uint8_t **data,
175 uint32_t *size, uint32_t *next_record_handle)
176{
177 assert(repo != NULL);
178 assert(curr_record != NULL);
179 assert(data != NULL);
180 assert(size != NULL);
181 assert(next_record_handle != NULL);
182
183 if (curr_record == repo->last) {
184 *data = NULL;
185 *size = 0;
186 *next_record_handle = get_next_record_handle(repo, curr_record);
187 return NULL;
188 }
189
190 *next_record_handle = get_next_record_handle(repo, curr_record->next);
191 *data = curr_record->next->data;
192 *size = curr_record->next->size;
193 return curr_record->next;
194}
195
196const pldm_pdr_record *
197pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
198 const pldm_pdr_record *curr_record, uint8_t **data,
199 uint32_t *size)
200{
201 assert(repo != NULL);
202
203 pldm_pdr_record *record = repo->first;
204 if (curr_record != NULL) {
205 record = curr_record->next;
206 }
207 while (record != NULL) {
208 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
209 if (hdr->type == pdr_type) {
210 if (data && size) {
211 *size = record->size;
212 *data = record->data;
213 }
214 return record;
215 }
216 record = record->next;
217 }
218
219 if (size) {
220 *size = 0;
221 }
222 return NULL;
223}
224
225uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
226{
227 assert(repo != NULL);
228
229 return repo->record_count;
230}
231
232uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
233{
234 assert(repo != NULL);
235
236 return repo->size;
237}
238
239uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
240 const pldm_pdr_record *record)
241{
242 assert(repo != NULL);
243 assert(record != NULL);
244
245 return record->record_handle;
246}
247
248inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
249{
250 assert(record != NULL);
251
252 return record->is_remote;
253}
254
255uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
256 uint16_t fru_rsi, uint16_t entity_type,
257 uint16_t entity_instance_num,
258 uint16_t container_id,
259 uint32_t bmc_record_handle)
260{
261 uint32_t size = sizeof(struct pldm_pdr_hdr) +
262 sizeof(struct pldm_pdr_fru_record_set);
263 uint8_t data[size];
264
265 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
266 hdr->version = 1;
267 hdr->record_handle = bmc_record_handle;
268 hdr->type = PLDM_PDR_FRU_RECORD_SET;
269 hdr->record_change_num = 0;
270 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
271 struct pldm_pdr_fru_record_set *fru =
272 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
273 sizeof(struct pldm_pdr_hdr));
274 fru->terminus_handle = htole16(terminus_handle);
275 fru->fru_rsi = htole16(fru_rsi);
276 fru->entity_type = htole16(entity_type);
277 fru->entity_instance_num = htole16(entity_instance_num);
278 fru->container_id = htole16(container_id);
279
280 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
281 terminus_handle);
282}
283
284const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
285 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
286 uint16_t *entity_type, uint16_t *entity_instance_num,
287 uint16_t *container_id)
288{
289 assert(terminus_handle != NULL);
290 assert(entity_type != NULL);
291 assert(entity_instance_num != NULL);
292 assert(container_id != NULL);
293
294 uint8_t *data = NULL;
295 uint32_t size = 0;
296 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
297 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
298 while (curr_record != NULL) {
299 struct pldm_pdr_fru_record_set *fru =
300 (struct pldm_pdr_fru_record_set
301 *)(data + sizeof(struct pldm_pdr_hdr));
302 if (fru->fru_rsi == htole16(fru_rsi)) {
303 *terminus_handle = le16toh(fru->terminus_handle);
304 *entity_type = le16toh(fru->entity_type);
305 *entity_instance_num =
306 le16toh(fru->entity_instance_num);
307 *container_id = le16toh(fru->container_id);
308 return curr_record;
309 }
310 data = NULL;
311 curr_record = pldm_pdr_find_record_by_type(
312 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
313 }
314
315 *terminus_handle = 0;
316 *entity_type = 0;
317 *entity_instance_num = 0;
318 *container_id = 0;
319
320 return NULL;
321}
322
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930323/* NOLINTNEXTLINE(readability-identifier-naming) */
324void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
325 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930327 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328 uint32_t size = 0;
329 const pldm_pdr_record *record;
330 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930331 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332
333 do {
334 if (record != NULL) {
335 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930336 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 struct pldm_terminus_locator_type_mctp_eid *value =
338 (struct pldm_terminus_locator_type_mctp_eid *)
339 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930340 if (pdr->terminus_handle == terminus_handle &&
341 pdr->tid == tid && value->eid == tl_eid) {
342 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343 break;
344 }
345 }
346 record = pldm_pdr_find_record_by_type(
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930347 repo, PLDM_TERMINUS_LOCATOR_PDR, record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348 } while (record);
349}
350
351typedef struct pldm_entity_association_tree {
352 pldm_entity_node *root;
353 uint16_t last_used_container_id;
354} pldm_entity_association_tree;
355
356typedef struct pldm_entity_node {
357 pldm_entity entity;
358 pldm_entity parent;
359 pldm_entity_node *first_child;
360 pldm_entity_node *next_sibling;
361 uint8_t association_type;
362} pldm_entity_node;
363
364static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
365{
366 assert(tree != NULL);
367 assert(tree->last_used_container_id != UINT16_MAX);
368
369 return ++tree->last_used_container_id;
370}
371
372pldm_entity pldm_entity_extract(pldm_entity_node *node)
373{
374 assert(node != NULL);
375
376 return node->entity;
377}
378
Andrew Jeffery319304f2023-04-05 13:53:18 +0930379pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380{
381 pldm_entity_association_tree *tree =
382 malloc(sizeof(pldm_entity_association_tree));
383 assert(tree != NULL);
384 tree->root = NULL;
385 tree->last_used_container_id = 0;
386
387 return tree;
388}
389
390static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
391 uint16_t entity_type)
392{
393 assert(start != NULL);
394
395 /* Insert after the the last node that matches the input entity type, or
396 * at the end if no such match occurrs
397 */
398 while (start->next_sibling != NULL) {
399 uint16_t this_type = start->entity.entity_type;
400 pldm_entity_node *next = start->next_sibling;
401 if (this_type == entity_type &&
402 (this_type != next->entity.entity_type)) {
403 break;
404 }
405 start = start->next_sibling;
406 }
407
408 return start;
409}
410
411pldm_entity_node *pldm_entity_association_tree_add(
412 pldm_entity_association_tree *tree, pldm_entity *entity,
413 uint16_t entity_instance_number, pldm_entity_node *parent,
414 uint8_t association_type)
415{
416 assert(tree != NULL);
417 assert(entity != NULL);
418
419 if (entity_instance_number != 0xFFFF && parent != NULL) {
420 pldm_entity node;
421 node.entity_type = entity->entity_type;
422 node.entity_instance_num = entity_instance_number;
423 if (pldm_is_current_parent_child(parent, &node)) {
424 return NULL;
425 }
426 }
427
428 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
429 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
430 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
431 assert(node != NULL);
432 node->first_child = NULL;
433 node->next_sibling = NULL;
434 node->parent.entity_type = 0;
435 node->parent.entity_instance_num = 0;
436 node->parent.entity_container_id = 0;
437 node->entity.entity_type = entity->entity_type;
438 node->entity.entity_instance_num =
439 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
440 node->association_type = association_type;
441
442 if (tree->root == NULL) {
443 assert(parent == NULL);
444 tree->root = node;
445 /* container_id 0 here indicates this is the top-most entry */
446 node->entity.entity_container_id = 0;
447 } else if (parent != NULL && parent->first_child == NULL) {
448 parent->first_child = node;
449 node->parent = parent->entity;
450 node->entity.entity_container_id = next_container_id(tree);
451 } else {
452 pldm_entity_node *start =
453 parent == NULL ? tree->root : parent->first_child;
454 pldm_entity_node *prev =
455 find_insertion_at(start, entity->entity_type);
456 assert(prev != NULL);
457 pldm_entity_node *next = prev->next_sibling;
458 if (prev->entity.entity_type == entity->entity_type) {
459 assert(prev->entity.entity_instance_num != UINT16_MAX);
460 node->entity.entity_instance_num =
461 entity_instance_number != 0xFFFF
462 ? entity_instance_number
463 : prev->entity.entity_instance_num + 1;
464 }
465 prev->next_sibling = node;
466 node->parent = prev->parent;
467 node->next_sibling = next;
468 node->entity.entity_container_id =
469 prev->entity.entity_container_id;
470 }
471 entity->entity_instance_num = node->entity.entity_instance_num;
472 entity->entity_container_id = node->entity.entity_container_id;
473
474 return node;
475}
476
477static void get_num_nodes(pldm_entity_node *node, size_t *num)
478{
479 if (node == NULL) {
480 return;
481 }
482
483 ++(*num);
484 get_num_nodes(node->next_sibling, num);
485 get_num_nodes(node->first_child, num);
486}
487
488static void entity_association_tree_visit(pldm_entity_node *node,
489 pldm_entity *entities, size_t *index)
490{
491 if (node == NULL) {
492 return;
493 }
494
495 pldm_entity *entity = &entities[*index];
496 ++(*index);
497 entity->entity_type = node->entity.entity_type;
498 entity->entity_instance_num = node->entity.entity_instance_num;
499 entity->entity_container_id = node->entity.entity_container_id;
500
501 entity_association_tree_visit(node->next_sibling, entities, index);
502 entity_association_tree_visit(node->first_child, entities, index);
503}
504
505void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
506 pldm_entity **entities, size_t *size)
507{
508 assert(tree != NULL);
509
510 *size = 0;
511 if (tree->root == NULL) {
512 return;
513 }
514
515 get_num_nodes(tree->root, size);
516 *entities = malloc(*size * sizeof(pldm_entity));
517 size_t index = 0;
518 entity_association_tree_visit(tree->root, *entities, &index);
519}
520
521static void entity_association_tree_destroy(pldm_entity_node *node)
522{
523 if (node == NULL) {
524 return;
525 }
526
527 entity_association_tree_destroy(node->next_sibling);
528 entity_association_tree_destroy(node->first_child);
529 free(node);
530}
531
532void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
533{
534 assert(tree != NULL);
535
536 entity_association_tree_destroy(tree->root);
537 free(tree);
538}
539
540inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
541{
542 assert(node != NULL);
543
544 return node->first_child != NULL;
545}
546
547inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
548{
549 assert(node != NULL);
550
551 return node->parent;
552}
553
554inline bool pldm_entity_is_exist_parent(pldm_entity_node *node)
555{
556 assert(node != NULL);
557
558 if (node->parent.entity_type == 0 &&
559 node->parent.entity_instance_num == 0 &&
560 node->parent.entity_container_id == 0) {
561 return false;
562 }
563
564 return true;
565}
566
567uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
568 uint8_t association_type)
569{
570 assert(node != NULL);
571 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
572 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
573
574 size_t count = 0;
575 pldm_entity_node *curr = node->first_child;
576 while (curr != NULL) {
577 if (curr->association_type == association_type) {
578 ++count;
579 }
580 curr = curr->next_sibling;
581 }
582
583 assert(count < UINT8_MAX);
584 return count;
585}
586
587bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
588{
589 assert(parent != NULL);
590 assert(node != NULL);
591
592 pldm_entity_node *curr = parent->first_child;
593 while (curr != NULL) {
594 if (node->entity_type == curr->entity.entity_type &&
595 node->entity_instance_num ==
596 curr->entity.entity_instance_num) {
597
598 return true;
599 }
600 curr = curr->next_sibling;
601 }
602
603 return false;
604}
605
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930606static void entity_association_pdr_add_children(pldm_entity_node *curr,
607 pldm_pdr *repo, uint16_t size,
608 uint8_t contained_count,
609 uint8_t association_type,
610 bool is_remote,
611 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612{
613 uint8_t pdr[size];
614 uint8_t *start = pdr;
615
616 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
617 hdr->version = 1;
618 hdr->record_handle = 0;
619 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
620 hdr->record_change_num = 0;
621 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
622 start += sizeof(struct pldm_pdr_hdr);
623
624 uint16_t *container_id = (uint16_t *)start;
625 *container_id = htole16(curr->first_child->entity.entity_container_id);
626 start += sizeof(uint16_t);
627 *start = association_type;
628 start += sizeof(uint8_t);
629
630 pldm_entity *entity = (pldm_entity *)start;
631 entity->entity_type = htole16(curr->entity.entity_type);
632 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
633 entity->entity_container_id = htole16(curr->entity.entity_container_id);
634 start += sizeof(pldm_entity);
635
636 *start = contained_count;
637 start += sizeof(uint8_t);
638
639 pldm_entity_node *node = curr->first_child;
640 while (node != NULL) {
641 if (node->association_type == association_type) {
642 pldm_entity *entity = (pldm_entity *)start;
643 entity->entity_type = htole16(node->entity.entity_type);
644 entity->entity_instance_num =
645 htole16(node->entity.entity_instance_num);
646 entity->entity_container_id =
647 htole16(node->entity.entity_container_id);
648 start += sizeof(pldm_entity);
649 }
650 node = node->next_sibling;
651 }
652
653 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
654}
655
656static void entity_association_pdr_add_entry(pldm_entity_node *curr,
657 pldm_pdr *repo, bool is_remote,
658 uint16_t terminus_handle)
659{
660 uint8_t num_logical_children =
661 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
662 uint8_t num_physical_children =
663 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
664
665 if (num_logical_children) {
666 uint16_t logical_pdr_size =
667 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
668 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
669 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930670 entity_association_pdr_add_children(
Andrew Jeffery9c766792022-08-10 23:12:49 +0930671 curr, repo, logical_pdr_size, num_logical_children,
672 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote, terminus_handle);
673 }
674
675 if (num_physical_children) {
676 uint16_t physical_pdr_size =
677 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
678 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
679 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930680 entity_association_pdr_add_children(
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681 curr, repo, physical_pdr_size, num_physical_children,
682 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
683 terminus_handle);
684 }
685}
686
687bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
688{
689 if (entities == NULL || num_entities == 0) {
690 return true;
691 }
692 size_t i = 0;
693 while (i < num_entities) {
694 if ((*entities + i)->entity_type == entity.entity_type) {
695 return true;
696 }
697 i++;
698 }
699 return false;
700}
701
702static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
703 pldm_entity **entities,
704 size_t num_entities, bool is_remote,
705 uint16_t terminus_handle)
706{
707 if (curr == NULL) {
708 return;
709 }
710 bool to_add = true;
711 to_add = is_present(curr->entity, entities, num_entities);
712 if (to_add) {
713 entity_association_pdr_add_entry(curr, repo, is_remote,
714 terminus_handle);
715 }
716 entity_association_pdr_add(curr->next_sibling, repo, entities,
717 num_entities, is_remote, terminus_handle);
718 entity_association_pdr_add(curr->first_child, repo, entities,
719 num_entities, is_remote, terminus_handle);
720}
721
722void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
723 pldm_pdr *repo, bool is_remote,
724 uint16_t terminus_handle)
725{
726 assert(tree != NULL);
727 assert(repo != NULL);
728
729 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
730 terminus_handle);
731}
732
733void pldm_entity_association_pdr_add_from_node(
734 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
735 size_t num_entities, bool is_remote, uint16_t terminus_handle)
736{
737 assert(repo != NULL);
738
739 entity_association_pdr_add(node, repo, entities, num_entities,
740 is_remote, terminus_handle);
741}
742
743void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
744 pldm_entity_node **node)
745{
746 if (tree_node == NULL) {
747 return;
748 }
749
750 if (tree_node->entity.entity_type == entity.entity_type &&
751 tree_node->entity.entity_instance_num ==
752 entity.entity_instance_num) {
753 *node = tree_node;
754 return;
755 }
756
757 find_entity_ref_in_tree(tree_node->first_child, entity, node);
758 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
759}
760
761void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
762 pldm_entity entity, pldm_entity_node **node)
763{
764 assert(tree != NULL);
765 find_entity_ref_in_tree(tree->root, entity, node);
766}
767
768void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
769 uint16_t terminus_handle)
770{
771 assert(repo != NULL);
772 bool removed = false;
773
774 pldm_pdr_record *record = repo->first;
775 pldm_pdr_record *prev = NULL;
776 while (record != NULL) {
777 pldm_pdr_record *next = record->next;
778 if (record->terminus_handle == terminus_handle) {
779 if (repo->first == record) {
780 repo->first = next;
781 } else {
782 prev->next = next;
783 }
784 if (repo->last == record) {
785 repo->last = prev;
786 }
787 if (record->data) {
788 free(record->data);
789 }
790 --repo->record_count;
791 repo->size -= record->size;
792 free(record);
793 removed = true;
794 } else {
795 prev = record;
796 }
797 record = next;
798 }
799
800 if (removed == true) {
801 record = repo->first;
802 uint32_t record_handle = 0;
803 while (record != NULL) {
804 record->record_handle = ++record_handle;
805 if (record->data != NULL) {
806 struct pldm_pdr_hdr *hdr =
807 (struct pldm_pdr_hdr *)(record->data);
808 hdr->record_handle =
809 htole32(record->record_handle);
810 }
811 record = record->next;
812 }
813 }
814}
815void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
816{
817 assert(repo != NULL);
818 bool removed = false;
819
820 pldm_pdr_record *record = repo->first;
821 pldm_pdr_record *prev = NULL;
822 while (record != NULL) {
823 pldm_pdr_record *next = record->next;
824 if (record->is_remote == true) {
825 if (repo->first == record) {
826 repo->first = next;
827 } else {
828 prev->next = next;
829 }
830 if (repo->last == record) {
831 repo->last = prev;
832 }
833 if (record->data) {
834 free(record->data);
835 }
836 --repo->record_count;
837 repo->size -= record->size;
838 free(record);
839 removed = true;
840 } else {
841 prev = record;
842 }
843 record = next;
844 }
845
846 if (removed == true) {
847 record = repo->first;
848 uint32_t record_handle = 0;
849 while (record != NULL) {
850 record->record_handle = ++record_handle;
851 if (record->data != NULL) {
852 struct pldm_pdr_hdr *hdr =
853 (struct pldm_pdr_hdr *)(record->data);
854 hdr->record_handle =
855 htole32(record->record_handle);
856 }
857 record = record->next;
858 }
859 }
860}
861
862void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
863 pldm_entity_node **out)
864{
865 if (node == NULL) {
866 return;
867 }
868
869 if (node->entity.entity_type == entity->entity_type &&
870 node->entity.entity_instance_num == entity->entity_instance_num) {
871 entity->entity_container_id = node->entity.entity_container_id;
872 *out = node;
873 return;
874 }
875
876 entity_association_tree_find(node->next_sibling, entity, out);
877 entity_association_tree_find(node->first_child, entity, out);
878}
879
880pldm_entity_node *
881pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
882 pldm_entity *entity)
883{
884 assert(tree != NULL);
885
886 pldm_entity_node *node = NULL;
887 entity_association_tree_find(tree->root, entity, &node);
888 return node;
889}
890
891static void entity_association_tree_copy(pldm_entity_node *org_node,
892 pldm_entity_node **new_node)
893{
894 if (org_node == NULL) {
895 return;
896 }
897 *new_node = malloc(sizeof(pldm_entity_node));
898 (*new_node)->parent = org_node->parent;
899 (*new_node)->entity = org_node->entity;
900 (*new_node)->association_type = org_node->association_type;
901 (*new_node)->first_child = NULL;
902 (*new_node)->next_sibling = NULL;
903 entity_association_tree_copy(org_node->first_child,
904 &((*new_node)->first_child));
905 entity_association_tree_copy(org_node->next_sibling,
906 &((*new_node)->next_sibling));
907}
908
909void pldm_entity_association_tree_copy_root(
910 pldm_entity_association_tree *org_tree,
911 pldm_entity_association_tree *new_tree)
912{
913 new_tree->last_used_container_id = org_tree->last_used_container_id;
914 entity_association_tree_copy(org_tree->root, &(new_tree->root));
915}
916
917void pldm_entity_association_tree_destroy_root(
918 pldm_entity_association_tree *tree)
919{
920 assert(tree != NULL);
921 entity_association_tree_destroy(tree->root);
922 tree->last_used_container_id = 0;
923 tree->root = NULL;
924}
925
926bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
927{
928 return ((tree->root == NULL) ? true : false);
929}
930
931void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
932 size_t *num_entities,
933 pldm_entity **entities)
934{
935 assert(pdr != NULL);
936 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
937 sizeof(struct pldm_pdr_entity_association));
938
939 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
940 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
941
942 const uint8_t *start = (uint8_t *)pdr;
943 const uint8_t *end =
944 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
945 start += sizeof(struct pldm_pdr_hdr);
946 struct pldm_pdr_entity_association *entity_association_pdr =
947 (struct pldm_pdr_entity_association *)start;
948 *num_entities = entity_association_pdr->num_children + 1;
949 assert(*num_entities >= 2);
950 *entities = malloc(sizeof(pldm_entity) * *num_entities);
951 assert(*entities != NULL);
952 assert(start + sizeof(struct pldm_pdr_entity_association) +
953 sizeof(pldm_entity) * (*num_entities - 2) ==
954 end);
955 (*entities)->entity_type =
956 le16toh(entity_association_pdr->container.entity_type);
957 (*entities)->entity_instance_num =
958 le16toh(entity_association_pdr->container.entity_instance_num);
959 (*entities)->entity_container_id =
960 le16toh(entity_association_pdr->container.entity_container_id);
961 pldm_entity *curr_entity = entity_association_pdr->children;
962 size_t i = 1;
963 while (i < *num_entities) {
964 (*entities + i)->entity_type =
965 le16toh(curr_entity->entity_type);
966 (*entities + i)->entity_instance_num =
967 le16toh(curr_entity->entity_instance_num);
968 (*entities + i)->entity_container_id =
969 le16toh(curr_entity->entity_container_id);
970 ++curr_entity;
971 ++i;
972 }
973}