blob: 68342effb1deda4c2984df25fa3a8284d26fb393 [file] [log] [blame]
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301#include "config.h"
Andrew Jeffery9c766792022-08-10 23:12:49 +09302#include "pdr.h"
3#include "platform.h"
4#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05305#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09306#include <stdlib.h>
7#include <string.h>
8
9typedef struct pldm_pdr_record {
10 uint32_t record_handle;
11 uint32_t size;
12 uint8_t *data;
13 struct pldm_pdr_record *next;
14 bool is_remote;
15 uint16_t terminus_handle;
16} pldm_pdr_record;
17
18typedef struct pldm_pdr {
19 uint32_t record_count;
20 uint32_t size;
21 pldm_pdr_record *first;
22 pldm_pdr_record *last;
23} pldm_pdr;
24
25static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
26 const pldm_pdr_record *record)
27{
28 assert(repo != NULL);
29 assert(record != NULL);
30
31 if (record == repo->last) {
32 return 0;
33 }
34 return record->next->record_handle;
35}
36
37static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
38{
39 assert(repo != NULL);
40 assert(record != NULL);
41
42 if (repo->first == NULL) {
43 assert(repo->last == NULL);
44 repo->first = record;
45 repo->last = record;
46 } else {
47 repo->last->next = record;
48 repo->last = record;
49 }
50 repo->size += record->size;
51 ++repo->record_count;
52}
53
54static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
55{
56 assert(repo != NULL);
57 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093058 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093059 assert(last_used_hdl != UINT32_MAX);
60
61 return last_used_hdl + 1;
62}
63
64static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
65 const uint8_t *data, uint32_t size,
66 uint32_t record_handle, bool is_remote,
67 uint16_t terminus_handle)
68{
69 assert(repo != NULL);
70 assert(size != 0);
71
72 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
73 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093074 record->record_handle = record_handle == 0 ?
75 get_new_record_handle(repo) :
76 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093077 record->size = size;
78 record->is_remote = is_remote;
79 record->terminus_handle = terminus_handle;
80 if (data != NULL) {
81 record->data = malloc(size);
82 assert(record->data != NULL);
83 memcpy(record->data, data, size);
84 /* If record handle is 0, that is an indication for this API to
85 * compute a new handle. For that reason, the computed handle
86 * needs to be populated in the PDR header. For a case where the
87 * caller supplied the record handle, it would exist in the
88 * header already.
89 */
90 if (!record_handle) {
91 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093092 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093093 hdr->record_handle = htole32(record->record_handle);
94 }
95 }
96 record->next = NULL;
97
98 return record;
99}
100
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930101LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
103 uint32_t record_handle, bool is_remote,
104 uint16_t terminus_handle)
105{
106 assert(size != 0);
107 assert(data != NULL);
108
109 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930110 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111 add_record(repo, record);
112
113 return record->record_handle;
114}
115
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930116LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930117pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118{
119 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
120 assert(repo != NULL);
121 repo->record_count = 0;
122 repo->size = 0;
123 repo->first = NULL;
124 repo->last = NULL;
125
126 return repo;
127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130void pldm_pdr_destroy(pldm_pdr *repo)
131{
132 assert(repo != NULL);
133
134 pldm_pdr_record *record = repo->first;
135 while (record != NULL) {
136 pldm_pdr_record *next = record->next;
137 if (record->data) {
138 free(record->data);
139 record->data = NULL;
140 }
141 free(record);
142 record = next;
143 }
144 free(repo);
145}
146
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930147LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
149 uint32_t record_handle,
150 uint8_t **data, uint32_t *size,
151 uint32_t *next_record_handle)
152{
153 assert(repo != NULL);
154 assert(data != NULL);
155 assert(size != NULL);
156 assert(next_record_handle != NULL);
157
158 if (!record_handle && (repo->first != NULL)) {
159 record_handle = repo->first->record_handle;
160 }
161 pldm_pdr_record *record = repo->first;
162 while (record != NULL) {
163 if (record->record_handle == record_handle) {
164 *size = record->size;
165 *data = record->data;
166 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930167 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168 return record;
169 }
170 record = record->next;
171 }
172
173 *size = 0;
174 *next_record_handle = 0;
175 return NULL;
176}
177
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930178LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179const pldm_pdr_record *
180pldm_pdr_get_next_record(const pldm_pdr *repo,
181 const pldm_pdr_record *curr_record, uint8_t **data,
182 uint32_t *size, uint32_t *next_record_handle)
183{
184 assert(repo != NULL);
185 assert(curr_record != NULL);
186 assert(data != NULL);
187 assert(size != NULL);
188 assert(next_record_handle != NULL);
189
190 if (curr_record == repo->last) {
191 *data = NULL;
192 *size = 0;
193 *next_record_handle = get_next_record_handle(repo, curr_record);
194 return NULL;
195 }
196
197 *next_record_handle = get_next_record_handle(repo, curr_record->next);
198 *data = curr_record->next->data;
199 *size = curr_record->next->size;
200 return curr_record->next;
201}
202
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930203LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204const pldm_pdr_record *
205pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
206 const pldm_pdr_record *curr_record, uint8_t **data,
207 uint32_t *size)
208{
209 assert(repo != NULL);
210
211 pldm_pdr_record *record = repo->first;
212 if (curr_record != NULL) {
213 record = curr_record->next;
214 }
215 while (record != NULL) {
216 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
217 if (hdr->type == pdr_type) {
218 if (data && size) {
219 *size = record->size;
220 *data = record->data;
221 }
222 return record;
223 }
224 record = record->next;
225 }
226
227 if (size) {
228 *size = 0;
229 }
230 return NULL;
231}
232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930233LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930234uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
235{
236 assert(repo != NULL);
237
238 return repo->record_count;
239}
240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930242uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
243{
244 assert(repo != NULL);
245
246 return repo->size;
247}
248
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930249LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930250uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
251 const pldm_pdr_record *record)
252{
253 assert(repo != NULL);
254 assert(record != NULL);
255
256 return record->record_handle;
257}
258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930259LIBPLDM_ABI_STABLE
260bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930261{
262 assert(record != NULL);
263
264 return record->is_remote;
265}
266
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930267LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
269 uint16_t fru_rsi, uint16_t entity_type,
270 uint16_t entity_instance_num,
271 uint16_t container_id,
272 uint32_t bmc_record_handle)
273{
274 uint32_t size = sizeof(struct pldm_pdr_hdr) +
275 sizeof(struct pldm_pdr_fru_record_set);
276 uint8_t data[size];
277
278 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
279 hdr->version = 1;
280 hdr->record_handle = bmc_record_handle;
281 hdr->type = PLDM_PDR_FRU_RECORD_SET;
282 hdr->record_change_num = 0;
283 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
284 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930285 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
286 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930287 fru->terminus_handle = htole16(terminus_handle);
288 fru->fru_rsi = htole16(fru_rsi);
289 fru->entity_type = htole16(entity_type);
290 fru->entity_instance_num = htole16(entity_instance_num);
291 fru->container_id = htole16(container_id);
292
293 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
294 terminus_handle);
295}
296
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930297LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930299 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
300 uint16_t *entity_type, uint16_t *entity_instance_num,
301 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302{
303 assert(terminus_handle != NULL);
304 assert(entity_type != NULL);
305 assert(entity_instance_num != NULL);
306 assert(container_id != NULL);
307
308 uint8_t *data = NULL;
309 uint32_t size = 0;
310 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930311 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312 while (curr_record != NULL) {
313 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 (struct pldm_pdr_fru_record_set
315 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316 if (fru->fru_rsi == htole16(fru_rsi)) {
317 *terminus_handle = le16toh(fru->terminus_handle);
318 *entity_type = le16toh(fru->entity_type);
319 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 *container_id = le16toh(fru->container_id);
322 return curr_record;
323 }
324 data = NULL;
325 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930326 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
327 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328 }
329
330 *terminus_handle = 0;
331 *entity_type = 0;
332 *entity_instance_num = 0;
333 *container_id = 0;
334
335 return NULL;
336}
337
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930338LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930339/* NOLINTNEXTLINE(readability-identifier-naming) */
340void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
341 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930343 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344 uint32_t size = 0;
345 const pldm_pdr_record *record;
346 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930347 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348
349 do {
350 if (record != NULL) {
351 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930354 (struct pldm_terminus_locator_type_mctp_eid *)
355 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930356 if (pdr->terminus_handle == terminus_handle &&
357 pdr->tid == tid && value->eid == tl_eid) {
358 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 break;
360 }
361 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930362 record = pldm_pdr_find_record_by_type(repo,
363 PLDM_TERMINUS_LOCATOR_PDR,
364 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 } while (record);
366}
367
368typedef struct pldm_entity_association_tree {
369 pldm_entity_node *root;
370 uint16_t last_used_container_id;
371} pldm_entity_association_tree;
372
373typedef struct pldm_entity_node {
374 pldm_entity entity;
375 pldm_entity parent;
376 pldm_entity_node *first_child;
377 pldm_entity_node *next_sibling;
378 uint8_t association_type;
379} pldm_entity_node;
380
381static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
382{
383 assert(tree != NULL);
384 assert(tree->last_used_container_id != UINT16_MAX);
385
386 return ++tree->last_used_container_id;
387}
388
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930389LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930390pldm_entity pldm_entity_extract(pldm_entity_node *node)
391{
392 assert(node != NULL);
393
394 return node->entity;
395}
396
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930397LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930398pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930399{
400 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930401 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930402 assert(tree != NULL);
403 tree->root = NULL;
404 tree->last_used_container_id = 0;
405
406 return tree;
407}
408
409static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
410 uint16_t entity_type)
411{
412 assert(start != NULL);
413
414 /* Insert after the the last node that matches the input entity type, or
415 * at the end if no such match occurrs
416 */
417 while (start->next_sibling != NULL) {
418 uint16_t this_type = start->entity.entity_type;
419 pldm_entity_node *next = start->next_sibling;
420 if (this_type == entity_type &&
421 (this_type != next->entity.entity_type)) {
422 break;
423 }
424 start = start->next_sibling;
425 }
426
427 return start;
428}
429
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930430LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930431pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930432 pldm_entity_association_tree *tree, pldm_entity *entity,
433 uint16_t entity_instance_number, pldm_entity_node *parent,
434 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435{
436 assert(tree != NULL);
437 assert(entity != NULL);
438
439 if (entity_instance_number != 0xFFFF && parent != NULL) {
440 pldm_entity node;
441 node.entity_type = entity->entity_type;
442 node.entity_instance_num = entity_instance_number;
443 if (pldm_is_current_parent_child(parent, &node)) {
444 return NULL;
445 }
446 }
447
448 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
449 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
450 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
451 assert(node != NULL);
452 node->first_child = NULL;
453 node->next_sibling = NULL;
454 node->parent.entity_type = 0;
455 node->parent.entity_instance_num = 0;
456 node->parent.entity_container_id = 0;
457 node->entity.entity_type = entity->entity_type;
458 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930459 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930460 node->association_type = association_type;
461
462 if (tree->root == NULL) {
463 assert(parent == NULL);
464 tree->root = node;
465 /* container_id 0 here indicates this is the top-most entry */
466 node->entity.entity_container_id = 0;
467 } else if (parent != NULL && parent->first_child == NULL) {
468 parent->first_child = node;
469 node->parent = parent->entity;
470 node->entity.entity_container_id = next_container_id(tree);
471 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930472 pldm_entity_node *start = parent == NULL ? tree->root :
473 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930475 find_insertion_at(start, entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476 assert(prev != NULL);
477 pldm_entity_node *next = prev->next_sibling;
478 if (prev->entity.entity_type == entity->entity_type) {
479 assert(prev->entity.entity_instance_num != UINT16_MAX);
480 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930481 entity_instance_number != 0xFFFF ?
482 entity_instance_number :
483 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930484 }
485 prev->next_sibling = node;
486 node->parent = prev->parent;
487 node->next_sibling = next;
488 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930489 prev->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930490 }
491 entity->entity_instance_num = node->entity.entity_instance_num;
492 entity->entity_container_id = node->entity.entity_container_id;
493
494 return node;
495}
496
497static void get_num_nodes(pldm_entity_node *node, size_t *num)
498{
499 if (node == NULL) {
500 return;
501 }
502
503 ++(*num);
504 get_num_nodes(node->next_sibling, num);
505 get_num_nodes(node->first_child, num);
506}
507
508static void entity_association_tree_visit(pldm_entity_node *node,
509 pldm_entity *entities, size_t *index)
510{
511 if (node == NULL) {
512 return;
513 }
514
515 pldm_entity *entity = &entities[*index];
516 ++(*index);
517 entity->entity_type = node->entity.entity_type;
518 entity->entity_instance_num = node->entity.entity_instance_num;
519 entity->entity_container_id = node->entity.entity_container_id;
520
521 entity_association_tree_visit(node->next_sibling, entities, index);
522 entity_association_tree_visit(node->first_child, entities, index);
523}
524
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930525LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930526void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
527 pldm_entity **entities, size_t *size)
528{
529 assert(tree != NULL);
530
531 *size = 0;
532 if (tree->root == NULL) {
533 return;
534 }
535
536 get_num_nodes(tree->root, size);
537 *entities = malloc(*size * sizeof(pldm_entity));
538 size_t index = 0;
539 entity_association_tree_visit(tree->root, *entities, &index);
540}
541
542static void entity_association_tree_destroy(pldm_entity_node *node)
543{
544 if (node == NULL) {
545 return;
546 }
547
548 entity_association_tree_destroy(node->next_sibling);
549 entity_association_tree_destroy(node->first_child);
550 free(node);
551}
552
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930553LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
555{
556 assert(tree != NULL);
557
558 entity_association_tree_destroy(tree->root);
559 free(tree);
560}
561
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930562LIBPLDM_ABI_STABLE
563bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564{
565 assert(node != NULL);
566
567 return node->first_child != NULL;
568}
569
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930570LIBPLDM_ABI_STABLE
571pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572{
573 assert(node != NULL);
574
575 return node->parent;
576}
577
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930578LIBPLDM_ABI_STABLE
579bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580{
581 assert(node != NULL);
582
583 if (node->parent.entity_type == 0 &&
584 node->parent.entity_instance_num == 0 &&
585 node->parent.entity_container_id == 0) {
586 return false;
587 }
588
589 return true;
590}
591
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930592LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930593uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
594 uint8_t association_type)
595{
596 assert(node != NULL);
597 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
598 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
599
600 size_t count = 0;
601 pldm_entity_node *curr = node->first_child;
602 while (curr != NULL) {
603 if (curr->association_type == association_type) {
604 ++count;
605 }
606 curr = curr->next_sibling;
607 }
608
609 assert(count < UINT8_MAX);
610 return count;
611}
612
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930613LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
615{
616 assert(parent != NULL);
617 assert(node != NULL);
618
619 pldm_entity_node *curr = parent->first_child;
620 while (curr != NULL) {
621 if (node->entity_type == curr->entity.entity_type &&
622 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930623 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624 return true;
625 }
626 curr = curr->next_sibling;
627 }
628
629 return false;
630}
631
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930632static void entity_association_pdr_add_children(pldm_entity_node *curr,
633 pldm_pdr *repo, uint16_t size,
634 uint8_t contained_count,
635 uint8_t association_type,
636 bool is_remote,
637 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930638{
639 uint8_t pdr[size];
640 uint8_t *start = pdr;
641
642 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
643 hdr->version = 1;
644 hdr->record_handle = 0;
645 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
646 hdr->record_change_num = 0;
647 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
648 start += sizeof(struct pldm_pdr_hdr);
649
650 uint16_t *container_id = (uint16_t *)start;
651 *container_id = htole16(curr->first_child->entity.entity_container_id);
652 start += sizeof(uint16_t);
653 *start = association_type;
654 start += sizeof(uint8_t);
655
656 pldm_entity *entity = (pldm_entity *)start;
657 entity->entity_type = htole16(curr->entity.entity_type);
658 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
659 entity->entity_container_id = htole16(curr->entity.entity_container_id);
660 start += sizeof(pldm_entity);
661
662 *start = contained_count;
663 start += sizeof(uint8_t);
664
665 pldm_entity_node *node = curr->first_child;
666 while (node != NULL) {
667 if (node->association_type == association_type) {
668 pldm_entity *entity = (pldm_entity *)start;
669 entity->entity_type = htole16(node->entity.entity_type);
670 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930671 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930672 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930673 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674 start += sizeof(pldm_entity);
675 }
676 node = node->next_sibling;
677 }
678
679 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
680}
681
682static void entity_association_pdr_add_entry(pldm_entity_node *curr,
683 pldm_pdr *repo, bool is_remote,
684 uint16_t terminus_handle)
685{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930686 uint8_t num_logical_children = pldm_entity_get_num_children(
687 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
688 uint8_t num_physical_children = pldm_entity_get_num_children(
689 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690
691 if (num_logical_children) {
692 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930693 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
694 sizeof(uint8_t) + sizeof(pldm_entity) +
695 sizeof(uint8_t) +
696 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930697 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930698 curr, repo, logical_pdr_size, num_logical_children,
699 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
700 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701 }
702
703 if (num_physical_children) {
704 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930705 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
706 sizeof(uint8_t) + sizeof(pldm_entity) +
707 sizeof(uint8_t) +
708 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930709 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930710 curr, repo, physical_pdr_size, num_physical_children,
711 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
712 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713 }
714}
715
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930716LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930717bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
718{
719 if (entities == NULL || num_entities == 0) {
720 return true;
721 }
722 size_t i = 0;
723 while (i < num_entities) {
724 if ((*entities + i)->entity_type == entity.entity_type) {
725 return true;
726 }
727 i++;
728 }
729 return false;
730}
731
732static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
733 pldm_entity **entities,
734 size_t num_entities, bool is_remote,
735 uint16_t terminus_handle)
736{
737 if (curr == NULL) {
738 return;
739 }
740 bool to_add = true;
741 to_add = is_present(curr->entity, entities, num_entities);
742 if (to_add) {
743 entity_association_pdr_add_entry(curr, repo, is_remote,
744 terminus_handle);
745 }
746 entity_association_pdr_add(curr->next_sibling, repo, entities,
747 num_entities, is_remote, terminus_handle);
748 entity_association_pdr_add(curr->first_child, repo, entities,
749 num_entities, is_remote, terminus_handle);
750}
751
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930752LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
754 pldm_pdr *repo, bool is_remote,
755 uint16_t terminus_handle)
756{
757 assert(tree != NULL);
758 assert(repo != NULL);
759
760 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
761 terminus_handle);
762}
763
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930764LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930766 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
767 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768{
769 assert(repo != NULL);
770
771 entity_association_pdr_add(node, repo, entities, num_entities,
772 is_remote, terminus_handle);
773}
774
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930775LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930776void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
777 pldm_entity_node **node)
778{
779 if (tree_node == NULL) {
780 return;
781 }
782
783 if (tree_node->entity.entity_type == entity.entity_type &&
784 tree_node->entity.entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930785 entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786 *node = tree_node;
787 return;
788 }
789
790 find_entity_ref_in_tree(tree_node->first_child, entity, node);
791 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
792}
793
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930794LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930795void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
796 pldm_entity entity, pldm_entity_node **node)
797{
798 assert(tree != NULL);
799 find_entity_ref_in_tree(tree->root, entity, node);
800}
801
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930802LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
804 uint16_t terminus_handle)
805{
806 assert(repo != NULL);
807 bool removed = false;
808
809 pldm_pdr_record *record = repo->first;
810 pldm_pdr_record *prev = NULL;
811 while (record != NULL) {
812 pldm_pdr_record *next = record->next;
813 if (record->terminus_handle == terminus_handle) {
814 if (repo->first == record) {
815 repo->first = next;
816 } else {
817 prev->next = next;
818 }
819 if (repo->last == record) {
820 repo->last = prev;
821 }
822 if (record->data) {
823 free(record->data);
824 }
825 --repo->record_count;
826 repo->size -= record->size;
827 free(record);
828 removed = true;
829 } else {
830 prev = record;
831 }
832 record = next;
833 }
834
835 if (removed == true) {
836 record = repo->first;
837 uint32_t record_handle = 0;
838 while (record != NULL) {
839 record->record_handle = ++record_handle;
840 if (record->data != NULL) {
841 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930842 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930843 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930844 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930845 }
846 record = record->next;
847 }
848 }
849}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930850
851LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930852void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
853{
854 assert(repo != NULL);
855 bool removed = false;
856
857 pldm_pdr_record *record = repo->first;
858 pldm_pdr_record *prev = NULL;
859 while (record != NULL) {
860 pldm_pdr_record *next = record->next;
861 if (record->is_remote == true) {
862 if (repo->first == record) {
863 repo->first = next;
864 } else {
865 prev->next = next;
866 }
867 if (repo->last == record) {
868 repo->last = prev;
869 }
870 if (record->data) {
871 free(record->data);
872 }
873 --repo->record_count;
874 repo->size -= record->size;
875 free(record);
876 removed = true;
877 } else {
878 prev = record;
879 }
880 record = next;
881 }
882
883 if (removed == true) {
884 record = repo->first;
885 uint32_t record_handle = 0;
886 while (record != NULL) {
887 record->record_handle = ++record_handle;
888 if (record->data != NULL) {
889 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930890 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930892 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893 }
894 record = record->next;
895 }
896 }
897}
898
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930899LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930900void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
901 pldm_entity_node **out)
902{
903 if (node == NULL) {
904 return;
905 }
906
907 if (node->entity.entity_type == entity->entity_type &&
908 node->entity.entity_instance_num == entity->entity_instance_num) {
909 entity->entity_container_id = node->entity.entity_container_id;
910 *out = node;
911 return;
912 }
913
914 entity_association_tree_find(node->next_sibling, entity, out);
915 entity_association_tree_find(node->first_child, entity, out);
916}
917
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930918LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919pldm_entity_node *
920pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
921 pldm_entity *entity)
922{
923 assert(tree != NULL);
924
925 pldm_entity_node *node = NULL;
926 entity_association_tree_find(tree->root, entity, &node);
927 return node;
928}
929
930static void entity_association_tree_copy(pldm_entity_node *org_node,
931 pldm_entity_node **new_node)
932{
933 if (org_node == NULL) {
934 return;
935 }
936 *new_node = malloc(sizeof(pldm_entity_node));
937 (*new_node)->parent = org_node->parent;
938 (*new_node)->entity = org_node->entity;
939 (*new_node)->association_type = org_node->association_type;
940 (*new_node)->first_child = NULL;
941 (*new_node)->next_sibling = NULL;
942 entity_association_tree_copy(org_node->first_child,
943 &((*new_node)->first_child));
944 entity_association_tree_copy(org_node->next_sibling,
945 &((*new_node)->next_sibling));
946}
947
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930948LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930950 pldm_entity_association_tree *org_tree,
951 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952{
953 new_tree->last_used_container_id = org_tree->last_used_container_id;
954 entity_association_tree_copy(org_tree->root, &(new_tree->root));
955}
956
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930957LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930959 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960{
961 assert(tree != NULL);
962 entity_association_tree_destroy(tree->root);
963 tree->last_used_container_id = 0;
964 tree->root = NULL;
965}
966
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930967LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930968bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
969{
970 return ((tree->root == NULL) ? true : false);
971}
972
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930973LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
975 size_t *num_entities,
976 pldm_entity **entities)
977{
978 assert(pdr != NULL);
979 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930980 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981
982 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
983 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
984
985 const uint8_t *start = (uint8_t *)pdr;
986 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930987 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930988 start += sizeof(struct pldm_pdr_hdr);
989 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930990 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991 *num_entities = entity_association_pdr->num_children + 1;
992 assert(*num_entities >= 2);
993 *entities = malloc(sizeof(pldm_entity) * *num_entities);
994 assert(*entities != NULL);
995 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930996 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997 end);
998 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930999 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301001 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301003 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301004 pldm_entity *curr_entity = entity_association_pdr->children;
1005 size_t i = 1;
1006 while (i < *num_entities) {
1007 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301008 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301010 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301012 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013 ++curr_entity;
1014 ++i;
1015 }
1016}