blob: e0cd5277559a612836ba4043f43df5e08669214f [file] [log] [blame]
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -06001#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;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050012 bool is_remote;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060013} pldm_pdr_record;
14
15typedef struct pldm_pdr {
16 uint32_t record_count;
17 uint32_t size;
18 uint32_t last_used_record_handle;
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->last_used_record_handle = record->record_handle;
50 ++repo->record_count;
51}
52
53static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
54{
55 assert(repo != NULL);
56 assert(repo->last_used_record_handle != UINT32_MAX);
57
58 return repo->last_used_record_handle + 1;
59}
60
61static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
62 const uint8_t *data, uint32_t size,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050063 uint32_t record_handle, bool is_remote)
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060064{
65 assert(repo != NULL);
66 assert(size != 0);
67
68 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
69 assert(record != NULL);
70 record->record_handle =
71 record_handle == 0 ? get_new_record_handle(repo) : record_handle;
72 record->size = size;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050073 record->is_remote = is_remote;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060074 if (data != NULL) {
75 record->data = malloc(size);
76 assert(record->data != NULL);
77 memcpy(record->data, data, size);
78 /* If record handle is 0, that is an indication for this API to
79 * compute a new handle. For that reason, the computed handle
80 * needs to be populated in the PDR header. For a case where the
81 * caller supplied the record handle, it would exist in the
82 * header already.
83 */
84 if (!record_handle) {
85 struct pldm_pdr_hdr *hdr =
86 (struct pldm_pdr_hdr *)(record->data);
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -050087 hdr->record_handle = htole32(record->record_handle);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060088 }
89 }
90 record->next = NULL;
91
92 return record;
93}
94
95uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050096 uint32_t record_handle, bool is_remote)
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060097{
98 assert(size != 0);
99 assert(data != NULL);
100
101 pldm_pdr_record *record =
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500102 make_new_record(repo, data, size, record_handle, is_remote);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600103 add_record(repo, record);
104
105 return record->record_handle;
106}
107
108pldm_pdr *pldm_pdr_init()
109{
110 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
111 assert(repo != NULL);
112 repo->record_count = 0;
113 repo->size = 0;
114 repo->last_used_record_handle = 0;
115 repo->first = NULL;
116 repo->last = NULL;
117
118 return repo;
119}
120
121void pldm_pdr_destroy(pldm_pdr *repo)
122{
123 assert(repo != NULL);
124
125 pldm_pdr_record *record = repo->first;
126 while (record != NULL) {
127 pldm_pdr_record *next = record->next;
128 if (record->data) {
129 free(record->data);
130 record->data = NULL;
131 }
132 free(record);
133 record = next;
134 }
135 free(repo);
136}
137
138const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
139 uint32_t record_handle,
140 uint8_t **data, uint32_t *size,
141 uint32_t *next_record_handle)
142{
143 assert(repo != NULL);
144 assert(data != NULL);
145 assert(size != NULL);
146 assert(next_record_handle != NULL);
147
148 if (!record_handle && (repo->first != NULL)) {
149 record_handle = repo->first->record_handle;
150 }
151 pldm_pdr_record *record = repo->first;
152 while (record != NULL) {
153 if (record->record_handle == record_handle) {
154 *size = record->size;
155 *data = record->data;
156 *next_record_handle =
157 get_next_record_handle(repo, record);
158 return record;
159 }
160 record = record->next;
161 }
162
163 *size = 0;
164 *next_record_handle = 0;
165 return NULL;
166}
167
168const pldm_pdr_record *
169pldm_pdr_get_next_record(const pldm_pdr *repo,
170 const pldm_pdr_record *curr_record, uint8_t **data,
171 uint32_t *size, uint32_t *next_record_handle)
172{
173 assert(repo != NULL);
174 assert(curr_record != NULL);
175 assert(data != NULL);
176 assert(size != NULL);
177 assert(next_record_handle != NULL);
178
179 if (curr_record == repo->last) {
180 *data = NULL;
181 *size = 0;
182 *next_record_handle = get_next_record_handle(repo, curr_record);
183 return NULL;
184 }
185
186 *next_record_handle = get_next_record_handle(repo, curr_record->next);
187 *data = curr_record->next->data;
188 *size = curr_record->next->size;
189 return curr_record->next;
190}
191
192const pldm_pdr_record *
193pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
194 const pldm_pdr_record *curr_record, uint8_t **data,
195 uint32_t *size)
196{
197 assert(repo != NULL);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600198
199 pldm_pdr_record *record = repo->first;
200 if (curr_record != NULL) {
201 record = curr_record->next;
202 }
203 while (record != NULL) {
204 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
205 if (hdr->type == pdr_type) {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500206 if (data && size) {
207 *size = record->size;
208 *data = record->data;
209 }
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600210 return record;
211 }
212 record = record->next;
213 }
214
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500215 if (size) {
216 *size = 0;
217 }
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600218 return NULL;
219}
220
221uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
222{
223 assert(repo != NULL);
224
225 return repo->record_count;
226}
227
228uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
229{
230 assert(repo != NULL);
231
232 return repo->size;
233}
234
235uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
236 const pldm_pdr_record *record)
237{
238 assert(repo != NULL);
239 assert(record != NULL);
240
241 return record->record_handle;
242}
Deepak Kodihallidb914672020-02-07 02:47:45 -0600243
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500244inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
245{
246 assert(record != NULL);
247
248 return record->is_remote;
249}
250
Deepak Kodihallidb914672020-02-07 02:47:45 -0600251uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
252 uint16_t fru_rsi, uint16_t entity_type,
253 uint16_t entity_instance_num,
254 uint16_t container_id)
255{
256 uint32_t size = sizeof(struct pldm_pdr_hdr) +
257 sizeof(struct pldm_pdr_fru_record_set);
258 uint8_t data[size];
259
260 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
261 hdr->version = 1;
262 hdr->record_handle = 0;
263 hdr->type = PLDM_PDR_FRU_RECORD_SET;
264 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500265 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
Deepak Kodihallidb914672020-02-07 02:47:45 -0600266 struct pldm_pdr_fru_record_set *fru =
267 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
268 sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500269 fru->terminus_handle = htole16(terminus_handle);
270 fru->fru_rsi = htole16(fru_rsi);
271 fru->entity_type = htole16(entity_type);
272 fru->entity_instance_num = htole16(entity_instance_num);
273 fru->container_id = htole16(container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600274
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500275 return pldm_pdr_add(repo, data, size, 0, false);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600276}
277
278const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
279 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
280 uint16_t *entity_type, uint16_t *entity_instance_num,
281 uint16_t *container_id)
282{
283 assert(terminus_handle != NULL);
284 assert(entity_type != NULL);
285 assert(entity_instance_num != NULL);
286 assert(container_id != NULL);
287
288 uint8_t *data = NULL;
289 uint32_t size = 0;
290 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
291 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
292 while (curr_record != NULL) {
293 struct pldm_pdr_fru_record_set *fru =
294 (struct pldm_pdr_fru_record_set
295 *)(data + sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500296 if (fru->fru_rsi == htole16(fru_rsi)) {
297 *terminus_handle = le16toh(fru->terminus_handle);
298 *entity_type = le16toh(fru->entity_type);
299 *entity_instance_num =
300 le16toh(fru->entity_instance_num);
301 *container_id = le16toh(fru->container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600302 return curr_record;
303 }
304 data = NULL;
305 curr_record = pldm_pdr_find_record_by_type(
306 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
307 }
308
309 *terminus_handle = 0;
310 *entity_type = 0;
311 *entity_instance_num = 0;
312 *container_id = 0;
313
314 return NULL;
315}
Deepak Kodihalli05787052020-03-10 01:54:08 -0500316
317typedef struct pldm_entity_association_tree {
318 pldm_entity_node *root;
319 uint16_t last_used_container_id;
320} pldm_entity_association_tree;
321
322typedef struct pldm_entity_node {
323 pldm_entity entity;
324 pldm_entity_node *first_child;
325 pldm_entity_node *next_sibling;
326 uint8_t association_type;
327} pldm_entity_node;
328
329static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
330{
331 assert(tree != NULL);
332 assert(tree->last_used_container_id != UINT16_MAX);
333
334 return ++tree->last_used_container_id;
335}
336
337pldm_entity_association_tree *pldm_entity_association_tree_init()
338{
339 pldm_entity_association_tree *tree =
340 malloc(sizeof(pldm_entity_association_tree));
341 assert(tree != NULL);
342 tree->root = NULL;
343 tree->last_used_container_id = 0;
344
345 return tree;
346}
347
348static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
349 uint16_t entity_type)
350{
351 assert(start != NULL);
352
353 /* Insert after the the last node that matches the input entity type, or
354 * at the end if no such match occurrs
355 */
356 while (start->next_sibling != NULL) {
357 uint16_t this_type = start->entity.entity_type;
358 pldm_entity_node *next = start->next_sibling;
359 if (this_type == entity_type &&
360 (this_type != next->entity.entity_type)) {
361 break;
362 }
363 start = start->next_sibling;
364 }
365
366 return start;
367}
368
369pldm_entity_node *
370pldm_entity_association_tree_add(pldm_entity_association_tree *tree,
371 pldm_entity *entity, pldm_entity_node *parent,
372 uint8_t association_type)
373{
374 assert(tree != NULL);
375 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
376 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
377 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
378 assert(node != NULL);
379 node->first_child = NULL;
380 node->next_sibling = NULL;
381 node->entity.entity_type = entity->entity_type;
382 node->entity.entity_instance_num = 1;
383 node->association_type = association_type;
384
385 if (tree->root == NULL) {
386 assert(parent == NULL);
387 tree->root = node;
388 /* container_id 0 here indicates this is the top-most entry */
389 node->entity.entity_container_id = 0;
390 } else if (parent != NULL && parent->first_child == NULL) {
391 parent->first_child = node;
392 node->entity.entity_container_id = next_container_id(tree);
393 } else {
394 pldm_entity_node *start =
395 parent == NULL ? tree->root : parent->first_child;
396 pldm_entity_node *prev =
397 find_insertion_at(start, entity->entity_type);
398 assert(prev != NULL);
399 pldm_entity_node *next = prev->next_sibling;
400 if (prev->entity.entity_type == entity->entity_type) {
401 assert(prev->entity.entity_instance_num != UINT16_MAX);
402 node->entity.entity_instance_num =
403 prev->entity.entity_instance_num + 1;
404 }
405 prev->next_sibling = node;
406 node->next_sibling = next;
407 node->entity.entity_container_id =
408 prev->entity.entity_container_id;
409 }
410 entity->entity_instance_num = node->entity.entity_instance_num;
411 entity->entity_container_id = node->entity.entity_container_id;
412
413 return node;
414}
415
416static void get_num_nodes(pldm_entity_node *node, size_t *num)
417{
418 if (node == NULL) {
419 return;
420 }
421
422 ++(*num);
423 get_num_nodes(node->next_sibling, num);
424 get_num_nodes(node->first_child, num);
425}
426
427static void entity_association_tree_visit(pldm_entity_node *node,
428 pldm_entity *entities, size_t *index)
429{
430 if (node == NULL) {
431 return;
432 }
433
434 pldm_entity *entity = &entities[*index];
435 ++(*index);
436 entity->entity_type = node->entity.entity_type;
437 entity->entity_instance_num = node->entity.entity_instance_num;
438 entity->entity_container_id = node->entity.entity_container_id;
439
440 entity_association_tree_visit(node->next_sibling, entities, index);
441 entity_association_tree_visit(node->first_child, entities, index);
442}
443
444void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
445 pldm_entity **entities, size_t *size)
446{
447 assert(tree != NULL);
448
449 *size = 0;
450 if (tree->root == NULL) {
451 return;
452 }
453
454 get_num_nodes(tree->root, size);
455 *entities = malloc(*size * sizeof(pldm_entity));
456 size_t index = 0;
457 entity_association_tree_visit(tree->root, *entities, &index);
458}
459
460static void entity_association_tree_destroy(pldm_entity_node *node)
461{
462 if (node == NULL) {
463 return;
464 }
465
466 entity_association_tree_destroy(node->next_sibling);
467 entity_association_tree_destroy(node->first_child);
468 free(node);
469}
470
471void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
472{
473 assert(tree != NULL);
474
475 entity_association_tree_destroy(tree->root);
476 free(tree);
477}
478
479inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
480{
481 assert(node != NULL);
482
483 return node->first_child != NULL;
484}
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500485
486uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
487 uint8_t association_type)
488{
489 assert(node != NULL);
490 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
491 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
492
493 size_t count = 0;
494 pldm_entity_node *curr = node->first_child;
495 while (curr != NULL) {
496 if (curr->association_type == association_type) {
497 ++count;
498 }
499 curr = curr->next_sibling;
500 }
501
502 assert(count < UINT8_MAX);
503 return count;
504}
505
506static void _entity_association_pdr_add_entry(pldm_entity_node *curr,
507 pldm_pdr *repo, uint16_t size,
508 uint8_t contained_count,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500509 uint8_t association_type,
510 bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500511{
512 uint8_t pdr[size];
513 uint8_t *start = pdr;
514
515 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
516 hdr->version = 1;
517 hdr->record_handle = 0;
518 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
519 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500520 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500521 start += sizeof(struct pldm_pdr_hdr);
522
523 uint16_t *container_id = (uint16_t *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500524 *container_id = htole16(curr->first_child->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500525 start += sizeof(uint16_t);
526 *start = association_type;
527 start += sizeof(uint8_t);
528
529 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500530 entity->entity_type = htole16(curr->entity.entity_type);
531 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
532 entity->entity_container_id = htole16(curr->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500533 start += sizeof(pldm_entity);
534
535 *start = contained_count;
536 start += sizeof(uint8_t);
537
538 pldm_entity_node *node = curr->first_child;
539 while (node != NULL) {
540 if (node->association_type == association_type) {
541 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500542 entity->entity_type = htole16(node->entity.entity_type);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500543 entity->entity_instance_num =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500544 htole16(node->entity.entity_instance_num);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500545 entity->entity_container_id =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500546 htole16(node->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500547 start += sizeof(pldm_entity);
548 }
549 node = node->next_sibling;
550 }
551
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500552 pldm_pdr_add(repo, pdr, size, 0, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500553}
554
555static void entity_association_pdr_add_entry(pldm_entity_node *curr,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500556 pldm_pdr *repo, bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500557{
558 uint8_t num_logical_children =
559 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
560 uint8_t num_physical_children =
561 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
562
563 if (num_logical_children) {
564 uint16_t logical_pdr_size =
565 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
566 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
567 (num_logical_children * sizeof(pldm_entity));
568 _entity_association_pdr_add_entry(
569 curr, repo, logical_pdr_size, num_logical_children,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500570 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500571 }
572
573 if (num_physical_children) {
574 uint16_t physical_pdr_size =
575 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
576 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
577 (num_physical_children * sizeof(pldm_entity));
578 _entity_association_pdr_add_entry(
579 curr, repo, physical_pdr_size, num_physical_children,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500580 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500581 }
582}
583
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500584static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
585 bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500586{
587 if (curr == NULL) {
588 return;
589 }
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500590 entity_association_pdr_add_entry(curr, repo, is_remote);
591 entity_association_pdr_add(curr->next_sibling, repo, is_remote);
592 entity_association_pdr_add(curr->first_child, repo, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500593}
594
595void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500596 pldm_pdr *repo, bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500597{
598 assert(tree != NULL);
599 assert(repo != NULL);
600
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500601 entity_association_pdr_add(tree->root, repo, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500602}
Deepak Kodihalli3b28ba82020-03-30 07:39:47 -0500603
604void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
605 pldm_entity_node **out)
606{
607 if (node == NULL) {
608 return;
609 }
610
611 if (node->entity.entity_type == entity->entity_type &&
612 node->entity.entity_instance_num == entity->entity_instance_num) {
613 entity->entity_container_id = node->entity.entity_container_id;
614 *out = node;
615 return;
616 }
617
618 entity_association_tree_find(node->next_sibling, entity, out);
619 entity_association_tree_find(node->first_child, entity, out);
620}
621
622pldm_entity_node *
623pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
624 pldm_entity *entity)
625{
626 assert(tree != NULL);
627
628 pldm_entity_node *node = NULL;
629 entity_association_tree_find(tree->root, entity, &node);
630 return node;
631}
632
633void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
634 size_t *num_entities,
635 pldm_entity **entities)
636{
637 assert(pdr != NULL);
638 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
639 sizeof(struct pldm_pdr_entity_association));
640
641 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
642 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
643
644 const uint8_t *start = (uint8_t *)pdr;
645 const uint8_t *end =
646 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
647 start += sizeof(struct pldm_pdr_hdr);
648 struct pldm_pdr_entity_association *entity_association_pdr =
649 (struct pldm_pdr_entity_association *)start;
650 *num_entities = entity_association_pdr->num_children + 1;
651 assert(*num_entities >= 2);
652 *entities = malloc(sizeof(pldm_entity) * *num_entities);
653 assert(*entities != NULL);
654 assert(start + sizeof(struct pldm_pdr_entity_association) +
655 sizeof(pldm_entity) * (*num_entities - 2) ==
656 end);
657 (*entities)->entity_type =
658 le16toh(entity_association_pdr->container.entity_type);
659 (*entities)->entity_instance_num =
660 le16toh(entity_association_pdr->container.entity_instance_num);
661 (*entities)->entity_container_id =
662 le16toh(entity_association_pdr->container.entity_container_id);
663 pldm_entity *curr_entity = entity_association_pdr->children;
664 size_t i = 1;
665 while (i < *num_entities) {
666 (*entities + i)->entity_type =
667 le16toh(curr_entity->entity_type);
668 (*entities + i)->entity_instance_num =
669 le16toh(curr_entity->entity_instance_num);
670 (*entities + i)->entity_container_id =
671 le16toh(curr_entity->entity_container_id);
672 ++curr_entity;
673 ++i;
674 }
675}