blob: 763fa72ea8fa84fd78390d07b5962e6b8e9bc410 [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{
134 assert(repo != NULL);
135
136 pldm_pdr_record *record = repo->first;
137 while (record != NULL) {
138 pldm_pdr_record *next = record->next;
139 if (record->data) {
140 free(record->data);
141 record->data = NULL;
142 }
143 free(record);
144 record = next;
145 }
146 free(repo);
147}
148
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930149LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
151 uint32_t record_handle,
152 uint8_t **data, uint32_t *size,
153 uint32_t *next_record_handle)
154{
155 assert(repo != NULL);
156 assert(data != NULL);
157 assert(size != NULL);
158 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930159 if (!repo || !data || !size || !next_record_handle) {
160 return NULL;
161 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930162
163 if (!record_handle && (repo->first != NULL)) {
164 record_handle = repo->first->record_handle;
165 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930166
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167 pldm_pdr_record *record = repo->first;
168 while (record != NULL) {
169 if (record->record_handle == record_handle) {
170 *size = record->size;
171 *data = record->data;
172 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930173 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930174 return record;
175 }
176 record = record->next;
177 }
178
179 *size = 0;
180 *next_record_handle = 0;
181 return NULL;
182}
183
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930184LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185const pldm_pdr_record *
186pldm_pdr_get_next_record(const pldm_pdr *repo,
187 const pldm_pdr_record *curr_record, uint8_t **data,
188 uint32_t *size, uint32_t *next_record_handle)
189{
190 assert(repo != NULL);
191 assert(curr_record != NULL);
192 assert(data != NULL);
193 assert(size != NULL);
194 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930195 if (!repo || !curr_record || !data || !size || !next_record_handle) {
196 return NULL;
197 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930198
199 if (curr_record == repo->last) {
200 *data = NULL;
201 *size = 0;
202 *next_record_handle = get_next_record_handle(repo, curr_record);
203 return NULL;
204 }
205
206 *next_record_handle = get_next_record_handle(repo, curr_record->next);
207 *data = curr_record->next->data;
208 *size = curr_record->next->size;
209 return curr_record->next;
210}
211
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930212LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930213const pldm_pdr_record *
214pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
215 const pldm_pdr_record *curr_record, uint8_t **data,
216 uint32_t *size)
217{
218 assert(repo != NULL);
219
220 pldm_pdr_record *record = repo->first;
221 if (curr_record != NULL) {
222 record = curr_record->next;
223 }
224 while (record != NULL) {
225 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
226 if (hdr->type == pdr_type) {
227 if (data && size) {
228 *size = record->size;
229 *data = record->data;
230 }
231 return record;
232 }
233 record = record->next;
234 }
235
236 if (size) {
237 *size = 0;
238 }
239 return NULL;
240}
241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
244{
245 assert(repo != NULL);
246
247 return repo->record_count;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
252{
253 assert(repo != NULL);
254
255 return repo->size;
256}
257
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930258LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
260 const pldm_pdr_record *record)
261{
262 assert(repo != NULL);
263 assert(record != NULL);
264
265 return record->record_handle;
266}
267
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930268LIBPLDM_ABI_STABLE
269bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930270{
271 assert(record != NULL);
272
273 return record->is_remote;
274}
275
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930276LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930277uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
278 uint16_t fru_rsi, uint16_t entity_type,
279 uint16_t entity_instance_num,
280 uint16_t container_id,
281 uint32_t bmc_record_handle)
282{
283 uint32_t size = sizeof(struct pldm_pdr_hdr) +
284 sizeof(struct pldm_pdr_fru_record_set);
285 uint8_t data[size];
286
287 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
288 hdr->version = 1;
289 hdr->record_handle = bmc_record_handle;
290 hdr->type = PLDM_PDR_FRU_RECORD_SET;
291 hdr->record_change_num = 0;
292 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
293 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930294 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
295 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930296 fru->terminus_handle = htole16(terminus_handle);
297 fru->fru_rsi = htole16(fru_rsi);
298 fru->entity_type = htole16(entity_type);
299 fru->entity_instance_num = htole16(entity_instance_num);
300 fru->container_id = htole16(container_id);
301
302 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
303 terminus_handle);
304}
305
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930306LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930308 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
309 uint16_t *entity_type, uint16_t *entity_instance_num,
310 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311{
312 assert(terminus_handle != NULL);
313 assert(entity_type != NULL);
314 assert(entity_instance_num != NULL);
315 assert(container_id != NULL);
316
317 uint8_t *data = NULL;
318 uint32_t size = 0;
319 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 while (curr_record != NULL) {
322 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930323 (struct pldm_pdr_fru_record_set
324 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325 if (fru->fru_rsi == htole16(fru_rsi)) {
326 *terminus_handle = le16toh(fru->terminus_handle);
327 *entity_type = le16toh(fru->entity_type);
328 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930329 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930330 *container_id = le16toh(fru->container_id);
331 return curr_record;
332 }
333 data = NULL;
334 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930335 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
336 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 }
338
339 *terminus_handle = 0;
340 *entity_type = 0;
341 *entity_instance_num = 0;
342 *container_id = 0;
343
344 return NULL;
345}
346
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930347LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930348/* NOLINTNEXTLINE(readability-identifier-naming) */
349void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
350 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930352 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353 uint32_t size = 0;
354 const pldm_pdr_record *record;
355 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930356 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930357
358 do {
359 if (record != NULL) {
360 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930361 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930362 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930363 (struct pldm_terminus_locator_type_mctp_eid *)
364 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930365 if (pdr->terminus_handle == terminus_handle &&
366 pdr->tid == tid && value->eid == tl_eid) {
367 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930368 break;
369 }
370 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 record = pldm_pdr_find_record_by_type(repo,
372 PLDM_TERMINUS_LOCATOR_PDR,
373 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 } while (record);
375}
376
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500377static bool pldm_record_handle_in_range(uint32_t record_handle,
378 uint32_t first_record_handle,
379 uint32_t last_record_handle)
380{
381 return record_handle >= first_record_handle &&
382 record_handle <= last_record_handle;
383}
384
385LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500386int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500387 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500388 uint8_t child_index, uint32_t range_exclude_start_handle,
389 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500390{
391 pldm_pdr_record *record;
392 if (!repo) {
393 return -EINVAL;
394 }
395
396 for (record = repo->first; record; record = record->next) {
397 bool is_container_entity_instance_number;
398 struct pldm_pdr_entity_association *pdr;
399 bool is_container_entity_type;
400 struct pldm_entity *child;
401 struct pldm_pdr_hdr *hdr;
402 bool in_range;
403
404 // pldm_pdr_add() takes only uint8_t* data as an argument.
405 // The expectation here is the pldm_pdr_hdr is the first field of the record data
406 hdr = (struct pldm_pdr_hdr *)record->data;
407 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
408 continue;
409 }
410 in_range = pldm_record_handle_in_range(
411 record->record_handle, range_exclude_start_handle,
412 range_exclude_end_handle);
413 if (in_range) {
414 continue;
415 }
416
417 // this cast is valid with respect to alignment because
418 // struct pldm_pdr_hdr is declared with __attribute__((packed))
419 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500420 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500421 continue;
422 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500423
424 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500425 is_container_entity_type = pdr->container.entity_type ==
426 entity_type;
427 is_container_entity_instance_number =
428 pdr->container.entity_instance_num == entity_instance;
429 if (is_container_entity_type &&
430 is_container_entity_instance_number) {
431 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500432 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500433 }
434 }
435 return -ENOKEY;
436}
437
Andrew Jeffery9c766792022-08-10 23:12:49 +0930438typedef struct pldm_entity_association_tree {
439 pldm_entity_node *root;
440 uint16_t last_used_container_id;
441} pldm_entity_association_tree;
442
443typedef struct pldm_entity_node {
444 pldm_entity entity;
445 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600446 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930447 pldm_entity_node *first_child;
448 pldm_entity_node *next_sibling;
449 uint8_t association_type;
450} pldm_entity_node;
451
452static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
453{
454 assert(tree != NULL);
455 assert(tree->last_used_container_id != UINT16_MAX);
456
457 return ++tree->last_used_container_id;
458}
459
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930460LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930461pldm_entity pldm_entity_extract(pldm_entity_node *node)
462{
463 assert(node != NULL);
464
465 return node->entity;
466}
467
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600468LIBPLDM_ABI_TESTING
469int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
470 uint16_t *cid)
471{
472 if (!entity) {
473 return -EINVAL;
474 }
475
476 *cid = entity->remote_container_id;
477 return 0;
478}
479
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930480LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930481pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482{
483 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930484 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930485 assert(tree != NULL);
486 tree->root = NULL;
487 tree->last_used_container_id = 0;
488
489 return tree;
490}
491
492static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
493 uint16_t entity_type)
494{
495 assert(start != NULL);
496
497 /* Insert after the the last node that matches the input entity type, or
498 * at the end if no such match occurrs
499 */
500 while (start->next_sibling != NULL) {
501 uint16_t this_type = start->entity.entity_type;
502 pldm_entity_node *next = start->next_sibling;
503 if (this_type == entity_type &&
504 (this_type != next->entity.entity_type)) {
505 break;
506 }
507 start = start->next_sibling;
508 }
509
510 return start;
511}
512
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930513LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930514pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930515 pldm_entity_association_tree *tree, pldm_entity *entity,
516 uint16_t entity_instance_number, pldm_entity_node *parent,
517 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930518{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500519 return pldm_entity_association_tree_add_entity(tree, entity,
520 entity_instance_number,
521 parent, association_type,
522 false, true, 0xFFFF);
523}
524
525LIBPLDM_ABI_TESTING
526pldm_entity_node *pldm_entity_association_tree_add_entity(
527 pldm_entity_association_tree *tree, pldm_entity *entity,
528 uint16_t entity_instance_number, pldm_entity_node *parent,
529 uint8_t association_type, bool is_remote, bool is_update_container_id,
530 uint16_t container_id)
531{
532 if ((!tree) || (!entity)) {
533 return NULL;
534 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930535
536 if (entity_instance_number != 0xFFFF && parent != NULL) {
537 pldm_entity node;
538 node.entity_type = entity->entity_type;
539 node.entity_instance_num = entity_instance_number;
540 if (pldm_is_current_parent_child(parent, &node)) {
541 return NULL;
542 }
543 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500544 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
545 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
546 return NULL;
547 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500549 if (!node) {
550 return NULL;
551 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930552 node->first_child = NULL;
553 node->next_sibling = NULL;
554 node->parent.entity_type = 0;
555 node->parent.entity_instance_num = 0;
556 node->parent.entity_container_id = 0;
557 node->entity.entity_type = entity->entity_type;
558 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930559 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930560 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600561 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500563 if (parent != NULL) {
564 free(node);
565 return NULL;
566 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567 tree->root = node;
568 /* container_id 0 here indicates this is the top-most entry */
569 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600570 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571 } else if (parent != NULL && parent->first_child == NULL) {
572 parent->first_child = node;
573 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500574
575 if (is_remote) {
576 node->remote_container_id = entity->entity_container_id;
577 }
578 if (is_update_container_id) {
579 if (container_id != 0xFFFF) {
580 node->entity.entity_container_id = container_id;
581 } else {
582 node->entity.entity_container_id =
583 next_container_id(tree);
584 }
585 } else {
586 node->entity.entity_container_id =
587 entity->entity_container_id;
588 }
589
590 if (!is_remote) {
591 node->remote_container_id =
592 node->entity.entity_container_id;
593 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930595 pldm_entity_node *start = parent == NULL ? tree->root :
596 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930597 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930598 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500599 if (!prev) {
600 free(node);
601 return NULL;
602 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 pldm_entity_node *next = prev->next_sibling;
604 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500605 if (prev->entity.entity_instance_num == UINT16_MAX) {
606 free(node);
607 return NULL;
608 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930609 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930610 entity_instance_number != 0xFFFF ?
611 entity_instance_number :
612 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613 }
614 prev->next_sibling = node;
615 node->parent = prev->parent;
616 node->next_sibling = next;
617 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930618 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600619 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 }
621 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500622 if (is_update_container_id) {
623 entity->entity_container_id = node->entity.entity_container_id;
624 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 return node;
626}
627
628static void get_num_nodes(pldm_entity_node *node, size_t *num)
629{
630 if (node == NULL) {
631 return;
632 }
633
634 ++(*num);
635 get_num_nodes(node->next_sibling, num);
636 get_num_nodes(node->first_child, num);
637}
638
639static void entity_association_tree_visit(pldm_entity_node *node,
640 pldm_entity *entities, size_t *index)
641{
642 if (node == NULL) {
643 return;
644 }
645
646 pldm_entity *entity = &entities[*index];
647 ++(*index);
648 entity->entity_type = node->entity.entity_type;
649 entity->entity_instance_num = node->entity.entity_instance_num;
650 entity->entity_container_id = node->entity.entity_container_id;
651
652 entity_association_tree_visit(node->next_sibling, entities, index);
653 entity_association_tree_visit(node->first_child, entities, index);
654}
655
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930656LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
658 pldm_entity **entities, size_t *size)
659{
660 assert(tree != NULL);
661
662 *size = 0;
663 if (tree->root == NULL) {
664 return;
665 }
666
667 get_num_nodes(tree->root, size);
668 *entities = malloc(*size * sizeof(pldm_entity));
669 size_t index = 0;
670 entity_association_tree_visit(tree->root, *entities, &index);
671}
672
673static void entity_association_tree_destroy(pldm_entity_node *node)
674{
675 if (node == NULL) {
676 return;
677 }
678
679 entity_association_tree_destroy(node->next_sibling);
680 entity_association_tree_destroy(node->first_child);
681 free(node);
682}
683
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930684LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
686{
687 assert(tree != NULL);
688
689 entity_association_tree_destroy(tree->root);
690 free(tree);
691}
692
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930693LIBPLDM_ABI_STABLE
694bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695{
696 assert(node != NULL);
697
698 return node->first_child != NULL;
699}
700
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930701LIBPLDM_ABI_STABLE
702pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930703{
704 assert(node != NULL);
705
706 return node->parent;
707}
708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930709LIBPLDM_ABI_STABLE
710bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711{
712 assert(node != NULL);
713
714 if (node->parent.entity_type == 0 &&
715 node->parent.entity_instance_num == 0 &&
716 node->parent.entity_container_id == 0) {
717 return false;
718 }
719
720 return true;
721}
722
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930723LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930724uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
725 uint8_t association_type)
726{
727 assert(node != NULL);
728 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
729 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
730
731 size_t count = 0;
732 pldm_entity_node *curr = node->first_child;
733 while (curr != NULL) {
734 if (curr->association_type == association_type) {
735 ++count;
736 }
737 curr = curr->next_sibling;
738 }
739
740 assert(count < UINT8_MAX);
741 return count;
742}
743
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930744LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
746{
747 assert(parent != NULL);
748 assert(node != NULL);
749
750 pldm_entity_node *curr = parent->first_child;
751 while (curr != NULL) {
752 if (node->entity_type == curr->entity.entity_type &&
753 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930754 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755 return true;
756 }
757 curr = curr->next_sibling;
758 }
759
760 return false;
761}
762
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500763static void entity_association_pdr_add_children(
764 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
765 uint8_t contained_count, uint8_t association_type, bool is_remote,
766 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930767{
768 uint8_t pdr[size];
769 uint8_t *start = pdr;
770
771 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
772 hdr->version = 1;
773 hdr->record_handle = 0;
774 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
775 hdr->record_change_num = 0;
776 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
777 start += sizeof(struct pldm_pdr_hdr);
778
779 uint16_t *container_id = (uint16_t *)start;
780 *container_id = htole16(curr->first_child->entity.entity_container_id);
781 start += sizeof(uint16_t);
782 *start = association_type;
783 start += sizeof(uint8_t);
784
785 pldm_entity *entity = (pldm_entity *)start;
786 entity->entity_type = htole16(curr->entity.entity_type);
787 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
788 entity->entity_container_id = htole16(curr->entity.entity_container_id);
789 start += sizeof(pldm_entity);
790
791 *start = contained_count;
792 start += sizeof(uint8_t);
793
794 pldm_entity_node *node = curr->first_child;
795 while (node != NULL) {
796 if (node->association_type == association_type) {
797 pldm_entity *entity = (pldm_entity *)start;
798 entity->entity_type = htole16(node->entity.entity_type);
799 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930800 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930801 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930802 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803 start += sizeof(pldm_entity);
804 }
805 node = node->next_sibling;
806 }
807
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500808 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
809 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930810}
811
812static void entity_association_pdr_add_entry(pldm_entity_node *curr,
813 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500814 uint16_t terminus_handle,
815 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930817 uint8_t num_logical_children = pldm_entity_get_num_children(
818 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
819 uint8_t num_physical_children = pldm_entity_get_num_children(
820 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930821
822 if (num_logical_children) {
823 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930824 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
825 sizeof(uint8_t) + sizeof(pldm_entity) +
826 sizeof(uint8_t) +
827 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930828 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930829 curr, repo, logical_pdr_size, num_logical_children,
830 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500831 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930832 }
833
834 if (num_physical_children) {
835 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930836 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
837 sizeof(uint8_t) + sizeof(pldm_entity) +
838 sizeof(uint8_t) +
839 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930840 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930841 curr, repo, physical_pdr_size, num_physical_children,
842 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500843 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844 }
845}
846
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930847LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930848bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
849{
850 if (entities == NULL || num_entities == 0) {
851 return true;
852 }
853 size_t i = 0;
854 while (i < num_entities) {
855 if ((*entities + i)->entity_type == entity.entity_type) {
856 return true;
857 }
858 i++;
859 }
860 return false;
861}
862
863static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
864 pldm_entity **entities,
865 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500866 uint16_t terminus_handle,
867 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868{
869 if (curr == NULL) {
870 return;
871 }
872 bool to_add = true;
873 to_add = is_present(curr->entity, entities, num_entities);
874 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500875 entity_association_pdr_add_entry(
876 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877 }
878 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500879 num_entities, is_remote, terminus_handle,
880 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930881 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500882 num_entities, is_remote, terminus_handle,
883 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930884}
885
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930886LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
888 pldm_pdr *repo, bool is_remote,
889 uint16_t terminus_handle)
890{
891 assert(tree != NULL);
892 assert(repo != NULL);
893
894 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500895 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896}
897
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930898LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930900 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
901 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930902{
903 assert(repo != NULL);
904
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500905 pldm_entity_association_pdr_add_from_node_with_record_handle(
906 node, repo, entities, num_entities, is_remote, terminus_handle,
907 0);
908}
909
910LIBPLDM_ABI_TESTING
911int pldm_entity_association_pdr_add_from_node_with_record_handle(
912 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
913 size_t num_entities, bool is_remote, uint16_t terminus_handle,
914 uint32_t record_handle)
915{
916 if (!node || !repo || !entities) {
917 return -EINVAL;
918 }
919
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500921 is_remote, terminus_handle, record_handle);
922
923 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924}
925
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930926LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
928 pldm_entity_node **node)
929{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600930 bool is_entity_container_id;
931 bool is_entity_instance_num;
932 bool is_type;
933
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934 if (tree_node == NULL) {
935 return;
936 }
937
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600938 is_type = tree_node->entity.entity_type == entity.entity_type;
939 is_entity_instance_num = tree_node->entity.entity_instance_num ==
940 entity.entity_instance_num;
941 is_entity_container_id = tree_node->entity.entity_container_id ==
942 entity.entity_container_id;
943
944 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945 *node = tree_node;
946 return;
947 }
948
949 find_entity_ref_in_tree(tree_node->first_child, entity, node);
950 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
951}
952
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930953LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
955 pldm_entity entity, pldm_entity_node **node)
956{
957 assert(tree != NULL);
958 find_entity_ref_in_tree(tree->root, entity, node);
959}
960
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930961LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
963 uint16_t terminus_handle)
964{
965 assert(repo != NULL);
966 bool removed = false;
967
968 pldm_pdr_record *record = repo->first;
969 pldm_pdr_record *prev = NULL;
970 while (record != NULL) {
971 pldm_pdr_record *next = record->next;
972 if (record->terminus_handle == terminus_handle) {
973 if (repo->first == record) {
974 repo->first = next;
975 } else {
976 prev->next = next;
977 }
978 if (repo->last == record) {
979 repo->last = prev;
980 }
981 if (record->data) {
982 free(record->data);
983 }
984 --repo->record_count;
985 repo->size -= record->size;
986 free(record);
987 removed = true;
988 } else {
989 prev = record;
990 }
991 record = next;
992 }
993
994 if (removed == true) {
995 record = repo->first;
996 uint32_t record_handle = 0;
997 while (record != NULL) {
998 record->record_handle = ++record_handle;
999 if (record->data != NULL) {
1000 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301001 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301003 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301004 }
1005 record = record->next;
1006 }
1007 }
1008}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301009
1010LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1012{
1013 assert(repo != NULL);
1014 bool removed = false;
1015
1016 pldm_pdr_record *record = repo->first;
1017 pldm_pdr_record *prev = NULL;
1018 while (record != NULL) {
1019 pldm_pdr_record *next = record->next;
1020 if (record->is_remote == true) {
1021 if (repo->first == record) {
1022 repo->first = next;
1023 } else {
1024 prev->next = next;
1025 }
1026 if (repo->last == record) {
1027 repo->last = prev;
1028 }
1029 if (record->data) {
1030 free(record->data);
1031 }
1032 --repo->record_count;
1033 repo->size -= record->size;
1034 free(record);
1035 removed = true;
1036 } else {
1037 prev = record;
1038 }
1039 record = next;
1040 }
1041
1042 if (removed == true) {
1043 record = repo->first;
1044 uint32_t record_handle = 0;
1045 while (record != NULL) {
1046 record->record_handle = ++record_handle;
1047 if (record->data != NULL) {
1048 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301049 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301051 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 }
1053 record = record->next;
1054 }
1055 }
1056}
1057
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001058LIBPLDM_ABI_TESTING
1059pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1060 uint32_t first, uint32_t last)
1061{
1062 pldm_pdr_record *record = NULL;
1063 pldm_pdr_record *curr;
1064
1065 if (!repo) {
1066 return NULL;
1067 }
1068 for (curr = repo->first; curr; curr = curr->next) {
1069 if (first > curr->record_handle || last < curr->record_handle) {
1070 continue;
1071 }
1072 if (!record || curr->record_handle > record->record_handle) {
1073 record = curr;
1074 }
1075 }
1076
1077 return record;
1078}
1079
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001080static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1081 pldm_entity *entity,
1082 pldm_entity_node **out,
1083 bool is_remote)
1084{
1085 assert(out != NULL && *out == NULL);
1086 if (node == NULL) {
1087 return;
1088 }
1089 bool is_entity_type;
1090 bool is_entity_instance_num;
1091
1092 is_entity_type = node->entity.entity_type == entity->entity_type;
1093 is_entity_instance_num = node->entity.entity_instance_num ==
1094 entity->entity_instance_num;
1095
1096 if (!is_remote ||
1097 node->remote_container_id == entity->entity_container_id) {
1098 if (is_entity_type && is_entity_instance_num) {
1099 entity->entity_container_id =
1100 node->entity.entity_container_id;
1101 *out = node;
1102 return;
1103 }
1104 }
1105 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1106 is_remote);
1107 entity_association_tree_find_if_remote(node->first_child, entity, out,
1108 is_remote);
1109}
1110
1111LIBPLDM_ABI_TESTING
1112pldm_entity_node *
1113pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1114 pldm_entity *entity, bool is_remote)
1115{
1116 if (!tree || !entity) {
1117 return NULL;
1118 }
1119 pldm_entity_node *node = NULL;
1120 entity_association_tree_find_if_remote(tree->root, entity, &node,
1121 is_remote);
1122 return node;
1123}
1124
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301125LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1127 pldm_entity_node **out)
1128{
1129 if (node == NULL) {
1130 return;
1131 }
1132
1133 if (node->entity.entity_type == entity->entity_type &&
1134 node->entity.entity_instance_num == entity->entity_instance_num) {
1135 entity->entity_container_id = node->entity.entity_container_id;
1136 *out = node;
1137 return;
1138 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301139 entity_association_tree_find(node->next_sibling, entity, out);
1140 entity_association_tree_find(node->first_child, entity, out);
1141}
1142
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301143LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301144pldm_entity_node *
1145pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1146 pldm_entity *entity)
1147{
1148 assert(tree != NULL);
1149
1150 pldm_entity_node *node = NULL;
1151 entity_association_tree_find(tree->root, entity, &node);
1152 return node;
1153}
1154
1155static void entity_association_tree_copy(pldm_entity_node *org_node,
1156 pldm_entity_node **new_node)
1157{
1158 if (org_node == NULL) {
1159 return;
1160 }
1161 *new_node = malloc(sizeof(pldm_entity_node));
1162 (*new_node)->parent = org_node->parent;
1163 (*new_node)->entity = org_node->entity;
1164 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001165 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166 (*new_node)->first_child = NULL;
1167 (*new_node)->next_sibling = NULL;
1168 entity_association_tree_copy(org_node->first_child,
1169 &((*new_node)->first_child));
1170 entity_association_tree_copy(org_node->next_sibling,
1171 &((*new_node)->next_sibling));
1172}
1173
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301174LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301175void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301176 pldm_entity_association_tree *org_tree,
1177 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301178{
1179 new_tree->last_used_container_id = org_tree->last_used_container_id;
1180 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1181}
1182
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301183LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301185 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301186{
1187 assert(tree != NULL);
1188 entity_association_tree_destroy(tree->root);
1189 tree->last_used_container_id = 0;
1190 tree->root = NULL;
1191}
1192
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301193LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301194bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1195{
1196 return ((tree->root == NULL) ? true : false);
1197}
1198
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301199LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301200void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1201 size_t *num_entities,
1202 pldm_entity **entities)
1203{
1204 assert(pdr != NULL);
1205 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301206 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301207
1208 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1209 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1210
1211 const uint8_t *start = (uint8_t *)pdr;
1212 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301213 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214 start += sizeof(struct pldm_pdr_hdr);
1215 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301216 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217 *num_entities = entity_association_pdr->num_children + 1;
1218 assert(*num_entities >= 2);
1219 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1220 assert(*entities != NULL);
1221 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301222 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223 end);
1224 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301225 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301227 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301229 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230 pldm_entity *curr_entity = entity_association_pdr->children;
1231 size_t i = 1;
1232 while (i < *num_entities) {
1233 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301234 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301236 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301238 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301239 ++curr_entity;
1240 ++i;
1241 }
1242}