blob: b29f6f1901fc1ddb705999ad147969c31e426c55 [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;
12} pldm_pdr_record;
13
14typedef struct pldm_pdr {
15 uint32_t record_count;
16 uint32_t size;
17 uint32_t last_used_record_handle;
18 pldm_pdr_record *first;
19 pldm_pdr_record *last;
20} pldm_pdr;
21
22static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
23 const pldm_pdr_record *record)
24{
25 assert(repo != NULL);
26 assert(record != NULL);
27
28 if (record == repo->last) {
29 return 0;
30 }
31 return record->next->record_handle;
32}
33
34static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
35{
36 assert(repo != NULL);
37 assert(record != NULL);
38
39 if (repo->first == NULL) {
40 assert(repo->last == NULL);
41 repo->first = record;
42 repo->last = record;
43 } else {
44 repo->last->next = record;
45 repo->last = record;
46 }
47 repo->size += record->size;
48 repo->last_used_record_handle = record->record_handle;
49 ++repo->record_count;
50}
51
52static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
53{
54 assert(repo != NULL);
55 assert(repo->last_used_record_handle != UINT32_MAX);
56
57 return repo->last_used_record_handle + 1;
58}
59
60static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
61 const uint8_t *data, uint32_t size,
62 uint32_t record_handle)
63{
64 assert(repo != NULL);
65 assert(size != 0);
66
67 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
68 assert(record != NULL);
69 record->record_handle =
70 record_handle == 0 ? get_new_record_handle(repo) : record_handle;
71 record->size = size;
72 if (data != NULL) {
73 record->data = malloc(size);
74 assert(record->data != NULL);
75 memcpy(record->data, data, size);
76 /* If record handle is 0, that is an indication for this API to
77 * compute a new handle. For that reason, the computed handle
78 * needs to be populated in the PDR header. For a case where the
79 * caller supplied the record handle, it would exist in the
80 * header already.
81 */
82 if (!record_handle) {
83 struct pldm_pdr_hdr *hdr =
84 (struct pldm_pdr_hdr *)(record->data);
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -050085 hdr->record_handle = htole32(record->record_handle);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060086 }
87 }
88 record->next = NULL;
89
90 return record;
91}
92
93uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
94 uint32_t record_handle)
95{
96 assert(size != 0);
97 assert(data != NULL);
98
99 pldm_pdr_record *record =
100 make_new_record(repo, data, size, record_handle);
101 add_record(repo, record);
102
103 return record->record_handle;
104}
105
106pldm_pdr *pldm_pdr_init()
107{
108 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
109 assert(repo != NULL);
110 repo->record_count = 0;
111 repo->size = 0;
112 repo->last_used_record_handle = 0;
113 repo->first = NULL;
114 repo->last = NULL;
115
116 return repo;
117}
118
119void pldm_pdr_destroy(pldm_pdr *repo)
120{
121 assert(repo != NULL);
122
123 pldm_pdr_record *record = repo->first;
124 while (record != NULL) {
125 pldm_pdr_record *next = record->next;
126 if (record->data) {
127 free(record->data);
128 record->data = NULL;
129 }
130 free(record);
131 record = next;
132 }
133 free(repo);
134}
135
136const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
137 uint32_t record_handle,
138 uint8_t **data, uint32_t *size,
139 uint32_t *next_record_handle)
140{
141 assert(repo != NULL);
142 assert(data != NULL);
143 assert(size != NULL);
144 assert(next_record_handle != NULL);
145
146 if (!record_handle && (repo->first != NULL)) {
147 record_handle = repo->first->record_handle;
148 }
149 pldm_pdr_record *record = repo->first;
150 while (record != NULL) {
151 if (record->record_handle == record_handle) {
152 *size = record->size;
153 *data = record->data;
154 *next_record_handle =
155 get_next_record_handle(repo, record);
156 return record;
157 }
158 record = record->next;
159 }
160
161 *size = 0;
162 *next_record_handle = 0;
163 return NULL;
164}
165
166const pldm_pdr_record *
167pldm_pdr_get_next_record(const pldm_pdr *repo,
168 const pldm_pdr_record *curr_record, uint8_t **data,
169 uint32_t *size, uint32_t *next_record_handle)
170{
171 assert(repo != NULL);
172 assert(curr_record != NULL);
173 assert(data != NULL);
174 assert(size != NULL);
175 assert(next_record_handle != NULL);
176
177 if (curr_record == repo->last) {
178 *data = NULL;
179 *size = 0;
180 *next_record_handle = get_next_record_handle(repo, curr_record);
181 return NULL;
182 }
183
184 *next_record_handle = get_next_record_handle(repo, curr_record->next);
185 *data = curr_record->next->data;
186 *size = curr_record->next->size;
187 return curr_record->next;
188}
189
190const pldm_pdr_record *
191pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
192 const pldm_pdr_record *curr_record, uint8_t **data,
193 uint32_t *size)
194{
195 assert(repo != NULL);
196 assert(data != NULL);
197 assert(size != NULL);
198
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) {
206 *size = record->size;
207 *data = record->data;
208 return record;
209 }
210 record = record->next;
211 }
212
213 *size = 0;
214 return NULL;
215}
216
217uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
218{
219 assert(repo != NULL);
220
221 return repo->record_count;
222}
223
224uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
225{
226 assert(repo != NULL);
227
228 return repo->size;
229}
230
231uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
232 const pldm_pdr_record *record)
233{
234 assert(repo != NULL);
235 assert(record != NULL);
236
237 return record->record_handle;
238}
Deepak Kodihallidb914672020-02-07 02:47:45 -0600239
240uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
241 uint16_t fru_rsi, uint16_t entity_type,
242 uint16_t entity_instance_num,
243 uint16_t container_id)
244{
245 uint32_t size = sizeof(struct pldm_pdr_hdr) +
246 sizeof(struct pldm_pdr_fru_record_set);
247 uint8_t data[size];
248
249 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
250 hdr->version = 1;
251 hdr->record_handle = 0;
252 hdr->type = PLDM_PDR_FRU_RECORD_SET;
253 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500254 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
Deepak Kodihallidb914672020-02-07 02:47:45 -0600255 struct pldm_pdr_fru_record_set *fru =
256 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
257 sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500258 fru->terminus_handle = htole16(terminus_handle);
259 fru->fru_rsi = htole16(fru_rsi);
260 fru->entity_type = htole16(entity_type);
261 fru->entity_instance_num = htole16(entity_instance_num);
262 fru->container_id = htole16(container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600263
264 return pldm_pdr_add(repo, data, size, 0);
265}
266
267const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
268 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
269 uint16_t *entity_type, uint16_t *entity_instance_num,
270 uint16_t *container_id)
271{
272 assert(terminus_handle != NULL);
273 assert(entity_type != NULL);
274 assert(entity_instance_num != NULL);
275 assert(container_id != NULL);
276
277 uint8_t *data = NULL;
278 uint32_t size = 0;
279 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
280 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
281 while (curr_record != NULL) {
282 struct pldm_pdr_fru_record_set *fru =
283 (struct pldm_pdr_fru_record_set
284 *)(data + sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500285 if (fru->fru_rsi == htole16(fru_rsi)) {
286 *terminus_handle = le16toh(fru->terminus_handle);
287 *entity_type = le16toh(fru->entity_type);
288 *entity_instance_num =
289 le16toh(fru->entity_instance_num);
290 *container_id = le16toh(fru->container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600291 return curr_record;
292 }
293 data = NULL;
294 curr_record = pldm_pdr_find_record_by_type(
295 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
296 }
297
298 *terminus_handle = 0;
299 *entity_type = 0;
300 *entity_instance_num = 0;
301 *container_id = 0;
302
303 return NULL;
304}
Deepak Kodihalli05787052020-03-10 01:54:08 -0500305
306typedef struct pldm_entity_association_tree {
307 pldm_entity_node *root;
308 uint16_t last_used_container_id;
309} pldm_entity_association_tree;
310
311typedef struct pldm_entity_node {
312 pldm_entity entity;
313 pldm_entity_node *first_child;
314 pldm_entity_node *next_sibling;
315 uint8_t association_type;
316} pldm_entity_node;
317
318static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
319{
320 assert(tree != NULL);
321 assert(tree->last_used_container_id != UINT16_MAX);
322
323 return ++tree->last_used_container_id;
324}
325
326pldm_entity_association_tree *pldm_entity_association_tree_init()
327{
328 pldm_entity_association_tree *tree =
329 malloc(sizeof(pldm_entity_association_tree));
330 assert(tree != NULL);
331 tree->root = NULL;
332 tree->last_used_container_id = 0;
333
334 return tree;
335}
336
337static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
338 uint16_t entity_type)
339{
340 assert(start != NULL);
341
342 /* Insert after the the last node that matches the input entity type, or
343 * at the end if no such match occurrs
344 */
345 while (start->next_sibling != NULL) {
346 uint16_t this_type = start->entity.entity_type;
347 pldm_entity_node *next = start->next_sibling;
348 if (this_type == entity_type &&
349 (this_type != next->entity.entity_type)) {
350 break;
351 }
352 start = start->next_sibling;
353 }
354
355 return start;
356}
357
358pldm_entity_node *
359pldm_entity_association_tree_add(pldm_entity_association_tree *tree,
360 pldm_entity *entity, pldm_entity_node *parent,
361 uint8_t association_type)
362{
363 assert(tree != NULL);
364 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
365 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
366 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
367 assert(node != NULL);
368 node->first_child = NULL;
369 node->next_sibling = NULL;
370 node->entity.entity_type = entity->entity_type;
371 node->entity.entity_instance_num = 1;
372 node->association_type = association_type;
373
374 if (tree->root == NULL) {
375 assert(parent == NULL);
376 tree->root = node;
377 /* container_id 0 here indicates this is the top-most entry */
378 node->entity.entity_container_id = 0;
379 } else if (parent != NULL && parent->first_child == NULL) {
380 parent->first_child = node;
381 node->entity.entity_container_id = next_container_id(tree);
382 } else {
383 pldm_entity_node *start =
384 parent == NULL ? tree->root : parent->first_child;
385 pldm_entity_node *prev =
386 find_insertion_at(start, entity->entity_type);
387 assert(prev != NULL);
388 pldm_entity_node *next = prev->next_sibling;
389 if (prev->entity.entity_type == entity->entity_type) {
390 assert(prev->entity.entity_instance_num != UINT16_MAX);
391 node->entity.entity_instance_num =
392 prev->entity.entity_instance_num + 1;
393 }
394 prev->next_sibling = node;
395 node->next_sibling = next;
396 node->entity.entity_container_id =
397 prev->entity.entity_container_id;
398 }
399 entity->entity_instance_num = node->entity.entity_instance_num;
400 entity->entity_container_id = node->entity.entity_container_id;
401
402 return node;
403}
404
405static void get_num_nodes(pldm_entity_node *node, size_t *num)
406{
407 if (node == NULL) {
408 return;
409 }
410
411 ++(*num);
412 get_num_nodes(node->next_sibling, num);
413 get_num_nodes(node->first_child, num);
414}
415
416static void entity_association_tree_visit(pldm_entity_node *node,
417 pldm_entity *entities, size_t *index)
418{
419 if (node == NULL) {
420 return;
421 }
422
423 pldm_entity *entity = &entities[*index];
424 ++(*index);
425 entity->entity_type = node->entity.entity_type;
426 entity->entity_instance_num = node->entity.entity_instance_num;
427 entity->entity_container_id = node->entity.entity_container_id;
428
429 entity_association_tree_visit(node->next_sibling, entities, index);
430 entity_association_tree_visit(node->first_child, entities, index);
431}
432
433void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
434 pldm_entity **entities, size_t *size)
435{
436 assert(tree != NULL);
437
438 *size = 0;
439 if (tree->root == NULL) {
440 return;
441 }
442
443 get_num_nodes(tree->root, size);
444 *entities = malloc(*size * sizeof(pldm_entity));
445 size_t index = 0;
446 entity_association_tree_visit(tree->root, *entities, &index);
447}
448
449static void entity_association_tree_destroy(pldm_entity_node *node)
450{
451 if (node == NULL) {
452 return;
453 }
454
455 entity_association_tree_destroy(node->next_sibling);
456 entity_association_tree_destroy(node->first_child);
457 free(node);
458}
459
460void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
461{
462 assert(tree != NULL);
463
464 entity_association_tree_destroy(tree->root);
465 free(tree);
466}
467
468inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
469{
470 assert(node != NULL);
471
472 return node->first_child != NULL;
473}
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500474
475uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
476 uint8_t association_type)
477{
478 assert(node != NULL);
479 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
480 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
481
482 size_t count = 0;
483 pldm_entity_node *curr = node->first_child;
484 while (curr != NULL) {
485 if (curr->association_type == association_type) {
486 ++count;
487 }
488 curr = curr->next_sibling;
489 }
490
491 assert(count < UINT8_MAX);
492 return count;
493}
494
495static void _entity_association_pdr_add_entry(pldm_entity_node *curr,
496 pldm_pdr *repo, uint16_t size,
497 uint8_t contained_count,
498 uint8_t association_type)
499{
500 uint8_t pdr[size];
501 uint8_t *start = pdr;
502
503 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
504 hdr->version = 1;
505 hdr->record_handle = 0;
506 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
507 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500508 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500509 start += sizeof(struct pldm_pdr_hdr);
510
511 uint16_t *container_id = (uint16_t *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500512 *container_id = htole16(curr->first_child->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500513 start += sizeof(uint16_t);
514 *start = association_type;
515 start += sizeof(uint8_t);
516
517 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500518 entity->entity_type = htole16(curr->entity.entity_type);
519 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
520 entity->entity_container_id = htole16(curr->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500521 start += sizeof(pldm_entity);
522
523 *start = contained_count;
524 start += sizeof(uint8_t);
525
526 pldm_entity_node *node = curr->first_child;
527 while (node != NULL) {
528 if (node->association_type == association_type) {
529 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500530 entity->entity_type = htole16(node->entity.entity_type);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500531 entity->entity_instance_num =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500532 htole16(node->entity.entity_instance_num);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500533 entity->entity_container_id =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500534 htole16(node->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500535 start += sizeof(pldm_entity);
536 }
537 node = node->next_sibling;
538 }
539
540 pldm_pdr_add(repo, pdr, size, 0);
541}
542
543static void entity_association_pdr_add_entry(pldm_entity_node *curr,
544 pldm_pdr *repo)
545{
546 uint8_t num_logical_children =
547 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
548 uint8_t num_physical_children =
549 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
550
551 if (num_logical_children) {
552 uint16_t logical_pdr_size =
553 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
554 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
555 (num_logical_children * sizeof(pldm_entity));
556 _entity_association_pdr_add_entry(
557 curr, repo, logical_pdr_size, num_logical_children,
558 PLDM_ENTITY_ASSOCIAION_LOGICAL);
559 }
560
561 if (num_physical_children) {
562 uint16_t physical_pdr_size =
563 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
564 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
565 (num_physical_children * sizeof(pldm_entity));
566 _entity_association_pdr_add_entry(
567 curr, repo, physical_pdr_size, num_physical_children,
568 PLDM_ENTITY_ASSOCIAION_PHYSICAL);
569 }
570}
571
572static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo)
573{
574 if (curr == NULL) {
575 return;
576 }
577 entity_association_pdr_add_entry(curr, repo);
578 entity_association_pdr_add(curr->next_sibling, repo);
579 entity_association_pdr_add(curr->first_child, repo);
580}
581
582void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
583 pldm_pdr *repo)
584{
585 assert(tree != NULL);
586 assert(repo != NULL);
587
588 entity_association_pdr_add(tree->root, repo);
589}
Deepak Kodihalli3b28ba82020-03-30 07:39:47 -0500590
591void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
592 pldm_entity_node **out)
593{
594 if (node == NULL) {
595 return;
596 }
597
598 if (node->entity.entity_type == entity->entity_type &&
599 node->entity.entity_instance_num == entity->entity_instance_num) {
600 entity->entity_container_id = node->entity.entity_container_id;
601 *out = node;
602 return;
603 }
604
605 entity_association_tree_find(node->next_sibling, entity, out);
606 entity_association_tree_find(node->first_child, entity, out);
607}
608
609pldm_entity_node *
610pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
611 pldm_entity *entity)
612{
613 assert(tree != NULL);
614
615 pldm_entity_node *node = NULL;
616 entity_association_tree_find(tree->root, entity, &node);
617 return node;
618}
619
620void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
621 size_t *num_entities,
622 pldm_entity **entities)
623{
624 assert(pdr != NULL);
625 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
626 sizeof(struct pldm_pdr_entity_association));
627
628 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
629 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
630
631 const uint8_t *start = (uint8_t *)pdr;
632 const uint8_t *end =
633 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
634 start += sizeof(struct pldm_pdr_hdr);
635 struct pldm_pdr_entity_association *entity_association_pdr =
636 (struct pldm_pdr_entity_association *)start;
637 *num_entities = entity_association_pdr->num_children + 1;
638 assert(*num_entities >= 2);
639 *entities = malloc(sizeof(pldm_entity) * *num_entities);
640 assert(*entities != NULL);
641 assert(start + sizeof(struct pldm_pdr_entity_association) +
642 sizeof(pldm_entity) * (*num_entities - 2) ==
643 end);
644 (*entities)->entity_type =
645 le16toh(entity_association_pdr->container.entity_type);
646 (*entities)->entity_instance_num =
647 le16toh(entity_association_pdr->container.entity_instance_num);
648 (*entities)->entity_container_id =
649 le16toh(entity_association_pdr->container.entity_container_id);
650 pldm_entity *curr_entity = entity_association_pdr->children;
651 size_t i = 1;
652 while (i < *num_entities) {
653 (*entities + i)->entity_type =
654 le16toh(curr_entity->entity_type);
655 (*entities + i)->entity_instance_num =
656 le16toh(curr_entity->entity_instance_num);
657 (*entities + i)->entity_container_id =
658 le16toh(curr_entity->entity_container_id);
659 ++curr_entity;
660 ++i;
661 }
662}