blob: 657612d67f68d85c53496e74067ebec35a224080 [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));
120 assert(repo != NULL);
121 repo->record_count = 0;
122 repo->size = 0;
123 repo->first = NULL;
124 repo->last = NULL;
125
126 return repo;
127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130void pldm_pdr_destroy(pldm_pdr *repo)
131{
132 assert(repo != NULL);
133
134 pldm_pdr_record *record = repo->first;
135 while (record != NULL) {
136 pldm_pdr_record *next = record->next;
137 if (record->data) {
138 free(record->data);
139 record->data = NULL;
140 }
141 free(record);
142 record = next;
143 }
144 free(repo);
145}
146
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930147LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
149 uint32_t record_handle,
150 uint8_t **data, uint32_t *size,
151 uint32_t *next_record_handle)
152{
153 assert(repo != NULL);
154 assert(data != NULL);
155 assert(size != NULL);
156 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930157 if (!repo || !data || !size || !next_record_handle) {
158 return NULL;
159 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930160
161 if (!record_handle && (repo->first != NULL)) {
162 record_handle = repo->first->record_handle;
163 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930164
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165 pldm_pdr_record *record = repo->first;
166 while (record != NULL) {
167 if (record->record_handle == record_handle) {
168 *size = record->size;
169 *data = record->data;
170 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930171 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930172 return record;
173 }
174 record = record->next;
175 }
176
177 *size = 0;
178 *next_record_handle = 0;
179 return NULL;
180}
181
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930182LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930183const pldm_pdr_record *
184pldm_pdr_get_next_record(const pldm_pdr *repo,
185 const pldm_pdr_record *curr_record, uint8_t **data,
186 uint32_t *size, uint32_t *next_record_handle)
187{
188 assert(repo != NULL);
189 assert(curr_record != NULL);
190 assert(data != NULL);
191 assert(size != NULL);
192 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930193 if (!repo || !curr_record || !data || !size || !next_record_handle) {
194 return NULL;
195 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196
197 if (curr_record == repo->last) {
198 *data = NULL;
199 *size = 0;
200 *next_record_handle = get_next_record_handle(repo, curr_record);
201 return NULL;
202 }
203
204 *next_record_handle = get_next_record_handle(repo, curr_record->next);
205 *data = curr_record->next->data;
206 *size = curr_record->next->size;
207 return curr_record->next;
208}
209
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930210LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930211const pldm_pdr_record *
212pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
213 const pldm_pdr_record *curr_record, uint8_t **data,
214 uint32_t *size)
215{
216 assert(repo != NULL);
217
218 pldm_pdr_record *record = repo->first;
219 if (curr_record != NULL) {
220 record = curr_record->next;
221 }
222 while (record != NULL) {
223 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
224 if (hdr->type == pdr_type) {
225 if (data && size) {
226 *size = record->size;
227 *data = record->data;
228 }
229 return record;
230 }
231 record = record->next;
232 }
233
234 if (size) {
235 *size = 0;
236 }
237 return NULL;
238}
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
242{
243 assert(repo != NULL);
244
245 return repo->record_count;
246}
247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930248LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
250{
251 assert(repo != NULL);
252
253 return repo->size;
254}
255
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930256LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930257uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
258 const pldm_pdr_record *record)
259{
260 assert(repo != NULL);
261 assert(record != NULL);
262
263 return record->record_handle;
264}
265
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
267bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268{
269 assert(record != NULL);
270
271 return record->is_remote;
272}
273
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930274LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930275uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
276 uint16_t fru_rsi, uint16_t entity_type,
277 uint16_t entity_instance_num,
278 uint16_t container_id,
279 uint32_t bmc_record_handle)
280{
281 uint32_t size = sizeof(struct pldm_pdr_hdr) +
282 sizeof(struct pldm_pdr_fru_record_set);
283 uint8_t data[size];
284
285 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
286 hdr->version = 1;
287 hdr->record_handle = bmc_record_handle;
288 hdr->type = PLDM_PDR_FRU_RECORD_SET;
289 hdr->record_change_num = 0;
290 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
291 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930292 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
293 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930294 fru->terminus_handle = htole16(terminus_handle);
295 fru->fru_rsi = htole16(fru_rsi);
296 fru->entity_type = htole16(entity_type);
297 fru->entity_instance_num = htole16(entity_instance_num);
298 fru->container_id = htole16(container_id);
299
300 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
301 terminus_handle);
302}
303
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930304LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930305const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930306 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
307 uint16_t *entity_type, uint16_t *entity_instance_num,
308 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930309{
310 assert(terminus_handle != NULL);
311 assert(entity_type != NULL);
312 assert(entity_instance_num != NULL);
313 assert(container_id != NULL);
314
315 uint8_t *data = NULL;
316 uint32_t size = 0;
317 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930318 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930319 while (curr_record != NULL) {
320 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 (struct pldm_pdr_fru_record_set
322 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323 if (fru->fru_rsi == htole16(fru_rsi)) {
324 *terminus_handle = le16toh(fru->terminus_handle);
325 *entity_type = le16toh(fru->entity_type);
326 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930327 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328 *container_id = le16toh(fru->container_id);
329 return curr_record;
330 }
331 data = NULL;
332 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
334 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335 }
336
337 *terminus_handle = 0;
338 *entity_type = 0;
339 *entity_instance_num = 0;
340 *container_id = 0;
341
342 return NULL;
343}
344
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930345LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930346/* NOLINTNEXTLINE(readability-identifier-naming) */
347void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
348 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930350 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 uint32_t size = 0;
352 const pldm_pdr_record *record;
353 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930354 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930355
356 do {
357 if (record != NULL) {
358 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930359 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930360 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930361 (struct pldm_terminus_locator_type_mctp_eid *)
362 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930363 if (pdr->terminus_handle == terminus_handle &&
364 pdr->tid == tid && value->eid == tl_eid) {
365 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 break;
367 }
368 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930369 record = pldm_pdr_find_record_by_type(repo,
370 PLDM_TERMINUS_LOCATOR_PDR,
371 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372 } while (record);
373}
374
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500375static bool pldm_record_handle_in_range(uint32_t record_handle,
376 uint32_t first_record_handle,
377 uint32_t last_record_handle)
378{
379 return record_handle >= first_record_handle &&
380 record_handle <= last_record_handle;
381}
382
383LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500384int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500385 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500386 uint8_t child_index, uint32_t range_exclude_start_handle,
387 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500388{
389 pldm_pdr_record *record;
390 if (!repo) {
391 return -EINVAL;
392 }
393
394 for (record = repo->first; record; record = record->next) {
395 bool is_container_entity_instance_number;
396 struct pldm_pdr_entity_association *pdr;
397 bool is_container_entity_type;
398 struct pldm_entity *child;
399 struct pldm_pdr_hdr *hdr;
400 bool in_range;
401
402 // pldm_pdr_add() takes only uint8_t* data as an argument.
403 // The expectation here is the pldm_pdr_hdr is the first field of the record data
404 hdr = (struct pldm_pdr_hdr *)record->data;
405 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
406 continue;
407 }
408 in_range = pldm_record_handle_in_range(
409 record->record_handle, range_exclude_start_handle,
410 range_exclude_end_handle);
411 if (in_range) {
412 continue;
413 }
414
415 // this cast is valid with respect to alignment because
416 // struct pldm_pdr_hdr is declared with __attribute__((packed))
417 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500418 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500419 continue;
420 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500421
422 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500423 is_container_entity_type = pdr->container.entity_type ==
424 entity_type;
425 is_container_entity_instance_number =
426 pdr->container.entity_instance_num == entity_instance;
427 if (is_container_entity_type &&
428 is_container_entity_instance_number) {
429 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500430 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500431 }
432 }
433 return -ENOKEY;
434}
435
Andrew Jeffery9c766792022-08-10 23:12:49 +0930436typedef struct pldm_entity_association_tree {
437 pldm_entity_node *root;
438 uint16_t last_used_container_id;
439} pldm_entity_association_tree;
440
441typedef struct pldm_entity_node {
442 pldm_entity entity;
443 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600444 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930445 pldm_entity_node *first_child;
446 pldm_entity_node *next_sibling;
447 uint8_t association_type;
448} pldm_entity_node;
449
450static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
451{
452 assert(tree != NULL);
453 assert(tree->last_used_container_id != UINT16_MAX);
454
455 return ++tree->last_used_container_id;
456}
457
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930458LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459pldm_entity pldm_entity_extract(pldm_entity_node *node)
460{
461 assert(node != NULL);
462
463 return node->entity;
464}
465
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600466LIBPLDM_ABI_TESTING
467int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
468 uint16_t *cid)
469{
470 if (!entity) {
471 return -EINVAL;
472 }
473
474 *cid = entity->remote_container_id;
475 return 0;
476}
477
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930478LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930479pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930480{
481 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930482 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483 assert(tree != NULL);
484 tree->root = NULL;
485 tree->last_used_container_id = 0;
486
487 return tree;
488}
489
490static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
491 uint16_t entity_type)
492{
493 assert(start != NULL);
494
495 /* Insert after the the last node that matches the input entity type, or
496 * at the end if no such match occurrs
497 */
498 while (start->next_sibling != NULL) {
499 uint16_t this_type = start->entity.entity_type;
500 pldm_entity_node *next = start->next_sibling;
501 if (this_type == entity_type &&
502 (this_type != next->entity.entity_type)) {
503 break;
504 }
505 start = start->next_sibling;
506 }
507
508 return start;
509}
510
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930511LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930512pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930513 pldm_entity_association_tree *tree, pldm_entity *entity,
514 uint16_t entity_instance_number, pldm_entity_node *parent,
515 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930516{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500517 return pldm_entity_association_tree_add_entity(tree, entity,
518 entity_instance_number,
519 parent, association_type,
520 false, true, 0xFFFF);
521}
522
523LIBPLDM_ABI_TESTING
524pldm_entity_node *pldm_entity_association_tree_add_entity(
525 pldm_entity_association_tree *tree, pldm_entity *entity,
526 uint16_t entity_instance_number, pldm_entity_node *parent,
527 uint8_t association_type, bool is_remote, bool is_update_container_id,
528 uint16_t container_id)
529{
530 if ((!tree) || (!entity)) {
531 return NULL;
532 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930533
534 if (entity_instance_number != 0xFFFF && parent != NULL) {
535 pldm_entity node;
536 node.entity_type = entity->entity_type;
537 node.entity_instance_num = entity_instance_number;
538 if (pldm_is_current_parent_child(parent, &node)) {
539 return NULL;
540 }
541 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500542 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
543 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
544 return NULL;
545 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930546 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500547 if (!node) {
548 return NULL;
549 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 node->first_child = NULL;
551 node->next_sibling = NULL;
552 node->parent.entity_type = 0;
553 node->parent.entity_instance_num = 0;
554 node->parent.entity_container_id = 0;
555 node->entity.entity_type = entity->entity_type;
556 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930557 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600559 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930560 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500561 if (parent != NULL) {
562 free(node);
563 return NULL;
564 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 tree->root = node;
566 /* container_id 0 here indicates this is the top-most entry */
567 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600568 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569 } else if (parent != NULL && parent->first_child == NULL) {
570 parent->first_child = node;
571 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500572
573 if (is_remote) {
574 node->remote_container_id = entity->entity_container_id;
575 }
576 if (is_update_container_id) {
577 if (container_id != 0xFFFF) {
578 node->entity.entity_container_id = container_id;
579 } else {
580 node->entity.entity_container_id =
581 next_container_id(tree);
582 }
583 } else {
584 node->entity.entity_container_id =
585 entity->entity_container_id;
586 }
587
588 if (!is_remote) {
589 node->remote_container_id =
590 node->entity.entity_container_id;
591 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930592 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930593 pldm_entity_node *start = parent == NULL ? tree->root :
594 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930596 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500597 if (!prev) {
598 free(node);
599 return NULL;
600 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930601 pldm_entity_node *next = prev->next_sibling;
602 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500603 if (prev->entity.entity_instance_num == UINT16_MAX) {
604 free(node);
605 return NULL;
606 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930607 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930608 entity_instance_number != 0xFFFF ?
609 entity_instance_number :
610 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 }
612 prev->next_sibling = node;
613 node->parent = prev->parent;
614 node->next_sibling = next;
615 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930616 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600617 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 }
619 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500620 if (is_update_container_id) {
621 entity->entity_container_id = node->entity.entity_container_id;
622 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930623 return node;
624}
625
626static void get_num_nodes(pldm_entity_node *node, size_t *num)
627{
628 if (node == NULL) {
629 return;
630 }
631
632 ++(*num);
633 get_num_nodes(node->next_sibling, num);
634 get_num_nodes(node->first_child, num);
635}
636
637static void entity_association_tree_visit(pldm_entity_node *node,
638 pldm_entity *entities, size_t *index)
639{
640 if (node == NULL) {
641 return;
642 }
643
644 pldm_entity *entity = &entities[*index];
645 ++(*index);
646 entity->entity_type = node->entity.entity_type;
647 entity->entity_instance_num = node->entity.entity_instance_num;
648 entity->entity_container_id = node->entity.entity_container_id;
649
650 entity_association_tree_visit(node->next_sibling, entities, index);
651 entity_association_tree_visit(node->first_child, entities, index);
652}
653
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930654LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
656 pldm_entity **entities, size_t *size)
657{
658 assert(tree != NULL);
659
660 *size = 0;
661 if (tree->root == NULL) {
662 return;
663 }
664
665 get_num_nodes(tree->root, size);
666 *entities = malloc(*size * sizeof(pldm_entity));
667 size_t index = 0;
668 entity_association_tree_visit(tree->root, *entities, &index);
669}
670
671static void entity_association_tree_destroy(pldm_entity_node *node)
672{
673 if (node == NULL) {
674 return;
675 }
676
677 entity_association_tree_destroy(node->next_sibling);
678 entity_association_tree_destroy(node->first_child);
679 free(node);
680}
681
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930682LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
684{
685 assert(tree != NULL);
686
687 entity_association_tree_destroy(tree->root);
688 free(tree);
689}
690
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930691LIBPLDM_ABI_STABLE
692bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693{
694 assert(node != NULL);
695
696 return node->first_child != NULL;
697}
698
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930699LIBPLDM_ABI_STABLE
700pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701{
702 assert(node != NULL);
703
704 return node->parent;
705}
706
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930707LIBPLDM_ABI_STABLE
708bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709{
710 assert(node != NULL);
711
712 if (node->parent.entity_type == 0 &&
713 node->parent.entity_instance_num == 0 &&
714 node->parent.entity_container_id == 0) {
715 return false;
716 }
717
718 return true;
719}
720
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930721LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
723 uint8_t association_type)
724{
725 assert(node != NULL);
726 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
727 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
728
729 size_t count = 0;
730 pldm_entity_node *curr = node->first_child;
731 while (curr != NULL) {
732 if (curr->association_type == association_type) {
733 ++count;
734 }
735 curr = curr->next_sibling;
736 }
737
738 assert(count < UINT8_MAX);
739 return count;
740}
741
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930742LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
744{
745 assert(parent != NULL);
746 assert(node != NULL);
747
748 pldm_entity_node *curr = parent->first_child;
749 while (curr != NULL) {
750 if (node->entity_type == curr->entity.entity_type &&
751 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930752 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753 return true;
754 }
755 curr = curr->next_sibling;
756 }
757
758 return false;
759}
760
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500761static void entity_association_pdr_add_children(
762 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
763 uint8_t contained_count, uint8_t association_type, bool is_remote,
764 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765{
766 uint8_t pdr[size];
767 uint8_t *start = pdr;
768
769 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
770 hdr->version = 1;
771 hdr->record_handle = 0;
772 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
773 hdr->record_change_num = 0;
774 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
775 start += sizeof(struct pldm_pdr_hdr);
776
777 uint16_t *container_id = (uint16_t *)start;
778 *container_id = htole16(curr->first_child->entity.entity_container_id);
779 start += sizeof(uint16_t);
780 *start = association_type;
781 start += sizeof(uint8_t);
782
783 pldm_entity *entity = (pldm_entity *)start;
784 entity->entity_type = htole16(curr->entity.entity_type);
785 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
786 entity->entity_container_id = htole16(curr->entity.entity_container_id);
787 start += sizeof(pldm_entity);
788
789 *start = contained_count;
790 start += sizeof(uint8_t);
791
792 pldm_entity_node *node = curr->first_child;
793 while (node != NULL) {
794 if (node->association_type == association_type) {
795 pldm_entity *entity = (pldm_entity *)start;
796 entity->entity_type = htole16(node->entity.entity_type);
797 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930798 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930799 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930800 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930801 start += sizeof(pldm_entity);
802 }
803 node = node->next_sibling;
804 }
805
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500806 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
807 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808}
809
810static void entity_association_pdr_add_entry(pldm_entity_node *curr,
811 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500812 uint16_t terminus_handle,
813 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930814{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 uint8_t num_logical_children = pldm_entity_get_num_children(
816 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
817 uint8_t num_physical_children = pldm_entity_get_num_children(
818 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819
820 if (num_logical_children) {
821 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930822 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
823 sizeof(uint8_t) + sizeof(pldm_entity) +
824 sizeof(uint8_t) +
825 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930826 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930827 curr, repo, logical_pdr_size, num_logical_children,
828 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500829 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830 }
831
832 if (num_physical_children) {
833 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930834 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
835 sizeof(uint8_t) + sizeof(pldm_entity) +
836 sizeof(uint8_t) +
837 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930838 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 curr, repo, physical_pdr_size, num_physical_children,
840 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500841 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842 }
843}
844
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930845LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
847{
848 if (entities == NULL || num_entities == 0) {
849 return true;
850 }
851 size_t i = 0;
852 while (i < num_entities) {
853 if ((*entities + i)->entity_type == entity.entity_type) {
854 return true;
855 }
856 i++;
857 }
858 return false;
859}
860
861static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
862 pldm_entity **entities,
863 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500864 uint16_t terminus_handle,
865 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930866{
867 if (curr == NULL) {
868 return;
869 }
870 bool to_add = true;
871 to_add = is_present(curr->entity, entities, num_entities);
872 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500873 entity_association_pdr_add_entry(
874 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930875 }
876 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500877 num_entities, is_remote, terminus_handle,
878 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500880 num_entities, is_remote, terminus_handle,
881 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882}
883
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930884LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
886 pldm_pdr *repo, bool is_remote,
887 uint16_t terminus_handle)
888{
889 assert(tree != NULL);
890 assert(repo != NULL);
891
892 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500893 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894}
895
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930896LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930897void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930898 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
899 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930900{
901 assert(repo != NULL);
902
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500903 pldm_entity_association_pdr_add_from_node_with_record_handle(
904 node, repo, entities, num_entities, is_remote, terminus_handle,
905 0);
906}
907
908LIBPLDM_ABI_TESTING
909int pldm_entity_association_pdr_add_from_node_with_record_handle(
910 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
911 size_t num_entities, bool is_remote, uint16_t terminus_handle,
912 uint32_t record_handle)
913{
914 if (!node || !repo || !entities) {
915 return -EINVAL;
916 }
917
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500919 is_remote, terminus_handle, record_handle);
920
921 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922}
923
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930924LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930925void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
926 pldm_entity_node **node)
927{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600928 bool is_entity_container_id;
929 bool is_entity_instance_num;
930 bool is_type;
931
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932 if (tree_node == NULL) {
933 return;
934 }
935
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600936 is_type = tree_node->entity.entity_type == entity.entity_type;
937 is_entity_instance_num = tree_node->entity.entity_instance_num ==
938 entity.entity_instance_num;
939 is_entity_container_id = tree_node->entity.entity_container_id ==
940 entity.entity_container_id;
941
942 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943 *node = tree_node;
944 return;
945 }
946
947 find_entity_ref_in_tree(tree_node->first_child, entity, node);
948 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
949}
950
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930951LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
953 pldm_entity entity, pldm_entity_node **node)
954{
955 assert(tree != NULL);
956 find_entity_ref_in_tree(tree->root, entity, node);
957}
958
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930959LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
961 uint16_t terminus_handle)
962{
963 assert(repo != NULL);
964 bool removed = false;
965
966 pldm_pdr_record *record = repo->first;
967 pldm_pdr_record *prev = NULL;
968 while (record != NULL) {
969 pldm_pdr_record *next = record->next;
970 if (record->terminus_handle == terminus_handle) {
971 if (repo->first == record) {
972 repo->first = next;
973 } else {
974 prev->next = next;
975 }
976 if (repo->last == record) {
977 repo->last = prev;
978 }
979 if (record->data) {
980 free(record->data);
981 }
982 --repo->record_count;
983 repo->size -= record->size;
984 free(record);
985 removed = true;
986 } else {
987 prev = record;
988 }
989 record = next;
990 }
991
992 if (removed == true) {
993 record = repo->first;
994 uint32_t record_handle = 0;
995 while (record != NULL) {
996 record->record_handle = ++record_handle;
997 if (record->data != NULL) {
998 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930999 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301001 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002 }
1003 record = record->next;
1004 }
1005 }
1006}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301007
1008LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1010{
1011 assert(repo != NULL);
1012 bool removed = false;
1013
1014 pldm_pdr_record *record = repo->first;
1015 pldm_pdr_record *prev = NULL;
1016 while (record != NULL) {
1017 pldm_pdr_record *next = record->next;
1018 if (record->is_remote == true) {
1019 if (repo->first == record) {
1020 repo->first = next;
1021 } else {
1022 prev->next = next;
1023 }
1024 if (repo->last == record) {
1025 repo->last = prev;
1026 }
1027 if (record->data) {
1028 free(record->data);
1029 }
1030 --repo->record_count;
1031 repo->size -= record->size;
1032 free(record);
1033 removed = true;
1034 } else {
1035 prev = record;
1036 }
1037 record = next;
1038 }
1039
1040 if (removed == true) {
1041 record = repo->first;
1042 uint32_t record_handle = 0;
1043 while (record != NULL) {
1044 record->record_handle = ++record_handle;
1045 if (record->data != NULL) {
1046 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301047 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301049 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050 }
1051 record = record->next;
1052 }
1053 }
1054}
1055
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001056LIBPLDM_ABI_TESTING
1057pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1058 uint32_t first, uint32_t last)
1059{
1060 pldm_pdr_record *record = NULL;
1061 pldm_pdr_record *curr;
1062
1063 if (!repo) {
1064 return NULL;
1065 }
1066 for (curr = repo->first; curr; curr = curr->next) {
1067 if (first > curr->record_handle || last < curr->record_handle) {
1068 continue;
1069 }
1070 if (!record || curr->record_handle > record->record_handle) {
1071 record = curr;
1072 }
1073 }
1074
1075 return record;
1076}
1077
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001078static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1079 pldm_entity *entity,
1080 pldm_entity_node **out,
1081 bool is_remote)
1082{
1083 assert(out != NULL && *out == NULL);
1084 if (node == NULL) {
1085 return;
1086 }
1087 bool is_entity_type;
1088 bool is_entity_instance_num;
1089
1090 is_entity_type = node->entity.entity_type == entity->entity_type;
1091 is_entity_instance_num = node->entity.entity_instance_num ==
1092 entity->entity_instance_num;
1093
1094 if (!is_remote ||
1095 node->remote_container_id == entity->entity_container_id) {
1096 if (is_entity_type && is_entity_instance_num) {
1097 entity->entity_container_id =
1098 node->entity.entity_container_id;
1099 *out = node;
1100 return;
1101 }
1102 }
1103 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1104 is_remote);
1105 entity_association_tree_find_if_remote(node->first_child, entity, out,
1106 is_remote);
1107}
1108
1109LIBPLDM_ABI_TESTING
1110pldm_entity_node *
1111pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1112 pldm_entity *entity, bool is_remote)
1113{
1114 if (!tree || !entity) {
1115 return NULL;
1116 }
1117 pldm_entity_node *node = NULL;
1118 entity_association_tree_find_if_remote(tree->root, entity, &node,
1119 is_remote);
1120 return node;
1121}
1122
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301123LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1125 pldm_entity_node **out)
1126{
1127 if (node == NULL) {
1128 return;
1129 }
1130
1131 if (node->entity.entity_type == entity->entity_type &&
1132 node->entity.entity_instance_num == entity->entity_instance_num) {
1133 entity->entity_container_id = node->entity.entity_container_id;
1134 *out = node;
1135 return;
1136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 entity_association_tree_find(node->next_sibling, entity, out);
1138 entity_association_tree_find(node->first_child, entity, out);
1139}
1140
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301141LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301142pldm_entity_node *
1143pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1144 pldm_entity *entity)
1145{
1146 assert(tree != NULL);
1147
1148 pldm_entity_node *node = NULL;
1149 entity_association_tree_find(tree->root, entity, &node);
1150 return node;
1151}
1152
1153static void entity_association_tree_copy(pldm_entity_node *org_node,
1154 pldm_entity_node **new_node)
1155{
1156 if (org_node == NULL) {
1157 return;
1158 }
1159 *new_node = malloc(sizeof(pldm_entity_node));
1160 (*new_node)->parent = org_node->parent;
1161 (*new_node)->entity = org_node->entity;
1162 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001163 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164 (*new_node)->first_child = NULL;
1165 (*new_node)->next_sibling = NULL;
1166 entity_association_tree_copy(org_node->first_child,
1167 &((*new_node)->first_child));
1168 entity_association_tree_copy(org_node->next_sibling,
1169 &((*new_node)->next_sibling));
1170}
1171
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301172LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301174 pldm_entity_association_tree *org_tree,
1175 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301176{
1177 new_tree->last_used_container_id = org_tree->last_used_container_id;
1178 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1179}
1180
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301181LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301183 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184{
1185 assert(tree != NULL);
1186 entity_association_tree_destroy(tree->root);
1187 tree->last_used_container_id = 0;
1188 tree->root = NULL;
1189}
1190
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301191LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301192bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1193{
1194 return ((tree->root == NULL) ? true : false);
1195}
1196
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301197LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1199 size_t *num_entities,
1200 pldm_entity **entities)
1201{
1202 assert(pdr != NULL);
1203 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301204 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205
1206 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1207 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1208
1209 const uint8_t *start = (uint8_t *)pdr;
1210 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301211 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212 start += sizeof(struct pldm_pdr_hdr);
1213 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301214 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215 *num_entities = entity_association_pdr->num_children + 1;
1216 assert(*num_entities >= 2);
1217 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1218 assert(*entities != NULL);
1219 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301220 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221 end);
1222 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301223 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301225 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301227 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 pldm_entity *curr_entity = entity_association_pdr->children;
1229 size_t i = 1;
1230 while (i < *num_entities) {
1231 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301232 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301234 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301236 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 ++curr_entity;
1238 ++i;
1239 }
1240}