blob: ff4fbd1087dc007098abcae5c417409c83219d6f [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>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06008#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09309
10typedef struct pldm_pdr_record {
11 uint32_t record_handle;
12 uint32_t size;
13 uint8_t *data;
14 struct pldm_pdr_record *next;
15 bool is_remote;
16 uint16_t terminus_handle;
17} pldm_pdr_record;
18
19typedef struct pldm_pdr {
20 uint32_t record_count;
21 uint32_t size;
22 pldm_pdr_record *first;
23 pldm_pdr_record *last;
24} pldm_pdr;
25
26static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
27 const pldm_pdr_record *record)
28{
29 assert(repo != NULL);
30 assert(record != NULL);
31
32 if (record == repo->last) {
33 return 0;
34 }
35 return record->next->record_handle;
36}
37
38static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
39{
40 assert(repo != NULL);
41 assert(record != NULL);
42
43 if (repo->first == NULL) {
44 assert(repo->last == NULL);
45 repo->first = record;
46 repo->last = record;
47 } else {
48 repo->last->next = record;
49 repo->last = record;
50 }
51 repo->size += record->size;
52 ++repo->record_count;
53}
54
55static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
56{
57 assert(repo != NULL);
58 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093059 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093060 assert(last_used_hdl != UINT32_MAX);
61
62 return last_used_hdl + 1;
63}
64
65static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
66 const uint8_t *data, uint32_t size,
67 uint32_t record_handle, bool is_remote,
68 uint16_t terminus_handle)
69{
70 assert(repo != NULL);
71 assert(size != 0);
72
73 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
74 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093075 record->record_handle = record_handle == 0 ?
76 get_new_record_handle(repo) :
77 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 record->size = size;
79 record->is_remote = is_remote;
80 record->terminus_handle = terminus_handle;
81 if (data != NULL) {
82 record->data = malloc(size);
83 assert(record->data != NULL);
84 memcpy(record->data, data, size);
85 /* If record handle is 0, that is an indication for this API to
86 * compute a new handle. For that reason, the computed handle
87 * needs to be populated in the PDR header. For a case where the
88 * caller supplied the record handle, it would exist in the
89 * header already.
90 */
91 if (!record_handle) {
92 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093093 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093094 hdr->record_handle = htole32(record->record_handle);
95 }
96 }
97 record->next = NULL;
98
99 return record;
100}
101
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930102LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930103uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
104 uint32_t record_handle, bool is_remote,
105 uint16_t terminus_handle)
106{
107 assert(size != 0);
108 assert(data != NULL);
109
110 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930111 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930112 add_record(repo, record);
113
114 return record->record_handle;
115}
116
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930117LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930118pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119{
120 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
121 assert(repo != NULL);
122 repo->record_count = 0;
123 repo->size = 0;
124 repo->first = NULL;
125 repo->last = NULL;
126
127 return repo;
128}
129
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930130LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930131void pldm_pdr_destroy(pldm_pdr *repo)
132{
133 assert(repo != NULL);
134
135 pldm_pdr_record *record = repo->first;
136 while (record != NULL) {
137 pldm_pdr_record *next = record->next;
138 if (record->data) {
139 free(record->data);
140 record->data = NULL;
141 }
142 free(record);
143 record = next;
144 }
145 free(repo);
146}
147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930149const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
150 uint32_t record_handle,
151 uint8_t **data, uint32_t *size,
152 uint32_t *next_record_handle)
153{
154 assert(repo != NULL);
155 assert(data != NULL);
156 assert(size != NULL);
157 assert(next_record_handle != NULL);
158
159 if (!record_handle && (repo->first != NULL)) {
160 record_handle = repo->first->record_handle;
161 }
162 pldm_pdr_record *record = repo->first;
163 while (record != NULL) {
164 if (record->record_handle == record_handle) {
165 *size = record->size;
166 *data = record->data;
167 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930168 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 return record;
170 }
171 record = record->next;
172 }
173
174 *size = 0;
175 *next_record_handle = 0;
176 return NULL;
177}
178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930180const pldm_pdr_record *
181pldm_pdr_get_next_record(const pldm_pdr *repo,
182 const pldm_pdr_record *curr_record, uint8_t **data,
183 uint32_t *size, uint32_t *next_record_handle)
184{
185 assert(repo != NULL);
186 assert(curr_record != NULL);
187 assert(data != NULL);
188 assert(size != NULL);
189 assert(next_record_handle != NULL);
190
191 if (curr_record == repo->last) {
192 *data = NULL;
193 *size = 0;
194 *next_record_handle = get_next_record_handle(repo, curr_record);
195 return NULL;
196 }
197
198 *next_record_handle = get_next_record_handle(repo, curr_record->next);
199 *data = curr_record->next->data;
200 *size = curr_record->next->size;
201 return curr_record->next;
202}
203
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930204LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205const pldm_pdr_record *
206pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
207 const pldm_pdr_record *curr_record, uint8_t **data,
208 uint32_t *size)
209{
210 assert(repo != NULL);
211
212 pldm_pdr_record *record = repo->first;
213 if (curr_record != NULL) {
214 record = curr_record->next;
215 }
216 while (record != NULL) {
217 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
218 if (hdr->type == pdr_type) {
219 if (data && size) {
220 *size = record->size;
221 *data = record->data;
222 }
223 return record;
224 }
225 record = record->next;
226 }
227
228 if (size) {
229 *size = 0;
230 }
231 return NULL;
232}
233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930234LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930235uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
236{
237 assert(repo != NULL);
238
239 return repo->record_count;
240}
241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
244{
245 assert(repo != NULL);
246
247 return repo->size;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
252 const pldm_pdr_record *record)
253{
254 assert(repo != NULL);
255 assert(record != NULL);
256
257 return record->record_handle;
258}
259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930260LIBPLDM_ABI_STABLE
261bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930262{
263 assert(record != NULL);
264
265 return record->is_remote;
266}
267
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930268LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930269uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
270 uint16_t fru_rsi, uint16_t entity_type,
271 uint16_t entity_instance_num,
272 uint16_t container_id,
273 uint32_t bmc_record_handle)
274{
275 uint32_t size = sizeof(struct pldm_pdr_hdr) +
276 sizeof(struct pldm_pdr_fru_record_set);
277 uint8_t data[size];
278
279 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
280 hdr->version = 1;
281 hdr->record_handle = bmc_record_handle;
282 hdr->type = PLDM_PDR_FRU_RECORD_SET;
283 hdr->record_change_num = 0;
284 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
285 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930286 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
287 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288 fru->terminus_handle = htole16(terminus_handle);
289 fru->fru_rsi = htole16(fru_rsi);
290 fru->entity_type = htole16(entity_type);
291 fru->entity_instance_num = htole16(entity_instance_num);
292 fru->container_id = htole16(container_id);
293
294 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
295 terminus_handle);
296}
297
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930298LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930300 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
301 uint16_t *entity_type, uint16_t *entity_instance_num,
302 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303{
304 assert(terminus_handle != NULL);
305 assert(entity_type != NULL);
306 assert(entity_instance_num != NULL);
307 assert(container_id != NULL);
308
309 uint8_t *data = NULL;
310 uint32_t size = 0;
311 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930312 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313 while (curr_record != NULL) {
314 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 (struct pldm_pdr_fru_record_set
316 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 if (fru->fru_rsi == htole16(fru_rsi)) {
318 *terminus_handle = le16toh(fru->terminus_handle);
319 *entity_type = le16toh(fru->entity_type);
320 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930322 *container_id = le16toh(fru->container_id);
323 return curr_record;
324 }
325 data = NULL;
326 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930327 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
328 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329 }
330
331 *terminus_handle = 0;
332 *entity_type = 0;
333 *entity_instance_num = 0;
334 *container_id = 0;
335
336 return NULL;
337}
338
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930339LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930340/* NOLINTNEXTLINE(readability-identifier-naming) */
341void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
342 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930344 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345 uint32_t size = 0;
346 const pldm_pdr_record *record;
347 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930348 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349
350 do {
351 if (record != NULL) {
352 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930353 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930355 (struct pldm_terminus_locator_type_mctp_eid *)
356 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930357 if (pdr->terminus_handle == terminus_handle &&
358 pdr->tid == tid && value->eid == tl_eid) {
359 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930360 break;
361 }
362 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930363 record = pldm_pdr_find_record_by_type(repo,
364 PLDM_TERMINUS_LOCATOR_PDR,
365 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 } while (record);
367}
368
369typedef struct pldm_entity_association_tree {
370 pldm_entity_node *root;
371 uint16_t last_used_container_id;
372} pldm_entity_association_tree;
373
374typedef struct pldm_entity_node {
375 pldm_entity entity;
376 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600377 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 pldm_entity_node *first_child;
379 pldm_entity_node *next_sibling;
380 uint8_t association_type;
381} pldm_entity_node;
382
383static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
384{
385 assert(tree != NULL);
386 assert(tree->last_used_container_id != UINT16_MAX);
387
388 return ++tree->last_used_container_id;
389}
390
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930391LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930392pldm_entity pldm_entity_extract(pldm_entity_node *node)
393{
394 assert(node != NULL);
395
396 return node->entity;
397}
398
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600399LIBPLDM_ABI_TESTING
400int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
401 uint16_t *cid)
402{
403 if (!entity) {
404 return -EINVAL;
405 }
406
407 *cid = entity->remote_container_id;
408 return 0;
409}
410
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930411LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930412pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930413{
414 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930415 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930416 assert(tree != NULL);
417 tree->root = NULL;
418 tree->last_used_container_id = 0;
419
420 return tree;
421}
422
423static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
424 uint16_t entity_type)
425{
426 assert(start != NULL);
427
428 /* Insert after the the last node that matches the input entity type, or
429 * at the end if no such match occurrs
430 */
431 while (start->next_sibling != NULL) {
432 uint16_t this_type = start->entity.entity_type;
433 pldm_entity_node *next = start->next_sibling;
434 if (this_type == entity_type &&
435 (this_type != next->entity.entity_type)) {
436 break;
437 }
438 start = start->next_sibling;
439 }
440
441 return start;
442}
443
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930444LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930446 pldm_entity_association_tree *tree, pldm_entity *entity,
447 uint16_t entity_instance_number, pldm_entity_node *parent,
448 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449{
450 assert(tree != NULL);
451 assert(entity != NULL);
452
453 if (entity_instance_number != 0xFFFF && parent != NULL) {
454 pldm_entity node;
455 node.entity_type = entity->entity_type;
456 node.entity_instance_num = entity_instance_number;
457 if (pldm_is_current_parent_child(parent, &node)) {
458 return NULL;
459 }
460 }
461
462 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
463 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
464 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
465 assert(node != NULL);
466 node->first_child = NULL;
467 node->next_sibling = NULL;
468 node->parent.entity_type = 0;
469 node->parent.entity_instance_num = 0;
470 node->parent.entity_container_id = 0;
471 node->entity.entity_type = entity->entity_type;
472 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600475 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476
477 if (tree->root == NULL) {
478 assert(parent == NULL);
479 tree->root = node;
480 /* container_id 0 here indicates this is the top-most entry */
481 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600482 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483 } else if (parent != NULL && parent->first_child == NULL) {
484 parent->first_child = node;
485 node->parent = parent->entity;
486 node->entity.entity_container_id = next_container_id(tree);
487 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930488 pldm_entity_node *start = parent == NULL ? tree->root :
489 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930490 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930491 find_insertion_at(start, entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930492 assert(prev != NULL);
493 pldm_entity_node *next = prev->next_sibling;
494 if (prev->entity.entity_type == entity->entity_type) {
495 assert(prev->entity.entity_instance_num != UINT16_MAX);
496 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930497 entity_instance_number != 0xFFFF ?
498 entity_instance_number :
499 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500 }
501 prev->next_sibling = node;
502 node->parent = prev->parent;
503 node->next_sibling = next;
504 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930505 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600506 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930507 }
508 entity->entity_instance_num = node->entity.entity_instance_num;
509 entity->entity_container_id = node->entity.entity_container_id;
510
511 return node;
512}
513
514static void get_num_nodes(pldm_entity_node *node, size_t *num)
515{
516 if (node == NULL) {
517 return;
518 }
519
520 ++(*num);
521 get_num_nodes(node->next_sibling, num);
522 get_num_nodes(node->first_child, num);
523}
524
525static void entity_association_tree_visit(pldm_entity_node *node,
526 pldm_entity *entities, size_t *index)
527{
528 if (node == NULL) {
529 return;
530 }
531
532 pldm_entity *entity = &entities[*index];
533 ++(*index);
534 entity->entity_type = node->entity.entity_type;
535 entity->entity_instance_num = node->entity.entity_instance_num;
536 entity->entity_container_id = node->entity.entity_container_id;
537
538 entity_association_tree_visit(node->next_sibling, entities, index);
539 entity_association_tree_visit(node->first_child, entities, index);
540}
541
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930542LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
544 pldm_entity **entities, size_t *size)
545{
546 assert(tree != NULL);
547
548 *size = 0;
549 if (tree->root == NULL) {
550 return;
551 }
552
553 get_num_nodes(tree->root, size);
554 *entities = malloc(*size * sizeof(pldm_entity));
555 size_t index = 0;
556 entity_association_tree_visit(tree->root, *entities, &index);
557}
558
559static void entity_association_tree_destroy(pldm_entity_node *node)
560{
561 if (node == NULL) {
562 return;
563 }
564
565 entity_association_tree_destroy(node->next_sibling);
566 entity_association_tree_destroy(node->first_child);
567 free(node);
568}
569
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930570LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
572{
573 assert(tree != NULL);
574
575 entity_association_tree_destroy(tree->root);
576 free(tree);
577}
578
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930579LIBPLDM_ABI_STABLE
580bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581{
582 assert(node != NULL);
583
584 return node->first_child != NULL;
585}
586
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930587LIBPLDM_ABI_STABLE
588pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589{
590 assert(node != NULL);
591
592 return node->parent;
593}
594
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930595LIBPLDM_ABI_STABLE
596bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930597{
598 assert(node != NULL);
599
600 if (node->parent.entity_type == 0 &&
601 node->parent.entity_instance_num == 0 &&
602 node->parent.entity_container_id == 0) {
603 return false;
604 }
605
606 return true;
607}
608
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930609LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
611 uint8_t association_type)
612{
613 assert(node != NULL);
614 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
615 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
616
617 size_t count = 0;
618 pldm_entity_node *curr = node->first_child;
619 while (curr != NULL) {
620 if (curr->association_type == association_type) {
621 ++count;
622 }
623 curr = curr->next_sibling;
624 }
625
626 assert(count < UINT8_MAX);
627 return count;
628}
629
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930630LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930631bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
632{
633 assert(parent != NULL);
634 assert(node != NULL);
635
636 pldm_entity_node *curr = parent->first_child;
637 while (curr != NULL) {
638 if (node->entity_type == curr->entity.entity_type &&
639 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930640 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930641 return true;
642 }
643 curr = curr->next_sibling;
644 }
645
646 return false;
647}
648
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930649static void entity_association_pdr_add_children(pldm_entity_node *curr,
650 pldm_pdr *repo, uint16_t size,
651 uint8_t contained_count,
652 uint8_t association_type,
653 bool is_remote,
654 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655{
656 uint8_t pdr[size];
657 uint8_t *start = pdr;
658
659 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
660 hdr->version = 1;
661 hdr->record_handle = 0;
662 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
663 hdr->record_change_num = 0;
664 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
665 start += sizeof(struct pldm_pdr_hdr);
666
667 uint16_t *container_id = (uint16_t *)start;
668 *container_id = htole16(curr->first_child->entity.entity_container_id);
669 start += sizeof(uint16_t);
670 *start = association_type;
671 start += sizeof(uint8_t);
672
673 pldm_entity *entity = (pldm_entity *)start;
674 entity->entity_type = htole16(curr->entity.entity_type);
675 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
676 entity->entity_container_id = htole16(curr->entity.entity_container_id);
677 start += sizeof(pldm_entity);
678
679 *start = contained_count;
680 start += sizeof(uint8_t);
681
682 pldm_entity_node *node = curr->first_child;
683 while (node != NULL) {
684 if (node->association_type == association_type) {
685 pldm_entity *entity = (pldm_entity *)start;
686 entity->entity_type = htole16(node->entity.entity_type);
687 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930688 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930689 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930690 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691 start += sizeof(pldm_entity);
692 }
693 node = node->next_sibling;
694 }
695
696 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
697}
698
699static void entity_association_pdr_add_entry(pldm_entity_node *curr,
700 pldm_pdr *repo, bool is_remote,
701 uint16_t terminus_handle)
702{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930703 uint8_t num_logical_children = pldm_entity_get_num_children(
704 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
705 uint8_t num_physical_children = pldm_entity_get_num_children(
706 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707
708 if (num_logical_children) {
709 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930710 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
711 sizeof(uint8_t) + sizeof(pldm_entity) +
712 sizeof(uint8_t) +
713 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930714 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930715 curr, repo, logical_pdr_size, num_logical_children,
716 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
717 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718 }
719
720 if (num_physical_children) {
721 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930722 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
723 sizeof(uint8_t) + sizeof(pldm_entity) +
724 sizeof(uint8_t) +
725 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930726 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930727 curr, repo, physical_pdr_size, num_physical_children,
728 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
729 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730 }
731}
732
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930733LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
735{
736 if (entities == NULL || num_entities == 0) {
737 return true;
738 }
739 size_t i = 0;
740 while (i < num_entities) {
741 if ((*entities + i)->entity_type == entity.entity_type) {
742 return true;
743 }
744 i++;
745 }
746 return false;
747}
748
749static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
750 pldm_entity **entities,
751 size_t num_entities, bool is_remote,
752 uint16_t terminus_handle)
753{
754 if (curr == NULL) {
755 return;
756 }
757 bool to_add = true;
758 to_add = is_present(curr->entity, entities, num_entities);
759 if (to_add) {
760 entity_association_pdr_add_entry(curr, repo, is_remote,
761 terminus_handle);
762 }
763 entity_association_pdr_add(curr->next_sibling, repo, entities,
764 num_entities, is_remote, terminus_handle);
765 entity_association_pdr_add(curr->first_child, repo, entities,
766 num_entities, is_remote, terminus_handle);
767}
768
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930769LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
771 pldm_pdr *repo, bool is_remote,
772 uint16_t terminus_handle)
773{
774 assert(tree != NULL);
775 assert(repo != NULL);
776
777 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
778 terminus_handle);
779}
780
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930781LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930782void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930783 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
784 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930785{
786 assert(repo != NULL);
787
788 entity_association_pdr_add(node, repo, entities, num_entities,
789 is_remote, terminus_handle);
790}
791
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930792LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
794 pldm_entity_node **node)
795{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600796 bool is_entity_container_id;
797 bool is_entity_instance_num;
798 bool is_type;
799
Andrew Jeffery9c766792022-08-10 23:12:49 +0930800 if (tree_node == NULL) {
801 return;
802 }
803
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600804 is_type = tree_node->entity.entity_type == entity.entity_type;
805 is_entity_instance_num = tree_node->entity.entity_instance_num ==
806 entity.entity_instance_num;
807 is_entity_container_id = tree_node->entity.entity_container_id ==
808 entity.entity_container_id;
809
810 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930811 *node = tree_node;
812 return;
813 }
814
815 find_entity_ref_in_tree(tree_node->first_child, entity, node);
816 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
817}
818
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930819LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930820void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
821 pldm_entity entity, pldm_entity_node **node)
822{
823 assert(tree != NULL);
824 find_entity_ref_in_tree(tree->root, entity, node);
825}
826
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930827LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930828void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
829 uint16_t terminus_handle)
830{
831 assert(repo != NULL);
832 bool removed = false;
833
834 pldm_pdr_record *record = repo->first;
835 pldm_pdr_record *prev = NULL;
836 while (record != NULL) {
837 pldm_pdr_record *next = record->next;
838 if (record->terminus_handle == terminus_handle) {
839 if (repo->first == record) {
840 repo->first = next;
841 } else {
842 prev->next = next;
843 }
844 if (repo->last == record) {
845 repo->last = prev;
846 }
847 if (record->data) {
848 free(record->data);
849 }
850 --repo->record_count;
851 repo->size -= record->size;
852 free(record);
853 removed = true;
854 } else {
855 prev = record;
856 }
857 record = next;
858 }
859
860 if (removed == true) {
861 record = repo->first;
862 uint32_t record_handle = 0;
863 while (record != NULL) {
864 record->record_handle = ++record_handle;
865 if (record->data != NULL) {
866 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930869 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870 }
871 record = record->next;
872 }
873 }
874}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930875
876LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
878{
879 assert(repo != NULL);
880 bool removed = false;
881
882 pldm_pdr_record *record = repo->first;
883 pldm_pdr_record *prev = NULL;
884 while (record != NULL) {
885 pldm_pdr_record *next = record->next;
886 if (record->is_remote == true) {
887 if (repo->first == record) {
888 repo->first = next;
889 } else {
890 prev->next = next;
891 }
892 if (repo->last == record) {
893 repo->last = prev;
894 }
895 if (record->data) {
896 free(record->data);
897 }
898 --repo->record_count;
899 repo->size -= record->size;
900 free(record);
901 removed = true;
902 } else {
903 prev = record;
904 }
905 record = next;
906 }
907
908 if (removed == true) {
909 record = repo->first;
910 uint32_t record_handle = 0;
911 while (record != NULL) {
912 record->record_handle = ++record_handle;
913 if (record->data != NULL) {
914 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930915 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930917 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 }
919 record = record->next;
920 }
921 }
922}
923
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930924LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930925void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
926 pldm_entity_node **out)
927{
928 if (node == NULL) {
929 return;
930 }
931
932 if (node->entity.entity_type == entity->entity_type &&
933 node->entity.entity_instance_num == entity->entity_instance_num) {
934 entity->entity_container_id = node->entity.entity_container_id;
935 *out = node;
936 return;
937 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930938 entity_association_tree_find(node->next_sibling, entity, out);
939 entity_association_tree_find(node->first_child, entity, out);
940}
941
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930942LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943pldm_entity_node *
944pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
945 pldm_entity *entity)
946{
947 assert(tree != NULL);
948
949 pldm_entity_node *node = NULL;
950 entity_association_tree_find(tree->root, entity, &node);
951 return node;
952}
953
954static void entity_association_tree_copy(pldm_entity_node *org_node,
955 pldm_entity_node **new_node)
956{
957 if (org_node == NULL) {
958 return;
959 }
960 *new_node = malloc(sizeof(pldm_entity_node));
961 (*new_node)->parent = org_node->parent;
962 (*new_node)->entity = org_node->entity;
963 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600964 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 (*new_node)->first_child = NULL;
966 (*new_node)->next_sibling = NULL;
967 entity_association_tree_copy(org_node->first_child,
968 &((*new_node)->first_child));
969 entity_association_tree_copy(org_node->next_sibling,
970 &((*new_node)->next_sibling));
971}
972
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930973LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930975 pldm_entity_association_tree *org_tree,
976 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930977{
978 new_tree->last_used_container_id = org_tree->last_used_container_id;
979 entity_association_tree_copy(org_tree->root, &(new_tree->root));
980}
981
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930982LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930983void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930984 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930985{
986 assert(tree != NULL);
987 entity_association_tree_destroy(tree->root);
988 tree->last_used_container_id = 0;
989 tree->root = NULL;
990}
991
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930992LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
994{
995 return ((tree->root == NULL) ? true : false);
996}
997
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930998LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930999void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1000 size_t *num_entities,
1001 pldm_entity **entities)
1002{
1003 assert(pdr != NULL);
1004 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301005 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006
1007 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1008 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1009
1010 const uint8_t *start = (uint8_t *)pdr;
1011 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301012 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013 start += sizeof(struct pldm_pdr_hdr);
1014 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301015 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016 *num_entities = entity_association_pdr->num_children + 1;
1017 assert(*num_entities >= 2);
1018 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1019 assert(*entities != NULL);
1020 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301021 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301022 end);
1023 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301024 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301025 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301026 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301028 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301029 pldm_entity *curr_entity = entity_association_pdr->children;
1030 size_t i = 1;
1031 while (i < *num_entities) {
1032 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301033 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301035 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301037 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038 ++curr_entity;
1039 ++i;
1040 }
1041}