blob: 7266ecd0ea79d07b2459adc8a9ced9f476770f60 [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 Jeffery5565fcd2023-06-30 13:21:32 +0930264uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
265 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930266 const pldm_pdr_record *record)
267{
268 assert(repo != NULL);
269 assert(record != NULL);
270
271 return record->record_handle;
272}
273
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930274LIBPLDM_ABI_STABLE
275bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930276{
277 assert(record != NULL);
278
279 return record->is_remote;
280}
281
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930282LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
284 uint16_t fru_rsi, uint16_t entity_type,
285 uint16_t entity_instance_num,
286 uint16_t container_id,
287 uint32_t bmc_record_handle)
288{
289 uint32_t size = sizeof(struct pldm_pdr_hdr) +
290 sizeof(struct pldm_pdr_fru_record_set);
291 uint8_t data[size];
292
293 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
294 hdr->version = 1;
295 hdr->record_handle = bmc_record_handle;
296 hdr->type = PLDM_PDR_FRU_RECORD_SET;
297 hdr->record_change_num = 0;
298 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
299 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930300 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
301 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302 fru->terminus_handle = htole16(terminus_handle);
303 fru->fru_rsi = htole16(fru_rsi);
304 fru->entity_type = htole16(entity_type);
305 fru->entity_instance_num = htole16(entity_instance_num);
306 fru->container_id = htole16(container_id);
307
308 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
309 terminus_handle);
310}
311
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930312LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
315 uint16_t *entity_type, uint16_t *entity_instance_num,
316 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317{
318 assert(terminus_handle != NULL);
319 assert(entity_type != NULL);
320 assert(entity_instance_num != NULL);
321 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930322 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
323 !container_id) {
324 return NULL;
325 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326
327 uint8_t *data = NULL;
328 uint32_t size = 0;
329 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930330 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930331 while (curr_record != NULL) {
332 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 (struct pldm_pdr_fru_record_set
334 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335 if (fru->fru_rsi == htole16(fru_rsi)) {
336 *terminus_handle = le16toh(fru->terminus_handle);
337 *entity_type = le16toh(fru->entity_type);
338 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930339 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340 *container_id = le16toh(fru->container_id);
341 return curr_record;
342 }
343 data = NULL;
344 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930345 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
346 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347 }
348
349 *terminus_handle = 0;
350 *entity_type = 0;
351 *entity_instance_num = 0;
352 *container_id = 0;
353
354 return NULL;
355}
356
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930357LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930358/* NOLINTNEXTLINE(readability-identifier-naming) */
359void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
360 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930361{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930362 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363 uint32_t size = 0;
364 const pldm_pdr_record *record;
365 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930366 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367
368 do {
369 if (record != NULL) {
370 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 (struct pldm_terminus_locator_type_mctp_eid *)
374 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930375 if (pdr->terminus_handle == terminus_handle &&
376 pdr->tid == tid && value->eid == tl_eid) {
377 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 break;
379 }
380 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930381 record = pldm_pdr_find_record_by_type(repo,
382 PLDM_TERMINUS_LOCATOR_PDR,
383 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930384 } while (record);
385}
386
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500387static bool pldm_record_handle_in_range(uint32_t record_handle,
388 uint32_t first_record_handle,
389 uint32_t last_record_handle)
390{
391 return record_handle >= first_record_handle &&
392 record_handle <= last_record_handle;
393}
394
395LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500396int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500397 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500398 uint8_t child_index, uint32_t range_exclude_start_handle,
399 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500400{
401 pldm_pdr_record *record;
402 if (!repo) {
403 return -EINVAL;
404 }
405
406 for (record = repo->first; record; record = record->next) {
407 bool is_container_entity_instance_number;
408 struct pldm_pdr_entity_association *pdr;
409 bool is_container_entity_type;
410 struct pldm_entity *child;
411 struct pldm_pdr_hdr *hdr;
412 bool in_range;
413
414 // pldm_pdr_add() takes only uint8_t* data as an argument.
415 // The expectation here is the pldm_pdr_hdr is the first field of the record data
416 hdr = (struct pldm_pdr_hdr *)record->data;
417 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
418 continue;
419 }
420 in_range = pldm_record_handle_in_range(
421 record->record_handle, range_exclude_start_handle,
422 range_exclude_end_handle);
423 if (in_range) {
424 continue;
425 }
426
427 // this cast is valid with respect to alignment because
428 // struct pldm_pdr_hdr is declared with __attribute__((packed))
429 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500430 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500431 continue;
432 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500433
434 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500435 is_container_entity_type = pdr->container.entity_type ==
436 entity_type;
437 is_container_entity_instance_number =
438 pdr->container.entity_instance_num == entity_instance;
439 if (is_container_entity_type &&
440 is_container_entity_instance_number) {
441 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500442 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500443 }
444 }
445 return -ENOKEY;
446}
447
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448typedef struct pldm_entity_association_tree {
449 pldm_entity_node *root;
450 uint16_t last_used_container_id;
451} pldm_entity_association_tree;
452
453typedef struct pldm_entity_node {
454 pldm_entity entity;
455 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600456 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930457 pldm_entity_node *first_child;
458 pldm_entity_node *next_sibling;
459 uint8_t association_type;
460} pldm_entity_node;
461
462static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
463{
464 assert(tree != NULL);
465 assert(tree->last_used_container_id != UINT16_MAX);
466
467 return ++tree->last_used_container_id;
468}
469
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930470LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471pldm_entity pldm_entity_extract(pldm_entity_node *node)
472{
473 assert(node != NULL);
474
475 return node->entity;
476}
477
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600478LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930479uint16_t
480pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600481{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930482 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600483
Andrew Jeffery15b88182023-06-30 13:29:17 +0930484 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600485}
486
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930487LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930488pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930489{
490 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930491 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930492 if (!tree) {
493 return NULL;
494 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930495 tree->root = NULL;
496 tree->last_used_container_id = 0;
497
498 return tree;
499}
500
501static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
502 uint16_t entity_type)
503{
504 assert(start != NULL);
505
506 /* Insert after the the last node that matches the input entity type, or
507 * at the end if no such match occurrs
508 */
509 while (start->next_sibling != NULL) {
510 uint16_t this_type = start->entity.entity_type;
511 pldm_entity_node *next = start->next_sibling;
512 if (this_type == entity_type &&
513 (this_type != next->entity.entity_type)) {
514 break;
515 }
516 start = start->next_sibling;
517 }
518
519 return start;
520}
521
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930522LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930523pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930524 pldm_entity_association_tree *tree, pldm_entity *entity,
525 uint16_t entity_instance_number, pldm_entity_node *parent,
526 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930527{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500528 return pldm_entity_association_tree_add_entity(tree, entity,
529 entity_instance_number,
530 parent, association_type,
531 false, true, 0xFFFF);
532}
533
534LIBPLDM_ABI_TESTING
535pldm_entity_node *pldm_entity_association_tree_add_entity(
536 pldm_entity_association_tree *tree, pldm_entity *entity,
537 uint16_t entity_instance_number, pldm_entity_node *parent,
538 uint8_t association_type, bool is_remote, bool is_update_container_id,
539 uint16_t container_id)
540{
541 if ((!tree) || (!entity)) {
542 return NULL;
543 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544
545 if (entity_instance_number != 0xFFFF && parent != NULL) {
546 pldm_entity node;
547 node.entity_type = entity->entity_type;
548 node.entity_instance_num = entity_instance_number;
549 if (pldm_is_current_parent_child(parent, &node)) {
550 return NULL;
551 }
552 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500553 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
554 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
555 return NULL;
556 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500558 if (!node) {
559 return NULL;
560 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 node->first_child = NULL;
562 node->next_sibling = NULL;
563 node->parent.entity_type = 0;
564 node->parent.entity_instance_num = 0;
565 node->parent.entity_container_id = 0;
566 node->entity.entity_type = entity->entity_type;
567 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930568 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600570 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500572 if (parent != NULL) {
573 free(node);
574 return NULL;
575 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 tree->root = node;
577 /* container_id 0 here indicates this is the top-most entry */
578 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600579 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 } else if (parent != NULL && parent->first_child == NULL) {
581 parent->first_child = node;
582 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500583
584 if (is_remote) {
585 node->remote_container_id = entity->entity_container_id;
586 }
587 if (is_update_container_id) {
588 if (container_id != 0xFFFF) {
589 node->entity.entity_container_id = container_id;
590 } else {
591 node->entity.entity_container_id =
592 next_container_id(tree);
593 }
594 } else {
595 node->entity.entity_container_id =
596 entity->entity_container_id;
597 }
598
599 if (!is_remote) {
600 node->remote_container_id =
601 node->entity.entity_container_id;
602 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930604 pldm_entity_node *start = parent == NULL ? tree->root :
605 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930607 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500608 if (!prev) {
609 free(node);
610 return NULL;
611 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 pldm_entity_node *next = prev->next_sibling;
613 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500614 if (prev->entity.entity_instance_num == UINT16_MAX) {
615 free(node);
616 return NULL;
617 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930619 entity_instance_number != 0xFFFF ?
620 entity_instance_number :
621 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 }
623 prev->next_sibling = node;
624 node->parent = prev->parent;
625 node->next_sibling = next;
626 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930627 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600628 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 }
630 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500631 if (is_update_container_id) {
632 entity->entity_container_id = node->entity.entity_container_id;
633 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 return node;
635}
636
637static void get_num_nodes(pldm_entity_node *node, size_t *num)
638{
639 if (node == NULL) {
640 return;
641 }
642
643 ++(*num);
644 get_num_nodes(node->next_sibling, num);
645 get_num_nodes(node->first_child, num);
646}
647
648static void entity_association_tree_visit(pldm_entity_node *node,
649 pldm_entity *entities, size_t *index)
650{
651 if (node == NULL) {
652 return;
653 }
654
655 pldm_entity *entity = &entities[*index];
656 ++(*index);
657 entity->entity_type = node->entity.entity_type;
658 entity->entity_instance_num = node->entity.entity_instance_num;
659 entity->entity_container_id = node->entity.entity_container_id;
660
661 entity_association_tree_visit(node->next_sibling, entities, index);
662 entity_association_tree_visit(node->first_child, entities, index);
663}
664
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930665LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
667 pldm_entity **entities, size_t *size)
668{
669 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930670 if (!tree || !entities || !size) {
671 return;
672 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673
674 *size = 0;
675 if (tree->root == NULL) {
676 return;
677 }
678
679 get_num_nodes(tree->root, size);
680 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930681 if (!entities) {
682 return;
683 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930684 size_t index = 0;
685 entity_association_tree_visit(tree->root, *entities, &index);
686}
687
688static void entity_association_tree_destroy(pldm_entity_node *node)
689{
690 if (node == NULL) {
691 return;
692 }
693
694 entity_association_tree_destroy(node->next_sibling);
695 entity_association_tree_destroy(node->first_child);
696 free(node);
697}
698
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930699LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930700void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
701{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930702 if (!tree) {
703 return;
704 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705
706 entity_association_tree_destroy(tree->root);
707 free(tree);
708}
709
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930710LIBPLDM_ABI_STABLE
711bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712{
713 assert(node != NULL);
714
715 return node->first_child != NULL;
716}
717
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930718LIBPLDM_ABI_STABLE
719pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720{
721 assert(node != NULL);
722
723 return node->parent;
724}
725
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930726LIBPLDM_ABI_STABLE
727bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930728{
729 assert(node != NULL);
730
731 if (node->parent.entity_type == 0 &&
732 node->parent.entity_instance_num == 0 &&
733 node->parent.entity_container_id == 0) {
734 return false;
735 }
736
737 return true;
738}
739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930740LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930741uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
742 uint8_t association_type)
743{
744 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930745 if (!node) {
746 return 0;
747 }
748
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
750 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930751 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
752 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
753 return 0;
754 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755
756 size_t count = 0;
757 pldm_entity_node *curr = node->first_child;
758 while (curr != NULL) {
759 if (curr->association_type == association_type) {
760 ++count;
761 }
762 curr = curr->next_sibling;
763 }
764
765 assert(count < UINT8_MAX);
766 return count;
767}
768
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930769LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
771{
772 assert(parent != NULL);
773 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930774 if (!parent || !node) {
775 return false;
776 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777
778 pldm_entity_node *curr = parent->first_child;
779 while (curr != NULL) {
780 if (node->entity_type == curr->entity.entity_type &&
781 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930782 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930783 return true;
784 }
785 curr = curr->next_sibling;
786 }
787
788 return false;
789}
790
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500791static void entity_association_pdr_add_children(
792 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
793 uint8_t contained_count, uint8_t association_type, bool is_remote,
794 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930795{
796 uint8_t pdr[size];
797 uint8_t *start = pdr;
798
799 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
800 hdr->version = 1;
801 hdr->record_handle = 0;
802 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
803 hdr->record_change_num = 0;
804 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
805 start += sizeof(struct pldm_pdr_hdr);
806
807 uint16_t *container_id = (uint16_t *)start;
808 *container_id = htole16(curr->first_child->entity.entity_container_id);
809 start += sizeof(uint16_t);
810 *start = association_type;
811 start += sizeof(uint8_t);
812
813 pldm_entity *entity = (pldm_entity *)start;
814 entity->entity_type = htole16(curr->entity.entity_type);
815 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
816 entity->entity_container_id = htole16(curr->entity.entity_container_id);
817 start += sizeof(pldm_entity);
818
819 *start = contained_count;
820 start += sizeof(uint8_t);
821
822 pldm_entity_node *node = curr->first_child;
823 while (node != NULL) {
824 if (node->association_type == association_type) {
825 pldm_entity *entity = (pldm_entity *)start;
826 entity->entity_type = htole16(node->entity.entity_type);
827 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930828 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930830 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831 start += sizeof(pldm_entity);
832 }
833 node = node->next_sibling;
834 }
835
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500836 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
837 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838}
839
840static void entity_association_pdr_add_entry(pldm_entity_node *curr,
841 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500842 uint16_t terminus_handle,
843 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930845 uint8_t num_logical_children = pldm_entity_get_num_children(
846 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
847 uint8_t num_physical_children = pldm_entity_get_num_children(
848 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849
850 if (num_logical_children) {
851 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
853 sizeof(uint8_t) + sizeof(pldm_entity) +
854 sizeof(uint8_t) +
855 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930856 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930857 curr, repo, logical_pdr_size, num_logical_children,
858 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500859 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930860 }
861
862 if (num_physical_children) {
863 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930864 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
865 sizeof(uint8_t) + sizeof(pldm_entity) +
866 sizeof(uint8_t) +
867 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930868 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930869 curr, repo, physical_pdr_size, num_physical_children,
870 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500871 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872 }
873}
874
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930875LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930876bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
877{
878 if (entities == NULL || num_entities == 0) {
879 return true;
880 }
881 size_t i = 0;
882 while (i < num_entities) {
883 if ((*entities + i)->entity_type == entity.entity_type) {
884 return true;
885 }
886 i++;
887 }
888 return false;
889}
890
891static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
892 pldm_entity **entities,
893 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500894 uint16_t terminus_handle,
895 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896{
897 if (curr == NULL) {
898 return;
899 }
900 bool to_add = true;
901 to_add = is_present(curr->entity, entities, num_entities);
902 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500903 entity_association_pdr_add_entry(
904 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905 }
906 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500907 num_entities, is_remote, terminus_handle,
908 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500910 num_entities, is_remote, terminus_handle,
911 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912}
913
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930914LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
916 pldm_pdr *repo, bool is_remote,
917 uint16_t terminus_handle)
918{
919 assert(tree != NULL);
920 assert(repo != NULL);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930921 if (!tree || !repo) {
922 return;
923 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924
925 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500926 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927}
928
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930929LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930931 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
932 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930933{
934 assert(repo != NULL);
935
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500936 pldm_entity_association_pdr_add_from_node_with_record_handle(
937 node, repo, entities, num_entities, is_remote, terminus_handle,
938 0);
939}
940
941LIBPLDM_ABI_TESTING
942int pldm_entity_association_pdr_add_from_node_with_record_handle(
943 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
944 size_t num_entities, bool is_remote, uint16_t terminus_handle,
945 uint32_t record_handle)
946{
947 if (!node || !repo || !entities) {
948 return -EINVAL;
949 }
950
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500952 is_remote, terminus_handle, record_handle);
953
954 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955}
956
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930957LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
959 pldm_entity_node **node)
960{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600961 bool is_entity_container_id;
962 bool is_entity_instance_num;
963 bool is_type;
964
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 if (tree_node == NULL) {
966 return;
967 }
968
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600969 is_type = tree_node->entity.entity_type == entity.entity_type;
970 is_entity_instance_num = tree_node->entity.entity_instance_num ==
971 entity.entity_instance_num;
972 is_entity_container_id = tree_node->entity.entity_container_id ==
973 entity.entity_container_id;
974
975 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930976 *node = tree_node;
977 return;
978 }
979
980 find_entity_ref_in_tree(tree_node->first_child, entity, node);
981 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
982}
983
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930984LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930985void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
986 pldm_entity entity, pldm_entity_node **node)
987{
988 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +0930989 if (!tree || !node) {
990 return;
991 }
992
Andrew Jeffery9c766792022-08-10 23:12:49 +0930993 find_entity_ref_in_tree(tree->root, entity, node);
994}
995
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930996LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
998 uint16_t terminus_handle)
999{
1000 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +09301001 if (!repo) {
1002 return;
1003 }
1004
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005 bool removed = false;
1006
1007 pldm_pdr_record *record = repo->first;
1008 pldm_pdr_record *prev = NULL;
1009 while (record != NULL) {
1010 pldm_pdr_record *next = record->next;
1011 if (record->terminus_handle == terminus_handle) {
1012 if (repo->first == record) {
1013 repo->first = next;
1014 } else {
1015 prev->next = next;
1016 }
1017 if (repo->last == record) {
1018 repo->last = prev;
1019 }
1020 if (record->data) {
1021 free(record->data);
1022 }
1023 --repo->record_count;
1024 repo->size -= record->size;
1025 free(record);
1026 removed = true;
1027 } else {
1028 prev = record;
1029 }
1030 record = next;
1031 }
1032
1033 if (removed == true) {
1034 record = repo->first;
1035 uint32_t record_handle = 0;
1036 while (record != NULL) {
1037 record->record_handle = ++record_handle;
1038 if (record->data != NULL) {
1039 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301042 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043 }
1044 record = record->next;
1045 }
1046 }
1047}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301048
1049LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1051{
1052 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301053 if (!repo) {
1054 return;
1055 }
1056
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 bool removed = false;
1058
1059 pldm_pdr_record *record = repo->first;
1060 pldm_pdr_record *prev = NULL;
1061 while (record != NULL) {
1062 pldm_pdr_record *next = record->next;
1063 if (record->is_remote == true) {
1064 if (repo->first == record) {
1065 repo->first = next;
1066 } else {
1067 prev->next = next;
1068 }
1069 if (repo->last == record) {
1070 repo->last = prev;
1071 }
1072 if (record->data) {
1073 free(record->data);
1074 }
1075 --repo->record_count;
1076 repo->size -= record->size;
1077 free(record);
1078 removed = true;
1079 } else {
1080 prev = record;
1081 }
1082 record = next;
1083 }
1084
1085 if (removed == true) {
1086 record = repo->first;
1087 uint32_t record_handle = 0;
1088 while (record != NULL) {
1089 record->record_handle = ++record_handle;
1090 if (record->data != NULL) {
1091 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301092 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301093 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301094 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095 }
1096 record = record->next;
1097 }
1098 }
1099}
1100
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001101LIBPLDM_ABI_TESTING
1102pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1103 uint32_t first, uint32_t last)
1104{
1105 pldm_pdr_record *record = NULL;
1106 pldm_pdr_record *curr;
1107
1108 if (!repo) {
1109 return NULL;
1110 }
1111 for (curr = repo->first; curr; curr = curr->next) {
1112 if (first > curr->record_handle || last < curr->record_handle) {
1113 continue;
1114 }
1115 if (!record || curr->record_handle > record->record_handle) {
1116 record = curr;
1117 }
1118 }
1119
1120 return record;
1121}
1122
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001123static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1124 pldm_entity *entity,
1125 pldm_entity_node **out,
1126 bool is_remote)
1127{
1128 assert(out != NULL && *out == NULL);
1129 if (node == NULL) {
1130 return;
1131 }
1132 bool is_entity_type;
1133 bool is_entity_instance_num;
1134
1135 is_entity_type = node->entity.entity_type == entity->entity_type;
1136 is_entity_instance_num = node->entity.entity_instance_num ==
1137 entity->entity_instance_num;
1138
1139 if (!is_remote ||
1140 node->remote_container_id == entity->entity_container_id) {
1141 if (is_entity_type && is_entity_instance_num) {
1142 entity->entity_container_id =
1143 node->entity.entity_container_id;
1144 *out = node;
1145 return;
1146 }
1147 }
1148 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1149 is_remote);
1150 entity_association_tree_find_if_remote(node->first_child, entity, out,
1151 is_remote);
1152}
1153
1154LIBPLDM_ABI_TESTING
1155pldm_entity_node *
1156pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1157 pldm_entity *entity, bool is_remote)
1158{
1159 if (!tree || !entity) {
1160 return NULL;
1161 }
1162 pldm_entity_node *node = NULL;
1163 entity_association_tree_find_if_remote(tree->root, entity, &node,
1164 is_remote);
1165 return node;
1166}
1167
Andrew Jeffery7f589312023-07-03 12:03:25 +09301168LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1170 pldm_entity_node **out)
1171{
1172 if (node == NULL) {
1173 return;
1174 }
1175
1176 if (node->entity.entity_type == entity->entity_type &&
1177 node->entity.entity_instance_num == entity->entity_instance_num) {
1178 entity->entity_container_id = node->entity.entity_container_id;
1179 *out = node;
1180 return;
1181 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182 entity_association_tree_find(node->next_sibling, entity, out);
1183 entity_association_tree_find(node->first_child, entity, out);
1184}
1185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187pldm_entity_node *
1188pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1189 pldm_entity *entity)
1190{
1191 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301192 if (!tree || !entity) {
1193 return NULL;
1194 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301195
1196 pldm_entity_node *node = NULL;
1197 entity_association_tree_find(tree->root, entity, &node);
1198 return node;
1199}
1200
1201static void entity_association_tree_copy(pldm_entity_node *org_node,
1202 pldm_entity_node **new_node)
1203{
1204 if (org_node == NULL) {
1205 return;
1206 }
1207 *new_node = malloc(sizeof(pldm_entity_node));
1208 (*new_node)->parent = org_node->parent;
1209 (*new_node)->entity = org_node->entity;
1210 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001211 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212 (*new_node)->first_child = NULL;
1213 (*new_node)->next_sibling = NULL;
1214 entity_association_tree_copy(org_node->first_child,
1215 &((*new_node)->first_child));
1216 entity_association_tree_copy(org_node->next_sibling,
1217 &((*new_node)->next_sibling));
1218}
1219
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301220LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301222 pldm_entity_association_tree *org_tree,
1223 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224{
1225 new_tree->last_used_container_id = org_tree->last_used_container_id;
1226 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1227}
1228
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301229LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301231 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232{
1233 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301234 if (!tree) {
1235 return;
1236 }
1237
Andrew Jeffery9c766792022-08-10 23:12:49 +09301238 entity_association_tree_destroy(tree->root);
1239 tree->last_used_container_id = 0;
1240 tree->root = NULL;
1241}
1242
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301243LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1245{
1246 return ((tree->root == NULL) ? true : false);
1247}
1248
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301249LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301250void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1251 size_t *num_entities,
1252 pldm_entity **entities)
1253{
1254 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301255 if (!pdr || !num_entities || !entities) {
1256 return;
1257 }
1258#define PDR_MIN_SIZE \
1259 (sizeof(struct pldm_pdr_hdr) + \
1260 sizeof(struct pldm_pdr_entity_association))
1261 assert(pdr_len >= PDR_MIN_SIZE);
1262 if (pdr_len < PDR_MIN_SIZE) {
1263 return;
1264 }
1265#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301266
1267 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1268 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1269
1270 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301271 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301272 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273 start += sizeof(struct pldm_pdr_hdr);
1274 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301275 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301276 *num_entities = entity_association_pdr->num_children + 1;
1277 assert(*num_entities >= 2);
1278 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1279 assert(*entities != NULL);
1280 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301281 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301282 end);
1283 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301284 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301285 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301287 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289 pldm_entity *curr_entity = entity_association_pdr->children;
1290 size_t i = 1;
1291 while (i < *num_entities) {
1292 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301293 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301295 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301296 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301297 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301298 ++curr_entity;
1299 ++i;
1300 }
1301}