blob: 639ddd36046d57d5fb7c004c8e6086f021215647 [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_DEPRECATED
Andrew Jefferya51ccc22023-06-28 21:57:46 +093038uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
39 uint32_t record_handle, bool is_remote,
40 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +093041{
Andrew Jeffery85268922023-07-11 06:44:04 +093042 assert(repo != NULL);
43 assert(data != NULL);
44 assert(size != 0);
Andrew Jeffery572a3952023-07-03 13:19:28 +093045 int rc = pldm_pdr_add_check(repo, data, size, is_remote,
46 terminus_handle, &record_handle);
47 (void)rc;
48 assert(!rc);
49 return record_handle;
50}
51
Andrew Jefferyca248ce2023-07-07 10:38:30 +093052LIBPLDM_ABI_STABLE
Andrew Jeffery572a3952023-07-03 13:19:28 +093053int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
54 bool is_remote, uint16_t terminus_handle,
55 uint32_t *record_handle)
56{
Andrew Jeffery572a3952023-07-03 13:19:28 +093057 if (!repo || !data || !size || !record_handle) {
58 return -EINVAL;
59 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093060
61 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093062 if (!record) {
63 return -ENOMEM;
64 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093065
Andrew Jeffery572a3952023-07-03 13:19:28 +093066 if (data) {
67 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093068 if (!record->data) {
69 free(record);
70 return -ENOMEM;
71 }
72 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093073 }
74
Andrew Jeffery9c766792022-08-10 23:12:49 +093075 record->size = size;
76 record->is_remote = is_remote;
77 record->terminus_handle = terminus_handle;
Andrew Jeffery572a3952023-07-03 13:19:28 +093078
79 if (*record_handle) {
80 record->record_handle = *record_handle;
81 } else {
82 uint32_t curr = repo->last ? repo->last->record_handle : 0;
Andrew Jeffery572a3952023-07-03 13:19:28 +093083 if (curr == UINT32_MAX) {
84 return -EOVERFLOW;
85 }
86 record->record_handle = curr + 1;
87
88 if (data != NULL) {
89 /* If record handle is 0, that is an indication for this API to
90 * compute a new handle. For that reason, the computed handle
91 * needs to be populated in the PDR header. For a case where the
92 * caller supplied the record handle, it would exist in the
93 * header already.
94 */
95 struct pldm_pdr_hdr *hdr = (void *)record->data;
Andrew Jeffery9c766792022-08-10 23:12:49 +093096 hdr->record_handle = htole32(record->record_handle);
97 }
98 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093099
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100 record->next = NULL;
101
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930102 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930103 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930104 repo->first = record;
105 repo->last = record;
106 } else {
107 repo->last->next = record;
108 repo->last = record;
109 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930110
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930111 repo->size += record->size;
112 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930113
Andrew Jeffery572a3952023-07-03 13:19:28 +0930114 *record_handle = record->record_handle;
115
116 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117}
118
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930119LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930120pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121{
122 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930123 if (!repo) {
124 return NULL;
125 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930126 repo->record_count = 0;
127 repo->size = 0;
128 repo->first = NULL;
129 repo->last = NULL;
130
131 return repo;
132}
133
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930134LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930135void pldm_pdr_destroy(pldm_pdr *repo)
136{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930137 if (!repo) {
138 return;
139 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930140
141 pldm_pdr_record *record = repo->first;
142 while (record != NULL) {
143 pldm_pdr_record *next = record->next;
144 if (record->data) {
145 free(record->data);
146 record->data = NULL;
147 }
148 free(record);
149 record = next;
150 }
151 free(repo);
152}
153
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930154LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930155const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
156 uint32_t record_handle,
157 uint8_t **data, uint32_t *size,
158 uint32_t *next_record_handle)
159{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930160 if (!repo || !data || !size || !next_record_handle) {
161 return NULL;
162 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930163
164 if (!record_handle && (repo->first != NULL)) {
165 record_handle = repo->first->record_handle;
166 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930167
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168 pldm_pdr_record *record = repo->first;
169 while (record != NULL) {
170 if (record->record_handle == record_handle) {
171 *size = record->size;
172 *data = record->data;
173 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930174 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930175 return record;
176 }
177 record = record->next;
178 }
179
180 *size = 0;
181 *next_record_handle = 0;
182 return NULL;
183}
184
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930185LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930186const pldm_pdr_record *
187pldm_pdr_get_next_record(const pldm_pdr *repo,
188 const pldm_pdr_record *curr_record, uint8_t **data,
189 uint32_t *size, uint32_t *next_record_handle)
190{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930191 if (!repo || !curr_record || !data || !size || !next_record_handle) {
192 return NULL;
193 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930194
195 if (curr_record == repo->last) {
196 *data = NULL;
197 *size = 0;
198 *next_record_handle = get_next_record_handle(repo, curr_record);
199 return NULL;
200 }
201
202 *next_record_handle = get_next_record_handle(repo, curr_record->next);
203 *data = curr_record->next->data;
204 *size = curr_record->next->size;
205 return curr_record->next;
206}
207
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930208LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930209const pldm_pdr_record *
210pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
211 const pldm_pdr_record *curr_record, uint8_t **data,
212 uint32_t *size)
213{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930214 if (!repo) {
215 return NULL;
216 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217
218 pldm_pdr_record *record = repo->first;
219 if (curr_record != NULL) {
220 record = curr_record->next;
221 }
222 while (record != NULL) {
223 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
224 if (hdr->type == pdr_type) {
225 if (data && size) {
226 *size = record->size;
227 *data = record->data;
228 }
229 return record;
230 }
231 record = record->next;
232 }
233
234 if (size) {
235 *size = 0;
236 }
237 return NULL;
238}
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
242{
243 assert(repo != NULL);
244
245 return repo->record_count;
246}
247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930248LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
250{
251 assert(repo != NULL);
252
253 return repo->size;
254}
255
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930256LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930257uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
258 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259 const pldm_pdr_record *record)
260{
261 assert(repo != NULL);
262 assert(record != NULL);
263
264 return record->record_handle;
265}
266
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930267LIBPLDM_ABI_STABLE
268bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930269{
270 assert(record != NULL);
271
272 return record->is_remote;
273}
274
Andrew Jefferya2c69112023-07-07 10:41:38 +0930275LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930276uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
277 uint16_t fru_rsi, uint16_t entity_type,
278 uint16_t entity_instance_num,
279 uint16_t container_id,
280 uint32_t bmc_record_handle)
281{
Andrew Jefferyc821a702023-07-03 13:32:11 +0930282 int rc = pldm_pdr_add_fru_record_set_check(
283 repo, terminus_handle, fru_rsi, entity_type,
284 entity_instance_num, container_id, &bmc_record_handle);
285 (void)rc;
286 assert(!rc);
287 return bmc_record_handle;
288}
289
Andrew Jefferya2c69112023-07-07 10:41:38 +0930290LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930291int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
292 uint16_t fru_rsi, uint16_t entity_type,
293 uint16_t entity_instance_num,
294 uint16_t container_id,
295 uint32_t *bmc_record_handle)
296{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930297 uint32_t size = sizeof(struct pldm_pdr_hdr) +
298 sizeof(struct pldm_pdr_fru_record_set);
299 uint8_t data[size];
300
301 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
302 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930303 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930304 hdr->type = PLDM_PDR_FRU_RECORD_SET;
305 hdr->record_change_num = 0;
306 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
307 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930308 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
309 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930310 fru->terminus_handle = htole16(terminus_handle);
311 fru->fru_rsi = htole16(fru_rsi);
312 fru->entity_type = htole16(entity_type);
313 fru->entity_instance_num = htole16(entity_instance_num);
314 fru->container_id = htole16(container_id);
315
Andrew Jefferyc821a702023-07-03 13:32:11 +0930316 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
317 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930318}
319
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930320LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930322 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
323 uint16_t *entity_type, uint16_t *entity_instance_num,
324 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930326 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
327 !container_id) {
328 return NULL;
329 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930330
331 uint8_t *data = NULL;
332 uint32_t size = 0;
333 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930334 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335 while (curr_record != NULL) {
336 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930337 (struct pldm_pdr_fru_record_set
338 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339 if (fru->fru_rsi == htole16(fru_rsi)) {
340 *terminus_handle = le16toh(fru->terminus_handle);
341 *entity_type = le16toh(fru->entity_type);
342 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930343 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344 *container_id = le16toh(fru->container_id);
345 return curr_record;
346 }
347 data = NULL;
348 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930349 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
350 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 }
352
353 *terminus_handle = 0;
354 *entity_type = 0;
355 *entity_instance_num = 0;
356 *container_id = 0;
357
358 return NULL;
359}
360
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930361LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930362/* NOLINTNEXTLINE(readability-identifier-naming) */
363void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
364 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930366 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367 uint32_t size = 0;
368 const pldm_pdr_record *record;
369 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930370 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930371
372 do {
373 if (record != NULL) {
374 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930375 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930376 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930377 (struct pldm_terminus_locator_type_mctp_eid *)
378 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930379 if (pdr->terminus_handle == terminus_handle &&
380 pdr->tid == tid && value->eid == tl_eid) {
381 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930382 break;
383 }
384 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930385 record = pldm_pdr_find_record_by_type(repo,
386 PLDM_TERMINUS_LOCATOR_PDR,
387 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930388 } while (record);
389}
390
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500391static bool pldm_record_handle_in_range(uint32_t record_handle,
392 uint32_t first_record_handle,
393 uint32_t last_record_handle)
394{
395 return record_handle >= first_record_handle &&
396 record_handle <= last_record_handle;
397}
398
399LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500400int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500401 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500402 uint8_t child_index, uint32_t range_exclude_start_handle,
403 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500404{
405 pldm_pdr_record *record;
406 if (!repo) {
407 return -EINVAL;
408 }
409
410 for (record = repo->first; record; record = record->next) {
411 bool is_container_entity_instance_number;
412 struct pldm_pdr_entity_association *pdr;
413 bool is_container_entity_type;
414 struct pldm_entity *child;
415 struct pldm_pdr_hdr *hdr;
416 bool in_range;
417
418 // pldm_pdr_add() takes only uint8_t* data as an argument.
419 // The expectation here is the pldm_pdr_hdr is the first field of the record data
420 hdr = (struct pldm_pdr_hdr *)record->data;
421 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
422 continue;
423 }
424 in_range = pldm_record_handle_in_range(
425 record->record_handle, range_exclude_start_handle,
426 range_exclude_end_handle);
427 if (in_range) {
428 continue;
429 }
430
431 // this cast is valid with respect to alignment because
432 // struct pldm_pdr_hdr is declared with __attribute__((packed))
433 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500434 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500435 continue;
436 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500437
438 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500439 is_container_entity_type = pdr->container.entity_type ==
440 entity_type;
441 is_container_entity_instance_number =
442 pdr->container.entity_instance_num == entity_instance;
443 if (is_container_entity_type &&
444 is_container_entity_instance_number) {
445 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500446 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500447 }
448 }
449 return -ENOKEY;
450}
451
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452typedef struct pldm_entity_association_tree {
453 pldm_entity_node *root;
454 uint16_t last_used_container_id;
455} pldm_entity_association_tree;
456
457typedef struct pldm_entity_node {
458 pldm_entity entity;
459 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600460 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930461 pldm_entity_node *first_child;
462 pldm_entity_node *next_sibling;
463 uint8_t association_type;
464} pldm_entity_node;
465
466static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
467{
468 assert(tree != NULL);
469 assert(tree->last_used_container_id != UINT16_MAX);
470
471 return ++tree->last_used_container_id;
472}
473
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930474LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475pldm_entity pldm_entity_extract(pldm_entity_node *node)
476{
477 assert(node != NULL);
478
479 return node->entity;
480}
481
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600482LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930483uint16_t
484pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600485{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930486 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600487
Andrew Jeffery15b88182023-06-30 13:29:17 +0930488 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600489}
490
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930491LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930492pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930493{
494 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930495 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930496 if (!tree) {
497 return NULL;
498 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930499 tree->root = NULL;
500 tree->last_used_container_id = 0;
501
502 return tree;
503}
504
505static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
506 uint16_t entity_type)
507{
508 assert(start != NULL);
509
510 /* Insert after the the last node that matches the input entity type, or
511 * at the end if no such match occurrs
512 */
513 while (start->next_sibling != NULL) {
514 uint16_t this_type = start->entity.entity_type;
515 pldm_entity_node *next = start->next_sibling;
516 if (this_type == entity_type &&
517 (this_type != next->entity.entity_type)) {
518 break;
519 }
520 start = start->next_sibling;
521 }
522
523 return start;
524}
525
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930526LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930527pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930528 pldm_entity_association_tree *tree, pldm_entity *entity,
529 uint16_t entity_instance_number, pldm_entity_node *parent,
530 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930531{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500532 return pldm_entity_association_tree_add_entity(tree, entity,
533 entity_instance_number,
534 parent, association_type,
535 false, true, 0xFFFF);
536}
537
538LIBPLDM_ABI_TESTING
539pldm_entity_node *pldm_entity_association_tree_add_entity(
540 pldm_entity_association_tree *tree, pldm_entity *entity,
541 uint16_t entity_instance_number, pldm_entity_node *parent,
542 uint8_t association_type, bool is_remote, bool is_update_container_id,
543 uint16_t container_id)
544{
545 if ((!tree) || (!entity)) {
546 return NULL;
547 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548
549 if (entity_instance_number != 0xFFFF && parent != NULL) {
550 pldm_entity node;
551 node.entity_type = entity->entity_type;
552 node.entity_instance_num = entity_instance_number;
553 if (pldm_is_current_parent_child(parent, &node)) {
554 return NULL;
555 }
556 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500557 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
558 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
559 return NULL;
560 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500562 if (!node) {
563 return NULL;
564 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 node->first_child = NULL;
566 node->next_sibling = NULL;
567 node->parent.entity_type = 0;
568 node->parent.entity_instance_num = 0;
569 node->parent.entity_container_id = 0;
570 node->entity.entity_type = entity->entity_type;
571 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930572 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600574 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930575 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500576 if (parent != NULL) {
577 free(node);
578 return NULL;
579 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 tree->root = node;
581 /* container_id 0 here indicates this is the top-most entry */
582 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600583 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 } else if (parent != NULL && parent->first_child == NULL) {
585 parent->first_child = node;
586 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500587
588 if (is_remote) {
589 node->remote_container_id = entity->entity_container_id;
590 }
591 if (is_update_container_id) {
592 if (container_id != 0xFFFF) {
593 node->entity.entity_container_id = container_id;
594 } else {
595 node->entity.entity_container_id =
596 next_container_id(tree);
597 }
598 } else {
599 node->entity.entity_container_id =
600 entity->entity_container_id;
601 }
602
603 if (!is_remote) {
604 node->remote_container_id =
605 node->entity.entity_container_id;
606 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930607 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930608 pldm_entity_node *start = parent == NULL ? tree->root :
609 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930611 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500612 if (!prev) {
613 free(node);
614 return NULL;
615 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 pldm_entity_node *next = prev->next_sibling;
617 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500618 if (prev->entity.entity_instance_num == UINT16_MAX) {
619 free(node);
620 return NULL;
621 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930623 entity_instance_number != 0xFFFF ?
624 entity_instance_number :
625 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626 }
627 prev->next_sibling = node;
628 node->parent = prev->parent;
629 node->next_sibling = next;
630 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930631 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600632 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930633 }
634 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500635 if (is_update_container_id) {
636 entity->entity_container_id = node->entity.entity_container_id;
637 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930638 return node;
639}
640
641static void get_num_nodes(pldm_entity_node *node, size_t *num)
642{
643 if (node == NULL) {
644 return;
645 }
646
647 ++(*num);
648 get_num_nodes(node->next_sibling, num);
649 get_num_nodes(node->first_child, num);
650}
651
652static void entity_association_tree_visit(pldm_entity_node *node,
653 pldm_entity *entities, size_t *index)
654{
655 if (node == NULL) {
656 return;
657 }
658
659 pldm_entity *entity = &entities[*index];
660 ++(*index);
661 entity->entity_type = node->entity.entity_type;
662 entity->entity_instance_num = node->entity.entity_instance_num;
663 entity->entity_container_id = node->entity.entity_container_id;
664
665 entity_association_tree_visit(node->next_sibling, entities, index);
666 entity_association_tree_visit(node->first_child, entities, index);
667}
668
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930669LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930670void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
671 pldm_entity **entities, size_t *size)
672{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930673 if (!tree || !entities || !size) {
674 return;
675 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930676
677 *size = 0;
678 if (tree->root == NULL) {
679 return;
680 }
681
682 get_num_nodes(tree->root, size);
683 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930684 if (!entities) {
685 return;
686 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 size_t index = 0;
688 entity_association_tree_visit(tree->root, *entities, &index);
689}
690
691static void entity_association_tree_destroy(pldm_entity_node *node)
692{
693 if (node == NULL) {
694 return;
695 }
696
697 entity_association_tree_destroy(node->next_sibling);
698 entity_association_tree_destroy(node->first_child);
699 free(node);
700}
701
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930702LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930703void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
704{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930705 if (!tree) {
706 return;
707 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708
709 entity_association_tree_destroy(tree->root);
710 free(tree);
711}
712
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930713LIBPLDM_ABI_STABLE
714bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930715{
716 assert(node != NULL);
717
718 return node->first_child != NULL;
719}
720
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930721LIBPLDM_ABI_STABLE
722pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723{
724 assert(node != NULL);
725
726 return node->parent;
727}
728
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930729LIBPLDM_ABI_STABLE
730bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731{
732 assert(node != NULL);
733
734 if (node->parent.entity_type == 0 &&
735 node->parent.entity_instance_num == 0 &&
736 node->parent.entity_container_id == 0) {
737 return false;
738 }
739
740 return true;
741}
742
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930743LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
745 uint8_t association_type)
746{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930747 if (!node) {
748 return 0;
749 }
750
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930751 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
752 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
753 return 0;
754 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755
756 size_t count = 0;
757 pldm_entity_node *curr = node->first_child;
758 while (curr != NULL) {
759 if (curr->association_type == association_type) {
760 ++count;
761 }
762 curr = curr->next_sibling;
763 }
764
765 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930766 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930767}
768
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930769LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
771{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930772 if (!parent || !node) {
773 return false;
774 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775
776 pldm_entity_node *curr = parent->first_child;
777 while (curr != NULL) {
778 if (node->entity_type == curr->entity.entity_type &&
779 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930780 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781 return true;
782 }
783 curr = curr->next_sibling;
784 }
785
786 return false;
787}
788
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500789static void entity_association_pdr_add_children(
790 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
791 uint8_t contained_count, uint8_t association_type, bool is_remote,
792 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793{
794 uint8_t pdr[size];
795 uint8_t *start = pdr;
796
797 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
798 hdr->version = 1;
799 hdr->record_handle = 0;
800 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
801 hdr->record_change_num = 0;
802 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
803 start += sizeof(struct pldm_pdr_hdr);
804
805 uint16_t *container_id = (uint16_t *)start;
806 *container_id = htole16(curr->first_child->entity.entity_container_id);
807 start += sizeof(uint16_t);
808 *start = association_type;
809 start += sizeof(uint8_t);
810
811 pldm_entity *entity = (pldm_entity *)start;
812 entity->entity_type = htole16(curr->entity.entity_type);
813 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
814 entity->entity_container_id = htole16(curr->entity.entity_container_id);
815 start += sizeof(pldm_entity);
816
817 *start = contained_count;
818 start += sizeof(uint8_t);
819
820 pldm_entity_node *node = curr->first_child;
821 while (node != NULL) {
822 if (node->association_type == association_type) {
823 pldm_entity *entity = (pldm_entity *)start;
824 entity->entity_type = htole16(node->entity.entity_type);
825 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930827 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930828 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829 start += sizeof(pldm_entity);
830 }
831 node = node->next_sibling;
832 }
833
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500834 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
835 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836}
837
838static void entity_association_pdr_add_entry(pldm_entity_node *curr,
839 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500840 uint16_t terminus_handle,
841 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930843 uint8_t num_logical_children = pldm_entity_get_num_children(
844 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
845 uint8_t num_physical_children = pldm_entity_get_num_children(
846 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847
848 if (num_logical_children) {
849 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930850 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
851 sizeof(uint8_t) + sizeof(pldm_entity) +
852 sizeof(uint8_t) +
853 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930854 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 curr, repo, logical_pdr_size, num_logical_children,
856 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500857 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930858 }
859
860 if (num_physical_children) {
861 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930862 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
863 sizeof(uint8_t) + sizeof(pldm_entity) +
864 sizeof(uint8_t) +
865 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930866 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 curr, repo, physical_pdr_size, num_physical_children,
868 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500869 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930870 }
871}
872
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930873LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
875{
876 if (entities == NULL || num_entities == 0) {
877 return true;
878 }
879 size_t i = 0;
880 while (i < num_entities) {
881 if ((*entities + i)->entity_type == entity.entity_type) {
882 return true;
883 }
884 i++;
885 }
886 return false;
887}
888
889static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
890 pldm_entity **entities,
891 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500892 uint16_t terminus_handle,
893 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894{
895 if (curr == NULL) {
896 return;
897 }
898 bool to_add = true;
899 to_add = is_present(curr->entity, entities, num_entities);
900 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500901 entity_association_pdr_add_entry(
902 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903 }
904 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500905 num_entities, is_remote, terminus_handle,
906 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500908 num_entities, is_remote, terminus_handle,
909 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910}
911
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930912LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
914 pldm_pdr *repo, bool is_remote,
915 uint16_t terminus_handle)
916{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930917 if (!tree || !repo) {
918 return;
919 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920
921 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500922 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930923}
924
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930925LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930927 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
928 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929{
Andrew Jefferycc394522023-07-03 12:49:31 +0930930 int rc = pldm_entity_association_pdr_add_from_node_check(
931 node, repo, entities, num_entities, is_remote, terminus_handle);
932 (void)rc;
933 assert(!rc);
934}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930935
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930936LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930937int pldm_entity_association_pdr_add_from_node_check(
938 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
939 size_t num_entities, bool is_remote, uint16_t terminus_handle)
940{
941 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500942 node, repo, entities, num_entities, is_remote, terminus_handle,
943 0);
944}
945
946LIBPLDM_ABI_TESTING
947int pldm_entity_association_pdr_add_from_node_with_record_handle(
948 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
949 size_t num_entities, bool is_remote, uint16_t terminus_handle,
950 uint32_t record_handle)
951{
952 if (!node || !repo || !entities) {
953 return -EINVAL;
954 }
955
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500957 is_remote, terminus_handle, record_handle);
958
959 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960}
961
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930962LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930963void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
964 pldm_entity_node **node)
965{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600966 bool is_entity_container_id;
967 bool is_entity_instance_num;
968 bool is_type;
969
Andrew Jeffery9c766792022-08-10 23:12:49 +0930970 if (tree_node == NULL) {
971 return;
972 }
973
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600974 is_type = tree_node->entity.entity_type == entity.entity_type;
975 is_entity_instance_num = tree_node->entity.entity_instance_num ==
976 entity.entity_instance_num;
977 is_entity_container_id = tree_node->entity.entity_container_id ==
978 entity.entity_container_id;
979
980 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 *node = tree_node;
982 return;
983 }
984
985 find_entity_ref_in_tree(tree_node->first_child, entity, node);
986 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
987}
988
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930989LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930990void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
991 pldm_entity entity, pldm_entity_node **node)
992{
Andrew Jefferyba47e832023-07-03 11:41:03 +0930993 if (!tree || !node) {
994 return;
995 }
996
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997 find_entity_ref_in_tree(tree->root, entity, node);
998}
999
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1002 uint16_t terminus_handle)
1003{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301004 if (!repo) {
1005 return;
1006 }
1007
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008 bool removed = false;
1009
1010 pldm_pdr_record *record = repo->first;
1011 pldm_pdr_record *prev = NULL;
1012 while (record != NULL) {
1013 pldm_pdr_record *next = record->next;
1014 if (record->terminus_handle == terminus_handle) {
1015 if (repo->first == record) {
1016 repo->first = next;
1017 } else {
1018 prev->next = next;
1019 }
1020 if (repo->last == record) {
1021 repo->last = prev;
1022 }
1023 if (record->data) {
1024 free(record->data);
1025 }
1026 --repo->record_count;
1027 repo->size -= record->size;
1028 free(record);
1029 removed = true;
1030 } else {
1031 prev = record;
1032 }
1033 record = next;
1034 }
1035
1036 if (removed == true) {
1037 record = repo->first;
1038 uint32_t record_handle = 0;
1039 while (record != NULL) {
1040 record->record_handle = ++record_handle;
1041 if (record->data != NULL) {
1042 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301043 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301045 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301046 }
1047 record = record->next;
1048 }
1049 }
1050}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301051
1052LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1054{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301055 if (!repo) {
1056 return;
1057 }
1058
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059 bool removed = false;
1060
1061 pldm_pdr_record *record = repo->first;
1062 pldm_pdr_record *prev = NULL;
1063 while (record != NULL) {
1064 pldm_pdr_record *next = record->next;
1065 if (record->is_remote == true) {
1066 if (repo->first == record) {
1067 repo->first = next;
1068 } else {
1069 prev->next = next;
1070 }
1071 if (repo->last == record) {
1072 repo->last = prev;
1073 }
1074 if (record->data) {
1075 free(record->data);
1076 }
1077 --repo->record_count;
1078 repo->size -= record->size;
1079 free(record);
1080 removed = true;
1081 } else {
1082 prev = record;
1083 }
1084 record = next;
1085 }
1086
1087 if (removed == true) {
1088 record = repo->first;
1089 uint32_t record_handle = 0;
1090 while (record != NULL) {
1091 record->record_handle = ++record_handle;
1092 if (record->data != NULL) {
1093 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301094 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301096 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301097 }
1098 record = record->next;
1099 }
1100 }
1101}
1102
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001103LIBPLDM_ABI_TESTING
1104pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1105 uint32_t first, uint32_t last)
1106{
1107 pldm_pdr_record *record = NULL;
1108 pldm_pdr_record *curr;
1109
1110 if (!repo) {
1111 return NULL;
1112 }
1113 for (curr = repo->first; curr; curr = curr->next) {
1114 if (first > curr->record_handle || last < curr->record_handle) {
1115 continue;
1116 }
1117 if (!record || curr->record_handle > record->record_handle) {
1118 record = curr;
1119 }
1120 }
1121
1122 return record;
1123}
1124
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001125static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1126 pldm_entity *entity,
1127 pldm_entity_node **out,
1128 bool is_remote)
1129{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001130 if (node == NULL) {
1131 return;
1132 }
1133 bool is_entity_type;
1134 bool is_entity_instance_num;
1135
1136 is_entity_type = node->entity.entity_type == entity->entity_type;
1137 is_entity_instance_num = node->entity.entity_instance_num ==
1138 entity->entity_instance_num;
1139
1140 if (!is_remote ||
1141 node->remote_container_id == entity->entity_container_id) {
1142 if (is_entity_type && is_entity_instance_num) {
1143 entity->entity_container_id =
1144 node->entity.entity_container_id;
1145 *out = node;
1146 return;
1147 }
1148 }
1149 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1150 is_remote);
1151 entity_association_tree_find_if_remote(node->first_child, entity, out,
1152 is_remote);
1153}
1154
1155LIBPLDM_ABI_TESTING
1156pldm_entity_node *
1157pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1158 pldm_entity *entity, bool is_remote)
1159{
1160 if (!tree || !entity) {
1161 return NULL;
1162 }
1163 pldm_entity_node *node = NULL;
1164 entity_association_tree_find_if_remote(tree->root, entity, &node,
1165 is_remote);
1166 return node;
1167}
1168
Andrew Jeffery7f589312023-07-03 12:03:25 +09301169LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301170void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1171 pldm_entity_node **out)
1172{
1173 if (node == NULL) {
1174 return;
1175 }
1176
1177 if (node->entity.entity_type == entity->entity_type &&
1178 node->entity.entity_instance_num == entity->entity_instance_num) {
1179 entity->entity_container_id = node->entity.entity_container_id;
1180 *out = node;
1181 return;
1182 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301183 entity_association_tree_find(node->next_sibling, entity, out);
1184 entity_association_tree_find(node->first_child, entity, out);
1185}
1186
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301187LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301188pldm_entity_node *
1189pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1190 pldm_entity *entity)
1191{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301192 if (!tree || !entity) {
1193 return NULL;
1194 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301195
1196 pldm_entity_node *node = NULL;
1197 entity_association_tree_find(tree->root, entity, &node);
1198 return node;
1199}
1200
1201static void entity_association_tree_copy(pldm_entity_node *org_node,
1202 pldm_entity_node **new_node)
1203{
1204 if (org_node == NULL) {
1205 return;
1206 }
1207 *new_node = malloc(sizeof(pldm_entity_node));
1208 (*new_node)->parent = org_node->parent;
1209 (*new_node)->entity = org_node->entity;
1210 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001211 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212 (*new_node)->first_child = NULL;
1213 (*new_node)->next_sibling = NULL;
1214 entity_association_tree_copy(org_node->first_child,
1215 &((*new_node)->first_child));
1216 entity_association_tree_copy(org_node->next_sibling,
1217 &((*new_node)->next_sibling));
1218}
1219
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301220LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301222 pldm_entity_association_tree *org_tree,
1223 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301224{
1225 new_tree->last_used_container_id = org_tree->last_used_container_id;
1226 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1227}
1228
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301229LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301231 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301233 if (!tree) {
1234 return;
1235 }
1236
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 entity_association_tree_destroy(tree->root);
1238 tree->last_used_container_id = 0;
1239 tree->root = NULL;
1240}
1241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301243bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1244{
1245 return ((tree->root == NULL) ? true : false);
1246}
1247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301248LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301249void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1250 size_t *num_entities,
1251 pldm_entity **entities)
1252{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301253 if (!pdr || !num_entities || !entities) {
1254 return;
1255 }
1256#define PDR_MIN_SIZE \
1257 (sizeof(struct pldm_pdr_hdr) + \
1258 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301259 if (pdr_len < PDR_MIN_SIZE) {
1260 return;
1261 }
1262#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301263
1264 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301265 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1266 return;
1267 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301268
1269 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301270 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301271 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301272 start += sizeof(struct pldm_pdr_hdr);
1273 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301274 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301275 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301276 if (l_num_entities < 2) {
1277 return;
1278 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301279 if (start + sizeof(struct pldm_pdr_entity_association) +
1280 sizeof(pldm_entity) * (l_num_entities - 2) !=
1281 end) {
1282 return;
1283 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301284 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301285 if (!l_entities) {
1286 return;
1287 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301288 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301289 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301290 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301291 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301292 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301293 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301295 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1296 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1297 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301298 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301299 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301300 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301301 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301302
1303 *num_entities = l_num_entities;
1304 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301305}