blob: 8a63e95f3d26f3193e857bd12fdffef628c1cb12 [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{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500450 return pldm_entity_association_tree_add_entity(tree, entity,
451 entity_instance_number,
452 parent, association_type,
453 false, true, 0xFFFF);
454}
455
456LIBPLDM_ABI_TESTING
457pldm_entity_node *pldm_entity_association_tree_add_entity(
458 pldm_entity_association_tree *tree, pldm_entity *entity,
459 uint16_t entity_instance_number, pldm_entity_node *parent,
460 uint8_t association_type, bool is_remote, bool is_update_container_id,
461 uint16_t container_id)
462{
463 if ((!tree) || (!entity)) {
464 return NULL;
465 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466
467 if (entity_instance_number != 0xFFFF && parent != NULL) {
468 pldm_entity node;
469 node.entity_type = entity->entity_type;
470 node.entity_instance_num = entity_instance_number;
471 if (pldm_is_current_parent_child(parent, &node)) {
472 return NULL;
473 }
474 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500475 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
476 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
477 return NULL;
478 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930479 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500480 if (!node) {
481 return NULL;
482 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483 node->first_child = NULL;
484 node->next_sibling = NULL;
485 node->parent.entity_type = 0;
486 node->parent.entity_instance_num = 0;
487 node->parent.entity_container_id = 0;
488 node->entity.entity_type = entity->entity_type;
489 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930490 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930491 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600492 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930493 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500494 if (parent != NULL) {
495 free(node);
496 return NULL;
497 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930498 tree->root = node;
499 /* container_id 0 here indicates this is the top-most entry */
500 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600501 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502 } else if (parent != NULL && parent->first_child == NULL) {
503 parent->first_child = node;
504 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500505
506 if (is_remote) {
507 node->remote_container_id = entity->entity_container_id;
508 }
509 if (is_update_container_id) {
510 if (container_id != 0xFFFF) {
511 node->entity.entity_container_id = container_id;
512 } else {
513 node->entity.entity_container_id =
514 next_container_id(tree);
515 }
516 } else {
517 node->entity.entity_container_id =
518 entity->entity_container_id;
519 }
520
521 if (!is_remote) {
522 node->remote_container_id =
523 node->entity.entity_container_id;
524 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930525 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930526 pldm_entity_node *start = parent == NULL ? tree->root :
527 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930528 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930529 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500530 if (!prev) {
531 free(node);
532 return NULL;
533 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930534 pldm_entity_node *next = prev->next_sibling;
535 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500536 if (prev->entity.entity_instance_num == UINT16_MAX) {
537 free(node);
538 return NULL;
539 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930541 entity_instance_number != 0xFFFF ?
542 entity_instance_number :
543 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544 }
545 prev->next_sibling = node;
546 node->parent = prev->parent;
547 node->next_sibling = next;
548 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930549 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600550 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 }
552 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500553 if (is_update_container_id) {
554 entity->entity_container_id = node->entity.entity_container_id;
555 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930556 return node;
557}
558
559static void get_num_nodes(pldm_entity_node *node, size_t *num)
560{
561 if (node == NULL) {
562 return;
563 }
564
565 ++(*num);
566 get_num_nodes(node->next_sibling, num);
567 get_num_nodes(node->first_child, num);
568}
569
570static void entity_association_tree_visit(pldm_entity_node *node,
571 pldm_entity *entities, size_t *index)
572{
573 if (node == NULL) {
574 return;
575 }
576
577 pldm_entity *entity = &entities[*index];
578 ++(*index);
579 entity->entity_type = node->entity.entity_type;
580 entity->entity_instance_num = node->entity.entity_instance_num;
581 entity->entity_container_id = node->entity.entity_container_id;
582
583 entity_association_tree_visit(node->next_sibling, entities, index);
584 entity_association_tree_visit(node->first_child, entities, index);
585}
586
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930587LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
589 pldm_entity **entities, size_t *size)
590{
591 assert(tree != NULL);
592
593 *size = 0;
594 if (tree->root == NULL) {
595 return;
596 }
597
598 get_num_nodes(tree->root, size);
599 *entities = malloc(*size * sizeof(pldm_entity));
600 size_t index = 0;
601 entity_association_tree_visit(tree->root, *entities, &index);
602}
603
604static void entity_association_tree_destroy(pldm_entity_node *node)
605{
606 if (node == NULL) {
607 return;
608 }
609
610 entity_association_tree_destroy(node->next_sibling);
611 entity_association_tree_destroy(node->first_child);
612 free(node);
613}
614
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930615LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
617{
618 assert(tree != NULL);
619
620 entity_association_tree_destroy(tree->root);
621 free(tree);
622}
623
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930624LIBPLDM_ABI_STABLE
625bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626{
627 assert(node != NULL);
628
629 return node->first_child != NULL;
630}
631
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930632LIBPLDM_ABI_STABLE
633pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634{
635 assert(node != NULL);
636
637 return node->parent;
638}
639
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930640LIBPLDM_ABI_STABLE
641bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930642{
643 assert(node != NULL);
644
645 if (node->parent.entity_type == 0 &&
646 node->parent.entity_instance_num == 0 &&
647 node->parent.entity_container_id == 0) {
648 return false;
649 }
650
651 return true;
652}
653
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930654LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
656 uint8_t association_type)
657{
658 assert(node != NULL);
659 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
660 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
661
662 size_t count = 0;
663 pldm_entity_node *curr = node->first_child;
664 while (curr != NULL) {
665 if (curr->association_type == association_type) {
666 ++count;
667 }
668 curr = curr->next_sibling;
669 }
670
671 assert(count < UINT8_MAX);
672 return count;
673}
674
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930675LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930676bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
677{
678 assert(parent != NULL);
679 assert(node != NULL);
680
681 pldm_entity_node *curr = parent->first_child;
682 while (curr != NULL) {
683 if (node->entity_type == curr->entity.entity_type &&
684 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930685 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686 return true;
687 }
688 curr = curr->next_sibling;
689 }
690
691 return false;
692}
693
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930694static void entity_association_pdr_add_children(pldm_entity_node *curr,
695 pldm_pdr *repo, uint16_t size,
696 uint8_t contained_count,
697 uint8_t association_type,
698 bool is_remote,
699 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930700{
701 uint8_t pdr[size];
702 uint8_t *start = pdr;
703
704 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
705 hdr->version = 1;
706 hdr->record_handle = 0;
707 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
708 hdr->record_change_num = 0;
709 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
710 start += sizeof(struct pldm_pdr_hdr);
711
712 uint16_t *container_id = (uint16_t *)start;
713 *container_id = htole16(curr->first_child->entity.entity_container_id);
714 start += sizeof(uint16_t);
715 *start = association_type;
716 start += sizeof(uint8_t);
717
718 pldm_entity *entity = (pldm_entity *)start;
719 entity->entity_type = htole16(curr->entity.entity_type);
720 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
721 entity->entity_container_id = htole16(curr->entity.entity_container_id);
722 start += sizeof(pldm_entity);
723
724 *start = contained_count;
725 start += sizeof(uint8_t);
726
727 pldm_entity_node *node = curr->first_child;
728 while (node != NULL) {
729 if (node->association_type == association_type) {
730 pldm_entity *entity = (pldm_entity *)start;
731 entity->entity_type = htole16(node->entity.entity_type);
732 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930733 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930735 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736 start += sizeof(pldm_entity);
737 }
738 node = node->next_sibling;
739 }
740
741 pldm_pdr_add(repo, pdr, size, 0, is_remote, terminus_handle);
742}
743
744static void entity_association_pdr_add_entry(pldm_entity_node *curr,
745 pldm_pdr *repo, bool is_remote,
746 uint16_t terminus_handle)
747{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930748 uint8_t num_logical_children = pldm_entity_get_num_children(
749 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
750 uint8_t num_physical_children = pldm_entity_get_num_children(
751 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752
753 if (num_logical_children) {
754 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930755 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
756 sizeof(uint8_t) + sizeof(pldm_entity) +
757 sizeof(uint8_t) +
758 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930759 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930760 curr, repo, logical_pdr_size, num_logical_children,
761 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
762 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763 }
764
765 if (num_physical_children) {
766 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930767 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
768 sizeof(uint8_t) + sizeof(pldm_entity) +
769 sizeof(uint8_t) +
770 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930771 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930772 curr, repo, physical_pdr_size, num_physical_children,
773 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
774 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775 }
776}
777
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930778LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930779bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
780{
781 if (entities == NULL || num_entities == 0) {
782 return true;
783 }
784 size_t i = 0;
785 while (i < num_entities) {
786 if ((*entities + i)->entity_type == entity.entity_type) {
787 return true;
788 }
789 i++;
790 }
791 return false;
792}
793
794static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
795 pldm_entity **entities,
796 size_t num_entities, bool is_remote,
797 uint16_t terminus_handle)
798{
799 if (curr == NULL) {
800 return;
801 }
802 bool to_add = true;
803 to_add = is_present(curr->entity, entities, num_entities);
804 if (to_add) {
805 entity_association_pdr_add_entry(curr, repo, is_remote,
806 terminus_handle);
807 }
808 entity_association_pdr_add(curr->next_sibling, repo, entities,
809 num_entities, is_remote, terminus_handle);
810 entity_association_pdr_add(curr->first_child, repo, entities,
811 num_entities, is_remote, terminus_handle);
812}
813
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930814LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
816 pldm_pdr *repo, bool is_remote,
817 uint16_t terminus_handle)
818{
819 assert(tree != NULL);
820 assert(repo != NULL);
821
822 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
823 terminus_handle);
824}
825
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930826LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930827void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930828 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
829 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830{
831 assert(repo != NULL);
832
833 entity_association_pdr_add(node, repo, entities, num_entities,
834 is_remote, terminus_handle);
835}
836
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930837LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
839 pldm_entity_node **node)
840{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600841 bool is_entity_container_id;
842 bool is_entity_instance_num;
843 bool is_type;
844
Andrew Jeffery9c766792022-08-10 23:12:49 +0930845 if (tree_node == NULL) {
846 return;
847 }
848
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600849 is_type = tree_node->entity.entity_type == entity.entity_type;
850 is_entity_instance_num = tree_node->entity.entity_instance_num ==
851 entity.entity_instance_num;
852 is_entity_container_id = tree_node->entity.entity_container_id ==
853 entity.entity_container_id;
854
855 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856 *node = tree_node;
857 return;
858 }
859
860 find_entity_ref_in_tree(tree_node->first_child, entity, node);
861 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
862}
863
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930864LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
866 pldm_entity entity, pldm_entity_node **node)
867{
868 assert(tree != NULL);
869 find_entity_ref_in_tree(tree->root, entity, node);
870}
871
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930872LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
874 uint16_t terminus_handle)
875{
876 assert(repo != NULL);
877 bool removed = false;
878
879 pldm_pdr_record *record = repo->first;
880 pldm_pdr_record *prev = NULL;
881 while (record != NULL) {
882 pldm_pdr_record *next = record->next;
883 if (record->terminus_handle == terminus_handle) {
884 if (repo->first == record) {
885 repo->first = next;
886 } else {
887 prev->next = next;
888 }
889 if (repo->last == record) {
890 repo->last = prev;
891 }
892 if (record->data) {
893 free(record->data);
894 }
895 --repo->record_count;
896 repo->size -= record->size;
897 free(record);
898 removed = true;
899 } else {
900 prev = record;
901 }
902 record = next;
903 }
904
905 if (removed == true) {
906 record = repo->first;
907 uint32_t record_handle = 0;
908 while (record != NULL) {
909 record->record_handle = ++record_handle;
910 if (record->data != NULL) {
911 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930912 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930914 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915 }
916 record = record->next;
917 }
918 }
919}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930920
921LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
923{
924 assert(repo != NULL);
925 bool removed = false;
926
927 pldm_pdr_record *record = repo->first;
928 pldm_pdr_record *prev = NULL;
929 while (record != NULL) {
930 pldm_pdr_record *next = record->next;
931 if (record->is_remote == true) {
932 if (repo->first == record) {
933 repo->first = next;
934 } else {
935 prev->next = next;
936 }
937 if (repo->last == record) {
938 repo->last = prev;
939 }
940 if (record->data) {
941 free(record->data);
942 }
943 --repo->record_count;
944 repo->size -= record->size;
945 free(record);
946 removed = true;
947 } else {
948 prev = record;
949 }
950 record = next;
951 }
952
953 if (removed == true) {
954 record = repo->first;
955 uint32_t record_handle = 0;
956 while (record != NULL) {
957 record->record_handle = ++record_handle;
958 if (record->data != NULL) {
959 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930960 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930961 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930962 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930963 }
964 record = record->next;
965 }
966 }
967}
968
Pavithra Barithaya4d694342023-05-19 08:04:41 -0500969LIBPLDM_ABI_TESTING
970pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
971 uint32_t first, uint32_t last)
972{
973 pldm_pdr_record *record = NULL;
974 pldm_pdr_record *curr;
975
976 if (!repo) {
977 return NULL;
978 }
979 for (curr = repo->first; curr; curr = curr->next) {
980 if (first > curr->record_handle || last < curr->record_handle) {
981 continue;
982 }
983 if (!record || curr->record_handle > record->record_handle) {
984 record = curr;
985 }
986 }
987
988 return record;
989}
990
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500991static void entity_association_tree_find_if_remote(pldm_entity_node *node,
992 pldm_entity *entity,
993 pldm_entity_node **out,
994 bool is_remote)
995{
996 assert(out != NULL && *out == NULL);
997 if (node == NULL) {
998 return;
999 }
1000 bool is_entity_type;
1001 bool is_entity_instance_num;
1002
1003 is_entity_type = node->entity.entity_type == entity->entity_type;
1004 is_entity_instance_num = node->entity.entity_instance_num ==
1005 entity->entity_instance_num;
1006
1007 if (!is_remote ||
1008 node->remote_container_id == entity->entity_container_id) {
1009 if (is_entity_type && is_entity_instance_num) {
1010 entity->entity_container_id =
1011 node->entity.entity_container_id;
1012 *out = node;
1013 return;
1014 }
1015 }
1016 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1017 is_remote);
1018 entity_association_tree_find_if_remote(node->first_child, entity, out,
1019 is_remote);
1020}
1021
1022LIBPLDM_ABI_TESTING
1023pldm_entity_node *
1024pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1025 pldm_entity *entity, bool is_remote)
1026{
1027 if (!tree || !entity) {
1028 return NULL;
1029 }
1030 pldm_entity_node *node = NULL;
1031 entity_association_tree_find_if_remote(tree->root, entity, &node,
1032 is_remote);
1033 return node;
1034}
1035
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301036LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1038 pldm_entity_node **out)
1039{
1040 if (node == NULL) {
1041 return;
1042 }
1043
1044 if (node->entity.entity_type == entity->entity_type &&
1045 node->entity.entity_instance_num == entity->entity_instance_num) {
1046 entity->entity_container_id = node->entity.entity_container_id;
1047 *out = node;
1048 return;
1049 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050 entity_association_tree_find(node->next_sibling, entity, out);
1051 entity_association_tree_find(node->first_child, entity, out);
1052}
1053
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301054LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055pldm_entity_node *
1056pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1057 pldm_entity *entity)
1058{
1059 assert(tree != NULL);
1060
1061 pldm_entity_node *node = NULL;
1062 entity_association_tree_find(tree->root, entity, &node);
1063 return node;
1064}
1065
1066static void entity_association_tree_copy(pldm_entity_node *org_node,
1067 pldm_entity_node **new_node)
1068{
1069 if (org_node == NULL) {
1070 return;
1071 }
1072 *new_node = malloc(sizeof(pldm_entity_node));
1073 (*new_node)->parent = org_node->parent;
1074 (*new_node)->entity = org_node->entity;
1075 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001076 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301077 (*new_node)->first_child = NULL;
1078 (*new_node)->next_sibling = NULL;
1079 entity_association_tree_copy(org_node->first_child,
1080 &((*new_node)->first_child));
1081 entity_association_tree_copy(org_node->next_sibling,
1082 &((*new_node)->next_sibling));
1083}
1084
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301085LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301086void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301087 pldm_entity_association_tree *org_tree,
1088 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301089{
1090 new_tree->last_used_container_id = org_tree->last_used_container_id;
1091 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1092}
1093
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301094LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301096 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097{
1098 assert(tree != NULL);
1099 entity_association_tree_destroy(tree->root);
1100 tree->last_used_container_id = 0;
1101 tree->root = NULL;
1102}
1103
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301104LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301105bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1106{
1107 return ((tree->root == NULL) ? true : false);
1108}
1109
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301110LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301111void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1112 size_t *num_entities,
1113 pldm_entity **entities)
1114{
1115 assert(pdr != NULL);
1116 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301117 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301118
1119 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1120 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1121
1122 const uint8_t *start = (uint8_t *)pdr;
1123 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301124 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301125 start += sizeof(struct pldm_pdr_hdr);
1126 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301127 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301128 *num_entities = entity_association_pdr->num_children + 1;
1129 assert(*num_entities >= 2);
1130 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1131 assert(*entities != NULL);
1132 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301133 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301134 end);
1135 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301136 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301138 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301140 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141 pldm_entity *curr_entity = entity_association_pdr->children;
1142 size_t i = 1;
1143 while (i < *num_entities) {
1144 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301145 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301147 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301148 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301149 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301150 ++curr_entity;
1151 ++i;
1152 }
1153}