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