blob: b3a5d5a276890d29560faa140b96286fe0b4a97f [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
323void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
324 uint8_t tid, uint8_t tlEid, bool validBit)
325{
326 uint8_t *outData = NULL;
327 uint32_t size = 0;
328 const pldm_pdr_record *record;
329 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
330 NULL, &outData, &size);
331
332 do {
333 if (record != NULL) {
334 struct pldm_terminus_locator_pdr *pdr =
335 (struct pldm_terminus_locator_pdr *)outData;
336 struct pldm_terminus_locator_type_mctp_eid *value =
337 (struct pldm_terminus_locator_type_mctp_eid *)
338 pdr->terminus_locator_value;
339 if (pdr->terminus_handle == terminusHandle &&
340 pdr->tid == tid && value->eid == tlEid) {
341 pdr->validity = validBit;
342 break;
343 }
344 }
345 record = pldm_pdr_find_record_by_type(
346 repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size);
347 } while (record);
348}
349
350typedef struct pldm_entity_association_tree {
351 pldm_entity_node *root;
352 uint16_t last_used_container_id;
353} pldm_entity_association_tree;
354
355typedef struct pldm_entity_node {
356 pldm_entity entity;
357 pldm_entity parent;
358 pldm_entity_node *first_child;
359 pldm_entity_node *next_sibling;
360 uint8_t association_type;
361} pldm_entity_node;
362
363static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
364{
365 assert(tree != NULL);
366 assert(tree->last_used_container_id != UINT16_MAX);
367
368 return ++tree->last_used_container_id;
369}
370
371pldm_entity pldm_entity_extract(pldm_entity_node *node)
372{
373 assert(node != NULL);
374
375 return node->entity;
376}
377
Andrew Jeffery319304f2023-04-05 13:53:18 +0930378pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379{
380 pldm_entity_association_tree *tree =
381 malloc(sizeof(pldm_entity_association_tree));
382 assert(tree != NULL);
383 tree->root = NULL;
384 tree->last_used_container_id = 0;
385
386 return tree;
387}
388
389static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
390 uint16_t entity_type)
391{
392 assert(start != NULL);
393
394 /* Insert after the the last node that matches the input entity type, or
395 * at the end if no such match occurrs
396 */
397 while (start->next_sibling != NULL) {
398 uint16_t this_type = start->entity.entity_type;
399 pldm_entity_node *next = start->next_sibling;
400 if (this_type == entity_type &&
401 (this_type != next->entity.entity_type)) {
402 break;
403 }
404 start = start->next_sibling;
405 }
406
407 return start;
408}
409
410pldm_entity_node *pldm_entity_association_tree_add(
411 pldm_entity_association_tree *tree, pldm_entity *entity,
412 uint16_t entity_instance_number, pldm_entity_node *parent,
413 uint8_t association_type)
414{
415 assert(tree != NULL);
416 assert(entity != NULL);
417
418 if (entity_instance_number != 0xFFFF && parent != NULL) {
419 pldm_entity node;
420 node.entity_type = entity->entity_type;
421 node.entity_instance_num = entity_instance_number;
422 if (pldm_is_current_parent_child(parent, &node)) {
423 return NULL;
424 }
425 }
426
427 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
428 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
429 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
430 assert(node != NULL);
431 node->first_child = NULL;
432 node->next_sibling = NULL;
433 node->parent.entity_type = 0;
434 node->parent.entity_instance_num = 0;
435 node->parent.entity_container_id = 0;
436 node->entity.entity_type = entity->entity_type;
437 node->entity.entity_instance_num =
438 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
439 node->association_type = association_type;
440
441 if (tree->root == NULL) {
442 assert(parent == NULL);
443 tree->root = node;
444 /* container_id 0 here indicates this is the top-most entry */
445 node->entity.entity_container_id = 0;
446 } else if (parent != NULL && parent->first_child == NULL) {
447 parent->first_child = node;
448 node->parent = parent->entity;
449 node->entity.entity_container_id = next_container_id(tree);
450 } else {
451 pldm_entity_node *start =
452 parent == NULL ? tree->root : parent->first_child;
453 pldm_entity_node *prev =
454 find_insertion_at(start, entity->entity_type);
455 assert(prev != NULL);
456 pldm_entity_node *next = prev->next_sibling;
457 if (prev->entity.entity_type == entity->entity_type) {
458 assert(prev->entity.entity_instance_num != UINT16_MAX);
459 node->entity.entity_instance_num =
460 entity_instance_number != 0xFFFF
461 ? entity_instance_number
462 : prev->entity.entity_instance_num + 1;
463 }
464 prev->next_sibling = node;
465 node->parent = prev->parent;
466 node->next_sibling = next;
467 node->entity.entity_container_id =
468 prev->entity.entity_container_id;
469 }
470 entity->entity_instance_num = node->entity.entity_instance_num;
471 entity->entity_container_id = node->entity.entity_container_id;
472
473 return node;
474}
475
476static void get_num_nodes(pldm_entity_node *node, size_t *num)
477{
478 if (node == NULL) {
479 return;
480 }
481
482 ++(*num);
483 get_num_nodes(node->next_sibling, num);
484 get_num_nodes(node->first_child, num);
485}
486
487static void entity_association_tree_visit(pldm_entity_node *node,
488 pldm_entity *entities, size_t *index)
489{
490 if (node == NULL) {
491 return;
492 }
493
494 pldm_entity *entity = &entities[*index];
495 ++(*index);
496 entity->entity_type = node->entity.entity_type;
497 entity->entity_instance_num = node->entity.entity_instance_num;
498 entity->entity_container_id = node->entity.entity_container_id;
499
500 entity_association_tree_visit(node->next_sibling, entities, index);
501 entity_association_tree_visit(node->first_child, entities, index);
502}
503
504void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
505 pldm_entity **entities, size_t *size)
506{
507 assert(tree != NULL);
508
509 *size = 0;
510 if (tree->root == NULL) {
511 return;
512 }
513
514 get_num_nodes(tree->root, size);
515 *entities = malloc(*size * sizeof(pldm_entity));
516 size_t index = 0;
517 entity_association_tree_visit(tree->root, *entities, &index);
518}
519
520static void entity_association_tree_destroy(pldm_entity_node *node)
521{
522 if (node == NULL) {
523 return;
524 }
525
526 entity_association_tree_destroy(node->next_sibling);
527 entity_association_tree_destroy(node->first_child);
528 free(node);
529}
530
531void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
532{
533 assert(tree != NULL);
534
535 entity_association_tree_destroy(tree->root);
536 free(tree);
537}
538
539inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
540{
541 assert(node != NULL);
542
543 return node->first_child != NULL;
544}
545
546inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
547{
548 assert(node != NULL);
549
550 return node->parent;
551}
552
553inline bool pldm_entity_is_exist_parent(pldm_entity_node *node)
554{
555 assert(node != NULL);
556
557 if (node->parent.entity_type == 0 &&
558 node->parent.entity_instance_num == 0 &&
559 node->parent.entity_container_id == 0) {
560 return false;
561 }
562
563 return true;
564}
565
566uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
567 uint8_t association_type)
568{
569 assert(node != NULL);
570 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
571 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
572
573 size_t count = 0;
574 pldm_entity_node *curr = node->first_child;
575 while (curr != NULL) {
576 if (curr->association_type == association_type) {
577 ++count;
578 }
579 curr = curr->next_sibling;
580 }
581
582 assert(count < UINT8_MAX);
583 return count;
584}
585
586bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
587{
588 assert(parent != NULL);
589 assert(node != NULL);
590
591 pldm_entity_node *curr = parent->first_child;
592 while (curr != NULL) {
593 if (node->entity_type == curr->entity.entity_type &&
594 node->entity_instance_num ==
595 curr->entity.entity_instance_num) {
596
597 return true;
598 }
599 curr = curr->next_sibling;
600 }
601
602 return false;
603}
604
605static void _entity_association_pdr_add_entry(pldm_entity_node *curr,
606 pldm_pdr *repo, uint16_t size,
607 uint8_t contained_count,
608 uint8_t association_type,
609 bool is_remote,
610 uint16_t terminus_handle)
611{
612 uint8_t pdr[size];
613 uint8_t *start = pdr;
614
615 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
616 hdr->version = 1;
617 hdr->record_handle = 0;
618 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
619 hdr->record_change_num = 0;
620 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
621 start += sizeof(struct pldm_pdr_hdr);
622
623 uint16_t *container_id = (uint16_t *)start;
624 *container_id = htole16(curr->first_child->entity.entity_container_id);
625 start += sizeof(uint16_t);
626 *start = association_type;
627 start += sizeof(uint8_t);
628
629 pldm_entity *entity = (pldm_entity *)start;
630 entity->entity_type = htole16(curr->entity.entity_type);
631 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
632 entity->entity_container_id = htole16(curr->entity.entity_container_id);
633 start += sizeof(pldm_entity);
634
635 *start = contained_count;
636 start += sizeof(uint8_t);
637
638 pldm_entity_node *node = curr->first_child;
639 while (node != NULL) {
640 if (node->association_type == association_type) {
641 pldm_entity *entity = (pldm_entity *)start;
642 entity->entity_type = htole16(node->entity.entity_type);
643 entity->entity_instance_num =
644 htole16(node->entity.entity_instance_num);
645 entity->entity_container_id =
646 htole16(node->entity.entity_container_id);
647 start += sizeof(pldm_entity);
648 }
649 node = node->next_sibling;
650 }
651
652 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
653}
654
655static void entity_association_pdr_add_entry(pldm_entity_node *curr,
656 pldm_pdr *repo, bool is_remote,
657 uint16_t terminus_handle)
658{
659 uint8_t num_logical_children =
660 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
661 uint8_t num_physical_children =
662 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
663
664 if (num_logical_children) {
665 uint16_t logical_pdr_size =
666 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
667 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
668 (num_logical_children * sizeof(pldm_entity));
669 _entity_association_pdr_add_entry(
670 curr, repo, logical_pdr_size, num_logical_children,
671 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote, terminus_handle);
672 }
673
674 if (num_physical_children) {
675 uint16_t physical_pdr_size =
676 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
677 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
678 (num_physical_children * sizeof(pldm_entity));
679 _entity_association_pdr_add_entry(
680 curr, repo, physical_pdr_size, num_physical_children,
681 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
682 terminus_handle);
683 }
684}
685
686bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
687{
688 if (entities == NULL || num_entities == 0) {
689 return true;
690 }
691 size_t i = 0;
692 while (i < num_entities) {
693 if ((*entities + i)->entity_type == entity.entity_type) {
694 return true;
695 }
696 i++;
697 }
698 return false;
699}
700
701static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
702 pldm_entity **entities,
703 size_t num_entities, bool is_remote,
704 uint16_t terminus_handle)
705{
706 if (curr == NULL) {
707 return;
708 }
709 bool to_add = true;
710 to_add = is_present(curr->entity, entities, num_entities);
711 if (to_add) {
712 entity_association_pdr_add_entry(curr, repo, is_remote,
713 terminus_handle);
714 }
715 entity_association_pdr_add(curr->next_sibling, repo, entities,
716 num_entities, is_remote, terminus_handle);
717 entity_association_pdr_add(curr->first_child, repo, entities,
718 num_entities, is_remote, terminus_handle);
719}
720
721void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
722 pldm_pdr *repo, bool is_remote,
723 uint16_t terminus_handle)
724{
725 assert(tree != NULL);
726 assert(repo != NULL);
727
728 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
729 terminus_handle);
730}
731
732void pldm_entity_association_pdr_add_from_node(
733 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
734 size_t num_entities, bool is_remote, uint16_t terminus_handle)
735{
736 assert(repo != NULL);
737
738 entity_association_pdr_add(node, repo, entities, num_entities,
739 is_remote, terminus_handle);
740}
741
742void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
743 pldm_entity_node **node)
744{
745 if (tree_node == NULL) {
746 return;
747 }
748
749 if (tree_node->entity.entity_type == entity.entity_type &&
750 tree_node->entity.entity_instance_num ==
751 entity.entity_instance_num) {
752 *node = tree_node;
753 return;
754 }
755
756 find_entity_ref_in_tree(tree_node->first_child, entity, node);
757 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
758}
759
760void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
761 pldm_entity entity, pldm_entity_node **node)
762{
763 assert(tree != NULL);
764 find_entity_ref_in_tree(tree->root, entity, node);
765}
766
767void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
768 uint16_t terminus_handle)
769{
770 assert(repo != NULL);
771 bool removed = false;
772
773 pldm_pdr_record *record = repo->first;
774 pldm_pdr_record *prev = NULL;
775 while (record != NULL) {
776 pldm_pdr_record *next = record->next;
777 if (record->terminus_handle == terminus_handle) {
778 if (repo->first == record) {
779 repo->first = next;
780 } else {
781 prev->next = next;
782 }
783 if (repo->last == record) {
784 repo->last = prev;
785 }
786 if (record->data) {
787 free(record->data);
788 }
789 --repo->record_count;
790 repo->size -= record->size;
791 free(record);
792 removed = true;
793 } else {
794 prev = record;
795 }
796 record = next;
797 }
798
799 if (removed == true) {
800 record = repo->first;
801 uint32_t record_handle = 0;
802 while (record != NULL) {
803 record->record_handle = ++record_handle;
804 if (record->data != NULL) {
805 struct pldm_pdr_hdr *hdr =
806 (struct pldm_pdr_hdr *)(record->data);
807 hdr->record_handle =
808 htole32(record->record_handle);
809 }
810 record = record->next;
811 }
812 }
813}
814void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
815{
816 assert(repo != NULL);
817 bool removed = false;
818
819 pldm_pdr_record *record = repo->first;
820 pldm_pdr_record *prev = NULL;
821 while (record != NULL) {
822 pldm_pdr_record *next = record->next;
823 if (record->is_remote == true) {
824 if (repo->first == record) {
825 repo->first = next;
826 } else {
827 prev->next = next;
828 }
829 if (repo->last == record) {
830 repo->last = prev;
831 }
832 if (record->data) {
833 free(record->data);
834 }
835 --repo->record_count;
836 repo->size -= record->size;
837 free(record);
838 removed = true;
839 } else {
840 prev = record;
841 }
842 record = next;
843 }
844
845 if (removed == true) {
846 record = repo->first;
847 uint32_t record_handle = 0;
848 while (record != NULL) {
849 record->record_handle = ++record_handle;
850 if (record->data != NULL) {
851 struct pldm_pdr_hdr *hdr =
852 (struct pldm_pdr_hdr *)(record->data);
853 hdr->record_handle =
854 htole32(record->record_handle);
855 }
856 record = record->next;
857 }
858 }
859}
860
861void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
862 pldm_entity_node **out)
863{
864 if (node == NULL) {
865 return;
866 }
867
868 if (node->entity.entity_type == entity->entity_type &&
869 node->entity.entity_instance_num == entity->entity_instance_num) {
870 entity->entity_container_id = node->entity.entity_container_id;
871 *out = node;
872 return;
873 }
874
875 entity_association_tree_find(node->next_sibling, entity, out);
876 entity_association_tree_find(node->first_child, entity, out);
877}
878
879pldm_entity_node *
880pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
881 pldm_entity *entity)
882{
883 assert(tree != NULL);
884
885 pldm_entity_node *node = NULL;
886 entity_association_tree_find(tree->root, entity, &node);
887 return node;
888}
889
890static void entity_association_tree_copy(pldm_entity_node *org_node,
891 pldm_entity_node **new_node)
892{
893 if (org_node == NULL) {
894 return;
895 }
896 *new_node = malloc(sizeof(pldm_entity_node));
897 (*new_node)->parent = org_node->parent;
898 (*new_node)->entity = org_node->entity;
899 (*new_node)->association_type = org_node->association_type;
900 (*new_node)->first_child = NULL;
901 (*new_node)->next_sibling = NULL;
902 entity_association_tree_copy(org_node->first_child,
903 &((*new_node)->first_child));
904 entity_association_tree_copy(org_node->next_sibling,
905 &((*new_node)->next_sibling));
906}
907
908void pldm_entity_association_tree_copy_root(
909 pldm_entity_association_tree *org_tree,
910 pldm_entity_association_tree *new_tree)
911{
912 new_tree->last_used_container_id = org_tree->last_used_container_id;
913 entity_association_tree_copy(org_tree->root, &(new_tree->root));
914}
915
916void pldm_entity_association_tree_destroy_root(
917 pldm_entity_association_tree *tree)
918{
919 assert(tree != NULL);
920 entity_association_tree_destroy(tree->root);
921 tree->last_used_container_id = 0;
922 tree->root = NULL;
923}
924
925bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
926{
927 return ((tree->root == NULL) ? true : false);
928}
929
930void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
931 size_t *num_entities,
932 pldm_entity **entities)
933{
934 assert(pdr != NULL);
935 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
936 sizeof(struct pldm_pdr_entity_association));
937
938 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
939 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
940
941 const uint8_t *start = (uint8_t *)pdr;
942 const uint8_t *end =
943 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
944 start += sizeof(struct pldm_pdr_hdr);
945 struct pldm_pdr_entity_association *entity_association_pdr =
946 (struct pldm_pdr_entity_association *)start;
947 *num_entities = entity_association_pdr->num_children + 1;
948 assert(*num_entities >= 2);
949 *entities = malloc(sizeof(pldm_entity) * *num_entities);
950 assert(*entities != NULL);
951 assert(start + sizeof(struct pldm_pdr_entity_association) +
952 sizeof(pldm_entity) * (*num_entities - 2) ==
953 end);
954 (*entities)->entity_type =
955 le16toh(entity_association_pdr->container.entity_type);
956 (*entities)->entity_instance_num =
957 le16toh(entity_association_pdr->container.entity_instance_num);
958 (*entities)->entity_container_id =
959 le16toh(entity_association_pdr->container.entity_container_id);
960 pldm_entity *curr_entity = entity_association_pdr->children;
961 size_t i = 1;
962 while (i < *num_entities) {
963 (*entities + i)->entity_type =
964 le16toh(curr_entity->entity_type);
965 (*entities + i)->entity_instance_num =
966 le16toh(curr_entity->entity_instance_num);
967 (*entities + i)->entity_container_id =
968 le16toh(curr_entity->entity_container_id);
969 ++curr_entity;
970 ++i;
971 }
972}