blob: 01f50021eda68ab1cc3e65d6d019b7aebe14e19e [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{
Andrew Jeffery572a3952023-07-03 13:19:28 +093042 int rc = pldm_pdr_add_check(repo, data, size, is_remote,
43 terminus_handle, &record_handle);
44 (void)rc;
45 assert(!rc);
46 return record_handle;
47}
48
49LIBPLDM_ABI_TESTING
50int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
51 bool is_remote, uint16_t terminus_handle,
52 uint32_t *record_handle)
53{
Andrew Jeffery9c766792022-08-10 23:12:49 +093054 assert(repo != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093055 assert(data != NULL);
Andrew Jeffery9c766792022-08-10 23:12:49 +093056 assert(size != 0);
Andrew Jeffery572a3952023-07-03 13:19:28 +093057 assert(record_handle != NULL);
58 if (!repo || !data || !size || !record_handle) {
59 return -EINVAL;
60 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093061
62 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
63 assert(record != NULL);
Andrew Jeffery572a3952023-07-03 13:19:28 +093064 if (!record) {
65 return -ENOMEM;
66 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093067
Andrew Jeffery572a3952023-07-03 13:19:28 +093068 if (data) {
69 record->data = malloc(size);
70 assert(record->data != NULL);
71 if (!record->data) {
72 free(record);
73 return -ENOMEM;
74 }
75 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093076 }
77
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 record->size = size;
79 record->is_remote = is_remote;
80 record->terminus_handle = terminus_handle;
Andrew Jeffery572a3952023-07-03 13:19:28 +093081
82 if (*record_handle) {
83 record->record_handle = *record_handle;
84 } else {
85 uint32_t curr = repo->last ? repo->last->record_handle : 0;
86 assert(curr != UINT32_MAX);
87 if (curr == UINT32_MAX) {
88 return -EOVERFLOW;
89 }
90 record->record_handle = curr + 1;
91
92 if (data != NULL) {
93 /* If record handle is 0, that is an indication for this API to
94 * compute a new handle. For that reason, the computed handle
95 * needs to be populated in the PDR header. For a case where the
96 * caller supplied the record handle, it would exist in the
97 * header already.
98 */
99 struct pldm_pdr_hdr *hdr = (void *)record->data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100 hdr->record_handle = htole32(record->record_handle);
101 }
102 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930103
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104 record->next = NULL;
105
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930106 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930107 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930108 repo->first = record;
109 repo->last = record;
110 } else {
111 repo->last->next = record;
112 repo->last = record;
113 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930115 repo->size += record->size;
116 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117
Andrew Jeffery572a3952023-07-03 13:19:28 +0930118 *record_handle = record->record_handle;
119
120 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121}
122
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930123LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930124pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930125{
126 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930127 if (!repo) {
128 return NULL;
129 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130 repo->record_count = 0;
131 repo->size = 0;
132 repo->first = NULL;
133 repo->last = NULL;
134
135 return repo;
136}
137
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930138LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930139void pldm_pdr_destroy(pldm_pdr *repo)
140{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930141 if (!repo) {
142 return;
143 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930144
145 pldm_pdr_record *record = repo->first;
146 while (record != NULL) {
147 pldm_pdr_record *next = record->next;
148 if (record->data) {
149 free(record->data);
150 record->data = NULL;
151 }
152 free(record);
153 record = next;
154 }
155 free(repo);
156}
157
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930158LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930159const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
160 uint32_t record_handle,
161 uint8_t **data, uint32_t *size,
162 uint32_t *next_record_handle)
163{
164 assert(repo != NULL);
165 assert(data != NULL);
166 assert(size != NULL);
167 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168 if (!repo || !data || !size || !next_record_handle) {
169 return NULL;
170 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930171
172 if (!record_handle && (repo->first != NULL)) {
173 record_handle = repo->first->record_handle;
174 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930175
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 pldm_pdr_record *record = repo->first;
177 while (record != NULL) {
178 if (record->record_handle == record_handle) {
179 *size = record->size;
180 *data = record->data;
181 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930182 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930183 return record;
184 }
185 record = record->next;
186 }
187
188 *size = 0;
189 *next_record_handle = 0;
190 return NULL;
191}
192
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930193LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930194const pldm_pdr_record *
195pldm_pdr_get_next_record(const pldm_pdr *repo,
196 const pldm_pdr_record *curr_record, uint8_t **data,
197 uint32_t *size, uint32_t *next_record_handle)
198{
199 assert(repo != NULL);
200 assert(curr_record != NULL);
201 assert(data != NULL);
202 assert(size != NULL);
203 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930204 if (!repo || !curr_record || !data || !size || !next_record_handle) {
205 return NULL;
206 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930207
208 if (curr_record == repo->last) {
209 *data = NULL;
210 *size = 0;
211 *next_record_handle = get_next_record_handle(repo, curr_record);
212 return NULL;
213 }
214
215 *next_record_handle = get_next_record_handle(repo, curr_record->next);
216 *data = curr_record->next->data;
217 *size = curr_record->next->size;
218 return curr_record->next;
219}
220
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930221LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222const pldm_pdr_record *
223pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
224 const pldm_pdr_record *curr_record, uint8_t **data,
225 uint32_t *size)
226{
227 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930228 if (!repo) {
229 return NULL;
230 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930231
232 pldm_pdr_record *record = repo->first;
233 if (curr_record != NULL) {
234 record = curr_record->next;
235 }
236 while (record != NULL) {
237 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
238 if (hdr->type == pdr_type) {
239 if (data && size) {
240 *size = record->size;
241 *data = record->data;
242 }
243 return record;
244 }
245 record = record->next;
246 }
247
248 if (size) {
249 *size = 0;
250 }
251 return NULL;
252}
253
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930254LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930255uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
256{
257 assert(repo != NULL);
258
259 return repo->record_count;
260}
261
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930262LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930263uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
264{
265 assert(repo != NULL);
266
267 return repo->size;
268}
269
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930270LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930271uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
272 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930273 const pldm_pdr_record *record)
274{
275 assert(repo != NULL);
276 assert(record != NULL);
277
278 return record->record_handle;
279}
280
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930281LIBPLDM_ABI_STABLE
282bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283{
284 assert(record != NULL);
285
286 return record->is_remote;
287}
288
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930289LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
291 uint16_t fru_rsi, uint16_t entity_type,
292 uint16_t entity_instance_num,
293 uint16_t container_id,
294 uint32_t bmc_record_handle)
295{
296 uint32_t size = sizeof(struct pldm_pdr_hdr) +
297 sizeof(struct pldm_pdr_fru_record_set);
298 uint8_t data[size];
299
300 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
301 hdr->version = 1;
302 hdr->record_handle = bmc_record_handle;
303 hdr->type = PLDM_PDR_FRU_RECORD_SET;
304 hdr->record_change_num = 0;
305 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
306 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930307 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
308 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930309 fru->terminus_handle = htole16(terminus_handle);
310 fru->fru_rsi = htole16(fru_rsi);
311 fru->entity_type = htole16(entity_type);
312 fru->entity_instance_num = htole16(entity_instance_num);
313 fru->container_id = htole16(container_id);
314
315 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
316 terminus_handle);
317}
318
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930319LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930320const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
322 uint16_t *entity_type, uint16_t *entity_instance_num,
323 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324{
325 assert(terminus_handle != NULL);
326 assert(entity_type != NULL);
327 assert(entity_instance_num != NULL);
328 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930329 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
330 !container_id) {
331 return NULL;
332 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333
334 uint8_t *data = NULL;
335 uint32_t size = 0;
336 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930337 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338 while (curr_record != NULL) {
339 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930340 (struct pldm_pdr_fru_record_set
341 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 if (fru->fru_rsi == htole16(fru_rsi)) {
343 *terminus_handle = le16toh(fru->terminus_handle);
344 *entity_type = le16toh(fru->entity_type);
345 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930346 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347 *container_id = le16toh(fru->container_id);
348 return curr_record;
349 }
350 data = NULL;
351 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
353 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354 }
355
356 *terminus_handle = 0;
357 *entity_type = 0;
358 *entity_instance_num = 0;
359 *container_id = 0;
360
361 return NULL;
362}
363
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930364LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930365/* NOLINTNEXTLINE(readability-identifier-naming) */
366void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
367 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930368{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370 uint32_t size = 0;
371 const pldm_pdr_record *record;
372 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930373 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374
375 do {
376 if (record != NULL) {
377 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930378 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930380 (struct pldm_terminus_locator_type_mctp_eid *)
381 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930382 if (pdr->terminus_handle == terminus_handle &&
383 pdr->tid == tid && value->eid == tl_eid) {
384 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930385 break;
386 }
387 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930388 record = pldm_pdr_find_record_by_type(repo,
389 PLDM_TERMINUS_LOCATOR_PDR,
390 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930391 } while (record);
392}
393
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500394static bool pldm_record_handle_in_range(uint32_t record_handle,
395 uint32_t first_record_handle,
396 uint32_t last_record_handle)
397{
398 return record_handle >= first_record_handle &&
399 record_handle <= last_record_handle;
400}
401
402LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500403int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500404 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500405 uint8_t child_index, uint32_t range_exclude_start_handle,
406 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500407{
408 pldm_pdr_record *record;
409 if (!repo) {
410 return -EINVAL;
411 }
412
413 for (record = repo->first; record; record = record->next) {
414 bool is_container_entity_instance_number;
415 struct pldm_pdr_entity_association *pdr;
416 bool is_container_entity_type;
417 struct pldm_entity *child;
418 struct pldm_pdr_hdr *hdr;
419 bool in_range;
420
421 // pldm_pdr_add() takes only uint8_t* data as an argument.
422 // The expectation here is the pldm_pdr_hdr is the first field of the record data
423 hdr = (struct pldm_pdr_hdr *)record->data;
424 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
425 continue;
426 }
427 in_range = pldm_record_handle_in_range(
428 record->record_handle, range_exclude_start_handle,
429 range_exclude_end_handle);
430 if (in_range) {
431 continue;
432 }
433
434 // this cast is valid with respect to alignment because
435 // struct pldm_pdr_hdr is declared with __attribute__((packed))
436 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500437 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500438 continue;
439 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500440
441 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500442 is_container_entity_type = pdr->container.entity_type ==
443 entity_type;
444 is_container_entity_instance_number =
445 pdr->container.entity_instance_num == entity_instance;
446 if (is_container_entity_type &&
447 is_container_entity_instance_number) {
448 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500449 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500450 }
451 }
452 return -ENOKEY;
453}
454
Andrew Jeffery9c766792022-08-10 23:12:49 +0930455typedef struct pldm_entity_association_tree {
456 pldm_entity_node *root;
457 uint16_t last_used_container_id;
458} pldm_entity_association_tree;
459
460typedef struct pldm_entity_node {
461 pldm_entity entity;
462 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600463 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930464 pldm_entity_node *first_child;
465 pldm_entity_node *next_sibling;
466 uint8_t association_type;
467} pldm_entity_node;
468
469static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
470{
471 assert(tree != NULL);
472 assert(tree->last_used_container_id != UINT16_MAX);
473
474 return ++tree->last_used_container_id;
475}
476
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930477LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930478pldm_entity pldm_entity_extract(pldm_entity_node *node)
479{
480 assert(node != NULL);
481
482 return node->entity;
483}
484
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600485LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930486uint16_t
487pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600488{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930489 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600490
Andrew Jeffery15b88182023-06-30 13:29:17 +0930491 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600492}
493
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930494LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930495pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930496{
497 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930498 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930499 if (!tree) {
500 return NULL;
501 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502 tree->root = NULL;
503 tree->last_used_container_id = 0;
504
505 return tree;
506}
507
508static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
509 uint16_t entity_type)
510{
511 assert(start != NULL);
512
513 /* Insert after the the last node that matches the input entity type, or
514 * at the end if no such match occurrs
515 */
516 while (start->next_sibling != NULL) {
517 uint16_t this_type = start->entity.entity_type;
518 pldm_entity_node *next = start->next_sibling;
519 if (this_type == entity_type &&
520 (this_type != next->entity.entity_type)) {
521 break;
522 }
523 start = start->next_sibling;
524 }
525
526 return start;
527}
528
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930529LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930530pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930531 pldm_entity_association_tree *tree, pldm_entity *entity,
532 uint16_t entity_instance_number, pldm_entity_node *parent,
533 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930534{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500535 return pldm_entity_association_tree_add_entity(tree, entity,
536 entity_instance_number,
537 parent, association_type,
538 false, true, 0xFFFF);
539}
540
541LIBPLDM_ABI_TESTING
542pldm_entity_node *pldm_entity_association_tree_add_entity(
543 pldm_entity_association_tree *tree, pldm_entity *entity,
544 uint16_t entity_instance_number, pldm_entity_node *parent,
545 uint8_t association_type, bool is_remote, bool is_update_container_id,
546 uint16_t container_id)
547{
548 if ((!tree) || (!entity)) {
549 return NULL;
550 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551
552 if (entity_instance_number != 0xFFFF && parent != NULL) {
553 pldm_entity node;
554 node.entity_type = entity->entity_type;
555 node.entity_instance_num = entity_instance_number;
556 if (pldm_is_current_parent_child(parent, &node)) {
557 return NULL;
558 }
559 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500560 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
561 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
562 return NULL;
563 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500565 if (!node) {
566 return NULL;
567 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930568 node->first_child = NULL;
569 node->next_sibling = NULL;
570 node->parent.entity_type = 0;
571 node->parent.entity_instance_num = 0;
572 node->parent.entity_container_id = 0;
573 node->entity.entity_type = entity->entity_type;
574 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930575 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600577 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500579 if (parent != NULL) {
580 free(node);
581 return NULL;
582 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583 tree->root = node;
584 /* container_id 0 here indicates this is the top-most entry */
585 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600586 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930587 } else if (parent != NULL && parent->first_child == NULL) {
588 parent->first_child = node;
589 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500590
591 if (is_remote) {
592 node->remote_container_id = entity->entity_container_id;
593 }
594 if (is_update_container_id) {
595 if (container_id != 0xFFFF) {
596 node->entity.entity_container_id = container_id;
597 } else {
598 node->entity.entity_container_id =
599 next_container_id(tree);
600 }
601 } else {
602 node->entity.entity_container_id =
603 entity->entity_container_id;
604 }
605
606 if (!is_remote) {
607 node->remote_container_id =
608 node->entity.entity_container_id;
609 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930611 pldm_entity_node *start = parent == NULL ? tree->root :
612 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930614 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500615 if (!prev) {
616 free(node);
617 return NULL;
618 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930619 pldm_entity_node *next = prev->next_sibling;
620 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500621 if (prev->entity.entity_instance_num == UINT16_MAX) {
622 free(node);
623 return NULL;
624 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930626 entity_instance_number != 0xFFFF ?
627 entity_instance_number :
628 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 }
630 prev->next_sibling = node;
631 node->parent = prev->parent;
632 node->next_sibling = next;
633 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930634 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600635 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930636 }
637 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500638 if (is_update_container_id) {
639 entity->entity_container_id = node->entity.entity_container_id;
640 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930641 return node;
642}
643
644static void get_num_nodes(pldm_entity_node *node, size_t *num)
645{
646 if (node == NULL) {
647 return;
648 }
649
650 ++(*num);
651 get_num_nodes(node->next_sibling, num);
652 get_num_nodes(node->first_child, num);
653}
654
655static void entity_association_tree_visit(pldm_entity_node *node,
656 pldm_entity *entities, size_t *index)
657{
658 if (node == NULL) {
659 return;
660 }
661
662 pldm_entity *entity = &entities[*index];
663 ++(*index);
664 entity->entity_type = node->entity.entity_type;
665 entity->entity_instance_num = node->entity.entity_instance_num;
666 entity->entity_container_id = node->entity.entity_container_id;
667
668 entity_association_tree_visit(node->next_sibling, entities, index);
669 entity_association_tree_visit(node->first_child, entities, index);
670}
671
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930672LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
674 pldm_entity **entities, size_t *size)
675{
676 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930677 if (!tree || !entities || !size) {
678 return;
679 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680
681 *size = 0;
682 if (tree->root == NULL) {
683 return;
684 }
685
686 get_num_nodes(tree->root, size);
687 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930688 if (!entities) {
689 return;
690 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691 size_t index = 0;
692 entity_association_tree_visit(tree->root, *entities, &index);
693}
694
695static void entity_association_tree_destroy(pldm_entity_node *node)
696{
697 if (node == NULL) {
698 return;
699 }
700
701 entity_association_tree_destroy(node->next_sibling);
702 entity_association_tree_destroy(node->first_child);
703 free(node);
704}
705
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930706LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
708{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930709 if (!tree) {
710 return;
711 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712
713 entity_association_tree_destroy(tree->root);
714 free(tree);
715}
716
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930717LIBPLDM_ABI_STABLE
718bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719{
720 assert(node != NULL);
721
722 return node->first_child != NULL;
723}
724
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930725LIBPLDM_ABI_STABLE
726pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727{
728 assert(node != NULL);
729
730 return node->parent;
731}
732
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930733LIBPLDM_ABI_STABLE
734bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735{
736 assert(node != NULL);
737
738 if (node->parent.entity_type == 0 &&
739 node->parent.entity_instance_num == 0 &&
740 node->parent.entity_container_id == 0) {
741 return false;
742 }
743
744 return true;
745}
746
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930747LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
749 uint8_t association_type)
750{
751 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930752 if (!node) {
753 return 0;
754 }
755
Andrew Jeffery9c766792022-08-10 23:12:49 +0930756 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
757 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930758 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
759 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
760 return 0;
761 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930762
763 size_t count = 0;
764 pldm_entity_node *curr = node->first_child;
765 while (curr != NULL) {
766 if (curr->association_type == association_type) {
767 ++count;
768 }
769 curr = curr->next_sibling;
770 }
771
772 assert(count < UINT8_MAX);
773 return count;
774}
775
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930776LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
778{
779 assert(parent != NULL);
780 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930781 if (!parent || !node) {
782 return false;
783 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930784
785 pldm_entity_node *curr = parent->first_child;
786 while (curr != NULL) {
787 if (node->entity_type == curr->entity.entity_type &&
788 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930789 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930790 return true;
791 }
792 curr = curr->next_sibling;
793 }
794
795 return false;
796}
797
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500798static void entity_association_pdr_add_children(
799 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
800 uint8_t contained_count, uint8_t association_type, bool is_remote,
801 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802{
803 uint8_t pdr[size];
804 uint8_t *start = pdr;
805
806 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
807 hdr->version = 1;
808 hdr->record_handle = 0;
809 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
810 hdr->record_change_num = 0;
811 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
812 start += sizeof(struct pldm_pdr_hdr);
813
814 uint16_t *container_id = (uint16_t *)start;
815 *container_id = htole16(curr->first_child->entity.entity_container_id);
816 start += sizeof(uint16_t);
817 *start = association_type;
818 start += sizeof(uint8_t);
819
820 pldm_entity *entity = (pldm_entity *)start;
821 entity->entity_type = htole16(curr->entity.entity_type);
822 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
823 entity->entity_container_id = htole16(curr->entity.entity_container_id);
824 start += sizeof(pldm_entity);
825
826 *start = contained_count;
827 start += sizeof(uint8_t);
828
829 pldm_entity_node *node = curr->first_child;
830 while (node != NULL) {
831 if (node->association_type == association_type) {
832 pldm_entity *entity = (pldm_entity *)start;
833 entity->entity_type = htole16(node->entity.entity_type);
834 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930835 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930837 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838 start += sizeof(pldm_entity);
839 }
840 node = node->next_sibling;
841 }
842
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500843 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
844 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930845}
846
847static void entity_association_pdr_add_entry(pldm_entity_node *curr,
848 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500849 uint16_t terminus_handle,
850 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930851{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 uint8_t num_logical_children = pldm_entity_get_num_children(
853 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
854 uint8_t num_physical_children = pldm_entity_get_num_children(
855 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856
857 if (num_logical_children) {
858 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930859 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
860 sizeof(uint8_t) + sizeof(pldm_entity) +
861 sizeof(uint8_t) +
862 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930863 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930864 curr, repo, logical_pdr_size, num_logical_children,
865 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500866 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930867 }
868
869 if (num_physical_children) {
870 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930871 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
872 sizeof(uint8_t) + sizeof(pldm_entity) +
873 sizeof(uint8_t) +
874 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930875 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930876 curr, repo, physical_pdr_size, num_physical_children,
877 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500878 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930879 }
880}
881
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930882LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930883bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
884{
885 if (entities == NULL || num_entities == 0) {
886 return true;
887 }
888 size_t i = 0;
889 while (i < num_entities) {
890 if ((*entities + i)->entity_type == entity.entity_type) {
891 return true;
892 }
893 i++;
894 }
895 return false;
896}
897
898static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
899 pldm_entity **entities,
900 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500901 uint16_t terminus_handle,
902 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903{
904 if (curr == NULL) {
905 return;
906 }
907 bool to_add = true;
908 to_add = is_present(curr->entity, entities, num_entities);
909 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500910 entity_association_pdr_add_entry(
911 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912 }
913 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500914 num_entities, is_remote, terminus_handle,
915 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500917 num_entities, is_remote, terminus_handle,
918 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919}
920
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930921LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930922void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
923 pldm_pdr *repo, bool is_remote,
924 uint16_t terminus_handle)
925{
926 assert(tree != NULL);
927 assert(repo != NULL);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930928 if (!tree || !repo) {
929 return;
930 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931
932 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500933 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934}
935
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930936LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930938 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
939 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940{
Andrew Jefferycc394522023-07-03 12:49:31 +0930941 int rc = pldm_entity_association_pdr_add_from_node_check(
942 node, repo, entities, num_entities, is_remote, terminus_handle);
943 (void)rc;
944 assert(!rc);
945}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946
Andrew Jefferycc394522023-07-03 12:49:31 +0930947LIBPLDM_ABI_TESTING
948int pldm_entity_association_pdr_add_from_node_check(
949 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
950 size_t num_entities, bool is_remote, uint16_t terminus_handle)
951{
952 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500953 node, repo, entities, num_entities, is_remote, terminus_handle,
954 0);
955}
956
957LIBPLDM_ABI_TESTING
958int pldm_entity_association_pdr_add_from_node_with_record_handle(
959 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
960 size_t num_entities, bool is_remote, uint16_t terminus_handle,
961 uint32_t record_handle)
962{
963 if (!node || !repo || !entities) {
964 return -EINVAL;
965 }
966
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500968 is_remote, terminus_handle, record_handle);
969
970 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971}
972
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930973LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
975 pldm_entity_node **node)
976{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600977 bool is_entity_container_id;
978 bool is_entity_instance_num;
979 bool is_type;
980
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 if (tree_node == NULL) {
982 return;
983 }
984
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600985 is_type = tree_node->entity.entity_type == entity.entity_type;
986 is_entity_instance_num = tree_node->entity.entity_instance_num ==
987 entity.entity_instance_num;
988 is_entity_container_id = tree_node->entity.entity_container_id ==
989 entity.entity_container_id;
990
991 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930992 *node = tree_node;
993 return;
994 }
995
996 find_entity_ref_in_tree(tree_node->first_child, entity, node);
997 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
998}
999
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1002 pldm_entity entity, pldm_entity_node **node)
1003{
1004 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +09301005 if (!tree || !node) {
1006 return;
1007 }
1008
Andrew Jeffery9c766792022-08-10 23:12:49 +09301009 find_entity_ref_in_tree(tree->root, entity, node);
1010}
1011
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301012LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1014 uint16_t terminus_handle)
1015{
1016 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +09301017 if (!repo) {
1018 return;
1019 }
1020
Andrew Jeffery9c766792022-08-10 23:12:49 +09301021 bool removed = false;
1022
1023 pldm_pdr_record *record = repo->first;
1024 pldm_pdr_record *prev = NULL;
1025 while (record != NULL) {
1026 pldm_pdr_record *next = record->next;
1027 if (record->terminus_handle == terminus_handle) {
1028 if (repo->first == record) {
1029 repo->first = next;
1030 } else {
1031 prev->next = next;
1032 }
1033 if (repo->last == record) {
1034 repo->last = prev;
1035 }
1036 if (record->data) {
1037 free(record->data);
1038 }
1039 --repo->record_count;
1040 repo->size -= record->size;
1041 free(record);
1042 removed = true;
1043 } else {
1044 prev = record;
1045 }
1046 record = next;
1047 }
1048
1049 if (removed == true) {
1050 record = repo->first;
1051 uint32_t record_handle = 0;
1052 while (record != NULL) {
1053 record->record_handle = ++record_handle;
1054 if (record->data != NULL) {
1055 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301056 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301058 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059 }
1060 record = record->next;
1061 }
1062 }
1063}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301064
1065LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301066void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1067{
1068 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301069 if (!repo) {
1070 return;
1071 }
1072
Andrew Jeffery9c766792022-08-10 23:12:49 +09301073 bool removed = false;
1074
1075 pldm_pdr_record *record = repo->first;
1076 pldm_pdr_record *prev = NULL;
1077 while (record != NULL) {
1078 pldm_pdr_record *next = record->next;
1079 if (record->is_remote == true) {
1080 if (repo->first == record) {
1081 repo->first = next;
1082 } else {
1083 prev->next = next;
1084 }
1085 if (repo->last == record) {
1086 repo->last = prev;
1087 }
1088 if (record->data) {
1089 free(record->data);
1090 }
1091 --repo->record_count;
1092 repo->size -= record->size;
1093 free(record);
1094 removed = true;
1095 } else {
1096 prev = record;
1097 }
1098 record = next;
1099 }
1100
1101 if (removed == true) {
1102 record = repo->first;
1103 uint32_t record_handle = 0;
1104 while (record != NULL) {
1105 record->record_handle = ++record_handle;
1106 if (record->data != NULL) {
1107 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301108 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301110 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301111 }
1112 record = record->next;
1113 }
1114 }
1115}
1116
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001117LIBPLDM_ABI_TESTING
1118pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1119 uint32_t first, uint32_t last)
1120{
1121 pldm_pdr_record *record = NULL;
1122 pldm_pdr_record *curr;
1123
1124 if (!repo) {
1125 return NULL;
1126 }
1127 for (curr = repo->first; curr; curr = curr->next) {
1128 if (first > curr->record_handle || last < curr->record_handle) {
1129 continue;
1130 }
1131 if (!record || curr->record_handle > record->record_handle) {
1132 record = curr;
1133 }
1134 }
1135
1136 return record;
1137}
1138
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001139static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1140 pldm_entity *entity,
1141 pldm_entity_node **out,
1142 bool is_remote)
1143{
1144 assert(out != NULL && *out == NULL);
1145 if (node == NULL) {
1146 return;
1147 }
1148 bool is_entity_type;
1149 bool is_entity_instance_num;
1150
1151 is_entity_type = node->entity.entity_type == entity->entity_type;
1152 is_entity_instance_num = node->entity.entity_instance_num ==
1153 entity->entity_instance_num;
1154
1155 if (!is_remote ||
1156 node->remote_container_id == entity->entity_container_id) {
1157 if (is_entity_type && is_entity_instance_num) {
1158 entity->entity_container_id =
1159 node->entity.entity_container_id;
1160 *out = node;
1161 return;
1162 }
1163 }
1164 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1165 is_remote);
1166 entity_association_tree_find_if_remote(node->first_child, entity, out,
1167 is_remote);
1168}
1169
1170LIBPLDM_ABI_TESTING
1171pldm_entity_node *
1172pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1173 pldm_entity *entity, bool is_remote)
1174{
1175 if (!tree || !entity) {
1176 return NULL;
1177 }
1178 pldm_entity_node *node = NULL;
1179 entity_association_tree_find_if_remote(tree->root, entity, &node,
1180 is_remote);
1181 return node;
1182}
1183
Andrew Jeffery7f589312023-07-03 12:03:25 +09301184LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301185void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1186 pldm_entity_node **out)
1187{
1188 if (node == NULL) {
1189 return;
1190 }
1191
1192 if (node->entity.entity_type == entity->entity_type &&
1193 node->entity.entity_instance_num == entity->entity_instance_num) {
1194 entity->entity_container_id = node->entity.entity_container_id;
1195 *out = node;
1196 return;
1197 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198 entity_association_tree_find(node->next_sibling, entity, out);
1199 entity_association_tree_find(node->first_child, entity, out);
1200}
1201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301202LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203pldm_entity_node *
1204pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1205 pldm_entity *entity)
1206{
1207 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301208 if (!tree || !entity) {
1209 return NULL;
1210 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301211
1212 pldm_entity_node *node = NULL;
1213 entity_association_tree_find(tree->root, entity, &node);
1214 return node;
1215}
1216
1217static void entity_association_tree_copy(pldm_entity_node *org_node,
1218 pldm_entity_node **new_node)
1219{
1220 if (org_node == NULL) {
1221 return;
1222 }
1223 *new_node = malloc(sizeof(pldm_entity_node));
1224 (*new_node)->parent = org_node->parent;
1225 (*new_node)->entity = org_node->entity;
1226 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001227 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 (*new_node)->first_child = NULL;
1229 (*new_node)->next_sibling = NULL;
1230 entity_association_tree_copy(org_node->first_child,
1231 &((*new_node)->first_child));
1232 entity_association_tree_copy(org_node->next_sibling,
1233 &((*new_node)->next_sibling));
1234}
1235
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301236LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301238 pldm_entity_association_tree *org_tree,
1239 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240{
1241 new_tree->last_used_container_id = org_tree->last_used_container_id;
1242 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1243}
1244
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301245LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301246void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301247 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301248{
1249 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301250 if (!tree) {
1251 return;
1252 }
1253
Andrew Jeffery9c766792022-08-10 23:12:49 +09301254 entity_association_tree_destroy(tree->root);
1255 tree->last_used_container_id = 0;
1256 tree->root = NULL;
1257}
1258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301259LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301260bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1261{
1262 return ((tree->root == NULL) ? true : false);
1263}
1264
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301265LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301266void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1267 size_t *num_entities,
1268 pldm_entity **entities)
1269{
1270 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301271 if (!pdr || !num_entities || !entities) {
1272 return;
1273 }
1274#define PDR_MIN_SIZE \
1275 (sizeof(struct pldm_pdr_hdr) + \
1276 sizeof(struct pldm_pdr_entity_association))
1277 assert(pdr_len >= PDR_MIN_SIZE);
1278 if (pdr_len < PDR_MIN_SIZE) {
1279 return;
1280 }
1281#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301282
1283 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1284 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1285
1286 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301287 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289 start += sizeof(struct pldm_pdr_hdr);
1290 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301291 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301292 *num_entities = entity_association_pdr->num_children + 1;
1293 assert(*num_entities >= 2);
1294 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1295 assert(*entities != NULL);
1296 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301297 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301298 end);
1299 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301300 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301301 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301302 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301303 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301304 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301305 pldm_entity *curr_entity = entity_association_pdr->children;
1306 size_t i = 1;
1307 while (i < *num_entities) {
1308 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301309 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301310 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301311 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301312 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301313 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301314 ++curr_entity;
1315 ++i;
1316 }
1317}