blob: 65b7e5c470769a6816c593a90b111593f079518b [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include "pdr.h"
2#include "platform.h"
3#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05304#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <stdlib.h>
6#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06007#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308
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));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930120 if (!repo) {
121 return NULL;
122 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123 repo->record_count = 0;
124 repo->size = 0;
125 repo->first = NULL;
126 repo->last = NULL;
127
128 return repo;
129}
130
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930131LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132void pldm_pdr_destroy(pldm_pdr *repo)
133{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930134 if (!repo) {
135 return;
136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137
138 pldm_pdr_record *record = repo->first;
139 while (record != NULL) {
140 pldm_pdr_record *next = record->next;
141 if (record->data) {
142 free(record->data);
143 record->data = NULL;
144 }
145 free(record);
146 record = next;
147 }
148 free(repo);
149}
150
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930151LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930152const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
153 uint32_t record_handle,
154 uint8_t **data, uint32_t *size,
155 uint32_t *next_record_handle)
156{
157 assert(repo != NULL);
158 assert(data != NULL);
159 assert(size != NULL);
160 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930161 if (!repo || !data || !size || !next_record_handle) {
162 return NULL;
163 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164
165 if (!record_handle && (repo->first != NULL)) {
166 record_handle = repo->first->record_handle;
167 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 pldm_pdr_record *record = repo->first;
170 while (record != NULL) {
171 if (record->record_handle == record_handle) {
172 *size = record->size;
173 *data = record->data;
174 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 return record;
177 }
178 record = record->next;
179 }
180
181 *size = 0;
182 *next_record_handle = 0;
183 return NULL;
184}
185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187const pldm_pdr_record *
188pldm_pdr_get_next_record(const pldm_pdr *repo,
189 const pldm_pdr_record *curr_record, uint8_t **data,
190 uint32_t *size, uint32_t *next_record_handle)
191{
192 assert(repo != NULL);
193 assert(curr_record != NULL);
194 assert(data != NULL);
195 assert(size != NULL);
196 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930197 if (!repo || !curr_record || !data || !size || !next_record_handle) {
198 return NULL;
199 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200
201 if (curr_record == repo->last) {
202 *data = NULL;
203 *size = 0;
204 *next_record_handle = get_next_record_handle(repo, curr_record);
205 return NULL;
206 }
207
208 *next_record_handle = get_next_record_handle(repo, curr_record->next);
209 *data = curr_record->next->data;
210 *size = curr_record->next->size;
211 return curr_record->next;
212}
213
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930214LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930215const pldm_pdr_record *
216pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
217 const pldm_pdr_record *curr_record, uint8_t **data,
218 uint32_t *size)
219{
220 assert(repo != NULL);
221
222 pldm_pdr_record *record = repo->first;
223 if (curr_record != NULL) {
224 record = curr_record->next;
225 }
226 while (record != NULL) {
227 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
228 if (hdr->type == pdr_type) {
229 if (data && size) {
230 *size = record->size;
231 *data = record->data;
232 }
233 return record;
234 }
235 record = record->next;
236 }
237
238 if (size) {
239 *size = 0;
240 }
241 return NULL;
242}
243
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930244LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930245uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
246{
247 assert(repo != NULL);
248
249 return repo->record_count;
250}
251
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930252LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930253uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
254{
255 assert(repo != NULL);
256
257 return repo->size;
258}
259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930260LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930261uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
262 const pldm_pdr_record *record)
263{
264 assert(repo != NULL);
265 assert(record != NULL);
266
267 return record->record_handle;
268}
269
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930270LIBPLDM_ABI_STABLE
271bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930272{
273 assert(record != NULL);
274
275 return record->is_remote;
276}
277
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930278LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
280 uint16_t fru_rsi, uint16_t entity_type,
281 uint16_t entity_instance_num,
282 uint16_t container_id,
283 uint32_t bmc_record_handle)
284{
285 uint32_t size = sizeof(struct pldm_pdr_hdr) +
286 sizeof(struct pldm_pdr_fru_record_set);
287 uint8_t data[size];
288
289 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
290 hdr->version = 1;
291 hdr->record_handle = bmc_record_handle;
292 hdr->type = PLDM_PDR_FRU_RECORD_SET;
293 hdr->record_change_num = 0;
294 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
295 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930296 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
297 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298 fru->terminus_handle = htole16(terminus_handle);
299 fru->fru_rsi = htole16(fru_rsi);
300 fru->entity_type = htole16(entity_type);
301 fru->entity_instance_num = htole16(entity_instance_num);
302 fru->container_id = htole16(container_id);
303
304 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
305 terminus_handle);
306}
307
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930308LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930309const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930310 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
311 uint16_t *entity_type, uint16_t *entity_instance_num,
312 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313{
314 assert(terminus_handle != NULL);
315 assert(entity_type != NULL);
316 assert(entity_instance_num != NULL);
317 assert(container_id != NULL);
318
319 uint8_t *data = NULL;
320 uint32_t size = 0;
321 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930322 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323 while (curr_record != NULL) {
324 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930325 (struct pldm_pdr_fru_record_set
326 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930327 if (fru->fru_rsi == htole16(fru_rsi)) {
328 *terminus_handle = le16toh(fru->terminus_handle);
329 *entity_type = le16toh(fru->entity_type);
330 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930331 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332 *container_id = le16toh(fru->container_id);
333 return curr_record;
334 }
335 data = NULL;
336 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930337 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
338 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339 }
340
341 *terminus_handle = 0;
342 *entity_type = 0;
343 *entity_instance_num = 0;
344 *container_id = 0;
345
346 return NULL;
347}
348
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930349LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930350/* NOLINTNEXTLINE(readability-identifier-naming) */
351void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
352 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930354 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930355 uint32_t size = 0;
356 const pldm_pdr_record *record;
357 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930358 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359
360 do {
361 if (record != NULL) {
362 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930363 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930364 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930365 (struct pldm_terminus_locator_type_mctp_eid *)
366 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930367 if (pdr->terminus_handle == terminus_handle &&
368 pdr->tid == tid && value->eid == tl_eid) {
369 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370 break;
371 }
372 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 record = pldm_pdr_find_record_by_type(repo,
374 PLDM_TERMINUS_LOCATOR_PDR,
375 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930376 } while (record);
377}
378
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500379static bool pldm_record_handle_in_range(uint32_t record_handle,
380 uint32_t first_record_handle,
381 uint32_t last_record_handle)
382{
383 return record_handle >= first_record_handle &&
384 record_handle <= last_record_handle;
385}
386
387LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500388int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500389 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500390 uint8_t child_index, uint32_t range_exclude_start_handle,
391 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500392{
393 pldm_pdr_record *record;
394 if (!repo) {
395 return -EINVAL;
396 }
397
398 for (record = repo->first; record; record = record->next) {
399 bool is_container_entity_instance_number;
400 struct pldm_pdr_entity_association *pdr;
401 bool is_container_entity_type;
402 struct pldm_entity *child;
403 struct pldm_pdr_hdr *hdr;
404 bool in_range;
405
406 // pldm_pdr_add() takes only uint8_t* data as an argument.
407 // The expectation here is the pldm_pdr_hdr is the first field of the record data
408 hdr = (struct pldm_pdr_hdr *)record->data;
409 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
410 continue;
411 }
412 in_range = pldm_record_handle_in_range(
413 record->record_handle, range_exclude_start_handle,
414 range_exclude_end_handle);
415 if (in_range) {
416 continue;
417 }
418
419 // this cast is valid with respect to alignment because
420 // struct pldm_pdr_hdr is declared with __attribute__((packed))
421 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500422 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500423 continue;
424 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500425
426 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500427 is_container_entity_type = pdr->container.entity_type ==
428 entity_type;
429 is_container_entity_instance_number =
430 pdr->container.entity_instance_num == entity_instance;
431 if (is_container_entity_type &&
432 is_container_entity_instance_number) {
433 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500434 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500435 }
436 }
437 return -ENOKEY;
438}
439
Andrew Jeffery9c766792022-08-10 23:12:49 +0930440typedef struct pldm_entity_association_tree {
441 pldm_entity_node *root;
442 uint16_t last_used_container_id;
443} pldm_entity_association_tree;
444
445typedef struct pldm_entity_node {
446 pldm_entity entity;
447 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600448 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930449 pldm_entity_node *first_child;
450 pldm_entity_node *next_sibling;
451 uint8_t association_type;
452} pldm_entity_node;
453
454static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
455{
456 assert(tree != NULL);
457 assert(tree->last_used_container_id != UINT16_MAX);
458
459 return ++tree->last_used_container_id;
460}
461
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930462LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463pldm_entity pldm_entity_extract(pldm_entity_node *node)
464{
465 assert(node != NULL);
466
467 return node->entity;
468}
469
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600470LIBPLDM_ABI_TESTING
471int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
472 uint16_t *cid)
473{
474 if (!entity) {
475 return -EINVAL;
476 }
477
478 *cid = entity->remote_container_id;
479 return 0;
480}
481
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930482LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930483pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930484{
485 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930486 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930487 assert(tree != NULL);
488 tree->root = NULL;
489 tree->last_used_container_id = 0;
490
491 return tree;
492}
493
494static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
495 uint16_t entity_type)
496{
497 assert(start != NULL);
498
499 /* Insert after the the last node that matches the input entity type, or
500 * at the end if no such match occurrs
501 */
502 while (start->next_sibling != NULL) {
503 uint16_t this_type = start->entity.entity_type;
504 pldm_entity_node *next = start->next_sibling;
505 if (this_type == entity_type &&
506 (this_type != next->entity.entity_type)) {
507 break;
508 }
509 start = start->next_sibling;
510 }
511
512 return start;
513}
514
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930515LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930516pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930517 pldm_entity_association_tree *tree, pldm_entity *entity,
518 uint16_t entity_instance_number, pldm_entity_node *parent,
519 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930520{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500521 return pldm_entity_association_tree_add_entity(tree, entity,
522 entity_instance_number,
523 parent, association_type,
524 false, true, 0xFFFF);
525}
526
527LIBPLDM_ABI_TESTING
528pldm_entity_node *pldm_entity_association_tree_add_entity(
529 pldm_entity_association_tree *tree, pldm_entity *entity,
530 uint16_t entity_instance_number, pldm_entity_node *parent,
531 uint8_t association_type, bool is_remote, bool is_update_container_id,
532 uint16_t container_id)
533{
534 if ((!tree) || (!entity)) {
535 return NULL;
536 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930537
538 if (entity_instance_number != 0xFFFF && parent != NULL) {
539 pldm_entity node;
540 node.entity_type = entity->entity_type;
541 node.entity_instance_num = entity_instance_number;
542 if (pldm_is_current_parent_child(parent, &node)) {
543 return NULL;
544 }
545 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500546 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
547 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
548 return NULL;
549 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500551 if (!node) {
552 return NULL;
553 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554 node->first_child = NULL;
555 node->next_sibling = NULL;
556 node->parent.entity_type = 0;
557 node->parent.entity_instance_num = 0;
558 node->parent.entity_container_id = 0;
559 node->entity.entity_type = entity->entity_type;
560 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930561 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600563 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500565 if (parent != NULL) {
566 free(node);
567 return NULL;
568 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569 tree->root = node;
570 /* container_id 0 here indicates this is the top-most entry */
571 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600572 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 } else if (parent != NULL && parent->first_child == NULL) {
574 parent->first_child = node;
575 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500576
577 if (is_remote) {
578 node->remote_container_id = entity->entity_container_id;
579 }
580 if (is_update_container_id) {
581 if (container_id != 0xFFFF) {
582 node->entity.entity_container_id = container_id;
583 } else {
584 node->entity.entity_container_id =
585 next_container_id(tree);
586 }
587 } else {
588 node->entity.entity_container_id =
589 entity->entity_container_id;
590 }
591
592 if (!is_remote) {
593 node->remote_container_id =
594 node->entity.entity_container_id;
595 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930596 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930597 pldm_entity_node *start = parent == NULL ? tree->root :
598 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930600 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500601 if (!prev) {
602 free(node);
603 return NULL;
604 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930605 pldm_entity_node *next = prev->next_sibling;
606 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500607 if (prev->entity.entity_instance_num == UINT16_MAX) {
608 free(node);
609 return NULL;
610 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930612 entity_instance_number != 0xFFFF ?
613 entity_instance_number :
614 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 }
616 prev->next_sibling = node;
617 node->parent = prev->parent;
618 node->next_sibling = next;
619 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930620 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600621 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 }
623 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500624 if (is_update_container_id) {
625 entity->entity_container_id = node->entity.entity_container_id;
626 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627 return node;
628}
629
630static void get_num_nodes(pldm_entity_node *node, size_t *num)
631{
632 if (node == NULL) {
633 return;
634 }
635
636 ++(*num);
637 get_num_nodes(node->next_sibling, num);
638 get_num_nodes(node->first_child, num);
639}
640
641static void entity_association_tree_visit(pldm_entity_node *node,
642 pldm_entity *entities, size_t *index)
643{
644 if (node == NULL) {
645 return;
646 }
647
648 pldm_entity *entity = &entities[*index];
649 ++(*index);
650 entity->entity_type = node->entity.entity_type;
651 entity->entity_instance_num = node->entity.entity_instance_num;
652 entity->entity_container_id = node->entity.entity_container_id;
653
654 entity_association_tree_visit(node->next_sibling, entities, index);
655 entity_association_tree_visit(node->first_child, entities, index);
656}
657
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930658LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
660 pldm_entity **entities, size_t *size)
661{
662 assert(tree != NULL);
663
664 *size = 0;
665 if (tree->root == NULL) {
666 return;
667 }
668
669 get_num_nodes(tree->root, size);
670 *entities = malloc(*size * sizeof(pldm_entity));
671 size_t index = 0;
672 entity_association_tree_visit(tree->root, *entities, &index);
673}
674
675static void entity_association_tree_destroy(pldm_entity_node *node)
676{
677 if (node == NULL) {
678 return;
679 }
680
681 entity_association_tree_destroy(node->next_sibling);
682 entity_association_tree_destroy(node->first_child);
683 free(node);
684}
685
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930686LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
688{
689 assert(tree != NULL);
690
691 entity_association_tree_destroy(tree->root);
692 free(tree);
693}
694
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930695LIBPLDM_ABI_STABLE
696bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697{
698 assert(node != NULL);
699
700 return node->first_child != NULL;
701}
702
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930703LIBPLDM_ABI_STABLE
704pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705{
706 assert(node != NULL);
707
708 return node->parent;
709}
710
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930711LIBPLDM_ABI_STABLE
712bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713{
714 assert(node != NULL);
715
716 if (node->parent.entity_type == 0 &&
717 node->parent.entity_instance_num == 0 &&
718 node->parent.entity_container_id == 0) {
719 return false;
720 }
721
722 return true;
723}
724
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930725LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
727 uint8_t association_type)
728{
729 assert(node != NULL);
730 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
731 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
732
733 size_t count = 0;
734 pldm_entity_node *curr = node->first_child;
735 while (curr != NULL) {
736 if (curr->association_type == association_type) {
737 ++count;
738 }
739 curr = curr->next_sibling;
740 }
741
742 assert(count < UINT8_MAX);
743 return count;
744}
745
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930746LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
748{
749 assert(parent != NULL);
750 assert(node != NULL);
751
752 pldm_entity_node *curr = parent->first_child;
753 while (curr != NULL) {
754 if (node->entity_type == curr->entity.entity_type &&
755 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930756 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930757 return true;
758 }
759 curr = curr->next_sibling;
760 }
761
762 return false;
763}
764
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500765static void entity_association_pdr_add_children(
766 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
767 uint8_t contained_count, uint8_t association_type, bool is_remote,
768 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930769{
770 uint8_t pdr[size];
771 uint8_t *start = pdr;
772
773 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
774 hdr->version = 1;
775 hdr->record_handle = 0;
776 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
777 hdr->record_change_num = 0;
778 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
779 start += sizeof(struct pldm_pdr_hdr);
780
781 uint16_t *container_id = (uint16_t *)start;
782 *container_id = htole16(curr->first_child->entity.entity_container_id);
783 start += sizeof(uint16_t);
784 *start = association_type;
785 start += sizeof(uint8_t);
786
787 pldm_entity *entity = (pldm_entity *)start;
788 entity->entity_type = htole16(curr->entity.entity_type);
789 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
790 entity->entity_container_id = htole16(curr->entity.entity_container_id);
791 start += sizeof(pldm_entity);
792
793 *start = contained_count;
794 start += sizeof(uint8_t);
795
796 pldm_entity_node *node = curr->first_child;
797 while (node != NULL) {
798 if (node->association_type == association_type) {
799 pldm_entity *entity = (pldm_entity *)start;
800 entity->entity_type = htole16(node->entity.entity_type);
801 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930802 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930804 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805 start += sizeof(pldm_entity);
806 }
807 node = node->next_sibling;
808 }
809
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500810 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
811 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812}
813
814static void entity_association_pdr_add_entry(pldm_entity_node *curr,
815 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500816 uint16_t terminus_handle,
817 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930819 uint8_t num_logical_children = pldm_entity_get_num_children(
820 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
821 uint8_t num_physical_children = pldm_entity_get_num_children(
822 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823
824 if (num_logical_children) {
825 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
827 sizeof(uint8_t) + sizeof(pldm_entity) +
828 sizeof(uint8_t) +
829 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930830 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930831 curr, repo, logical_pdr_size, num_logical_children,
832 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500833 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930834 }
835
836 if (num_physical_children) {
837 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930838 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
839 sizeof(uint8_t) + sizeof(pldm_entity) +
840 sizeof(uint8_t) +
841 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930842 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930843 curr, repo, physical_pdr_size, num_physical_children,
844 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500845 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846 }
847}
848
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930849LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930850bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
851{
852 if (entities == NULL || num_entities == 0) {
853 return true;
854 }
855 size_t i = 0;
856 while (i < num_entities) {
857 if ((*entities + i)->entity_type == entity.entity_type) {
858 return true;
859 }
860 i++;
861 }
862 return false;
863}
864
865static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
866 pldm_entity **entities,
867 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500868 uint16_t terminus_handle,
869 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870{
871 if (curr == NULL) {
872 return;
873 }
874 bool to_add = true;
875 to_add = is_present(curr->entity, entities, num_entities);
876 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500877 entity_association_pdr_add_entry(
878 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879 }
880 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500881 num_entities, is_remote, terminus_handle,
882 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930883 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500884 num_entities, is_remote, terminus_handle,
885 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886}
887
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930888LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930889void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
890 pldm_pdr *repo, bool is_remote,
891 uint16_t terminus_handle)
892{
893 assert(tree != NULL);
894 assert(repo != NULL);
895
896 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500897 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930898}
899
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930900LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930902 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
903 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904{
905 assert(repo != NULL);
906
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500907 pldm_entity_association_pdr_add_from_node_with_record_handle(
908 node, repo, entities, num_entities, is_remote, terminus_handle,
909 0);
910}
911
912LIBPLDM_ABI_TESTING
913int pldm_entity_association_pdr_add_from_node_with_record_handle(
914 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
915 size_t num_entities, bool is_remote, uint16_t terminus_handle,
916 uint32_t record_handle)
917{
918 if (!node || !repo || !entities) {
919 return -EINVAL;
920 }
921
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500923 is_remote, terminus_handle, record_handle);
924
925 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926}
927
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930928LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
930 pldm_entity_node **node)
931{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600932 bool is_entity_container_id;
933 bool is_entity_instance_num;
934 bool is_type;
935
Andrew Jeffery9c766792022-08-10 23:12:49 +0930936 if (tree_node == NULL) {
937 return;
938 }
939
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600940 is_type = tree_node->entity.entity_type == entity.entity_type;
941 is_entity_instance_num = tree_node->entity.entity_instance_num ==
942 entity.entity_instance_num;
943 is_entity_container_id = tree_node->entity.entity_container_id ==
944 entity.entity_container_id;
945
946 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930947 *node = tree_node;
948 return;
949 }
950
951 find_entity_ref_in_tree(tree_node->first_child, entity, node);
952 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
953}
954
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930955LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
957 pldm_entity entity, pldm_entity_node **node)
958{
959 assert(tree != NULL);
960 find_entity_ref_in_tree(tree->root, entity, node);
961}
962
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930963LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930964void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
965 uint16_t terminus_handle)
966{
967 assert(repo != NULL);
968 bool removed = false;
969
970 pldm_pdr_record *record = repo->first;
971 pldm_pdr_record *prev = NULL;
972 while (record != NULL) {
973 pldm_pdr_record *next = record->next;
974 if (record->terminus_handle == terminus_handle) {
975 if (repo->first == record) {
976 repo->first = next;
977 } else {
978 prev->next = next;
979 }
980 if (repo->last == record) {
981 repo->last = prev;
982 }
983 if (record->data) {
984 free(record->data);
985 }
986 --repo->record_count;
987 repo->size -= record->size;
988 free(record);
989 removed = true;
990 } else {
991 prev = record;
992 }
993 record = next;
994 }
995
996 if (removed == true) {
997 record = repo->first;
998 uint32_t record_handle = 0;
999 while (record != NULL) {
1000 record->record_handle = ++record_handle;
1001 if (record->data != NULL) {
1002 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301003 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301004 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301005 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006 }
1007 record = record->next;
1008 }
1009 }
1010}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301011
1012LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1014{
1015 assert(repo != NULL);
1016 bool removed = false;
1017
1018 pldm_pdr_record *record = repo->first;
1019 pldm_pdr_record *prev = NULL;
1020 while (record != NULL) {
1021 pldm_pdr_record *next = record->next;
1022 if (record->is_remote == true) {
1023 if (repo->first == record) {
1024 repo->first = next;
1025 } else {
1026 prev->next = next;
1027 }
1028 if (repo->last == record) {
1029 repo->last = prev;
1030 }
1031 if (record->data) {
1032 free(record->data);
1033 }
1034 --repo->record_count;
1035 repo->size -= record->size;
1036 free(record);
1037 removed = true;
1038 } else {
1039 prev = record;
1040 }
1041 record = next;
1042 }
1043
1044 if (removed == true) {
1045 record = repo->first;
1046 uint32_t record_handle = 0;
1047 while (record != NULL) {
1048 record->record_handle = ++record_handle;
1049 if (record->data != NULL) {
1050 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301051 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301053 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 }
1055 record = record->next;
1056 }
1057 }
1058}
1059
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001060LIBPLDM_ABI_TESTING
1061pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1062 uint32_t first, uint32_t last)
1063{
1064 pldm_pdr_record *record = NULL;
1065 pldm_pdr_record *curr;
1066
1067 if (!repo) {
1068 return NULL;
1069 }
1070 for (curr = repo->first; curr; curr = curr->next) {
1071 if (first > curr->record_handle || last < curr->record_handle) {
1072 continue;
1073 }
1074 if (!record || curr->record_handle > record->record_handle) {
1075 record = curr;
1076 }
1077 }
1078
1079 return record;
1080}
1081
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001082static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1083 pldm_entity *entity,
1084 pldm_entity_node **out,
1085 bool is_remote)
1086{
1087 assert(out != NULL && *out == NULL);
1088 if (node == NULL) {
1089 return;
1090 }
1091 bool is_entity_type;
1092 bool is_entity_instance_num;
1093
1094 is_entity_type = node->entity.entity_type == entity->entity_type;
1095 is_entity_instance_num = node->entity.entity_instance_num ==
1096 entity->entity_instance_num;
1097
1098 if (!is_remote ||
1099 node->remote_container_id == entity->entity_container_id) {
1100 if (is_entity_type && is_entity_instance_num) {
1101 entity->entity_container_id =
1102 node->entity.entity_container_id;
1103 *out = node;
1104 return;
1105 }
1106 }
1107 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1108 is_remote);
1109 entity_association_tree_find_if_remote(node->first_child, entity, out,
1110 is_remote);
1111}
1112
1113LIBPLDM_ABI_TESTING
1114pldm_entity_node *
1115pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1116 pldm_entity *entity, bool is_remote)
1117{
1118 if (!tree || !entity) {
1119 return NULL;
1120 }
1121 pldm_entity_node *node = NULL;
1122 entity_association_tree_find_if_remote(tree->root, entity, &node,
1123 is_remote);
1124 return node;
1125}
1126
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301127LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301128void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1129 pldm_entity_node **out)
1130{
1131 if (node == NULL) {
1132 return;
1133 }
1134
1135 if (node->entity.entity_type == entity->entity_type &&
1136 node->entity.entity_instance_num == entity->entity_instance_num) {
1137 entity->entity_container_id = node->entity.entity_container_id;
1138 *out = node;
1139 return;
1140 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141 entity_association_tree_find(node->next_sibling, entity, out);
1142 entity_association_tree_find(node->first_child, entity, out);
1143}
1144
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301145LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146pldm_entity_node *
1147pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1148 pldm_entity *entity)
1149{
1150 assert(tree != NULL);
1151
1152 pldm_entity_node *node = NULL;
1153 entity_association_tree_find(tree->root, entity, &node);
1154 return node;
1155}
1156
1157static void entity_association_tree_copy(pldm_entity_node *org_node,
1158 pldm_entity_node **new_node)
1159{
1160 if (org_node == NULL) {
1161 return;
1162 }
1163 *new_node = malloc(sizeof(pldm_entity_node));
1164 (*new_node)->parent = org_node->parent;
1165 (*new_node)->entity = org_node->entity;
1166 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001167 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301168 (*new_node)->first_child = NULL;
1169 (*new_node)->next_sibling = NULL;
1170 entity_association_tree_copy(org_node->first_child,
1171 &((*new_node)->first_child));
1172 entity_association_tree_copy(org_node->next_sibling,
1173 &((*new_node)->next_sibling));
1174}
1175
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301176LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301177void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301178 pldm_entity_association_tree *org_tree,
1179 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301180{
1181 new_tree->last_used_container_id = org_tree->last_used_container_id;
1182 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1183}
1184
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301185LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301186void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301187 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301188{
1189 assert(tree != NULL);
1190 entity_association_tree_destroy(tree->root);
1191 tree->last_used_container_id = 0;
1192 tree->root = NULL;
1193}
1194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301196bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1197{
1198 return ((tree->root == NULL) ? true : false);
1199}
1200
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301201LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301202void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1203 size_t *num_entities,
1204 pldm_entity **entities)
1205{
1206 assert(pdr != NULL);
1207 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301208 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301209
1210 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1211 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1212
1213 const uint8_t *start = (uint8_t *)pdr;
1214 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301215 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216 start += sizeof(struct pldm_pdr_hdr);
1217 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301218 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301219 *num_entities = entity_association_pdr->num_children + 1;
1220 assert(*num_entities >= 2);
1221 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1222 assert(*entities != NULL);
1223 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301224 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301225 end);
1226 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301227 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301229 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301231 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232 pldm_entity *curr_entity = entity_association_pdr->children;
1233 size_t i = 1;
1234 while (i < *num_entities) {
1235 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301236 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301238 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301239 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301240 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301241 ++curr_entity;
1242 ++i;
1243 }
1244}