blob: 0ef9163c215740b377e86418b8b9e2f782cab60a [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
Andrew Jefferya51ccc22023-06-28 21:57:46 +093037LIBPLDM_ABI_STABLE
38uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
39 uint32_t record_handle, bool is_remote,
40 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +093041{
42 assert(repo != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093043 assert(data != NULL);
Andrew Jeffery9c766792022-08-10 23:12:49 +093044 assert(size != 0);
45
46 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
47 assert(record != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093048
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093049 if (record_handle) {
50 record->record_handle = record_handle;
51 } else {
52 uint32_t curr = repo->last ? repo->last->record_handle : 0;
53 assert(curr != UINT32_MAX);
54 record->record_handle = curr + 1;
55 }
56
Andrew Jeffery9c766792022-08-10 23:12:49 +093057 record->size = size;
58 record->is_remote = is_remote;
59 record->terminus_handle = terminus_handle;
60 if (data != NULL) {
61 record->data = malloc(size);
62 assert(record->data != NULL);
63 memcpy(record->data, data, size);
64 /* If record handle is 0, that is an indication for this API to
65 * compute a new handle. For that reason, the computed handle
66 * needs to be populated in the PDR header. For a case where the
67 * caller supplied the record handle, it would exist in the
68 * header already.
69 */
70 if (!record_handle) {
71 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093072 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093073 hdr->record_handle = htole32(record->record_handle);
74 }
75 }
76 record->next = NULL;
77
Andrew Jeffery8d231da2023-07-04 11:28:46 +093078 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093079 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +093080 repo->first = record;
81 repo->last = record;
82 } else {
83 repo->last->next = record;
84 repo->last = record;
85 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093086
Andrew Jefferya51ccc22023-06-28 21:57:46 +093087 repo->size += record->size;
88 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +093089
90 return record->record_handle;
91}
92
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093093LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +093094pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +093095{
96 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +093097 if (!repo) {
98 return NULL;
99 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100 repo->record_count = 0;
101 repo->size = 0;
102 repo->first = NULL;
103 repo->last = NULL;
104
105 return repo;
106}
107
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930108LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109void pldm_pdr_destroy(pldm_pdr *repo)
110{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930111 if (!repo) {
112 return;
113 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114
115 pldm_pdr_record *record = repo->first;
116 while (record != NULL) {
117 pldm_pdr_record *next = record->next;
118 if (record->data) {
119 free(record->data);
120 record->data = NULL;
121 }
122 free(record);
123 record = next;
124 }
125 free(repo);
126}
127
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930128LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930129const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
130 uint32_t record_handle,
131 uint8_t **data, uint32_t *size,
132 uint32_t *next_record_handle)
133{
134 assert(repo != NULL);
135 assert(data != NULL);
136 assert(size != NULL);
137 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930138 if (!repo || !data || !size || !next_record_handle) {
139 return NULL;
140 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930141
142 if (!record_handle && (repo->first != NULL)) {
143 record_handle = repo->first->record_handle;
144 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930145
Andrew Jeffery9c766792022-08-10 23:12:49 +0930146 pldm_pdr_record *record = repo->first;
147 while (record != NULL) {
148 if (record->record_handle == record_handle) {
149 *size = record->size;
150 *data = record->data;
151 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930152 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930153 return record;
154 }
155 record = record->next;
156 }
157
158 *size = 0;
159 *next_record_handle = 0;
160 return NULL;
161}
162
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930163LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164const pldm_pdr_record *
165pldm_pdr_get_next_record(const pldm_pdr *repo,
166 const pldm_pdr_record *curr_record, uint8_t **data,
167 uint32_t *size, uint32_t *next_record_handle)
168{
169 assert(repo != NULL);
170 assert(curr_record != NULL);
171 assert(data != NULL);
172 assert(size != NULL);
173 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930174 if (!repo || !curr_record || !data || !size || !next_record_handle) {
175 return NULL;
176 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930177
178 if (curr_record == repo->last) {
179 *data = NULL;
180 *size = 0;
181 *next_record_handle = get_next_record_handle(repo, curr_record);
182 return NULL;
183 }
184
185 *next_record_handle = get_next_record_handle(repo, curr_record->next);
186 *data = curr_record->next->data;
187 *size = curr_record->next->size;
188 return curr_record->next;
189}
190
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930191LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930192const pldm_pdr_record *
193pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
194 const pldm_pdr_record *curr_record, uint8_t **data,
195 uint32_t *size)
196{
197 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930198 if (!repo) {
199 return NULL;
200 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201
202 pldm_pdr_record *record = repo->first;
203 if (curr_record != NULL) {
204 record = curr_record->next;
205 }
206 while (record != NULL) {
207 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
208 if (hdr->type == pdr_type) {
209 if (data && size) {
210 *size = record->size;
211 *data = record->data;
212 }
213 return record;
214 }
215 record = record->next;
216 }
217
218 if (size) {
219 *size = 0;
220 }
221 return NULL;
222}
223
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930224LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930225uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
226{
227 assert(repo != NULL);
228
229 return repo->record_count;
230}
231
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930232LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930233uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
234{
235 assert(repo != NULL);
236
237 return repo->size;
238}
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930241uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
242 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243 const pldm_pdr_record *record)
244{
245 assert(repo != NULL);
246 assert(record != NULL);
247
248 return record->record_handle;
249}
250
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930251LIBPLDM_ABI_STABLE
252bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930253{
254 assert(record != NULL);
255
256 return record->is_remote;
257}
258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930259LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930260uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
261 uint16_t fru_rsi, uint16_t entity_type,
262 uint16_t entity_instance_num,
263 uint16_t container_id,
264 uint32_t bmc_record_handle)
265{
266 uint32_t size = sizeof(struct pldm_pdr_hdr) +
267 sizeof(struct pldm_pdr_fru_record_set);
268 uint8_t data[size];
269
270 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
271 hdr->version = 1;
272 hdr->record_handle = bmc_record_handle;
273 hdr->type = PLDM_PDR_FRU_RECORD_SET;
274 hdr->record_change_num = 0;
275 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
276 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930277 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
278 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279 fru->terminus_handle = htole16(terminus_handle);
280 fru->fru_rsi = htole16(fru_rsi);
281 fru->entity_type = htole16(entity_type);
282 fru->entity_instance_num = htole16(entity_instance_num);
283 fru->container_id = htole16(container_id);
284
285 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
286 terminus_handle);
287}
288
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930289LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930291 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
292 uint16_t *entity_type, uint16_t *entity_instance_num,
293 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930294{
295 assert(terminus_handle != NULL);
296 assert(entity_type != NULL);
297 assert(entity_instance_num != NULL);
298 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930299 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
300 !container_id) {
301 return NULL;
302 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303
304 uint8_t *data = NULL;
305 uint32_t size = 0;
306 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930307 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308 while (curr_record != NULL) {
309 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930310 (struct pldm_pdr_fru_record_set
311 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312 if (fru->fru_rsi == htole16(fru_rsi)) {
313 *terminus_handle = le16toh(fru->terminus_handle);
314 *entity_type = le16toh(fru->entity_type);
315 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930316 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 *container_id = le16toh(fru->container_id);
318 return curr_record;
319 }
320 data = NULL;
321 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930322 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
323 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324 }
325
326 *terminus_handle = 0;
327 *entity_type = 0;
328 *entity_instance_num = 0;
329 *container_id = 0;
330
331 return NULL;
332}
333
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930334LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930335/* NOLINTNEXTLINE(readability-identifier-naming) */
336void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
337 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930339 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340 uint32_t size = 0;
341 const pldm_pdr_record *record;
342 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930343 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344
345 do {
346 if (record != NULL) {
347 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930350 (struct pldm_terminus_locator_type_mctp_eid *)
351 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930352 if (pdr->terminus_handle == terminus_handle &&
353 pdr->tid == tid && value->eid == tl_eid) {
354 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930355 break;
356 }
357 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930358 record = pldm_pdr_find_record_by_type(repo,
359 PLDM_TERMINUS_LOCATOR_PDR,
360 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930361 } while (record);
362}
363
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500364static bool pldm_record_handle_in_range(uint32_t record_handle,
365 uint32_t first_record_handle,
366 uint32_t last_record_handle)
367{
368 return record_handle >= first_record_handle &&
369 record_handle <= last_record_handle;
370}
371
372LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500373int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500374 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500375 uint8_t child_index, uint32_t range_exclude_start_handle,
376 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500377{
378 pldm_pdr_record *record;
379 if (!repo) {
380 return -EINVAL;
381 }
382
383 for (record = repo->first; record; record = record->next) {
384 bool is_container_entity_instance_number;
385 struct pldm_pdr_entity_association *pdr;
386 bool is_container_entity_type;
387 struct pldm_entity *child;
388 struct pldm_pdr_hdr *hdr;
389 bool in_range;
390
391 // pldm_pdr_add() takes only uint8_t* data as an argument.
392 // The expectation here is the pldm_pdr_hdr is the first field of the record data
393 hdr = (struct pldm_pdr_hdr *)record->data;
394 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
395 continue;
396 }
397 in_range = pldm_record_handle_in_range(
398 record->record_handle, range_exclude_start_handle,
399 range_exclude_end_handle);
400 if (in_range) {
401 continue;
402 }
403
404 // this cast is valid with respect to alignment because
405 // struct pldm_pdr_hdr is declared with __attribute__((packed))
406 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500407 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500408 continue;
409 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500410
411 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500412 is_container_entity_type = pdr->container.entity_type ==
413 entity_type;
414 is_container_entity_instance_number =
415 pdr->container.entity_instance_num == entity_instance;
416 if (is_container_entity_type &&
417 is_container_entity_instance_number) {
418 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500419 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500420 }
421 }
422 return -ENOKEY;
423}
424
Andrew Jeffery9c766792022-08-10 23:12:49 +0930425typedef struct pldm_entity_association_tree {
426 pldm_entity_node *root;
427 uint16_t last_used_container_id;
428} pldm_entity_association_tree;
429
430typedef struct pldm_entity_node {
431 pldm_entity entity;
432 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600433 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930434 pldm_entity_node *first_child;
435 pldm_entity_node *next_sibling;
436 uint8_t association_type;
437} pldm_entity_node;
438
439static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
440{
441 assert(tree != NULL);
442 assert(tree->last_used_container_id != UINT16_MAX);
443
444 return ++tree->last_used_container_id;
445}
446
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930447LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448pldm_entity pldm_entity_extract(pldm_entity_node *node)
449{
450 assert(node != NULL);
451
452 return node->entity;
453}
454
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600455LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930456uint16_t
457pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600458{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930459 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600460
Andrew Jeffery15b88182023-06-30 13:29:17 +0930461 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600462}
463
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930464LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930465pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466{
467 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930468 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930469 if (!tree) {
470 return NULL;
471 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472 tree->root = NULL;
473 tree->last_used_container_id = 0;
474
475 return tree;
476}
477
478static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
479 uint16_t entity_type)
480{
481 assert(start != NULL);
482
483 /* Insert after the the last node that matches the input entity type, or
484 * at the end if no such match occurrs
485 */
486 while (start->next_sibling != NULL) {
487 uint16_t this_type = start->entity.entity_type;
488 pldm_entity_node *next = start->next_sibling;
489 if (this_type == entity_type &&
490 (this_type != next->entity.entity_type)) {
491 break;
492 }
493 start = start->next_sibling;
494 }
495
496 return start;
497}
498
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930499LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930501 pldm_entity_association_tree *tree, pldm_entity *entity,
502 uint16_t entity_instance_number, pldm_entity_node *parent,
503 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930504{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500505 return pldm_entity_association_tree_add_entity(tree, entity,
506 entity_instance_number,
507 parent, association_type,
508 false, true, 0xFFFF);
509}
510
511LIBPLDM_ABI_TESTING
512pldm_entity_node *pldm_entity_association_tree_add_entity(
513 pldm_entity_association_tree *tree, pldm_entity *entity,
514 uint16_t entity_instance_number, pldm_entity_node *parent,
515 uint8_t association_type, bool is_remote, bool is_update_container_id,
516 uint16_t container_id)
517{
518 if ((!tree) || (!entity)) {
519 return NULL;
520 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930521
522 if (entity_instance_number != 0xFFFF && parent != NULL) {
523 pldm_entity node;
524 node.entity_type = entity->entity_type;
525 node.entity_instance_num = entity_instance_number;
526 if (pldm_is_current_parent_child(parent, &node)) {
527 return NULL;
528 }
529 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500530 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
531 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
532 return NULL;
533 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930534 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500535 if (!node) {
536 return NULL;
537 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538 node->first_child = NULL;
539 node->next_sibling = NULL;
540 node->parent.entity_type = 0;
541 node->parent.entity_instance_num = 0;
542 node->parent.entity_container_id = 0;
543 node->entity.entity_type = entity->entity_type;
544 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930545 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930546 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600547 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500549 if (parent != NULL) {
550 free(node);
551 return NULL;
552 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930553 tree->root = node;
554 /* container_id 0 here indicates this is the top-most entry */
555 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600556 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 } else if (parent != NULL && parent->first_child == NULL) {
558 parent->first_child = node;
559 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500560
561 if (is_remote) {
562 node->remote_container_id = entity->entity_container_id;
563 }
564 if (is_update_container_id) {
565 if (container_id != 0xFFFF) {
566 node->entity.entity_container_id = container_id;
567 } else {
568 node->entity.entity_container_id =
569 next_container_id(tree);
570 }
571 } else {
572 node->entity.entity_container_id =
573 entity->entity_container_id;
574 }
575
576 if (!is_remote) {
577 node->remote_container_id =
578 node->entity.entity_container_id;
579 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930581 pldm_entity_node *start = parent == NULL ? tree->root :
582 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930584 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500585 if (!prev) {
586 free(node);
587 return NULL;
588 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589 pldm_entity_node *next = prev->next_sibling;
590 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500591 if (prev->entity.entity_instance_num == UINT16_MAX) {
592 free(node);
593 return NULL;
594 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930596 entity_instance_number != 0xFFFF ?
597 entity_instance_number :
598 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 }
600 prev->next_sibling = node;
601 node->parent = prev->parent;
602 node->next_sibling = next;
603 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930604 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600605 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 }
607 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500608 if (is_update_container_id) {
609 entity->entity_container_id = node->entity.entity_container_id;
610 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 return node;
612}
613
614static void get_num_nodes(pldm_entity_node *node, size_t *num)
615{
616 if (node == NULL) {
617 return;
618 }
619
620 ++(*num);
621 get_num_nodes(node->next_sibling, num);
622 get_num_nodes(node->first_child, num);
623}
624
625static void entity_association_tree_visit(pldm_entity_node *node,
626 pldm_entity *entities, size_t *index)
627{
628 if (node == NULL) {
629 return;
630 }
631
632 pldm_entity *entity = &entities[*index];
633 ++(*index);
634 entity->entity_type = node->entity.entity_type;
635 entity->entity_instance_num = node->entity.entity_instance_num;
636 entity->entity_container_id = node->entity.entity_container_id;
637
638 entity_association_tree_visit(node->next_sibling, entities, index);
639 entity_association_tree_visit(node->first_child, entities, index);
640}
641
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930642LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
644 pldm_entity **entities, size_t *size)
645{
646 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930647 if (!tree || !entities || !size) {
648 return;
649 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930650
651 *size = 0;
652 if (tree->root == NULL) {
653 return;
654 }
655
656 get_num_nodes(tree->root, size);
657 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930658 if (!entities) {
659 return;
660 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930661 size_t index = 0;
662 entity_association_tree_visit(tree->root, *entities, &index);
663}
664
665static void entity_association_tree_destroy(pldm_entity_node *node)
666{
667 if (node == NULL) {
668 return;
669 }
670
671 entity_association_tree_destroy(node->next_sibling);
672 entity_association_tree_destroy(node->first_child);
673 free(node);
674}
675
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930676LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
678{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930679 if (!tree) {
680 return;
681 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930682
683 entity_association_tree_destroy(tree->root);
684 free(tree);
685}
686
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930687LIBPLDM_ABI_STABLE
688bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930689{
690 assert(node != NULL);
691
692 return node->first_child != NULL;
693}
694
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930695LIBPLDM_ABI_STABLE
696pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697{
698 assert(node != NULL);
699
700 return node->parent;
701}
702
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930703LIBPLDM_ABI_STABLE
704bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930705{
706 assert(node != NULL);
707
708 if (node->parent.entity_type == 0 &&
709 node->parent.entity_instance_num == 0 &&
710 node->parent.entity_container_id == 0) {
711 return false;
712 }
713
714 return true;
715}
716
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930717LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
719 uint8_t association_type)
720{
721 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930722 if (!node) {
723 return 0;
724 }
725
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
727 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930728 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
729 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
730 return 0;
731 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732
733 size_t count = 0;
734 pldm_entity_node *curr = node->first_child;
735 while (curr != NULL) {
736 if (curr->association_type == association_type) {
737 ++count;
738 }
739 curr = curr->next_sibling;
740 }
741
742 assert(count < UINT8_MAX);
743 return count;
744}
745
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930746LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
748{
749 assert(parent != NULL);
750 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930751 if (!parent || !node) {
752 return false;
753 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930754
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 Jefferyd11bf9f2023-06-30 15:47:41 +0930852LIBPLDM_ABI_DEPRECATED
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);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930898 if (!tree || !repo) {
899 return;
900 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901
902 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500903 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904}
905
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930906LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930908 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
909 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910{
Andrew Jefferycc394522023-07-03 12:49:31 +0930911 int rc = pldm_entity_association_pdr_add_from_node_check(
912 node, repo, entities, num_entities, is_remote, terminus_handle);
913 (void)rc;
914 assert(!rc);
915}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916
Andrew Jefferycc394522023-07-03 12:49:31 +0930917LIBPLDM_ABI_TESTING
918int pldm_entity_association_pdr_add_from_node_check(
919 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
920 size_t num_entities, bool is_remote, uint16_t terminus_handle)
921{
922 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500923 node, repo, entities, num_entities, is_remote, terminus_handle,
924 0);
925}
926
927LIBPLDM_ABI_TESTING
928int pldm_entity_association_pdr_add_from_node_with_record_handle(
929 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
930 size_t num_entities, bool is_remote, uint16_t terminus_handle,
931 uint32_t record_handle)
932{
933 if (!node || !repo || !entities) {
934 return -EINVAL;
935 }
936
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500938 is_remote, terminus_handle, record_handle);
939
940 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941}
942
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930943LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930944void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
945 pldm_entity_node **node)
946{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600947 bool is_entity_container_id;
948 bool is_entity_instance_num;
949 bool is_type;
950
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 if (tree_node == NULL) {
952 return;
953 }
954
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600955 is_type = tree_node->entity.entity_type == entity.entity_type;
956 is_entity_instance_num = tree_node->entity.entity_instance_num ==
957 entity.entity_instance_num;
958 is_entity_container_id = tree_node->entity.entity_container_id ==
959 entity.entity_container_id;
960
961 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930962 *node = tree_node;
963 return;
964 }
965
966 find_entity_ref_in_tree(tree_node->first_child, entity, node);
967 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
968}
969
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930970LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
972 pldm_entity entity, pldm_entity_node **node)
973{
974 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +0930975 if (!tree || !node) {
976 return;
977 }
978
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979 find_entity_ref_in_tree(tree->root, entity, node);
980}
981
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930982LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930983void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
984 uint16_t terminus_handle)
985{
986 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +0930987 if (!repo) {
988 return;
989 }
990
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991 bool removed = false;
992
993 pldm_pdr_record *record = repo->first;
994 pldm_pdr_record *prev = NULL;
995 while (record != NULL) {
996 pldm_pdr_record *next = record->next;
997 if (record->terminus_handle == terminus_handle) {
998 if (repo->first == record) {
999 repo->first = next;
1000 } else {
1001 prev->next = next;
1002 }
1003 if (repo->last == record) {
1004 repo->last = prev;
1005 }
1006 if (record->data) {
1007 free(record->data);
1008 }
1009 --repo->record_count;
1010 repo->size -= record->size;
1011 free(record);
1012 removed = true;
1013 } else {
1014 prev = record;
1015 }
1016 record = next;
1017 }
1018
1019 if (removed == true) {
1020 record = repo->first;
1021 uint32_t record_handle = 0;
1022 while (record != NULL) {
1023 record->record_handle = ++record_handle;
1024 if (record->data != NULL) {
1025 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301026 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301028 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301029 }
1030 record = record->next;
1031 }
1032 }
1033}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301034
1035LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1037{
1038 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301039 if (!repo) {
1040 return;
1041 }
1042
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043 bool removed = false;
1044
1045 pldm_pdr_record *record = repo->first;
1046 pldm_pdr_record *prev = NULL;
1047 while (record != NULL) {
1048 pldm_pdr_record *next = record->next;
1049 if (record->is_remote == true) {
1050 if (repo->first == record) {
1051 repo->first = next;
1052 } else {
1053 prev->next = next;
1054 }
1055 if (repo->last == record) {
1056 repo->last = prev;
1057 }
1058 if (record->data) {
1059 free(record->data);
1060 }
1061 --repo->record_count;
1062 repo->size -= record->size;
1063 free(record);
1064 removed = true;
1065 } else {
1066 prev = record;
1067 }
1068 record = next;
1069 }
1070
1071 if (removed == true) {
1072 record = repo->first;
1073 uint32_t record_handle = 0;
1074 while (record != NULL) {
1075 record->record_handle = ++record_handle;
1076 if (record->data != NULL) {
1077 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301078 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301079 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301080 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081 }
1082 record = record->next;
1083 }
1084 }
1085}
1086
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001087LIBPLDM_ABI_TESTING
1088pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1089 uint32_t first, uint32_t last)
1090{
1091 pldm_pdr_record *record = NULL;
1092 pldm_pdr_record *curr;
1093
1094 if (!repo) {
1095 return NULL;
1096 }
1097 for (curr = repo->first; curr; curr = curr->next) {
1098 if (first > curr->record_handle || last < curr->record_handle) {
1099 continue;
1100 }
1101 if (!record || curr->record_handle > record->record_handle) {
1102 record = curr;
1103 }
1104 }
1105
1106 return record;
1107}
1108
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001109static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1110 pldm_entity *entity,
1111 pldm_entity_node **out,
1112 bool is_remote)
1113{
1114 assert(out != NULL && *out == NULL);
1115 if (node == NULL) {
1116 return;
1117 }
1118 bool is_entity_type;
1119 bool is_entity_instance_num;
1120
1121 is_entity_type = node->entity.entity_type == entity->entity_type;
1122 is_entity_instance_num = node->entity.entity_instance_num ==
1123 entity->entity_instance_num;
1124
1125 if (!is_remote ||
1126 node->remote_container_id == entity->entity_container_id) {
1127 if (is_entity_type && is_entity_instance_num) {
1128 entity->entity_container_id =
1129 node->entity.entity_container_id;
1130 *out = node;
1131 return;
1132 }
1133 }
1134 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1135 is_remote);
1136 entity_association_tree_find_if_remote(node->first_child, entity, out,
1137 is_remote);
1138}
1139
1140LIBPLDM_ABI_TESTING
1141pldm_entity_node *
1142pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1143 pldm_entity *entity, bool is_remote)
1144{
1145 if (!tree || !entity) {
1146 return NULL;
1147 }
1148 pldm_entity_node *node = NULL;
1149 entity_association_tree_find_if_remote(tree->root, entity, &node,
1150 is_remote);
1151 return node;
1152}
1153
Andrew Jeffery7f589312023-07-03 12:03:25 +09301154LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301155void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1156 pldm_entity_node **out)
1157{
1158 if (node == NULL) {
1159 return;
1160 }
1161
1162 if (node->entity.entity_type == entity->entity_type &&
1163 node->entity.entity_instance_num == entity->entity_instance_num) {
1164 entity->entity_container_id = node->entity.entity_container_id;
1165 *out = node;
1166 return;
1167 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301168 entity_association_tree_find(node->next_sibling, entity, out);
1169 entity_association_tree_find(node->first_child, entity, out);
1170}
1171
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301172LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173pldm_entity_node *
1174pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1175 pldm_entity *entity)
1176{
1177 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301178 if (!tree || !entity) {
1179 return NULL;
1180 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181
1182 pldm_entity_node *node = NULL;
1183 entity_association_tree_find(tree->root, entity, &node);
1184 return node;
1185}
1186
1187static void entity_association_tree_copy(pldm_entity_node *org_node,
1188 pldm_entity_node **new_node)
1189{
1190 if (org_node == NULL) {
1191 return;
1192 }
1193 *new_node = malloc(sizeof(pldm_entity_node));
1194 (*new_node)->parent = org_node->parent;
1195 (*new_node)->entity = org_node->entity;
1196 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001197 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198 (*new_node)->first_child = NULL;
1199 (*new_node)->next_sibling = NULL;
1200 entity_association_tree_copy(org_node->first_child,
1201 &((*new_node)->first_child));
1202 entity_association_tree_copy(org_node->next_sibling,
1203 &((*new_node)->next_sibling));
1204}
1205
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301206LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301207void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301208 pldm_entity_association_tree *org_tree,
1209 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301210{
1211 new_tree->last_used_container_id = org_tree->last_used_container_id;
1212 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1213}
1214
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301215LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301217 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218{
1219 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301220 if (!tree) {
1221 return;
1222 }
1223
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224 entity_association_tree_destroy(tree->root);
1225 tree->last_used_container_id = 0;
1226 tree->root = NULL;
1227}
1228
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301229LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1231{
1232 return ((tree->root == NULL) ? true : false);
1233}
1234
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301235LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301236void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1237 size_t *num_entities,
1238 pldm_entity **entities)
1239{
1240 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301241 if (!pdr || !num_entities || !entities) {
1242 return;
1243 }
1244#define PDR_MIN_SIZE \
1245 (sizeof(struct pldm_pdr_hdr) + \
1246 sizeof(struct pldm_pdr_entity_association))
1247 assert(pdr_len >= PDR_MIN_SIZE);
1248 if (pdr_len < PDR_MIN_SIZE) {
1249 return;
1250 }
1251#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301252
1253 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1254 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1255
1256 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301257 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301258 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301259 start += sizeof(struct pldm_pdr_hdr);
1260 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301261 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262 *num_entities = entity_association_pdr->num_children + 1;
1263 assert(*num_entities >= 2);
1264 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1265 assert(*entities != NULL);
1266 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301267 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301268 end);
1269 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301270 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301272 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301274 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301275 pldm_entity *curr_entity = entity_association_pdr->children;
1276 size_t i = 1;
1277 while (i < *num_entities) {
1278 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301281 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301282 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284 ++curr_entity;
1285 ++i;
1286 }
1287}