blob: e78d8cdb2dd9f2b89a7d23efa1d900dfe59767c1 [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 Jefferyca248ce2023-07-07 10:38:30 +093037LIBPLDM_ABI_STABLE
Andrew Jeffery572a3952023-07-03 13:19:28 +093038int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
39 bool is_remote, uint16_t terminus_handle,
40 uint32_t *record_handle)
41{
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093042 uint32_t curr;
43
Andrew Jeffery3b93d092023-07-17 13:01:50 +093044 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093045 return -EINVAL;
46 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093047
Andrew Jeffery3b93d092023-07-17 13:01:50 +093048 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093049 curr = *record_handle;
50 } else if (repo->last) {
51 curr = repo->last->record_handle;
52 if (curr == UINT32_MAX) {
53 return -EOVERFLOW;
54 }
55 curr += 1;
56 } else {
57 curr = 1;
58 }
59
Andrew Jeffery9c766792022-08-10 23:12:49 +093060 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093061 if (!record) {
62 return -ENOMEM;
63 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093064
Andrew Jeffery572a3952023-07-03 13:19:28 +093065 if (data) {
66 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093067 if (!record->data) {
68 free(record);
69 return -ENOMEM;
70 }
71 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093072 }
73
Andrew Jeffery9c766792022-08-10 23:12:49 +093074 record->size = size;
75 record->is_remote = is_remote;
76 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093077 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093078
Andrew Jeffery3b93d092023-07-17 13:01:50 +093079 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093080 /* If record handle is 0, that is an indication for this API to
81 * compute a new handle. For that reason, the computed handle
82 * needs to be populated in the PDR header. For a case where the
83 * caller supplied the record handle, it would exist in the
84 * header already.
85 */
86 struct pldm_pdr_hdr *hdr = (void *)record->data;
87 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093088 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093089
Andrew Jeffery9c766792022-08-10 23:12:49 +093090 record->next = NULL;
91
Andrew Jeffery8d231da2023-07-04 11:28:46 +093092 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093093 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +093094 repo->first = record;
95 repo->last = record;
96 } else {
97 repo->last->next = record;
98 repo->last = record;
99 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930101 repo->size += record->size;
102 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930103
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930104 if (record_handle) {
105 *record_handle = record->record_handle;
106 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930107
108 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109}
110
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930111LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930112pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930113{
114 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930115 if (!repo) {
116 return NULL;
117 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118 repo->record_count = 0;
119 repo->size = 0;
120 repo->first = NULL;
121 repo->last = NULL;
122
123 return repo;
124}
125
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930126LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127void pldm_pdr_destroy(pldm_pdr *repo)
128{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930129 if (!repo) {
130 return;
131 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132
133 pldm_pdr_record *record = repo->first;
134 while (record != NULL) {
135 pldm_pdr_record *next = record->next;
136 if (record->data) {
137 free(record->data);
138 record->data = NULL;
139 }
140 free(record);
141 record = next;
142 }
143 free(repo);
144}
145
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930146LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930147const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
148 uint32_t record_handle,
149 uint8_t **data, uint32_t *size,
150 uint32_t *next_record_handle)
151{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930152 if (!repo || !data || !size || !next_record_handle) {
153 return NULL;
154 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930155
156 if (!record_handle && (repo->first != NULL)) {
157 record_handle = repo->first->record_handle;
158 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930159
Andrew Jeffery9c766792022-08-10 23:12:49 +0930160 pldm_pdr_record *record = repo->first;
161 while (record != NULL) {
162 if (record->record_handle == record_handle) {
163 *size = record->size;
164 *data = record->data;
165 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930166 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167 return record;
168 }
169 record = record->next;
170 }
171
172 *size = 0;
173 *next_record_handle = 0;
174 return NULL;
175}
176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178const pldm_pdr_record *
179pldm_pdr_get_next_record(const pldm_pdr *repo,
180 const pldm_pdr_record *curr_record, uint8_t **data,
181 uint32_t *size, uint32_t *next_record_handle)
182{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930183 if (!repo || !curr_record || !data || !size || !next_record_handle) {
184 return NULL;
185 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930186
187 if (curr_record == repo->last) {
188 *data = NULL;
189 *size = 0;
190 *next_record_handle = get_next_record_handle(repo, curr_record);
191 return NULL;
192 }
193
194 *next_record_handle = get_next_record_handle(repo, curr_record->next);
195 *data = curr_record->next->data;
196 *size = curr_record->next->size;
197 return curr_record->next;
198}
199
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930200LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201const pldm_pdr_record *
202pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
203 const pldm_pdr_record *curr_record, uint8_t **data,
204 uint32_t *size)
205{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930206 if (!repo) {
207 return NULL;
208 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930209
210 pldm_pdr_record *record = repo->first;
211 if (curr_record != NULL) {
212 record = curr_record->next;
213 }
214 while (record != NULL) {
215 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
216 if (hdr->type == pdr_type) {
217 if (data && size) {
218 *size = record->size;
219 *data = record->data;
220 }
221 return record;
222 }
223 record = record->next;
224 }
225
226 if (size) {
227 *size = 0;
228 }
229 return NULL;
230}
231
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930232LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930233uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
234{
235 assert(repo != NULL);
236
237 return repo->record_count;
238}
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
242{
243 assert(repo != NULL);
244
245 return repo->size;
246}
247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930248LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930249uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
250 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251 const pldm_pdr_record *record)
252{
253 assert(repo != NULL);
254 assert(record != NULL);
255
256 return record->record_handle;
257}
258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930259LIBPLDM_ABI_STABLE
260bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930261{
262 assert(record != NULL);
263
264 return record->is_remote;
265}
266
Andrew Jefferya2c69112023-07-07 10:41:38 +0930267LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930268int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
269 uint16_t fru_rsi, uint16_t entity_type,
270 uint16_t entity_instance_num,
271 uint16_t container_id,
272 uint32_t *bmc_record_handle)
273{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930274 if (!repo || !bmc_record_handle) {
275 return -EINVAL;
276 }
277
Andrew Jeffery9c766792022-08-10 23:12:49 +0930278 uint32_t size = sizeof(struct pldm_pdr_hdr) +
279 sizeof(struct pldm_pdr_fru_record_set);
280 uint8_t data[size];
281
282 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
283 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930284 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930285 hdr->type = PLDM_PDR_FRU_RECORD_SET;
286 hdr->record_change_num = 0;
287 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
288 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930289 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
290 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930291 fru->terminus_handle = htole16(terminus_handle);
292 fru->fru_rsi = htole16(fru_rsi);
293 fru->entity_type = htole16(entity_type);
294 fru->entity_instance_num = htole16(entity_instance_num);
295 fru->container_id = htole16(container_id);
296
Andrew Jefferyc821a702023-07-03 13:32:11 +0930297 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
298 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299}
300
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930301LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930303 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
304 uint16_t *entity_type, uint16_t *entity_instance_num,
305 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930306{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930307 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
308 !container_id) {
309 return NULL;
310 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311
312 uint8_t *data = NULL;
313 uint32_t size = 0;
314 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316 while (curr_record != NULL) {
317 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930318 (struct pldm_pdr_fru_record_set
319 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930320 if (fru->fru_rsi == htole16(fru_rsi)) {
321 *terminus_handle = le16toh(fru->terminus_handle);
322 *entity_type = le16toh(fru->entity_type);
323 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930324 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325 *container_id = le16toh(fru->container_id);
326 return curr_record;
327 }
328 data = NULL;
329 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930330 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
331 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332 }
333
334 *terminus_handle = 0;
335 *entity_type = 0;
336 *entity_instance_num = 0;
337 *container_id = 0;
338
339 return NULL;
340}
341
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930342LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930343/* NOLINTNEXTLINE(readability-identifier-naming) */
344void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
345 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930347 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348 uint32_t size = 0;
349 const pldm_pdr_record *record;
350 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930351 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930352
353 do {
354 if (record != NULL) {
355 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930356 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930357 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930358 (struct pldm_terminus_locator_type_mctp_eid *)
359 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930360 if (pdr->terminus_handle == terminus_handle &&
361 pdr->tid == tid && value->eid == tl_eid) {
362 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363 break;
364 }
365 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930366 record = pldm_pdr_find_record_by_type(repo,
367 PLDM_TERMINUS_LOCATOR_PDR,
368 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369 } while (record);
370}
371
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500372static bool pldm_record_handle_in_range(uint32_t record_handle,
373 uint32_t first_record_handle,
374 uint32_t last_record_handle)
375{
376 return record_handle >= first_record_handle &&
377 record_handle <= last_record_handle;
378}
379
380LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500381int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500382 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500383 uint8_t child_index, uint32_t range_exclude_start_handle,
384 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500385{
386 pldm_pdr_record *record;
387 if (!repo) {
388 return -EINVAL;
389 }
390
391 for (record = repo->first; record; record = record->next) {
392 bool is_container_entity_instance_number;
393 struct pldm_pdr_entity_association *pdr;
394 bool is_container_entity_type;
395 struct pldm_entity *child;
396 struct pldm_pdr_hdr *hdr;
397 bool in_range;
398
399 // pldm_pdr_add() takes only uint8_t* data as an argument.
400 // The expectation here is the pldm_pdr_hdr is the first field of the record data
401 hdr = (struct pldm_pdr_hdr *)record->data;
402 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
403 continue;
404 }
405 in_range = pldm_record_handle_in_range(
406 record->record_handle, range_exclude_start_handle,
407 range_exclude_end_handle);
408 if (in_range) {
409 continue;
410 }
411
412 // this cast is valid with respect to alignment because
413 // struct pldm_pdr_hdr is declared with __attribute__((packed))
414 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500415 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500416 continue;
417 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500418
419 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500420 is_container_entity_type = pdr->container.entity_type ==
421 entity_type;
422 is_container_entity_instance_number =
423 pdr->container.entity_instance_num == entity_instance;
424 if (is_container_entity_type &&
425 is_container_entity_instance_number) {
426 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500427 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500428 }
429 }
430 return -ENOKEY;
431}
432
Andrew Jeffery9c766792022-08-10 23:12:49 +0930433typedef struct pldm_entity_association_tree {
434 pldm_entity_node *root;
435 uint16_t last_used_container_id;
436} pldm_entity_association_tree;
437
438typedef struct pldm_entity_node {
439 pldm_entity entity;
440 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600441 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930442 pldm_entity_node *first_child;
443 pldm_entity_node *next_sibling;
444 uint8_t association_type;
445} pldm_entity_node;
446
447static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
448{
449 assert(tree != NULL);
450 assert(tree->last_used_container_id != UINT16_MAX);
451
452 return ++tree->last_used_container_id;
453}
454
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930455LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930456pldm_entity pldm_entity_extract(pldm_entity_node *node)
457{
458 assert(node != NULL);
459
460 return node->entity;
461}
462
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600463LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930464uint16_t
465pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600466{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930467 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600468
Andrew Jeffery15b88182023-06-30 13:29:17 +0930469 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600470}
471
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930472LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930473pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474{
475 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930476 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930477 if (!tree) {
478 return NULL;
479 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930480 tree->root = NULL;
481 tree->last_used_container_id = 0;
482
483 return tree;
484}
485
486static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
487 uint16_t entity_type)
488{
489 assert(start != NULL);
490
491 /* Insert after the the last node that matches the input entity type, or
492 * at the end if no such match occurrs
493 */
494 while (start->next_sibling != NULL) {
495 uint16_t this_type = start->entity.entity_type;
496 pldm_entity_node *next = start->next_sibling;
497 if (this_type == entity_type &&
498 (this_type != next->entity.entity_type)) {
499 break;
500 }
501 start = start->next_sibling;
502 }
503
504 return start;
505}
506
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930507LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930509 pldm_entity_association_tree *tree, pldm_entity *entity,
510 uint16_t entity_instance_number, pldm_entity_node *parent,
511 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930512{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500513 return pldm_entity_association_tree_add_entity(tree, entity,
514 entity_instance_number,
515 parent, association_type,
516 false, true, 0xFFFF);
517}
518
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500519LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500520pldm_entity_node *pldm_entity_association_tree_add_entity(
521 pldm_entity_association_tree *tree, pldm_entity *entity,
522 uint16_t entity_instance_number, pldm_entity_node *parent,
523 uint8_t association_type, bool is_remote, bool is_update_container_id,
524 uint16_t container_id)
525{
526 if ((!tree) || (!entity)) {
527 return NULL;
528 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930529
530 if (entity_instance_number != 0xFFFF && parent != NULL) {
531 pldm_entity node;
532 node.entity_type = entity->entity_type;
533 node.entity_instance_num = entity_instance_number;
534 if (pldm_is_current_parent_child(parent, &node)) {
535 return NULL;
536 }
537 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500538 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
539 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
540 return NULL;
541 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930542 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500543 if (!node) {
544 return NULL;
545 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930546 node->first_child = NULL;
547 node->next_sibling = NULL;
548 node->parent.entity_type = 0;
549 node->parent.entity_instance_num = 0;
550 node->parent.entity_container_id = 0;
551 node->entity.entity_type = entity->entity_type;
552 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930553 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600555 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930556 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500557 if (parent != NULL) {
558 free(node);
559 return NULL;
560 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 tree->root = node;
562 /* container_id 0 here indicates this is the top-most entry */
563 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600564 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930566 /* Ensure next_container_id() will yield a valid ID */
567 if (tree->last_used_container_id == UINT16_MAX) {
568 free(node);
569 return NULL;
570 }
571
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572 parent->first_child = node;
573 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500574
575 if (is_remote) {
576 node->remote_container_id = entity->entity_container_id;
577 }
578 if (is_update_container_id) {
579 if (container_id != 0xFFFF) {
580 node->entity.entity_container_id = container_id;
581 } else {
582 node->entity.entity_container_id =
583 next_container_id(tree);
584 }
585 } else {
586 node->entity.entity_container_id =
587 entity->entity_container_id;
588 }
589
590 if (!is_remote) {
591 node->remote_container_id =
592 node->entity.entity_container_id;
593 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930595 pldm_entity_node *start = parent == NULL ? tree->root :
596 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930597 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930598 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500599 if (!prev) {
600 free(node);
601 return NULL;
602 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 pldm_entity_node *next = prev->next_sibling;
604 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500605 if (prev->entity.entity_instance_num == UINT16_MAX) {
606 free(node);
607 return NULL;
608 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930609 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930610 entity_instance_number != 0xFFFF ?
611 entity_instance_number :
612 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613 }
614 prev->next_sibling = node;
615 node->parent = prev->parent;
616 node->next_sibling = next;
617 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930618 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600619 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 }
621 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500622 if (is_update_container_id) {
623 entity->entity_container_id = node->entity.entity_container_id;
624 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 return node;
626}
627
628static void get_num_nodes(pldm_entity_node *node, size_t *num)
629{
630 if (node == NULL) {
631 return;
632 }
633
634 ++(*num);
635 get_num_nodes(node->next_sibling, num);
636 get_num_nodes(node->first_child, num);
637}
638
639static void entity_association_tree_visit(pldm_entity_node *node,
640 pldm_entity *entities, size_t *index)
641{
642 if (node == NULL) {
643 return;
644 }
645
646 pldm_entity *entity = &entities[*index];
647 ++(*index);
648 entity->entity_type = node->entity.entity_type;
649 entity->entity_instance_num = node->entity.entity_instance_num;
650 entity->entity_container_id = node->entity.entity_container_id;
651
652 entity_association_tree_visit(node->next_sibling, entities, index);
653 entity_association_tree_visit(node->first_child, entities, index);
654}
655
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930656LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
658 pldm_entity **entities, size_t *size)
659{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930660 if (!tree || !entities || !size) {
661 return;
662 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930663
664 *size = 0;
665 if (tree->root == NULL) {
666 return;
667 }
668
669 get_num_nodes(tree->root, size);
670 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930671 if (!entities) {
672 return;
673 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674 size_t index = 0;
675 entity_association_tree_visit(tree->root, *entities, &index);
676}
677
678static void entity_association_tree_destroy(pldm_entity_node *node)
679{
680 if (node == NULL) {
681 return;
682 }
683
684 entity_association_tree_destroy(node->next_sibling);
685 entity_association_tree_destroy(node->first_child);
686 free(node);
687}
688
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930689LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930690void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
691{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930692 if (!tree) {
693 return;
694 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695
696 entity_association_tree_destroy(tree->root);
697 free(tree);
698}
699
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930700LIBPLDM_ABI_STABLE
701bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702{
703 assert(node != NULL);
704
705 return node->first_child != NULL;
706}
707
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930708LIBPLDM_ABI_STABLE
709pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930710{
711 assert(node != NULL);
712
713 return node->parent;
714}
715
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930716LIBPLDM_ABI_STABLE
717bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718{
719 assert(node != NULL);
720
721 if (node->parent.entity_type == 0 &&
722 node->parent.entity_instance_num == 0 &&
723 node->parent.entity_container_id == 0) {
724 return false;
725 }
726
727 return true;
728}
729
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930730LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
732 uint8_t association_type)
733{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930734 if (!node) {
735 return 0;
736 }
737
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930738 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
739 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
740 return 0;
741 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742
743 size_t count = 0;
744 pldm_entity_node *curr = node->first_child;
745 while (curr != NULL) {
746 if (curr->association_type == association_type) {
747 ++count;
748 }
749 curr = curr->next_sibling;
750 }
751
752 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930753 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930754}
755
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930756LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930757bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
758{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930759 if (!parent || !node) {
760 return false;
761 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930762
763 pldm_entity_node *curr = parent->first_child;
764 while (curr != NULL) {
765 if (node->entity_type == curr->entity.entity_type &&
766 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930767 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768 return true;
769 }
770 curr = curr->next_sibling;
771 }
772
773 return false;
774}
775
Andrew Jeffery65945992023-07-17 15:04:21 +0930776static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500777 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
778 uint8_t contained_count, uint8_t association_type, bool is_remote,
779 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930780{
781 uint8_t pdr[size];
782 uint8_t *start = pdr;
783
784 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
785 hdr->version = 1;
786 hdr->record_handle = 0;
787 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
788 hdr->record_change_num = 0;
789 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
790 start += sizeof(struct pldm_pdr_hdr);
791
792 uint16_t *container_id = (uint16_t *)start;
793 *container_id = htole16(curr->first_child->entity.entity_container_id);
794 start += sizeof(uint16_t);
795 *start = association_type;
796 start += sizeof(uint8_t);
797
798 pldm_entity *entity = (pldm_entity *)start;
799 entity->entity_type = htole16(curr->entity.entity_type);
800 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
801 entity->entity_container_id = htole16(curr->entity.entity_container_id);
802 start += sizeof(pldm_entity);
803
804 *start = contained_count;
805 start += sizeof(uint8_t);
806
807 pldm_entity_node *node = curr->first_child;
808 while (node != NULL) {
809 if (node->association_type == association_type) {
810 pldm_entity *entity = (pldm_entity *)start;
811 entity->entity_type = htole16(node->entity.entity_type);
812 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930813 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930814 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816 start += sizeof(pldm_entity);
817 }
818 node = node->next_sibling;
819 }
820
Andrew Jeffery65945992023-07-17 15:04:21 +0930821 return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
822 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823}
824
Andrew Jeffery65945992023-07-17 15:04:21 +0930825static int entity_association_pdr_add_entry(pldm_entity_node *curr,
826 pldm_pdr *repo, bool is_remote,
827 uint16_t terminus_handle,
828 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930830 uint8_t num_logical_children = pldm_entity_get_num_children(
831 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
832 uint8_t num_physical_children = pldm_entity_get_num_children(
833 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930834 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930835
836 if (num_logical_children) {
837 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930838 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
839 sizeof(uint8_t) + sizeof(pldm_entity) +
840 sizeof(uint8_t) +
841 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930842 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930843 curr, repo, logical_pdr_size, num_logical_children,
844 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500845 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930846 if (rc < 0) {
847 return rc;
848 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930849 }
850
851 if (num_physical_children) {
852 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930853 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
854 sizeof(uint8_t) + sizeof(pldm_entity) +
855 sizeof(uint8_t) +
856 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930857 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930858 curr, repo, physical_pdr_size, num_physical_children,
859 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500860 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930861 if (rc < 0) {
862 return rc;
863 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930864 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930865
866 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930867}
868
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930869static bool is_present(pldm_entity entity, pldm_entity **entities,
870 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871{
872 if (entities == NULL || num_entities == 0) {
873 return true;
874 }
875 size_t i = 0;
876 while (i < num_entities) {
877 if ((*entities + i)->entity_type == entity.entity_type) {
878 return true;
879 }
880 i++;
881 }
882 return false;
883}
884
Andrew Jeffery65945992023-07-17 15:04:21 +0930885static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
886 pldm_entity **entities,
887 size_t num_entities, bool is_remote,
888 uint16_t terminus_handle,
889 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890{
Andrew Jeffery65945992023-07-17 15:04:21 +0930891 int rc;
892
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930894 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930896
897 if (is_present(curr->entity, entities, num_entities)) {
898 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500899 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930900 if (rc) {
901 return rc;
902 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930904
905 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
906 num_entities, is_remote,
907 terminus_handle, record_handle);
908 if (rc) {
909 return rc;
910 }
911
912 return entity_association_pdr_add(curr->first_child, repo, entities,
913 num_entities, is_remote,
914 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915}
916
Andrew Jeffery096685b2023-07-17 17:36:14 +0930917LIBPLDM_ABI_STABLE
Andrew Jeffery65945992023-07-17 15:04:21 +0930918int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
919 pldm_pdr *repo, bool is_remote,
920 uint16_t terminus_handle)
921{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930922 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930923 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930924 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930925
Andrew Jeffery65945992023-07-17 15:04:21 +0930926 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
927 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930928}
929
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930930LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930931int pldm_entity_association_pdr_add_from_node_check(
932 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
933 size_t num_entities, bool is_remote, uint16_t terminus_handle)
934{
935 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500936 node, repo, entities, num_entities, is_remote, terminus_handle,
937 0);
938}
939
940LIBPLDM_ABI_TESTING
941int pldm_entity_association_pdr_add_from_node_with_record_handle(
942 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
943 size_t num_entities, bool is_remote, uint16_t terminus_handle,
944 uint32_t record_handle)
945{
946 if (!node || !repo || !entities) {
947 return -EINVAL;
948 }
949
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500951 is_remote, terminus_handle, record_handle);
952
953 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954}
955
Andrew Jeffery643c4432023-07-17 15:36:03 +0930956static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
957 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600959 bool is_entity_container_id;
960 bool is_entity_instance_num;
961 bool is_type;
962
Andrew Jeffery9c766792022-08-10 23:12:49 +0930963 if (tree_node == NULL) {
964 return;
965 }
966
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600967 is_type = tree_node->entity.entity_type == entity.entity_type;
968 is_entity_instance_num = tree_node->entity.entity_instance_num ==
969 entity.entity_instance_num;
970 is_entity_container_id = tree_node->entity.entity_container_id ==
971 entity.entity_container_id;
972
973 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974 *node = tree_node;
975 return;
976 }
977
978 find_entity_ref_in_tree(tree_node->first_child, entity, node);
979 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
980}
981
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930982LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930983void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
984 pldm_entity entity, pldm_entity_node **node)
985{
Andrew Jefferyba47e832023-07-03 11:41:03 +0930986 if (!tree || !node) {
987 return;
988 }
989
Andrew Jeffery9c766792022-08-10 23:12:49 +0930990 find_entity_ref_in_tree(tree->root, entity, node);
991}
992
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930993LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930994void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
995 uint16_t terminus_handle)
996{
Andrew Jeffery438dd492023-07-03 11:51:43 +0930997 if (!repo) {
998 return;
999 }
1000
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001 bool removed = false;
1002
1003 pldm_pdr_record *record = repo->first;
1004 pldm_pdr_record *prev = NULL;
1005 while (record != NULL) {
1006 pldm_pdr_record *next = record->next;
1007 if (record->terminus_handle == terminus_handle) {
1008 if (repo->first == record) {
1009 repo->first = next;
1010 } else {
1011 prev->next = next;
1012 }
1013 if (repo->last == record) {
1014 repo->last = prev;
1015 }
1016 if (record->data) {
1017 free(record->data);
1018 }
1019 --repo->record_count;
1020 repo->size -= record->size;
1021 free(record);
1022 removed = true;
1023 } else {
1024 prev = record;
1025 }
1026 record = next;
1027 }
1028
1029 if (removed == true) {
1030 record = repo->first;
1031 uint32_t record_handle = 0;
1032 while (record != NULL) {
1033 record->record_handle = ++record_handle;
1034 if (record->data != NULL) {
1035 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301036 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 }
1040 record = record->next;
1041 }
1042 }
1043}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301044
1045LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301046void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1047{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301048 if (!repo) {
1049 return;
1050 }
1051
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052 bool removed = false;
1053
1054 pldm_pdr_record *record = repo->first;
1055 pldm_pdr_record *prev = NULL;
1056 while (record != NULL) {
1057 pldm_pdr_record *next = record->next;
1058 if (record->is_remote == true) {
1059 if (repo->first == record) {
1060 repo->first = next;
1061 } else {
1062 prev->next = next;
1063 }
1064 if (repo->last == record) {
1065 repo->last = prev;
1066 }
1067 if (record->data) {
1068 free(record->data);
1069 }
1070 --repo->record_count;
1071 repo->size -= record->size;
1072 free(record);
1073 removed = true;
1074 } else {
1075 prev = record;
1076 }
1077 record = next;
1078 }
1079
1080 if (removed == true) {
1081 record = repo->first;
1082 uint32_t record_handle = 0;
1083 while (record != NULL) {
1084 record->record_handle = ++record_handle;
1085 if (record->data != NULL) {
1086 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301087 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301088 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301089 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301090 }
1091 record = record->next;
1092 }
1093 }
1094}
1095
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001096LIBPLDM_ABI_TESTING
1097pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1098 uint32_t first, uint32_t last)
1099{
1100 pldm_pdr_record *record = NULL;
1101 pldm_pdr_record *curr;
1102
1103 if (!repo) {
1104 return NULL;
1105 }
1106 for (curr = repo->first; curr; curr = curr->next) {
1107 if (first > curr->record_handle || last < curr->record_handle) {
1108 continue;
1109 }
1110 if (!record || curr->record_handle > record->record_handle) {
1111 record = curr;
1112 }
1113 }
1114
1115 return record;
1116}
1117
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001118static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1119 pldm_entity *entity,
1120 pldm_entity_node **out,
1121 bool is_remote)
1122{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001123 if (node == NULL) {
1124 return;
1125 }
1126 bool is_entity_type;
1127 bool is_entity_instance_num;
1128
1129 is_entity_type = node->entity.entity_type == entity->entity_type;
1130 is_entity_instance_num = node->entity.entity_instance_num ==
1131 entity->entity_instance_num;
1132
1133 if (!is_remote ||
1134 node->remote_container_id == entity->entity_container_id) {
1135 if (is_entity_type && is_entity_instance_num) {
1136 entity->entity_container_id =
1137 node->entity.entity_container_id;
1138 *out = node;
1139 return;
1140 }
1141 }
1142 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1143 is_remote);
1144 entity_association_tree_find_if_remote(node->first_child, entity, out,
1145 is_remote);
1146}
1147
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001148LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001149pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1150 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001151{
1152 if (!tree || !entity) {
1153 return NULL;
1154 }
1155 pldm_entity_node *node = NULL;
1156 entity_association_tree_find_if_remote(tree->root, entity, &node,
1157 is_remote);
1158 return node;
1159}
1160
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301161static void entity_association_tree_find(pldm_entity_node *node,
1162 pldm_entity *entity,
1163 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301164{
1165 if (node == NULL) {
1166 return;
1167 }
1168
1169 if (node->entity.entity_type == entity->entity_type &&
1170 node->entity.entity_instance_num == entity->entity_instance_num) {
1171 entity->entity_container_id = node->entity.entity_container_id;
1172 *out = node;
1173 return;
1174 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301175 entity_association_tree_find(node->next_sibling, entity, out);
1176 entity_association_tree_find(node->first_child, entity, out);
1177}
1178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301180pldm_entity_node *
1181pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1182 pldm_entity *entity)
1183{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301184 if (!tree || !entity) {
1185 return NULL;
1186 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187
1188 pldm_entity_node *node = NULL;
1189 entity_association_tree_find(tree->root, entity, &node);
1190 return node;
1191}
1192
1193static void entity_association_tree_copy(pldm_entity_node *org_node,
1194 pldm_entity_node **new_node)
1195{
1196 if (org_node == NULL) {
1197 return;
1198 }
1199 *new_node = malloc(sizeof(pldm_entity_node));
1200 (*new_node)->parent = org_node->parent;
1201 (*new_node)->entity = org_node->entity;
1202 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001203 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301204 (*new_node)->first_child = NULL;
1205 (*new_node)->next_sibling = NULL;
1206 entity_association_tree_copy(org_node->first_child,
1207 &((*new_node)->first_child));
1208 entity_association_tree_copy(org_node->next_sibling,
1209 &((*new_node)->next_sibling));
1210}
1211
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301212LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301213void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301214 pldm_entity_association_tree *org_tree,
1215 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216{
1217 new_tree->last_used_container_id = org_tree->last_used_container_id;
1218 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1219}
1220
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301221LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301223 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301225 if (!tree) {
1226 return;
1227 }
1228
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229 entity_association_tree_destroy(tree->root);
1230 tree->last_used_container_id = 0;
1231 tree->root = NULL;
1232}
1233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301234LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1236{
1237 return ((tree->root == NULL) ? true : false);
1238}
1239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301241void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1242 size_t *num_entities,
1243 pldm_entity **entities)
1244{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301245 if (!pdr || !num_entities || !entities) {
1246 return;
1247 }
1248#define PDR_MIN_SIZE \
1249 (sizeof(struct pldm_pdr_hdr) + \
1250 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301251 if (pdr_len < PDR_MIN_SIZE) {
1252 return;
1253 }
1254#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301255
1256 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301257 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1258 return;
1259 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301260
1261 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301262 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301263 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301264 start += sizeof(struct pldm_pdr_hdr);
1265 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301266 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301267 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301268 if (l_num_entities < 2) {
1269 return;
1270 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301271 if (start + sizeof(struct pldm_pdr_entity_association) +
1272 sizeof(pldm_entity) * (l_num_entities - 2) !=
1273 end) {
1274 return;
1275 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301276 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301277 if (!l_entities) {
1278 return;
1279 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301280 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301281 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301282 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301284 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301285 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301286 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301287 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1288 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1289 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301290 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301291 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301292 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301293 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301294
1295 *num_entities = l_num_entities;
1296 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297}