blob: 5012d8820937c95cf70ade0b10faacc0fd13d492 [file] [log] [blame]
Andrew Jeffery9c766792022-08-10 23:12:49 +09301#include "pdr.h"
2#include "platform.h"
3#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05304#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <stdlib.h>
6#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06007#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308
9typedef struct pldm_pdr_record {
10 uint32_t record_handle;
11 uint32_t size;
12 uint8_t *data;
13 struct pldm_pdr_record *next;
14 bool is_remote;
15 uint16_t terminus_handle;
16} pldm_pdr_record;
17
18typedef struct pldm_pdr {
19 uint32_t record_count;
20 uint32_t size;
21 pldm_pdr_record *first;
22 pldm_pdr_record *last;
23} pldm_pdr;
24
25static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
26 const pldm_pdr_record *record)
27{
28 assert(repo != NULL);
29 assert(record != NULL);
30
31 if (record == repo->last) {
32 return 0;
33 }
34 return record->next->record_handle;
35}
36
37static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
38{
39 assert(repo != NULL);
40 assert(record != NULL);
41
42 if (repo->first == NULL) {
43 assert(repo->last == NULL);
44 repo->first = record;
45 repo->last = record;
46 } else {
47 repo->last->next = record;
48 repo->last = record;
49 }
50 repo->size += record->size;
51 ++repo->record_count;
52}
53
54static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
55{
56 assert(repo != NULL);
57 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093058 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093059 assert(last_used_hdl != UINT32_MAX);
60
61 return last_used_hdl + 1;
62}
63
64static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
65 const uint8_t *data, uint32_t size,
66 uint32_t record_handle, bool is_remote,
67 uint16_t terminus_handle)
68{
69 assert(repo != NULL);
70 assert(size != 0);
71
72 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
73 assert(record != NULL);
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093074 record->record_handle = record_handle == 0 ?
75 get_new_record_handle(repo) :
76 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093077 record->size = size;
78 record->is_remote = is_remote;
79 record->terminus_handle = terminus_handle;
80 if (data != NULL) {
81 record->data = malloc(size);
82 assert(record->data != NULL);
83 memcpy(record->data, data, size);
84 /* If record handle is 0, that is an indication for this API to
85 * compute a new handle. For that reason, the computed handle
86 * needs to be populated in the PDR header. For a case where the
87 * caller supplied the record handle, it would exist in the
88 * header already.
89 */
90 if (!record_handle) {
91 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093092 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093093 hdr->record_handle = htole32(record->record_handle);
94 }
95 }
96 record->next = NULL;
97
98 return record;
99}
100
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930101LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
103 uint32_t record_handle, bool is_remote,
104 uint16_t terminus_handle)
105{
106 assert(size != 0);
107 assert(data != NULL);
108
109 pldm_pdr_record *record = make_new_record(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930110 repo, data, size, record_handle, is_remote, terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111 add_record(repo, record);
112
113 return record->record_handle;
114}
115
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930116LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930117pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118{
119 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930120 if (!repo) {
121 return NULL;
122 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123 repo->record_count = 0;
124 repo->size = 0;
125 repo->first = NULL;
126 repo->last = NULL;
127
128 return repo;
129}
130
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930131LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132void pldm_pdr_destroy(pldm_pdr *repo)
133{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930134 if (!repo) {
135 return;
136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137
138 pldm_pdr_record *record = repo->first;
139 while (record != NULL) {
140 pldm_pdr_record *next = record->next;
141 if (record->data) {
142 free(record->data);
143 record->data = NULL;
144 }
145 free(record);
146 record = next;
147 }
148 free(repo);
149}
150
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930151LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930152const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
153 uint32_t record_handle,
154 uint8_t **data, uint32_t *size,
155 uint32_t *next_record_handle)
156{
157 assert(repo != NULL);
158 assert(data != NULL);
159 assert(size != NULL);
160 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930161 if (!repo || !data || !size || !next_record_handle) {
162 return NULL;
163 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164
165 if (!record_handle && (repo->first != NULL)) {
166 record_handle = repo->first->record_handle;
167 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 pldm_pdr_record *record = repo->first;
170 while (record != NULL) {
171 if (record->record_handle == record_handle) {
172 *size = record->size;
173 *data = record->data;
174 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 return record;
177 }
178 record = record->next;
179 }
180
181 *size = 0;
182 *next_record_handle = 0;
183 return NULL;
184}
185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187const pldm_pdr_record *
188pldm_pdr_get_next_record(const pldm_pdr *repo,
189 const pldm_pdr_record *curr_record, uint8_t **data,
190 uint32_t *size, uint32_t *next_record_handle)
191{
192 assert(repo != NULL);
193 assert(curr_record != NULL);
194 assert(data != NULL);
195 assert(size != NULL);
196 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930197 if (!repo || !curr_record || !data || !size || !next_record_handle) {
198 return NULL;
199 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930200
201 if (curr_record == repo->last) {
202 *data = NULL;
203 *size = 0;
204 *next_record_handle = get_next_record_handle(repo, curr_record);
205 return NULL;
206 }
207
208 *next_record_handle = get_next_record_handle(repo, curr_record->next);
209 *data = curr_record->next->data;
210 *size = curr_record->next->size;
211 return curr_record->next;
212}
213
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930214LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930215const pldm_pdr_record *
216pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
217 const pldm_pdr_record *curr_record, uint8_t **data,
218 uint32_t *size)
219{
220 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930221 if (!repo) {
222 return NULL;
223 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224
225 pldm_pdr_record *record = repo->first;
226 if (curr_record != NULL) {
227 record = curr_record->next;
228 }
229 while (record != NULL) {
230 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
231 if (hdr->type == pdr_type) {
232 if (data && size) {
233 *size = record->size;
234 *data = record->data;
235 }
236 return record;
237 }
238 record = record->next;
239 }
240
241 if (size) {
242 *size = 0;
243 }
244 return NULL;
245}
246
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930247LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
249{
250 assert(repo != NULL);
251
252 return repo->record_count;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
257{
258 assert(repo != NULL);
259
260 return repo->size;
261}
262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930263LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930264uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
265 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930266 const pldm_pdr_record *record)
267{
268 assert(repo != NULL);
269 assert(record != NULL);
270
271 return record->record_handle;
272}
273
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930274LIBPLDM_ABI_STABLE
275bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930276{
277 assert(record != NULL);
278
279 return record->is_remote;
280}
281
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930282LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
284 uint16_t fru_rsi, uint16_t entity_type,
285 uint16_t entity_instance_num,
286 uint16_t container_id,
287 uint32_t bmc_record_handle)
288{
289 uint32_t size = sizeof(struct pldm_pdr_hdr) +
290 sizeof(struct pldm_pdr_fru_record_set);
291 uint8_t data[size];
292
293 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
294 hdr->version = 1;
295 hdr->record_handle = bmc_record_handle;
296 hdr->type = PLDM_PDR_FRU_RECORD_SET;
297 hdr->record_change_num = 0;
298 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
299 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930300 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
301 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302 fru->terminus_handle = htole16(terminus_handle);
303 fru->fru_rsi = htole16(fru_rsi);
304 fru->entity_type = htole16(entity_type);
305 fru->entity_instance_num = htole16(entity_instance_num);
306 fru->container_id = htole16(container_id);
307
308 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
309 terminus_handle);
310}
311
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930312LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
315 uint16_t *entity_type, uint16_t *entity_instance_num,
316 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317{
318 assert(terminus_handle != NULL);
319 assert(entity_type != NULL);
320 assert(entity_instance_num != NULL);
321 assert(container_id != NULL);
322
323 uint8_t *data = NULL;
324 uint32_t size = 0;
325 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930326 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930327 while (curr_record != NULL) {
328 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930329 (struct pldm_pdr_fru_record_set
330 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930331 if (fru->fru_rsi == htole16(fru_rsi)) {
332 *terminus_handle = le16toh(fru->terminus_handle);
333 *entity_type = le16toh(fru->entity_type);
334 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930335 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930336 *container_id = le16toh(fru->container_id);
337 return curr_record;
338 }
339 data = NULL;
340 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
342 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343 }
344
345 *terminus_handle = 0;
346 *entity_type = 0;
347 *entity_instance_num = 0;
348 *container_id = 0;
349
350 return NULL;
351}
352
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930353LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930354/* NOLINTNEXTLINE(readability-identifier-naming) */
355void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
356 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930357{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930358 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 uint32_t size = 0;
360 const pldm_pdr_record *record;
361 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930362 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363
364 do {
365 if (record != NULL) {
366 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930367 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930368 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930369 (struct pldm_terminus_locator_type_mctp_eid *)
370 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930371 if (pdr->terminus_handle == terminus_handle &&
372 pdr->tid == tid && value->eid == tl_eid) {
373 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 break;
375 }
376 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930377 record = pldm_pdr_find_record_by_type(repo,
378 PLDM_TERMINUS_LOCATOR_PDR,
379 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 } while (record);
381}
382
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500383static bool pldm_record_handle_in_range(uint32_t record_handle,
384 uint32_t first_record_handle,
385 uint32_t last_record_handle)
386{
387 return record_handle >= first_record_handle &&
388 record_handle <= last_record_handle;
389}
390
391LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500392int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500393 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500394 uint8_t child_index, uint32_t range_exclude_start_handle,
395 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500396{
397 pldm_pdr_record *record;
398 if (!repo) {
399 return -EINVAL;
400 }
401
402 for (record = repo->first; record; record = record->next) {
403 bool is_container_entity_instance_number;
404 struct pldm_pdr_entity_association *pdr;
405 bool is_container_entity_type;
406 struct pldm_entity *child;
407 struct pldm_pdr_hdr *hdr;
408 bool in_range;
409
410 // pldm_pdr_add() takes only uint8_t* data as an argument.
411 // The expectation here is the pldm_pdr_hdr is the first field of the record data
412 hdr = (struct pldm_pdr_hdr *)record->data;
413 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
414 continue;
415 }
416 in_range = pldm_record_handle_in_range(
417 record->record_handle, range_exclude_start_handle,
418 range_exclude_end_handle);
419 if (in_range) {
420 continue;
421 }
422
423 // this cast is valid with respect to alignment because
424 // struct pldm_pdr_hdr is declared with __attribute__((packed))
425 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500426 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500427 continue;
428 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500429
430 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500431 is_container_entity_type = pdr->container.entity_type ==
432 entity_type;
433 is_container_entity_instance_number =
434 pdr->container.entity_instance_num == entity_instance;
435 if (is_container_entity_type &&
436 is_container_entity_instance_number) {
437 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500438 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500439 }
440 }
441 return -ENOKEY;
442}
443
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444typedef struct pldm_entity_association_tree {
445 pldm_entity_node *root;
446 uint16_t last_used_container_id;
447} pldm_entity_association_tree;
448
449typedef struct pldm_entity_node {
450 pldm_entity entity;
451 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600452 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930453 pldm_entity_node *first_child;
454 pldm_entity_node *next_sibling;
455 uint8_t association_type;
456} pldm_entity_node;
457
458static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
459{
460 assert(tree != NULL);
461 assert(tree->last_used_container_id != UINT16_MAX);
462
463 return ++tree->last_used_container_id;
464}
465
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930466LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930467pldm_entity pldm_entity_extract(pldm_entity_node *node)
468{
469 assert(node != NULL);
470
471 return node->entity;
472}
473
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600474LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930475uint16_t
476pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600477{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930478 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600479
Andrew Jeffery15b88182023-06-30 13:29:17 +0930480 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600481}
482
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930483LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930484pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930485{
486 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930487 malloc(sizeof(pldm_entity_association_tree));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930488 assert(tree != NULL);
489 tree->root = NULL;
490 tree->last_used_container_id = 0;
491
492 return tree;
493}
494
495static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
496 uint16_t entity_type)
497{
498 assert(start != NULL);
499
500 /* Insert after the the last node that matches the input entity type, or
501 * at the end if no such match occurrs
502 */
503 while (start->next_sibling != NULL) {
504 uint16_t this_type = start->entity.entity_type;
505 pldm_entity_node *next = start->next_sibling;
506 if (this_type == entity_type &&
507 (this_type != next->entity.entity_type)) {
508 break;
509 }
510 start = start->next_sibling;
511 }
512
513 return start;
514}
515
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930516LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930517pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930518 pldm_entity_association_tree *tree, pldm_entity *entity,
519 uint16_t entity_instance_number, pldm_entity_node *parent,
520 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930521{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500522 return pldm_entity_association_tree_add_entity(tree, entity,
523 entity_instance_number,
524 parent, association_type,
525 false, true, 0xFFFF);
526}
527
528LIBPLDM_ABI_TESTING
529pldm_entity_node *pldm_entity_association_tree_add_entity(
530 pldm_entity_association_tree *tree, pldm_entity *entity,
531 uint16_t entity_instance_number, pldm_entity_node *parent,
532 uint8_t association_type, bool is_remote, bool is_update_container_id,
533 uint16_t container_id)
534{
535 if ((!tree) || (!entity)) {
536 return NULL;
537 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538
539 if (entity_instance_number != 0xFFFF && parent != NULL) {
540 pldm_entity node;
541 node.entity_type = entity->entity_type;
542 node.entity_instance_num = entity_instance_number;
543 if (pldm_is_current_parent_child(parent, &node)) {
544 return NULL;
545 }
546 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500547 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
548 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
549 return NULL;
550 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500552 if (!node) {
553 return NULL;
554 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930555 node->first_child = NULL;
556 node->next_sibling = NULL;
557 node->parent.entity_type = 0;
558 node->parent.entity_instance_num = 0;
559 node->parent.entity_container_id = 0;
560 node->entity.entity_type = entity->entity_type;
561 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930562 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600564 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500566 if (parent != NULL) {
567 free(node);
568 return NULL;
569 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930570 tree->root = node;
571 /* container_id 0 here indicates this is the top-most entry */
572 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600573 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 } else if (parent != NULL && parent->first_child == NULL) {
575 parent->first_child = node;
576 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500577
578 if (is_remote) {
579 node->remote_container_id = entity->entity_container_id;
580 }
581 if (is_update_container_id) {
582 if (container_id != 0xFFFF) {
583 node->entity.entity_container_id = container_id;
584 } else {
585 node->entity.entity_container_id =
586 next_container_id(tree);
587 }
588 } else {
589 node->entity.entity_container_id =
590 entity->entity_container_id;
591 }
592
593 if (!is_remote) {
594 node->remote_container_id =
595 node->entity.entity_container_id;
596 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930597 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930598 pldm_entity_node *start = parent == NULL ? tree->root :
599 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930601 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500602 if (!prev) {
603 free(node);
604 return NULL;
605 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 pldm_entity_node *next = prev->next_sibling;
607 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500608 if (prev->entity.entity_instance_num == UINT16_MAX) {
609 free(node);
610 return NULL;
611 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930613 entity_instance_number != 0xFFFF ?
614 entity_instance_number :
615 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 }
617 prev->next_sibling = node;
618 node->parent = prev->parent;
619 node->next_sibling = next;
620 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930621 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600622 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930623 }
624 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500625 if (is_update_container_id) {
626 entity->entity_container_id = node->entity.entity_container_id;
627 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930628 return node;
629}
630
631static void get_num_nodes(pldm_entity_node *node, size_t *num)
632{
633 if (node == NULL) {
634 return;
635 }
636
637 ++(*num);
638 get_num_nodes(node->next_sibling, num);
639 get_num_nodes(node->first_child, num);
640}
641
642static void entity_association_tree_visit(pldm_entity_node *node,
643 pldm_entity *entities, size_t *index)
644{
645 if (node == NULL) {
646 return;
647 }
648
649 pldm_entity *entity = &entities[*index];
650 ++(*index);
651 entity->entity_type = node->entity.entity_type;
652 entity->entity_instance_num = node->entity.entity_instance_num;
653 entity->entity_container_id = node->entity.entity_container_id;
654
655 entity_association_tree_visit(node->next_sibling, entities, index);
656 entity_association_tree_visit(node->first_child, entities, index);
657}
658
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930659LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930660void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
661 pldm_entity **entities, size_t *size)
662{
663 assert(tree != NULL);
664
665 *size = 0;
666 if (tree->root == NULL) {
667 return;
668 }
669
670 get_num_nodes(tree->root, size);
671 *entities = malloc(*size * sizeof(pldm_entity));
672 size_t index = 0;
673 entity_association_tree_visit(tree->root, *entities, &index);
674}
675
676static void entity_association_tree_destroy(pldm_entity_node *node)
677{
678 if (node == NULL) {
679 return;
680 }
681
682 entity_association_tree_destroy(node->next_sibling);
683 entity_association_tree_destroy(node->first_child);
684 free(node);
685}
686
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930687LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
689{
690 assert(tree != NULL);
691
692 entity_association_tree_destroy(tree->root);
693 free(tree);
694}
695
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930696LIBPLDM_ABI_STABLE
697bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698{
699 assert(node != NULL);
700
701 return node->first_child != NULL;
702}
703
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930704LIBPLDM_ABI_STABLE
705pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706{
707 assert(node != NULL);
708
709 return node->parent;
710}
711
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930712LIBPLDM_ABI_STABLE
713bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714{
715 assert(node != NULL);
716
717 if (node->parent.entity_type == 0 &&
718 node->parent.entity_instance_num == 0 &&
719 node->parent.entity_container_id == 0) {
720 return false;
721 }
722
723 return true;
724}
725
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930726LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
728 uint8_t association_type)
729{
730 assert(node != NULL);
731 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
732 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
733
734 size_t count = 0;
735 pldm_entity_node *curr = node->first_child;
736 while (curr != NULL) {
737 if (curr->association_type == association_type) {
738 ++count;
739 }
740 curr = curr->next_sibling;
741 }
742
743 assert(count < UINT8_MAX);
744 return count;
745}
746
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930747LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
749{
750 assert(parent != NULL);
751 assert(node != NULL);
752
753 pldm_entity_node *curr = parent->first_child;
754 while (curr != NULL) {
755 if (node->entity_type == curr->entity.entity_type &&
756 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930757 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758 return true;
759 }
760 curr = curr->next_sibling;
761 }
762
763 return false;
764}
765
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500766static void entity_association_pdr_add_children(
767 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
768 uint8_t contained_count, uint8_t association_type, bool is_remote,
769 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770{
771 uint8_t pdr[size];
772 uint8_t *start = pdr;
773
774 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
775 hdr->version = 1;
776 hdr->record_handle = 0;
777 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
778 hdr->record_change_num = 0;
779 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
780 start += sizeof(struct pldm_pdr_hdr);
781
782 uint16_t *container_id = (uint16_t *)start;
783 *container_id = htole16(curr->first_child->entity.entity_container_id);
784 start += sizeof(uint16_t);
785 *start = association_type;
786 start += sizeof(uint8_t);
787
788 pldm_entity *entity = (pldm_entity *)start;
789 entity->entity_type = htole16(curr->entity.entity_type);
790 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
791 entity->entity_container_id = htole16(curr->entity.entity_container_id);
792 start += sizeof(pldm_entity);
793
794 *start = contained_count;
795 start += sizeof(uint8_t);
796
797 pldm_entity_node *node = curr->first_child;
798 while (node != NULL) {
799 if (node->association_type == association_type) {
800 pldm_entity *entity = (pldm_entity *)start;
801 entity->entity_type = htole16(node->entity.entity_type);
802 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930803 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930805 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930806 start += sizeof(pldm_entity);
807 }
808 node = node->next_sibling;
809 }
810
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500811 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
812 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813}
814
815static void entity_association_pdr_add_entry(pldm_entity_node *curr,
816 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500817 uint16_t terminus_handle,
818 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930820 uint8_t num_logical_children = pldm_entity_get_num_children(
821 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
822 uint8_t num_physical_children = pldm_entity_get_num_children(
823 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824
825 if (num_logical_children) {
826 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930827 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
828 sizeof(uint8_t) + sizeof(pldm_entity) +
829 sizeof(uint8_t) +
830 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930831 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930832 curr, repo, logical_pdr_size, num_logical_children,
833 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500834 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930835 }
836
837 if (num_physical_children) {
838 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
840 sizeof(uint8_t) + sizeof(pldm_entity) +
841 sizeof(uint8_t) +
842 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930843 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930844 curr, repo, physical_pdr_size, num_physical_children,
845 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500846 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847 }
848}
849
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930850LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930851bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
852{
853 if (entities == NULL || num_entities == 0) {
854 return true;
855 }
856 size_t i = 0;
857 while (i < num_entities) {
858 if ((*entities + i)->entity_type == entity.entity_type) {
859 return true;
860 }
861 i++;
862 }
863 return false;
864}
865
866static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
867 pldm_entity **entities,
868 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500869 uint16_t terminus_handle,
870 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871{
872 if (curr == NULL) {
873 return;
874 }
875 bool to_add = true;
876 to_add = is_present(curr->entity, entities, num_entities);
877 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500878 entity_association_pdr_add_entry(
879 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930880 }
881 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500882 num_entities, is_remote, terminus_handle,
883 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930884 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500885 num_entities, is_remote, terminus_handle,
886 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887}
888
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930889LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
891 pldm_pdr *repo, bool is_remote,
892 uint16_t terminus_handle)
893{
894 assert(tree != NULL);
895 assert(repo != NULL);
896
897 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500898 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899}
900
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930901LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930902void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930903 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
904 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905{
906 assert(repo != NULL);
907
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500908 pldm_entity_association_pdr_add_from_node_with_record_handle(
909 node, repo, entities, num_entities, is_remote, terminus_handle,
910 0);
911}
912
913LIBPLDM_ABI_TESTING
914int pldm_entity_association_pdr_add_from_node_with_record_handle(
915 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
916 size_t num_entities, bool is_remote, uint16_t terminus_handle,
917 uint32_t record_handle)
918{
919 if (!node || !repo || !entities) {
920 return -EINVAL;
921 }
922
Andrew Jeffery9c766792022-08-10 23:12:49 +0930923 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500924 is_remote, terminus_handle, record_handle);
925
926 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927}
928
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930929LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
931 pldm_entity_node **node)
932{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600933 bool is_entity_container_id;
934 bool is_entity_instance_num;
935 bool is_type;
936
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937 if (tree_node == NULL) {
938 return;
939 }
940
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600941 is_type = tree_node->entity.entity_type == entity.entity_type;
942 is_entity_instance_num = tree_node->entity.entity_instance_num ==
943 entity.entity_instance_num;
944 is_entity_container_id = tree_node->entity.entity_container_id ==
945 entity.entity_container_id;
946
947 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948 *node = tree_node;
949 return;
950 }
951
952 find_entity_ref_in_tree(tree_node->first_child, entity, node);
953 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
954}
955
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930956LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
958 pldm_entity entity, pldm_entity_node **node)
959{
960 assert(tree != NULL);
961 find_entity_ref_in_tree(tree->root, entity, node);
962}
963
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930964LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
966 uint16_t terminus_handle)
967{
968 assert(repo != NULL);
969 bool removed = false;
970
971 pldm_pdr_record *record = repo->first;
972 pldm_pdr_record *prev = NULL;
973 while (record != NULL) {
974 pldm_pdr_record *next = record->next;
975 if (record->terminus_handle == terminus_handle) {
976 if (repo->first == record) {
977 repo->first = next;
978 } else {
979 prev->next = next;
980 }
981 if (repo->last == record) {
982 repo->last = prev;
983 }
984 if (record->data) {
985 free(record->data);
986 }
987 --repo->record_count;
988 repo->size -= record->size;
989 free(record);
990 removed = true;
991 } else {
992 prev = record;
993 }
994 record = next;
995 }
996
997 if (removed == true) {
998 record = repo->first;
999 uint32_t record_handle = 0;
1000 while (record != NULL) {
1001 record->record_handle = ++record_handle;
1002 if (record->data != NULL) {
1003 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301004 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301006 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 }
1008 record = record->next;
1009 }
1010 }
1011}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301012
1013LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301014void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1015{
1016 assert(repo != NULL);
1017 bool removed = false;
1018
1019 pldm_pdr_record *record = repo->first;
1020 pldm_pdr_record *prev = NULL;
1021 while (record != NULL) {
1022 pldm_pdr_record *next = record->next;
1023 if (record->is_remote == true) {
1024 if (repo->first == record) {
1025 repo->first = next;
1026 } else {
1027 prev->next = next;
1028 }
1029 if (repo->last == record) {
1030 repo->last = prev;
1031 }
1032 if (record->data) {
1033 free(record->data);
1034 }
1035 --repo->record_count;
1036 repo->size -= record->size;
1037 free(record);
1038 removed = true;
1039 } else {
1040 prev = record;
1041 }
1042 record = next;
1043 }
1044
1045 if (removed == true) {
1046 record = repo->first;
1047 uint32_t record_handle = 0;
1048 while (record != NULL) {
1049 record->record_handle = ++record_handle;
1050 if (record->data != NULL) {
1051 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301052 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301054 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055 }
1056 record = record->next;
1057 }
1058 }
1059}
1060
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001061LIBPLDM_ABI_TESTING
1062pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1063 uint32_t first, uint32_t last)
1064{
1065 pldm_pdr_record *record = NULL;
1066 pldm_pdr_record *curr;
1067
1068 if (!repo) {
1069 return NULL;
1070 }
1071 for (curr = repo->first; curr; curr = curr->next) {
1072 if (first > curr->record_handle || last < curr->record_handle) {
1073 continue;
1074 }
1075 if (!record || curr->record_handle > record->record_handle) {
1076 record = curr;
1077 }
1078 }
1079
1080 return record;
1081}
1082
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001083static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1084 pldm_entity *entity,
1085 pldm_entity_node **out,
1086 bool is_remote)
1087{
1088 assert(out != NULL && *out == NULL);
1089 if (node == NULL) {
1090 return;
1091 }
1092 bool is_entity_type;
1093 bool is_entity_instance_num;
1094
1095 is_entity_type = node->entity.entity_type == entity->entity_type;
1096 is_entity_instance_num = node->entity.entity_instance_num ==
1097 entity->entity_instance_num;
1098
1099 if (!is_remote ||
1100 node->remote_container_id == entity->entity_container_id) {
1101 if (is_entity_type && is_entity_instance_num) {
1102 entity->entity_container_id =
1103 node->entity.entity_container_id;
1104 *out = node;
1105 return;
1106 }
1107 }
1108 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1109 is_remote);
1110 entity_association_tree_find_if_remote(node->first_child, entity, out,
1111 is_remote);
1112}
1113
1114LIBPLDM_ABI_TESTING
1115pldm_entity_node *
1116pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1117 pldm_entity *entity, bool is_remote)
1118{
1119 if (!tree || !entity) {
1120 return NULL;
1121 }
1122 pldm_entity_node *node = NULL;
1123 entity_association_tree_find_if_remote(tree->root, entity, &node,
1124 is_remote);
1125 return node;
1126}
1127
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301128LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301129void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1130 pldm_entity_node **out)
1131{
1132 if (node == NULL) {
1133 return;
1134 }
1135
1136 if (node->entity.entity_type == entity->entity_type &&
1137 node->entity.entity_instance_num == entity->entity_instance_num) {
1138 entity->entity_container_id = node->entity.entity_container_id;
1139 *out = node;
1140 return;
1141 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301142 entity_association_tree_find(node->next_sibling, entity, out);
1143 entity_association_tree_find(node->first_child, entity, out);
1144}
1145
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301146LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301147pldm_entity_node *
1148pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1149 pldm_entity *entity)
1150{
1151 assert(tree != NULL);
1152
1153 pldm_entity_node *node = NULL;
1154 entity_association_tree_find(tree->root, entity, &node);
1155 return node;
1156}
1157
1158static void entity_association_tree_copy(pldm_entity_node *org_node,
1159 pldm_entity_node **new_node)
1160{
1161 if (org_node == NULL) {
1162 return;
1163 }
1164 *new_node = malloc(sizeof(pldm_entity_node));
1165 (*new_node)->parent = org_node->parent;
1166 (*new_node)->entity = org_node->entity;
1167 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001168 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169 (*new_node)->first_child = NULL;
1170 (*new_node)->next_sibling = NULL;
1171 entity_association_tree_copy(org_node->first_child,
1172 &((*new_node)->first_child));
1173 entity_association_tree_copy(org_node->next_sibling,
1174 &((*new_node)->next_sibling));
1175}
1176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301178void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301179 pldm_entity_association_tree *org_tree,
1180 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181{
1182 new_tree->last_used_container_id = org_tree->last_used_container_id;
1183 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1184}
1185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301188 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301189{
1190 assert(tree != NULL);
1191 entity_association_tree_destroy(tree->root);
1192 tree->last_used_container_id = 0;
1193 tree->root = NULL;
1194}
1195
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301196LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301197bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1198{
1199 return ((tree->root == NULL) ? true : false);
1200}
1201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301202LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1204 size_t *num_entities,
1205 pldm_entity **entities)
1206{
1207 assert(pdr != NULL);
1208 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301209 sizeof(struct pldm_pdr_entity_association));
Andrew Jeffery9c766792022-08-10 23:12:49 +09301210
1211 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1212 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1213
1214 const uint8_t *start = (uint8_t *)pdr;
1215 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301216 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217 start += sizeof(struct pldm_pdr_hdr);
1218 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301219 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220 *num_entities = entity_association_pdr->num_children + 1;
1221 assert(*num_entities >= 2);
1222 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1223 assert(*entities != NULL);
1224 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301225 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226 end);
1227 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301228 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301230 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301231 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301232 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233 pldm_entity *curr_entity = entity_association_pdr->children;
1234 size_t i = 1;
1235 while (i < *num_entities) {
1236 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301237 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301238 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301239 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301241 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301242 ++curr_entity;
1243 ++i;
1244 }
1245}