blob: a611c7362ea2c1ed54c4292af4c65d7846f3735f [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_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268uint32_t pldm_pdr_add_fru_record_set(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 Jefferyc821a702023-07-03 13:32:11 +0930274 int rc = pldm_pdr_add_fru_record_set_check(
275 repo, terminus_handle, fru_rsi, entity_type,
276 entity_instance_num, container_id, &bmc_record_handle);
277 (void)rc;
278 assert(!rc);
279 return bmc_record_handle;
280}
281
Andrew Jefferya2c69112023-07-07 10:41:38 +0930282LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930283int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
284 uint16_t fru_rsi, uint16_t entity_type,
285 uint16_t entity_instance_num,
286 uint16_t container_id,
287 uint32_t *bmc_record_handle)
288{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930289 if (!repo || !bmc_record_handle) {
290 return -EINVAL;
291 }
292
Andrew Jeffery9c766792022-08-10 23:12:49 +0930293 uint32_t size = sizeof(struct pldm_pdr_hdr) +
294 sizeof(struct pldm_pdr_fru_record_set);
295 uint8_t data[size];
296
297 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
298 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930299 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930300 hdr->type = PLDM_PDR_FRU_RECORD_SET;
301 hdr->record_change_num = 0;
302 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
303 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930304 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
305 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930306 fru->terminus_handle = htole16(terminus_handle);
307 fru->fru_rsi = htole16(fru_rsi);
308 fru->entity_type = htole16(entity_type);
309 fru->entity_instance_num = htole16(entity_instance_num);
310 fru->container_id = htole16(container_id);
311
Andrew Jefferyc821a702023-07-03 13:32:11 +0930312 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
313 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930314}
315
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930316LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930318 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
319 uint16_t *entity_type, uint16_t *entity_instance_num,
320 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930322 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
323 !container_id) {
324 return NULL;
325 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326
327 uint8_t *data = NULL;
328 uint32_t size = 0;
329 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930330 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930331 while (curr_record != NULL) {
332 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 (struct pldm_pdr_fru_record_set
334 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335 if (fru->fru_rsi == htole16(fru_rsi)) {
336 *terminus_handle = le16toh(fru->terminus_handle);
337 *entity_type = le16toh(fru->entity_type);
338 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930339 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930340 *container_id = le16toh(fru->container_id);
341 return curr_record;
342 }
343 data = NULL;
344 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930345 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
346 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347 }
348
349 *terminus_handle = 0;
350 *entity_type = 0;
351 *entity_instance_num = 0;
352 *container_id = 0;
353
354 return NULL;
355}
356
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930357LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930358/* NOLINTNEXTLINE(readability-identifier-naming) */
359void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
360 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930361{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930362 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363 uint32_t size = 0;
364 const pldm_pdr_record *record;
365 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930366 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930367
368 do {
369 if (record != NULL) {
370 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930371 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 (struct pldm_terminus_locator_type_mctp_eid *)
374 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930375 if (pdr->terminus_handle == terminus_handle &&
376 pdr->tid == tid && value->eid == tl_eid) {
377 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 break;
379 }
380 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930381 record = pldm_pdr_find_record_by_type(repo,
382 PLDM_TERMINUS_LOCATOR_PDR,
383 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930384 } while (record);
385}
386
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500387static bool pldm_record_handle_in_range(uint32_t record_handle,
388 uint32_t first_record_handle,
389 uint32_t last_record_handle)
390{
391 return record_handle >= first_record_handle &&
392 record_handle <= last_record_handle;
393}
394
395LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500396int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500397 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500398 uint8_t child_index, uint32_t range_exclude_start_handle,
399 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500400{
401 pldm_pdr_record *record;
402 if (!repo) {
403 return -EINVAL;
404 }
405
406 for (record = repo->first; record; record = record->next) {
407 bool is_container_entity_instance_number;
408 struct pldm_pdr_entity_association *pdr;
409 bool is_container_entity_type;
410 struct pldm_entity *child;
411 struct pldm_pdr_hdr *hdr;
412 bool in_range;
413
414 // pldm_pdr_add() takes only uint8_t* data as an argument.
415 // The expectation here is the pldm_pdr_hdr is the first field of the record data
416 hdr = (struct pldm_pdr_hdr *)record->data;
417 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
418 continue;
419 }
420 in_range = pldm_record_handle_in_range(
421 record->record_handle, range_exclude_start_handle,
422 range_exclude_end_handle);
423 if (in_range) {
424 continue;
425 }
426
427 // this cast is valid with respect to alignment because
428 // struct pldm_pdr_hdr is declared with __attribute__((packed))
429 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500430 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500431 continue;
432 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500433
434 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500435 is_container_entity_type = pdr->container.entity_type ==
436 entity_type;
437 is_container_entity_instance_number =
438 pdr->container.entity_instance_num == entity_instance;
439 if (is_container_entity_type &&
440 is_container_entity_instance_number) {
441 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500442 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500443 }
444 }
445 return -ENOKEY;
446}
447
Andrew Jeffery9c766792022-08-10 23:12:49 +0930448typedef struct pldm_entity_association_tree {
449 pldm_entity_node *root;
450 uint16_t last_used_container_id;
451} pldm_entity_association_tree;
452
453typedef struct pldm_entity_node {
454 pldm_entity entity;
455 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600456 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930457 pldm_entity_node *first_child;
458 pldm_entity_node *next_sibling;
459 uint8_t association_type;
460} pldm_entity_node;
461
462static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
463{
464 assert(tree != NULL);
465 assert(tree->last_used_container_id != UINT16_MAX);
466
467 return ++tree->last_used_container_id;
468}
469
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930470LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471pldm_entity pldm_entity_extract(pldm_entity_node *node)
472{
473 assert(node != NULL);
474
475 return node->entity;
476}
477
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600478LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930479uint16_t
480pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600481{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930482 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600483
Andrew Jeffery15b88182023-06-30 13:29:17 +0930484 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600485}
486
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930487LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930488pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930489{
490 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930491 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930492 if (!tree) {
493 return NULL;
494 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930495 tree->root = NULL;
496 tree->last_used_container_id = 0;
497
498 return tree;
499}
500
501static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
502 uint16_t entity_type)
503{
504 assert(start != NULL);
505
506 /* Insert after the the last node that matches the input entity type, or
507 * at the end if no such match occurrs
508 */
509 while (start->next_sibling != NULL) {
510 uint16_t this_type = start->entity.entity_type;
511 pldm_entity_node *next = start->next_sibling;
512 if (this_type == entity_type &&
513 (this_type != next->entity.entity_type)) {
514 break;
515 }
516 start = start->next_sibling;
517 }
518
519 return start;
520}
521
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930522LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930523pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930524 pldm_entity_association_tree *tree, pldm_entity *entity,
525 uint16_t entity_instance_number, pldm_entity_node *parent,
526 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930527{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500528 return pldm_entity_association_tree_add_entity(tree, entity,
529 entity_instance_number,
530 parent, association_type,
531 false, true, 0xFFFF);
532}
533
534LIBPLDM_ABI_TESTING
535pldm_entity_node *pldm_entity_association_tree_add_entity(
536 pldm_entity_association_tree *tree, pldm_entity *entity,
537 uint16_t entity_instance_number, pldm_entity_node *parent,
538 uint8_t association_type, bool is_remote, bool is_update_container_id,
539 uint16_t container_id)
540{
541 if ((!tree) || (!entity)) {
542 return NULL;
543 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544
545 if (entity_instance_number != 0xFFFF && parent != NULL) {
546 pldm_entity node;
547 node.entity_type = entity->entity_type;
548 node.entity_instance_num = entity_instance_number;
549 if (pldm_is_current_parent_child(parent, &node)) {
550 return NULL;
551 }
552 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500553 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
554 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
555 return NULL;
556 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500558 if (!node) {
559 return NULL;
560 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 node->first_child = NULL;
562 node->next_sibling = NULL;
563 node->parent.entity_type = 0;
564 node->parent.entity_instance_num = 0;
565 node->parent.entity_container_id = 0;
566 node->entity.entity_type = entity->entity_type;
567 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930568 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600570 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500572 if (parent != NULL) {
573 free(node);
574 return NULL;
575 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 tree->root = node;
577 /* container_id 0 here indicates this is the top-most entry */
578 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600579 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 } else if (parent != NULL && parent->first_child == NULL) {
581 parent->first_child = node;
582 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500583
584 if (is_remote) {
585 node->remote_container_id = entity->entity_container_id;
586 }
587 if (is_update_container_id) {
588 if (container_id != 0xFFFF) {
589 node->entity.entity_container_id = container_id;
590 } else {
591 node->entity.entity_container_id =
592 next_container_id(tree);
593 }
594 } else {
595 node->entity.entity_container_id =
596 entity->entity_container_id;
597 }
598
599 if (!is_remote) {
600 node->remote_container_id =
601 node->entity.entity_container_id;
602 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930604 pldm_entity_node *start = parent == NULL ? tree->root :
605 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930607 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500608 if (!prev) {
609 free(node);
610 return NULL;
611 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 pldm_entity_node *next = prev->next_sibling;
613 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500614 if (prev->entity.entity_instance_num == UINT16_MAX) {
615 free(node);
616 return NULL;
617 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930619 entity_instance_number != 0xFFFF ?
620 entity_instance_number :
621 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 }
623 prev->next_sibling = node;
624 node->parent = prev->parent;
625 node->next_sibling = next;
626 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930627 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600628 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 }
630 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500631 if (is_update_container_id) {
632 entity->entity_container_id = node->entity.entity_container_id;
633 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 return node;
635}
636
637static void get_num_nodes(pldm_entity_node *node, size_t *num)
638{
639 if (node == NULL) {
640 return;
641 }
642
643 ++(*num);
644 get_num_nodes(node->next_sibling, num);
645 get_num_nodes(node->first_child, num);
646}
647
648static void entity_association_tree_visit(pldm_entity_node *node,
649 pldm_entity *entities, size_t *index)
650{
651 if (node == NULL) {
652 return;
653 }
654
655 pldm_entity *entity = &entities[*index];
656 ++(*index);
657 entity->entity_type = node->entity.entity_type;
658 entity->entity_instance_num = node->entity.entity_instance_num;
659 entity->entity_container_id = node->entity.entity_container_id;
660
661 entity_association_tree_visit(node->next_sibling, entities, index);
662 entity_association_tree_visit(node->first_child, entities, index);
663}
664
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930665LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
667 pldm_entity **entities, size_t *size)
668{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930669 if (!tree || !entities || !size) {
670 return;
671 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930672
673 *size = 0;
674 if (tree->root == NULL) {
675 return;
676 }
677
678 get_num_nodes(tree->root, size);
679 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930680 if (!entities) {
681 return;
682 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683 size_t index = 0;
684 entity_association_tree_visit(tree->root, *entities, &index);
685}
686
687static void entity_association_tree_destroy(pldm_entity_node *node)
688{
689 if (node == NULL) {
690 return;
691 }
692
693 entity_association_tree_destroy(node->next_sibling);
694 entity_association_tree_destroy(node->first_child);
695 free(node);
696}
697
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930698LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930699void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
700{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930701 if (!tree) {
702 return;
703 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704
705 entity_association_tree_destroy(tree->root);
706 free(tree);
707}
708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930709LIBPLDM_ABI_STABLE
710bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711{
712 assert(node != NULL);
713
714 return node->first_child != NULL;
715}
716
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930717LIBPLDM_ABI_STABLE
718pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719{
720 assert(node != NULL);
721
722 return node->parent;
723}
724
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930725LIBPLDM_ABI_STABLE
726bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727{
728 assert(node != NULL);
729
730 if (node->parent.entity_type == 0 &&
731 node->parent.entity_instance_num == 0 &&
732 node->parent.entity_container_id == 0) {
733 return false;
734 }
735
736 return true;
737}
738
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930739LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930740uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
741 uint8_t association_type)
742{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930743 if (!node) {
744 return 0;
745 }
746
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930747 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
748 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
749 return 0;
750 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751
752 size_t count = 0;
753 pldm_entity_node *curr = node->first_child;
754 while (curr != NULL) {
755 if (curr->association_type == association_type) {
756 ++count;
757 }
758 curr = curr->next_sibling;
759 }
760
761 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930762 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763}
764
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930765LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
767{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930768 if (!parent || !node) {
769 return false;
770 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771
772 pldm_entity_node *curr = parent->first_child;
773 while (curr != NULL) {
774 if (node->entity_type == curr->entity.entity_type &&
775 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930776 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777 return true;
778 }
779 curr = curr->next_sibling;
780 }
781
782 return false;
783}
784
Andrew Jeffery65945992023-07-17 15:04:21 +0930785static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500786 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
787 uint8_t contained_count, uint8_t association_type, bool is_remote,
788 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930789{
790 uint8_t pdr[size];
791 uint8_t *start = pdr;
792
793 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
794 hdr->version = 1;
795 hdr->record_handle = 0;
796 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
797 hdr->record_change_num = 0;
798 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
799 start += sizeof(struct pldm_pdr_hdr);
800
801 uint16_t *container_id = (uint16_t *)start;
802 *container_id = htole16(curr->first_child->entity.entity_container_id);
803 start += sizeof(uint16_t);
804 *start = association_type;
805 start += sizeof(uint8_t);
806
807 pldm_entity *entity = (pldm_entity *)start;
808 entity->entity_type = htole16(curr->entity.entity_type);
809 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
810 entity->entity_container_id = htole16(curr->entity.entity_container_id);
811 start += sizeof(pldm_entity);
812
813 *start = contained_count;
814 start += sizeof(uint8_t);
815
816 pldm_entity_node *node = curr->first_child;
817 while (node != NULL) {
818 if (node->association_type == association_type) {
819 pldm_entity *entity = (pldm_entity *)start;
820 entity->entity_type = htole16(node->entity.entity_type);
821 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930822 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930823 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930824 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825 start += sizeof(pldm_entity);
826 }
827 node = node->next_sibling;
828 }
829
Andrew Jeffery65945992023-07-17 15:04:21 +0930830 return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
831 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930832}
833
Andrew Jeffery65945992023-07-17 15:04:21 +0930834static int entity_association_pdr_add_entry(pldm_entity_node *curr,
835 pldm_pdr *repo, bool is_remote,
836 uint16_t terminus_handle,
837 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 uint8_t num_logical_children = pldm_entity_get_num_children(
840 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
841 uint8_t num_physical_children = pldm_entity_get_num_children(
842 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930843 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844
845 if (num_logical_children) {
846 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930847 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
848 sizeof(uint8_t) + sizeof(pldm_entity) +
849 sizeof(uint8_t) +
850 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930851 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 curr, repo, logical_pdr_size, num_logical_children,
853 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500854 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930855 if (rc < 0) {
856 return rc;
857 }
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 Jeffery65945992023-07-17 15:04:21 +0930866 rc = 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 Jeffery65945992023-07-17 15:04:21 +0930870 if (rc < 0) {
871 return rc;
872 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930874
875 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930876}
877
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930878static bool is_present(pldm_entity entity, pldm_entity **entities,
879 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930880{
881 if (entities == NULL || num_entities == 0) {
882 return true;
883 }
884 size_t i = 0;
885 while (i < num_entities) {
886 if ((*entities + i)->entity_type == entity.entity_type) {
887 return true;
888 }
889 i++;
890 }
891 return false;
892}
893
Andrew Jeffery65945992023-07-17 15:04:21 +0930894static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
895 pldm_entity **entities,
896 size_t num_entities, bool is_remote,
897 uint16_t terminus_handle,
898 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899{
Andrew Jeffery65945992023-07-17 15:04:21 +0930900 int rc;
901
Andrew Jeffery9c766792022-08-10 23:12:49 +0930902 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930903 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930905
906 if (is_present(curr->entity, entities, num_entities)) {
907 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500908 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930909 if (rc) {
910 return rc;
911 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930913
914 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
915 num_entities, is_remote,
916 terminus_handle, record_handle);
917 if (rc) {
918 return rc;
919 }
920
921 return entity_association_pdr_add(curr->first_child, repo, entities,
922 num_entities, is_remote,
923 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924}
925
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930926LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
928 pldm_pdr *repo, bool is_remote,
929 uint16_t terminus_handle)
930{
Andrew Jeffery65945992023-07-17 15:04:21 +0930931 int rc = pldm_entity_association_pdr_add_check(tree, repo, is_remote,
932 terminus_handle);
933 (void)rc;
934 assert(!rc);
935}
936
937LIBPLDM_ABI_TESTING
938int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
939 pldm_pdr *repo, bool is_remote,
940 uint16_t terminus_handle)
941{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930942 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930943 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930944 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945
Andrew Jeffery65945992023-07-17 15:04:21 +0930946 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
947 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948}
949
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930950LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930952 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
953 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930954{
Andrew Jefferycc394522023-07-03 12:49:31 +0930955 int rc = pldm_entity_association_pdr_add_from_node_check(
956 node, repo, entities, num_entities, is_remote, terminus_handle);
957 (void)rc;
958 assert(!rc);
959}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930961LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930962int pldm_entity_association_pdr_add_from_node_check(
963 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
964 size_t num_entities, bool is_remote, uint16_t terminus_handle)
965{
966 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500967 node, repo, entities, num_entities, is_remote, terminus_handle,
968 0);
969}
970
971LIBPLDM_ABI_TESTING
972int pldm_entity_association_pdr_add_from_node_with_record_handle(
973 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
974 size_t num_entities, bool is_remote, uint16_t terminus_handle,
975 uint32_t record_handle)
976{
977 if (!node || !repo || !entities) {
978 return -EINVAL;
979 }
980
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500982 is_remote, terminus_handle, record_handle);
983
984 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930985}
986
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930987LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930988void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
989 pldm_entity_node **node)
990{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600991 bool is_entity_container_id;
992 bool is_entity_instance_num;
993 bool is_type;
994
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995 if (tree_node == NULL) {
996 return;
997 }
998
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600999 is_type = tree_node->entity.entity_type == entity.entity_type;
1000 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1001 entity.entity_instance_num;
1002 is_entity_container_id = tree_node->entity.entity_container_id ==
1003 entity.entity_container_id;
1004
1005 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006 *node = tree_node;
1007 return;
1008 }
1009
1010 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1011 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1012}
1013
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301014LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301015void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1016 pldm_entity entity, pldm_entity_node **node)
1017{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301018 if (!tree || !node) {
1019 return;
1020 }
1021
Andrew Jeffery9c766792022-08-10 23:12:49 +09301022 find_entity_ref_in_tree(tree->root, entity, node);
1023}
1024
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301025LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301026void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1027 uint16_t terminus_handle)
1028{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301029 if (!repo) {
1030 return;
1031 }
1032
Andrew Jeffery9c766792022-08-10 23:12:49 +09301033 bool removed = false;
1034
1035 pldm_pdr_record *record = repo->first;
1036 pldm_pdr_record *prev = NULL;
1037 while (record != NULL) {
1038 pldm_pdr_record *next = record->next;
1039 if (record->terminus_handle == terminus_handle) {
1040 if (repo->first == record) {
1041 repo->first = next;
1042 } else {
1043 prev->next = next;
1044 }
1045 if (repo->last == record) {
1046 repo->last = prev;
1047 }
1048 if (record->data) {
1049 free(record->data);
1050 }
1051 --repo->record_count;
1052 repo->size -= record->size;
1053 free(record);
1054 removed = true;
1055 } else {
1056 prev = record;
1057 }
1058 record = next;
1059 }
1060
1061 if (removed == true) {
1062 record = repo->first;
1063 uint32_t record_handle = 0;
1064 while (record != NULL) {
1065 record->record_handle = ++record_handle;
1066 if (record->data != NULL) {
1067 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301068 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301069 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301070 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301071 }
1072 record = record->next;
1073 }
1074 }
1075}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301076
1077LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301078void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1079{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301080 if (!repo) {
1081 return;
1082 }
1083
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084 bool removed = false;
1085
1086 pldm_pdr_record *record = repo->first;
1087 pldm_pdr_record *prev = NULL;
1088 while (record != NULL) {
1089 pldm_pdr_record *next = record->next;
1090 if (record->is_remote == true) {
1091 if (repo->first == record) {
1092 repo->first = next;
1093 } else {
1094 prev->next = next;
1095 }
1096 if (repo->last == record) {
1097 repo->last = prev;
1098 }
1099 if (record->data) {
1100 free(record->data);
1101 }
1102 --repo->record_count;
1103 repo->size -= record->size;
1104 free(record);
1105 removed = true;
1106 } else {
1107 prev = record;
1108 }
1109 record = next;
1110 }
1111
1112 if (removed == true) {
1113 record = repo->first;
1114 uint32_t record_handle = 0;
1115 while (record != NULL) {
1116 record->record_handle = ++record_handle;
1117 if (record->data != NULL) {
1118 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301119 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301120 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301121 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301122 }
1123 record = record->next;
1124 }
1125 }
1126}
1127
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001128LIBPLDM_ABI_TESTING
1129pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1130 uint32_t first, uint32_t last)
1131{
1132 pldm_pdr_record *record = NULL;
1133 pldm_pdr_record *curr;
1134
1135 if (!repo) {
1136 return NULL;
1137 }
1138 for (curr = repo->first; curr; curr = curr->next) {
1139 if (first > curr->record_handle || last < curr->record_handle) {
1140 continue;
1141 }
1142 if (!record || curr->record_handle > record->record_handle) {
1143 record = curr;
1144 }
1145 }
1146
1147 return record;
1148}
1149
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001150static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1151 pldm_entity *entity,
1152 pldm_entity_node **out,
1153 bool is_remote)
1154{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001155 if (node == NULL) {
1156 return;
1157 }
1158 bool is_entity_type;
1159 bool is_entity_instance_num;
1160
1161 is_entity_type = node->entity.entity_type == entity->entity_type;
1162 is_entity_instance_num = node->entity.entity_instance_num ==
1163 entity->entity_instance_num;
1164
1165 if (!is_remote ||
1166 node->remote_container_id == entity->entity_container_id) {
1167 if (is_entity_type && is_entity_instance_num) {
1168 entity->entity_container_id =
1169 node->entity.entity_container_id;
1170 *out = node;
1171 return;
1172 }
1173 }
1174 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1175 is_remote);
1176 entity_association_tree_find_if_remote(node->first_child, entity, out,
1177 is_remote);
1178}
1179
1180LIBPLDM_ABI_TESTING
1181pldm_entity_node *
1182pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1183 pldm_entity *entity, bool is_remote)
1184{
1185 if (!tree || !entity) {
1186 return NULL;
1187 }
1188 pldm_entity_node *node = NULL;
1189 entity_association_tree_find_if_remote(tree->root, entity, &node,
1190 is_remote);
1191 return node;
1192}
1193
Andrew Jeffery7f589312023-07-03 12:03:25 +09301194LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301195void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1196 pldm_entity_node **out)
1197{
1198 if (node == NULL) {
1199 return;
1200 }
1201
1202 if (node->entity.entity_type == entity->entity_type &&
1203 node->entity.entity_instance_num == entity->entity_instance_num) {
1204 entity->entity_container_id = node->entity.entity_container_id;
1205 *out = node;
1206 return;
1207 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301208 entity_association_tree_find(node->next_sibling, entity, out);
1209 entity_association_tree_find(node->first_child, entity, out);
1210}
1211
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301212LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301213pldm_entity_node *
1214pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1215 pldm_entity *entity)
1216{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301217 if (!tree || !entity) {
1218 return NULL;
1219 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220
1221 pldm_entity_node *node = NULL;
1222 entity_association_tree_find(tree->root, entity, &node);
1223 return node;
1224}
1225
1226static void entity_association_tree_copy(pldm_entity_node *org_node,
1227 pldm_entity_node **new_node)
1228{
1229 if (org_node == NULL) {
1230 return;
1231 }
1232 *new_node = malloc(sizeof(pldm_entity_node));
1233 (*new_node)->parent = org_node->parent;
1234 (*new_node)->entity = org_node->entity;
1235 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001236 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 (*new_node)->first_child = NULL;
1238 (*new_node)->next_sibling = NULL;
1239 entity_association_tree_copy(org_node->first_child,
1240 &((*new_node)->first_child));
1241 entity_association_tree_copy(org_node->next_sibling,
1242 &((*new_node)->next_sibling));
1243}
1244
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301245LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301246void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301247 pldm_entity_association_tree *org_tree,
1248 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301249{
1250 new_tree->last_used_container_id = org_tree->last_used_container_id;
1251 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1252}
1253
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301254LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301255void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301256 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301257{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301258 if (!tree) {
1259 return;
1260 }
1261
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262 entity_association_tree_destroy(tree->root);
1263 tree->last_used_container_id = 0;
1264 tree->root = NULL;
1265}
1266
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301267LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301268bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1269{
1270 return ((tree->root == NULL) ? true : false);
1271}
1272
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301273LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301274void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1275 size_t *num_entities,
1276 pldm_entity **entities)
1277{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301278 if (!pdr || !num_entities || !entities) {
1279 return;
1280 }
1281#define PDR_MIN_SIZE \
1282 (sizeof(struct pldm_pdr_hdr) + \
1283 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301284 if (pdr_len < PDR_MIN_SIZE) {
1285 return;
1286 }
1287#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301288
1289 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301290 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1291 return;
1292 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301293
1294 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301295 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301296 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297 start += sizeof(struct pldm_pdr_hdr);
1298 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301299 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301300 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301301 if (l_num_entities < 2) {
1302 return;
1303 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301304 if (start + sizeof(struct pldm_pdr_entity_association) +
1305 sizeof(pldm_entity) * (l_num_entities - 2) !=
1306 end) {
1307 return;
1308 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301309 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301310 if (!l_entities) {
1311 return;
1312 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301313 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301314 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301315 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301316 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301317 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301318 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301319 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301320 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1321 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1322 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301323 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301324 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301325 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301326 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301327
1328 *num_entities = l_num_entities;
1329 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301330}