blob: c3501770a78cd45e6193a52b67d81623c505871e [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include "pdr.h"
2#include "platform.h"
3#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05304#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <stdlib.h>
6#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06007#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308
9typedef struct pldm_pdr_record {
10 uint32_t record_handle;
11 uint32_t size;
12 uint8_t *data;
13 struct pldm_pdr_record *next;
14 bool is_remote;
15 uint16_t terminus_handle;
16} pldm_pdr_record;
17
18typedef struct pldm_pdr {
19 uint32_t record_count;
20 uint32_t size;
21 pldm_pdr_record *first;
22 pldm_pdr_record *last;
23} pldm_pdr;
24
25static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
26 const pldm_pdr_record *record)
27{
28 assert(repo != NULL);
29 assert(record != NULL);
30
31 if (record == repo->last) {
32 return 0;
33 }
34 return record->next->record_handle;
35}
36
37static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
38{
39 assert(repo != NULL);
40 assert(record != NULL);
41
42 if (repo->first == NULL) {
43 assert(repo->last == NULL);
44 repo->first = record;
45 repo->last = record;
46 } else {
47 repo->last->next = record;
48 repo->last = record;
49 }
50 repo->size += record->size;
51 ++repo->record_count;
52}
53
54static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
55{
56 assert(repo != NULL);
57 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093058 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093059 assert(last_used_hdl != UINT32_MAX);
60
61 return last_used_hdl + 1;
62}
63
64static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
65 const uint8_t *data, uint32_t size,
66 uint32_t record_handle, bool is_remote,
67 uint16_t terminus_handle)
68{
69 assert(repo != NULL);
70 assert(size != 0);
71
72 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
73 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093074 record->record_handle = record_handle == 0 ?
75 get_new_record_handle(repo) :
76 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093077 record->size = size;
78 record->is_remote = is_remote;
79 record->terminus_handle = terminus_handle;
80 if (data != NULL) {
81 record->data = malloc(size);
82 assert(record->data != NULL);
83 memcpy(record->data, data, size);
84 /* If record handle is 0, that is an indication for this API to
85 * compute a new handle. For that reason, the computed handle
86 * needs to be populated in the PDR header. For a case where the
87 * caller supplied the record handle, it would exist in the
88 * header already.
89 */
90 if (!record_handle) {
91 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093092 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093093 hdr->record_handle = htole32(record->record_handle);
94 }
95 }
96 record->next = NULL;
97
98 return record;
99}
100
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930101LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
103 uint32_t record_handle, bool is_remote,
104 uint16_t terminus_handle)
105{
106 assert(size != 0);
107 assert(data != NULL);
108
109 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930110 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111 add_record(repo, record);
112
113 return record->record_handle;
114}
115
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930116LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930117pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118{
119 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930120 if (!repo) {
121 return NULL;
122 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123 repo->record_count = 0;
124 repo->size = 0;
125 repo->first = NULL;
126 repo->last = NULL;
127
128 return repo;
129}
130
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930131LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132void pldm_pdr_destroy(pldm_pdr *repo)
133{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930134 if (!repo) {
135 return;
136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137
138 pldm_pdr_record *record = repo->first;
139 while (record != NULL) {
140 pldm_pdr_record *next = record->next;
141 if (record->data) {
142 free(record->data);
143 record->data = NULL;
144 }
145 free(record);
146 record = next;
147 }
148 free(repo);
149}
150
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930151LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930152const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
153 uint32_t record_handle,
154 uint8_t **data, uint32_t *size,
155 uint32_t *next_record_handle)
156{
157 assert(repo != NULL);
158 assert(data != NULL);
159 assert(size != NULL);
160 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930161 if (!repo || !data || !size || !next_record_handle) {
162 return NULL;
163 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164
165 if (!record_handle && (repo->first != NULL)) {
166 record_handle = repo->first->record_handle;
167 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 pldm_pdr_record *record = repo->first;
170 while (record != NULL) {
171 if (record->record_handle == record_handle) {
172 *size = record->size;
173 *data = record->data;
174 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 return record;
177 }
178 record = record->next;
179 }
180
181 *size = 0;
182 *next_record_handle = 0;
183 return NULL;
184}
185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187const pldm_pdr_record *
188pldm_pdr_get_next_record(const pldm_pdr *repo,
189 const pldm_pdr_record *curr_record, uint8_t **data,
190 uint32_t *size, uint32_t *next_record_handle)
191{
192 assert(repo != NULL);
193 assert(curr_record != NULL);
194 assert(data != NULL);
195 assert(size != NULL);
196 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930197 if (!repo || !curr_record || !data || !size || !next_record_handle) {
198 return NULL;
199 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200
201 if (curr_record == repo->last) {
202 *data = NULL;
203 *size = 0;
204 *next_record_handle = get_next_record_handle(repo, curr_record);
205 return NULL;
206 }
207
208 *next_record_handle = get_next_record_handle(repo, curr_record->next);
209 *data = curr_record->next->data;
210 *size = curr_record->next->size;
211 return curr_record->next;
212}
213
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930214LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930215const pldm_pdr_record *
216pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
217 const pldm_pdr_record *curr_record, uint8_t **data,
218 uint32_t *size)
219{
220 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930221 if (!repo) {
222 return NULL;
223 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224
225 pldm_pdr_record *record = repo->first;
226 if (curr_record != NULL) {
227 record = curr_record->next;
228 }
229 while (record != NULL) {
230 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
231 if (hdr->type == pdr_type) {
232 if (data && size) {
233 *size = record->size;
234 *data = record->data;
235 }
236 return record;
237 }
238 record = record->next;
239 }
240
241 if (size) {
242 *size = 0;
243 }
244 return NULL;
245}
246
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930247LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
249{
250 assert(repo != NULL);
251
252 return repo->record_count;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
257{
258 assert(repo != NULL);
259
260 return repo->size;
261}
262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930263LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930264uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
265 const pldm_pdr_record *record)
266{
267 assert(repo != NULL);
268 assert(record != NULL);
269
270 return record->record_handle;
271}
272
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930273LIBPLDM_ABI_STABLE
274bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930275{
276 assert(record != NULL);
277
278 return record->is_remote;
279}
280
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930281LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930282uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
283 uint16_t fru_rsi, uint16_t entity_type,
284 uint16_t entity_instance_num,
285 uint16_t container_id,
286 uint32_t bmc_record_handle)
287{
288 uint32_t size = sizeof(struct pldm_pdr_hdr) +
289 sizeof(struct pldm_pdr_fru_record_set);
290 uint8_t data[size];
291
292 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
293 hdr->version = 1;
294 hdr->record_handle = bmc_record_handle;
295 hdr->type = PLDM_PDR_FRU_RECORD_SET;
296 hdr->record_change_num = 0;
297 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
298 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930299 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
300 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930301 fru->terminus_handle = htole16(terminus_handle);
302 fru->fru_rsi = htole16(fru_rsi);
303 fru->entity_type = htole16(entity_type);
304 fru->entity_instance_num = htole16(entity_instance_num);
305 fru->container_id = htole16(container_id);
306
307 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
308 terminus_handle);
309}
310
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930311LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930313 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
314 uint16_t *entity_type, uint16_t *entity_instance_num,
315 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316{
317 assert(terminus_handle != NULL);
318 assert(entity_type != NULL);
319 assert(entity_instance_num != NULL);
320 assert(container_id != NULL);
321
322 uint8_t *data = NULL;
323 uint32_t size = 0;
324 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930325 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326 while (curr_record != NULL) {
327 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930328 (struct pldm_pdr_fru_record_set
329 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930330 if (fru->fru_rsi == htole16(fru_rsi)) {
331 *terminus_handle = le16toh(fru->terminus_handle);
332 *entity_type = le16toh(fru->entity_type);
333 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930334 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335 *container_id = le16toh(fru->container_id);
336 return curr_record;
337 }
338 data = NULL;
339 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930340 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
341 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 }
343
344 *terminus_handle = 0;
345 *entity_type = 0;
346 *entity_instance_num = 0;
347 *container_id = 0;
348
349 return NULL;
350}
351
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930352LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930353/* NOLINTNEXTLINE(readability-identifier-naming) */
354void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
355 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930356{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930357 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930358 uint32_t size = 0;
359 const pldm_pdr_record *record;
360 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930361 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930362
363 do {
364 if (record != NULL) {
365 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930366 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930368 (struct pldm_terminus_locator_type_mctp_eid *)
369 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930370 if (pdr->terminus_handle == terminus_handle &&
371 pdr->tid == tid && value->eid == tl_eid) {
372 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930373 break;
374 }
375 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930376 record = pldm_pdr_find_record_by_type(repo,
377 PLDM_TERMINUS_LOCATOR_PDR,
378 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379 } while (record);
380}
381
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500382static bool pldm_record_handle_in_range(uint32_t record_handle,
383 uint32_t first_record_handle,
384 uint32_t last_record_handle)
385{
386 return record_handle >= first_record_handle &&
387 record_handle <= last_record_handle;
388}
389
390LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500391int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500392 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500393 uint8_t child_index, uint32_t range_exclude_start_handle,
394 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500395{
396 pldm_pdr_record *record;
397 if (!repo) {
398 return -EINVAL;
399 }
400
401 for (record = repo->first; record; record = record->next) {
402 bool is_container_entity_instance_number;
403 struct pldm_pdr_entity_association *pdr;
404 bool is_container_entity_type;
405 struct pldm_entity *child;
406 struct pldm_pdr_hdr *hdr;
407 bool in_range;
408
409 // pldm_pdr_add() takes only uint8_t* data as an argument.
410 // The expectation here is the pldm_pdr_hdr is the first field of the record data
411 hdr = (struct pldm_pdr_hdr *)record->data;
412 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
413 continue;
414 }
415 in_range = pldm_record_handle_in_range(
416 record->record_handle, range_exclude_start_handle,
417 range_exclude_end_handle);
418 if (in_range) {
419 continue;
420 }
421
422 // this cast is valid with respect to alignment because
423 // struct pldm_pdr_hdr is declared with __attribute__((packed))
424 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500425 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500426 continue;
427 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500428
429 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500430 is_container_entity_type = pdr->container.entity_type ==
431 entity_type;
432 is_container_entity_instance_number =
433 pdr->container.entity_instance_num == entity_instance;
434 if (is_container_entity_type &&
435 is_container_entity_instance_number) {
436 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500437 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500438 }
439 }
440 return -ENOKEY;
441}
442
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443typedef struct pldm_entity_association_tree {
444 pldm_entity_node *root;
445 uint16_t last_used_container_id;
446} pldm_entity_association_tree;
447
448typedef struct pldm_entity_node {
449 pldm_entity entity;
450 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600451 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452 pldm_entity_node *first_child;
453 pldm_entity_node *next_sibling;
454 uint8_t association_type;
455} pldm_entity_node;
456
457static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
458{
459 assert(tree != NULL);
460 assert(tree->last_used_container_id != UINT16_MAX);
461
462 return ++tree->last_used_container_id;
463}
464
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930465LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466pldm_entity pldm_entity_extract(pldm_entity_node *node)
467{
468 assert(node != NULL);
469
470 return node->entity;
471}
472
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600473LIBPLDM_ABI_TESTING
474int pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity,
475 uint16_t *cid)
476{
477 if (!entity) {
478 return -EINVAL;
479 }
480
481 *cid = entity->remote_container_id;
482 return 0;
483}
484
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930485LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930486pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930487{
488 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930489 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930490 assert(tree != NULL);
491 tree->root = NULL;
492 tree->last_used_container_id = 0;
493
494 return tree;
495}
496
497static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
498 uint16_t entity_type)
499{
500 assert(start != NULL);
501
502 /* Insert after the the last node that matches the input entity type, or
503 * at the end if no such match occurrs
504 */
505 while (start->next_sibling != NULL) {
506 uint16_t this_type = start->entity.entity_type;
507 pldm_entity_node *next = start->next_sibling;
508 if (this_type == entity_type &&
509 (this_type != next->entity.entity_type)) {
510 break;
511 }
512 start = start->next_sibling;
513 }
514
515 return start;
516}
517
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930518LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930519pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930520 pldm_entity_association_tree *tree, pldm_entity *entity,
521 uint16_t entity_instance_number, pldm_entity_node *parent,
522 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930523{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500524 return pldm_entity_association_tree_add_entity(tree, entity,
525 entity_instance_number,
526 parent, association_type,
527 false, true, 0xFFFF);
528}
529
530LIBPLDM_ABI_TESTING
531pldm_entity_node *pldm_entity_association_tree_add_entity(
532 pldm_entity_association_tree *tree, pldm_entity *entity,
533 uint16_t entity_instance_number, pldm_entity_node *parent,
534 uint8_t association_type, bool is_remote, bool is_update_container_id,
535 uint16_t container_id)
536{
537 if ((!tree) || (!entity)) {
538 return NULL;
539 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540
541 if (entity_instance_number != 0xFFFF && parent != NULL) {
542 pldm_entity node;
543 node.entity_type = entity->entity_type;
544 node.entity_instance_num = entity_instance_number;
545 if (pldm_is_current_parent_child(parent, &node)) {
546 return NULL;
547 }
548 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500549 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
550 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
551 return NULL;
552 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930553 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500554 if (!node) {
555 return NULL;
556 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 node->first_child = NULL;
558 node->next_sibling = NULL;
559 node->parent.entity_type = 0;
560 node->parent.entity_instance_num = 0;
561 node->parent.entity_container_id = 0;
562 node->entity.entity_type = entity->entity_type;
563 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930564 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600566 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500568 if (parent != NULL) {
569 free(node);
570 return NULL;
571 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572 tree->root = node;
573 /* container_id 0 here indicates this is the top-most entry */
574 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600575 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 } else if (parent != NULL && parent->first_child == NULL) {
577 parent->first_child = node;
578 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500579
580 if (is_remote) {
581 node->remote_container_id = entity->entity_container_id;
582 }
583 if (is_update_container_id) {
584 if (container_id != 0xFFFF) {
585 node->entity.entity_container_id = container_id;
586 } else {
587 node->entity.entity_container_id =
588 next_container_id(tree);
589 }
590 } else {
591 node->entity.entity_container_id =
592 entity->entity_container_id;
593 }
594
595 if (!is_remote) {
596 node->remote_container_id =
597 node->entity.entity_container_id;
598 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930600 pldm_entity_node *start = parent == NULL ? tree->root :
601 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930602 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930603 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500604 if (!prev) {
605 free(node);
606 return NULL;
607 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608 pldm_entity_node *next = prev->next_sibling;
609 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500610 if (prev->entity.entity_instance_num == UINT16_MAX) {
611 free(node);
612 return NULL;
613 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930615 entity_instance_number != 0xFFFF ?
616 entity_instance_number :
617 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 }
619 prev->next_sibling = node;
620 node->parent = prev->parent;
621 node->next_sibling = next;
622 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930623 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600624 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 }
626 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500627 if (is_update_container_id) {
628 entity->entity_container_id = node->entity.entity_container_id;
629 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930630 return node;
631}
632
633static void get_num_nodes(pldm_entity_node *node, size_t *num)
634{
635 if (node == NULL) {
636 return;
637 }
638
639 ++(*num);
640 get_num_nodes(node->next_sibling, num);
641 get_num_nodes(node->first_child, num);
642}
643
644static void entity_association_tree_visit(pldm_entity_node *node,
645 pldm_entity *entities, size_t *index)
646{
647 if (node == NULL) {
648 return;
649 }
650
651 pldm_entity *entity = &entities[*index];
652 ++(*index);
653 entity->entity_type = node->entity.entity_type;
654 entity->entity_instance_num = node->entity.entity_instance_num;
655 entity->entity_container_id = node->entity.entity_container_id;
656
657 entity_association_tree_visit(node->next_sibling, entities, index);
658 entity_association_tree_visit(node->first_child, entities, index);
659}
660
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930661LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930662void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
663 pldm_entity **entities, size_t *size)
664{
665 assert(tree != NULL);
666
667 *size = 0;
668 if (tree->root == NULL) {
669 return;
670 }
671
672 get_num_nodes(tree->root, size);
673 *entities = malloc(*size * sizeof(pldm_entity));
674 size_t index = 0;
675 entity_association_tree_visit(tree->root, *entities, &index);
676}
677
678static void entity_association_tree_destroy(pldm_entity_node *node)
679{
680 if (node == NULL) {
681 return;
682 }
683
684 entity_association_tree_destroy(node->next_sibling);
685 entity_association_tree_destroy(node->first_child);
686 free(node);
687}
688
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930689LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
691{
692 assert(tree != NULL);
693
694 entity_association_tree_destroy(tree->root);
695 free(tree);
696}
697
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930698LIBPLDM_ABI_STABLE
699bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930700{
701 assert(node != NULL);
702
703 return node->first_child != NULL;
704}
705
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930706LIBPLDM_ABI_STABLE
707pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708{
709 assert(node != NULL);
710
711 return node->parent;
712}
713
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930714LIBPLDM_ABI_STABLE
715bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930716{
717 assert(node != NULL);
718
719 if (node->parent.entity_type == 0 &&
720 node->parent.entity_instance_num == 0 &&
721 node->parent.entity_container_id == 0) {
722 return false;
723 }
724
725 return true;
726}
727
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930728LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930729uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
730 uint8_t association_type)
731{
732 assert(node != NULL);
733 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
734 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
735
736 size_t count = 0;
737 pldm_entity_node *curr = node->first_child;
738 while (curr != NULL) {
739 if (curr->association_type == association_type) {
740 ++count;
741 }
742 curr = curr->next_sibling;
743 }
744
745 assert(count < UINT8_MAX);
746 return count;
747}
748
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930749LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
751{
752 assert(parent != NULL);
753 assert(node != NULL);
754
755 pldm_entity_node *curr = parent->first_child;
756 while (curr != NULL) {
757 if (node->entity_type == curr->entity.entity_type &&
758 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930759 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760 return true;
761 }
762 curr = curr->next_sibling;
763 }
764
765 return false;
766}
767
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500768static void entity_association_pdr_add_children(
769 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
770 uint8_t contained_count, uint8_t association_type, bool is_remote,
771 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930772{
773 uint8_t pdr[size];
774 uint8_t *start = pdr;
775
776 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
777 hdr->version = 1;
778 hdr->record_handle = 0;
779 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
780 hdr->record_change_num = 0;
781 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
782 start += sizeof(struct pldm_pdr_hdr);
783
784 uint16_t *container_id = (uint16_t *)start;
785 *container_id = htole16(curr->first_child->entity.entity_container_id);
786 start += sizeof(uint16_t);
787 *start = association_type;
788 start += sizeof(uint8_t);
789
790 pldm_entity *entity = (pldm_entity *)start;
791 entity->entity_type = htole16(curr->entity.entity_type);
792 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
793 entity->entity_container_id = htole16(curr->entity.entity_container_id);
794 start += sizeof(pldm_entity);
795
796 *start = contained_count;
797 start += sizeof(uint8_t);
798
799 pldm_entity_node *node = curr->first_child;
800 while (node != NULL) {
801 if (node->association_type == association_type) {
802 pldm_entity *entity = (pldm_entity *)start;
803 entity->entity_type = htole16(node->entity.entity_type);
804 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930805 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930806 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930807 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 start += sizeof(pldm_entity);
809 }
810 node = node->next_sibling;
811 }
812
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500813 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
814 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815}
816
817static void entity_association_pdr_add_entry(pldm_entity_node *curr,
818 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500819 uint16_t terminus_handle,
820 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930821{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930822 uint8_t num_logical_children = pldm_entity_get_num_children(
823 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
824 uint8_t num_physical_children = pldm_entity_get_num_children(
825 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930826
827 if (num_logical_children) {
828 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930829 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
830 sizeof(uint8_t) + sizeof(pldm_entity) +
831 sizeof(uint8_t) +
832 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930833 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930834 curr, repo, logical_pdr_size, num_logical_children,
835 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500836 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837 }
838
839 if (num_physical_children) {
840 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930841 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
842 sizeof(uint8_t) + sizeof(pldm_entity) +
843 sizeof(uint8_t) +
844 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930845 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930846 curr, repo, physical_pdr_size, num_physical_children,
847 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500848 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849 }
850}
851
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930852LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
854{
855 if (entities == NULL || num_entities == 0) {
856 return true;
857 }
858 size_t i = 0;
859 while (i < num_entities) {
860 if ((*entities + i)->entity_type == entity.entity_type) {
861 return true;
862 }
863 i++;
864 }
865 return false;
866}
867
868static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
869 pldm_entity **entities,
870 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500871 uint16_t terminus_handle,
872 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873{
874 if (curr == NULL) {
875 return;
876 }
877 bool to_add = true;
878 to_add = is_present(curr->entity, entities, num_entities);
879 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500880 entity_association_pdr_add_entry(
881 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882 }
883 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500884 num_entities, is_remote, terminus_handle,
885 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500887 num_entities, is_remote, terminus_handle,
888 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930889}
890
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930891LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
893 pldm_pdr *repo, bool is_remote,
894 uint16_t terminus_handle)
895{
896 assert(tree != NULL);
897 assert(repo != NULL);
898
899 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500900 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901}
902
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930903LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930905 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
906 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907{
908 assert(repo != NULL);
909
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500910 pldm_entity_association_pdr_add_from_node_with_record_handle(
911 node, repo, entities, num_entities, is_remote, terminus_handle,
912 0);
913}
914
915LIBPLDM_ABI_TESTING
916int pldm_entity_association_pdr_add_from_node_with_record_handle(
917 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
918 size_t num_entities, bool is_remote, uint16_t terminus_handle,
919 uint32_t record_handle)
920{
921 if (!node || !repo || !entities) {
922 return -EINVAL;
923 }
924
Andrew Jeffery9c766792022-08-10 23:12:49 +0930925 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500926 is_remote, terminus_handle, record_handle);
927
928 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929}
930
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930931LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
933 pldm_entity_node **node)
934{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600935 bool is_entity_container_id;
936 bool is_entity_instance_num;
937 bool is_type;
938
Andrew Jeffery9c766792022-08-10 23:12:49 +0930939 if (tree_node == NULL) {
940 return;
941 }
942
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600943 is_type = tree_node->entity.entity_type == entity.entity_type;
944 is_entity_instance_num = tree_node->entity.entity_instance_num ==
945 entity.entity_instance_num;
946 is_entity_container_id = tree_node->entity.entity_container_id ==
947 entity.entity_container_id;
948
949 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 *node = tree_node;
951 return;
952 }
953
954 find_entity_ref_in_tree(tree_node->first_child, entity, node);
955 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
956}
957
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930958LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
960 pldm_entity entity, pldm_entity_node **node)
961{
962 assert(tree != NULL);
963 find_entity_ref_in_tree(tree->root, entity, node);
964}
965
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930966LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
968 uint16_t terminus_handle)
969{
970 assert(repo != NULL);
971 bool removed = false;
972
973 pldm_pdr_record *record = repo->first;
974 pldm_pdr_record *prev = NULL;
975 while (record != NULL) {
976 pldm_pdr_record *next = record->next;
977 if (record->terminus_handle == terminus_handle) {
978 if (repo->first == record) {
979 repo->first = next;
980 } else {
981 prev->next = next;
982 }
983 if (repo->last == record) {
984 repo->last = prev;
985 }
986 if (record->data) {
987 free(record->data);
988 }
989 --repo->record_count;
990 repo->size -= record->size;
991 free(record);
992 removed = true;
993 } else {
994 prev = record;
995 }
996 record = next;
997 }
998
999 if (removed == true) {
1000 record = repo->first;
1001 uint32_t record_handle = 0;
1002 while (record != NULL) {
1003 record->record_handle = ++record_handle;
1004 if (record->data != NULL) {
1005 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301006 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301008 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009 }
1010 record = record->next;
1011 }
1012 }
1013}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301014
1015LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1017{
1018 assert(repo != NULL);
1019 bool removed = false;
1020
1021 pldm_pdr_record *record = repo->first;
1022 pldm_pdr_record *prev = NULL;
1023 while (record != NULL) {
1024 pldm_pdr_record *next = record->next;
1025 if (record->is_remote == true) {
1026 if (repo->first == record) {
1027 repo->first = next;
1028 } else {
1029 prev->next = next;
1030 }
1031 if (repo->last == record) {
1032 repo->last = prev;
1033 }
1034 if (record->data) {
1035 free(record->data);
1036 }
1037 --repo->record_count;
1038 repo->size -= record->size;
1039 free(record);
1040 removed = true;
1041 } else {
1042 prev = record;
1043 }
1044 record = next;
1045 }
1046
1047 if (removed == true) {
1048 record = repo->first;
1049 uint32_t record_handle = 0;
1050 while (record != NULL) {
1051 record->record_handle = ++record_handle;
1052 if (record->data != NULL) {
1053 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301054 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301056 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 }
1058 record = record->next;
1059 }
1060 }
1061}
1062
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001063LIBPLDM_ABI_TESTING
1064pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1065 uint32_t first, uint32_t last)
1066{
1067 pldm_pdr_record *record = NULL;
1068 pldm_pdr_record *curr;
1069
1070 if (!repo) {
1071 return NULL;
1072 }
1073 for (curr = repo->first; curr; curr = curr->next) {
1074 if (first > curr->record_handle || last < curr->record_handle) {
1075 continue;
1076 }
1077 if (!record || curr->record_handle > record->record_handle) {
1078 record = curr;
1079 }
1080 }
1081
1082 return record;
1083}
1084
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001085static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1086 pldm_entity *entity,
1087 pldm_entity_node **out,
1088 bool is_remote)
1089{
1090 assert(out != NULL && *out == NULL);
1091 if (node == NULL) {
1092 return;
1093 }
1094 bool is_entity_type;
1095 bool is_entity_instance_num;
1096
1097 is_entity_type = node->entity.entity_type == entity->entity_type;
1098 is_entity_instance_num = node->entity.entity_instance_num ==
1099 entity->entity_instance_num;
1100
1101 if (!is_remote ||
1102 node->remote_container_id == entity->entity_container_id) {
1103 if (is_entity_type && is_entity_instance_num) {
1104 entity->entity_container_id =
1105 node->entity.entity_container_id;
1106 *out = node;
1107 return;
1108 }
1109 }
1110 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1111 is_remote);
1112 entity_association_tree_find_if_remote(node->first_child, entity, out,
1113 is_remote);
1114}
1115
1116LIBPLDM_ABI_TESTING
1117pldm_entity_node *
1118pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1119 pldm_entity *entity, bool is_remote)
1120{
1121 if (!tree || !entity) {
1122 return NULL;
1123 }
1124 pldm_entity_node *node = NULL;
1125 entity_association_tree_find_if_remote(tree->root, entity, &node,
1126 is_remote);
1127 return node;
1128}
1129
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301130LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301131void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1132 pldm_entity_node **out)
1133{
1134 if (node == NULL) {
1135 return;
1136 }
1137
1138 if (node->entity.entity_type == entity->entity_type &&
1139 node->entity.entity_instance_num == entity->entity_instance_num) {
1140 entity->entity_container_id = node->entity.entity_container_id;
1141 *out = node;
1142 return;
1143 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301144 entity_association_tree_find(node->next_sibling, entity, out);
1145 entity_association_tree_find(node->first_child, entity, out);
1146}
1147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301149pldm_entity_node *
1150pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1151 pldm_entity *entity)
1152{
1153 assert(tree != NULL);
1154
1155 pldm_entity_node *node = NULL;
1156 entity_association_tree_find(tree->root, entity, &node);
1157 return node;
1158}
1159
1160static void entity_association_tree_copy(pldm_entity_node *org_node,
1161 pldm_entity_node **new_node)
1162{
1163 if (org_node == NULL) {
1164 return;
1165 }
1166 *new_node = malloc(sizeof(pldm_entity_node));
1167 (*new_node)->parent = org_node->parent;
1168 (*new_node)->entity = org_node->entity;
1169 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001170 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301171 (*new_node)->first_child = NULL;
1172 (*new_node)->next_sibling = NULL;
1173 entity_association_tree_copy(org_node->first_child,
1174 &((*new_node)->first_child));
1175 entity_association_tree_copy(org_node->next_sibling,
1176 &((*new_node)->next_sibling));
1177}
1178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301180void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301181 pldm_entity_association_tree *org_tree,
1182 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301183{
1184 new_tree->last_used_container_id = org_tree->last_used_container_id;
1185 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1186}
1187
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301188LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301189void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301190 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301191{
1192 assert(tree != NULL);
1193 entity_association_tree_destroy(tree->root);
1194 tree->last_used_container_id = 0;
1195 tree->root = NULL;
1196}
1197
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301198LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1200{
1201 return ((tree->root == NULL) ? true : false);
1202}
1203
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301204LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1206 size_t *num_entities,
1207 pldm_entity **entities)
1208{
1209 assert(pdr != NULL);
1210 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301211 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212
1213 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1214 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1215
1216 const uint8_t *start = (uint8_t *)pdr;
1217 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301218 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301219 start += sizeof(struct pldm_pdr_hdr);
1220 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301221 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222 *num_entities = entity_association_pdr->num_children + 1;
1223 assert(*num_entities >= 2);
1224 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1225 assert(*entities != NULL);
1226 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301227 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 end);
1229 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301230 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301231 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301232 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301234 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235 pldm_entity *curr_entity = entity_association_pdr->children;
1236 size_t i = 1;
1237 while (i < *num_entities) {
1238 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301239 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301241 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301242 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301243 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244 ++curr_entity;
1245 ++i;
1246 }
1247}