blob: a4277ccccf6e203cff757097e002600b9df1b6ad [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 Jefferyc6cc0282023-07-17 12:11:37 +093057 uint32_t curr;
58
Andrew Jeffery3b93d092023-07-17 13:01:50 +093059 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093060 return -EINVAL;
61 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093062
Andrew Jeffery3b93d092023-07-17 13:01:50 +093063 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093064 curr = *record_handle;
65 } else if (repo->last) {
66 curr = repo->last->record_handle;
67 if (curr == UINT32_MAX) {
68 return -EOVERFLOW;
69 }
70 curr += 1;
71 } else {
72 curr = 1;
73 }
74
Andrew Jeffery9c766792022-08-10 23:12:49 +093075 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093076 if (!record) {
77 return -ENOMEM;
78 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093079
Andrew Jeffery572a3952023-07-03 13:19:28 +093080 if (data) {
81 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093082 if (!record->data) {
83 free(record);
84 return -ENOMEM;
85 }
86 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093087 }
88
Andrew Jeffery9c766792022-08-10 23:12:49 +093089 record->size = size;
90 record->is_remote = is_remote;
91 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093092 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093093
Andrew Jeffery3b93d092023-07-17 13:01:50 +093094 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093095 /* If record handle is 0, that is an indication for this API to
96 * compute a new handle. For that reason, the computed handle
97 * needs to be populated in the PDR header. For a case where the
98 * caller supplied the record handle, it would exist in the
99 * header already.
100 */
101 struct pldm_pdr_hdr *hdr = (void *)record->data;
102 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930103 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930104
Andrew Jeffery9c766792022-08-10 23:12:49 +0930105 record->next = NULL;
106
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930107 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930108 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930109 repo->first = record;
110 repo->last = record;
111 } else {
112 repo->last->next = record;
113 repo->last = record;
114 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930115
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930116 repo->size += record->size;
117 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930119 if (record_handle) {
120 *record_handle = record->record_handle;
121 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930122
123 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930124}
125
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930126LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930127pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128{
129 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930130 if (!repo) {
131 return NULL;
132 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930133 repo->record_count = 0;
134 repo->size = 0;
135 repo->first = NULL;
136 repo->last = NULL;
137
138 return repo;
139}
140
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930141LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930142void pldm_pdr_destroy(pldm_pdr *repo)
143{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930144 if (!repo) {
145 return;
146 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930147
148 pldm_pdr_record *record = repo->first;
149 while (record != NULL) {
150 pldm_pdr_record *next = record->next;
151 if (record->data) {
152 free(record->data);
153 record->data = NULL;
154 }
155 free(record);
156 record = next;
157 }
158 free(repo);
159}
160
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930161LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930162const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
163 uint32_t record_handle,
164 uint8_t **data, uint32_t *size,
165 uint32_t *next_record_handle)
166{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930167 if (!repo || !data || !size || !next_record_handle) {
168 return NULL;
169 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930170
171 if (!record_handle && (repo->first != NULL)) {
172 record_handle = repo->first->record_handle;
173 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930174
Andrew Jeffery9c766792022-08-10 23:12:49 +0930175 pldm_pdr_record *record = repo->first;
176 while (record != NULL) {
177 if (record->record_handle == record_handle) {
178 *size = record->size;
179 *data = record->data;
180 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930181 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930182 return record;
183 }
184 record = record->next;
185 }
186
187 *size = 0;
188 *next_record_handle = 0;
189 return NULL;
190}
191
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930192LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930193const pldm_pdr_record *
194pldm_pdr_get_next_record(const pldm_pdr *repo,
195 const pldm_pdr_record *curr_record, uint8_t **data,
196 uint32_t *size, uint32_t *next_record_handle)
197{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930198 if (!repo || !curr_record || !data || !size || !next_record_handle) {
199 return NULL;
200 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930201
202 if (curr_record == repo->last) {
203 *data = NULL;
204 *size = 0;
205 *next_record_handle = get_next_record_handle(repo, curr_record);
206 return NULL;
207 }
208
209 *next_record_handle = get_next_record_handle(repo, curr_record->next);
210 *data = curr_record->next->data;
211 *size = curr_record->next->size;
212 return curr_record->next;
213}
214
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930215LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930216const pldm_pdr_record *
217pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
218 const pldm_pdr_record *curr_record, uint8_t **data,
219 uint32_t *size)
220{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930221 if (!repo) {
222 return NULL;
223 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930224
225 pldm_pdr_record *record = repo->first;
226 if (curr_record != NULL) {
227 record = curr_record->next;
228 }
229 while (record != NULL) {
230 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
231 if (hdr->type == pdr_type) {
232 if (data && size) {
233 *size = record->size;
234 *data = record->data;
235 }
236 return record;
237 }
238 record = record->next;
239 }
240
241 if (size) {
242 *size = 0;
243 }
244 return NULL;
245}
246
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930247LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
249{
250 assert(repo != NULL);
251
252 return repo->record_count;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930256uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
257{
258 assert(repo != NULL);
259
260 return repo->size;
261}
262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930263LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930264uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
265 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930266 const pldm_pdr_record *record)
267{
268 assert(repo != NULL);
269 assert(record != NULL);
270
271 return record->record_handle;
272}
273
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930274LIBPLDM_ABI_STABLE
275bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930276{
277 assert(record != NULL);
278
279 return record->is_remote;
280}
281
Andrew Jefferya2c69112023-07-07 10:41:38 +0930282LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
284 uint16_t fru_rsi, uint16_t entity_type,
285 uint16_t entity_instance_num,
286 uint16_t container_id,
287 uint32_t bmc_record_handle)
288{
Andrew Jefferyc821a702023-07-03 13:32:11 +0930289 int rc = pldm_pdr_add_fru_record_set_check(
290 repo, terminus_handle, fru_rsi, entity_type,
291 entity_instance_num, container_id, &bmc_record_handle);
292 (void)rc;
293 assert(!rc);
294 return bmc_record_handle;
295}
296
Andrew Jefferya2c69112023-07-07 10:41:38 +0930297LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930298int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
299 uint16_t fru_rsi, uint16_t entity_type,
300 uint16_t entity_instance_num,
301 uint16_t container_id,
302 uint32_t *bmc_record_handle)
303{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930304 if (!repo || !bmc_record_handle) {
305 return -EINVAL;
306 }
307
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308 uint32_t size = sizeof(struct pldm_pdr_hdr) +
309 sizeof(struct pldm_pdr_fru_record_set);
310 uint8_t data[size];
311
312 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
313 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930314 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930315 hdr->type = PLDM_PDR_FRU_RECORD_SET;
316 hdr->record_change_num = 0;
317 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
318 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930319 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
320 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 fru->terminus_handle = htole16(terminus_handle);
322 fru->fru_rsi = htole16(fru_rsi);
323 fru->entity_type = htole16(entity_type);
324 fru->entity_instance_num = htole16(entity_instance_num);
325 fru->container_id = htole16(container_id);
326
Andrew Jefferyc821a702023-07-03 13:32:11 +0930327 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
328 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329}
330
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930331LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
334 uint16_t *entity_type, uint16_t *entity_instance_num,
335 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930336{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930337 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
338 !container_id) {
339 return NULL;
340 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930341
342 uint8_t *data = NULL;
343 uint32_t size = 0;
344 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930345 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346 while (curr_record != NULL) {
347 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 (struct pldm_pdr_fru_record_set
349 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930350 if (fru->fru_rsi == htole16(fru_rsi)) {
351 *terminus_handle = le16toh(fru->terminus_handle);
352 *entity_type = le16toh(fru->entity_type);
353 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930354 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930355 *container_id = le16toh(fru->container_id);
356 return curr_record;
357 }
358 data = NULL;
359 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930360 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
361 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930362 }
363
364 *terminus_handle = 0;
365 *entity_type = 0;
366 *entity_instance_num = 0;
367 *container_id = 0;
368
369 return NULL;
370}
371
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930372LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930373/* NOLINTNEXTLINE(readability-identifier-naming) */
374void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
375 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930376{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378 uint32_t size = 0;
379 const pldm_pdr_record *record;
380 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930381 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930382
383 do {
384 if (record != NULL) {
385 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930386 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930387 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930388 (struct pldm_terminus_locator_type_mctp_eid *)
389 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930390 if (pdr->terminus_handle == terminus_handle &&
391 pdr->tid == tid && value->eid == tl_eid) {
392 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930393 break;
394 }
395 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930396 record = pldm_pdr_find_record_by_type(repo,
397 PLDM_TERMINUS_LOCATOR_PDR,
398 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930399 } while (record);
400}
401
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500402static bool pldm_record_handle_in_range(uint32_t record_handle,
403 uint32_t first_record_handle,
404 uint32_t last_record_handle)
405{
406 return record_handle >= first_record_handle &&
407 record_handle <= last_record_handle;
408}
409
410LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500411int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500412 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500413 uint8_t child_index, uint32_t range_exclude_start_handle,
414 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500415{
416 pldm_pdr_record *record;
417 if (!repo) {
418 return -EINVAL;
419 }
420
421 for (record = repo->first; record; record = record->next) {
422 bool is_container_entity_instance_number;
423 struct pldm_pdr_entity_association *pdr;
424 bool is_container_entity_type;
425 struct pldm_entity *child;
426 struct pldm_pdr_hdr *hdr;
427 bool in_range;
428
429 // pldm_pdr_add() takes only uint8_t* data as an argument.
430 // The expectation here is the pldm_pdr_hdr is the first field of the record data
431 hdr = (struct pldm_pdr_hdr *)record->data;
432 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
433 continue;
434 }
435 in_range = pldm_record_handle_in_range(
436 record->record_handle, range_exclude_start_handle,
437 range_exclude_end_handle);
438 if (in_range) {
439 continue;
440 }
441
442 // this cast is valid with respect to alignment because
443 // struct pldm_pdr_hdr is declared with __attribute__((packed))
444 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500445 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500446 continue;
447 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500448
449 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500450 is_container_entity_type = pdr->container.entity_type ==
451 entity_type;
452 is_container_entity_instance_number =
453 pdr->container.entity_instance_num == entity_instance;
454 if (is_container_entity_type &&
455 is_container_entity_instance_number) {
456 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500457 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500458 }
459 }
460 return -ENOKEY;
461}
462
Andrew Jeffery9c766792022-08-10 23:12:49 +0930463typedef struct pldm_entity_association_tree {
464 pldm_entity_node *root;
465 uint16_t last_used_container_id;
466} pldm_entity_association_tree;
467
468typedef struct pldm_entity_node {
469 pldm_entity entity;
470 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600471 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930472 pldm_entity_node *first_child;
473 pldm_entity_node *next_sibling;
474 uint8_t association_type;
475} pldm_entity_node;
476
477static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
478{
479 assert(tree != NULL);
480 assert(tree->last_used_container_id != UINT16_MAX);
481
482 return ++tree->last_used_container_id;
483}
484
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930485LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930486pldm_entity pldm_entity_extract(pldm_entity_node *node)
487{
488 assert(node != NULL);
489
490 return node->entity;
491}
492
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600493LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930494uint16_t
495pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600496{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930497 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600498
Andrew Jeffery15b88182023-06-30 13:29:17 +0930499 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600500}
501
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930502LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930503pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930504{
505 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930506 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930507 if (!tree) {
508 return NULL;
509 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930510 tree->root = NULL;
511 tree->last_used_container_id = 0;
512
513 return tree;
514}
515
516static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
517 uint16_t entity_type)
518{
519 assert(start != NULL);
520
521 /* Insert after the the last node that matches the input entity type, or
522 * at the end if no such match occurrs
523 */
524 while (start->next_sibling != NULL) {
525 uint16_t this_type = start->entity.entity_type;
526 pldm_entity_node *next = start->next_sibling;
527 if (this_type == entity_type &&
528 (this_type != next->entity.entity_type)) {
529 break;
530 }
531 start = start->next_sibling;
532 }
533
534 return start;
535}
536
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930537LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930539 pldm_entity_association_tree *tree, pldm_entity *entity,
540 uint16_t entity_instance_number, pldm_entity_node *parent,
541 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930542{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500543 return pldm_entity_association_tree_add_entity(tree, entity,
544 entity_instance_number,
545 parent, association_type,
546 false, true, 0xFFFF);
547}
548
549LIBPLDM_ABI_TESTING
550pldm_entity_node *pldm_entity_association_tree_add_entity(
551 pldm_entity_association_tree *tree, pldm_entity *entity,
552 uint16_t entity_instance_number, pldm_entity_node *parent,
553 uint8_t association_type, bool is_remote, bool is_update_container_id,
554 uint16_t container_id)
555{
556 if ((!tree) || (!entity)) {
557 return NULL;
558 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930559
560 if (entity_instance_number != 0xFFFF && parent != NULL) {
561 pldm_entity node;
562 node.entity_type = entity->entity_type;
563 node.entity_instance_num = entity_instance_number;
564 if (pldm_is_current_parent_child(parent, &node)) {
565 return NULL;
566 }
567 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500568 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
569 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
570 return NULL;
571 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500573 if (!node) {
574 return NULL;
575 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930576 node->first_child = NULL;
577 node->next_sibling = NULL;
578 node->parent.entity_type = 0;
579 node->parent.entity_instance_num = 0;
580 node->parent.entity_container_id = 0;
581 node->entity.entity_type = entity->entity_type;
582 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930583 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600585 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930586 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500587 if (parent != NULL) {
588 free(node);
589 return NULL;
590 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591 tree->root = node;
592 /* container_id 0 here indicates this is the top-most entry */
593 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600594 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595 } else if (parent != NULL && parent->first_child == NULL) {
596 parent->first_child = node;
597 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500598
599 if (is_remote) {
600 node->remote_container_id = entity->entity_container_id;
601 }
602 if (is_update_container_id) {
603 if (container_id != 0xFFFF) {
604 node->entity.entity_container_id = container_id;
605 } else {
606 node->entity.entity_container_id =
607 next_container_id(tree);
608 }
609 } else {
610 node->entity.entity_container_id =
611 entity->entity_container_id;
612 }
613
614 if (!is_remote) {
615 node->remote_container_id =
616 node->entity.entity_container_id;
617 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930619 pldm_entity_node *start = parent == NULL ? tree->root :
620 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930621 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930622 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500623 if (!prev) {
624 free(node);
625 return NULL;
626 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627 pldm_entity_node *next = prev->next_sibling;
628 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500629 if (prev->entity.entity_instance_num == UINT16_MAX) {
630 free(node);
631 return NULL;
632 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930633 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930634 entity_instance_number != 0xFFFF ?
635 entity_instance_number :
636 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637 }
638 prev->next_sibling = node;
639 node->parent = prev->parent;
640 node->next_sibling = next;
641 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930642 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600643 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930644 }
645 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500646 if (is_update_container_id) {
647 entity->entity_container_id = node->entity.entity_container_id;
648 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930649 return node;
650}
651
652static void get_num_nodes(pldm_entity_node *node, size_t *num)
653{
654 if (node == NULL) {
655 return;
656 }
657
658 ++(*num);
659 get_num_nodes(node->next_sibling, num);
660 get_num_nodes(node->first_child, num);
661}
662
663static void entity_association_tree_visit(pldm_entity_node *node,
664 pldm_entity *entities, size_t *index)
665{
666 if (node == NULL) {
667 return;
668 }
669
670 pldm_entity *entity = &entities[*index];
671 ++(*index);
672 entity->entity_type = node->entity.entity_type;
673 entity->entity_instance_num = node->entity.entity_instance_num;
674 entity->entity_container_id = node->entity.entity_container_id;
675
676 entity_association_tree_visit(node->next_sibling, entities, index);
677 entity_association_tree_visit(node->first_child, entities, index);
678}
679
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930680LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
682 pldm_entity **entities, size_t *size)
683{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930684 if (!tree || !entities || !size) {
685 return;
686 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687
688 *size = 0;
689 if (tree->root == NULL) {
690 return;
691 }
692
693 get_num_nodes(tree->root, size);
694 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930695 if (!entities) {
696 return;
697 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698 size_t index = 0;
699 entity_association_tree_visit(tree->root, *entities, &index);
700}
701
702static void entity_association_tree_destroy(pldm_entity_node *node)
703{
704 if (node == NULL) {
705 return;
706 }
707
708 entity_association_tree_destroy(node->next_sibling);
709 entity_association_tree_destroy(node->first_child);
710 free(node);
711}
712
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930713LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
715{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930716 if (!tree) {
717 return;
718 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719
720 entity_association_tree_destroy(tree->root);
721 free(tree);
722}
723
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930724LIBPLDM_ABI_STABLE
725bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930726{
727 assert(node != NULL);
728
729 return node->first_child != NULL;
730}
731
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930732LIBPLDM_ABI_STABLE
733pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734{
735 assert(node != NULL);
736
737 return node->parent;
738}
739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930740LIBPLDM_ABI_STABLE
741bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742{
743 assert(node != NULL);
744
745 if (node->parent.entity_type == 0 &&
746 node->parent.entity_instance_num == 0 &&
747 node->parent.entity_container_id == 0) {
748 return false;
749 }
750
751 return true;
752}
753
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930754LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
756 uint8_t association_type)
757{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930758 if (!node) {
759 return 0;
760 }
761
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930762 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
763 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
764 return 0;
765 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766
767 size_t count = 0;
768 pldm_entity_node *curr = node->first_child;
769 while (curr != NULL) {
770 if (curr->association_type == association_type) {
771 ++count;
772 }
773 curr = curr->next_sibling;
774 }
775
776 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930777 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930778}
779
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930780LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
782{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930783 if (!parent || !node) {
784 return false;
785 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786
787 pldm_entity_node *curr = parent->first_child;
788 while (curr != NULL) {
789 if (node->entity_type == curr->entity.entity_type &&
790 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930791 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930792 return true;
793 }
794 curr = curr->next_sibling;
795 }
796
797 return false;
798}
799
Andrew Jeffery65945992023-07-17 15:04:21 +0930800static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500801 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
802 uint8_t contained_count, uint8_t association_type, bool is_remote,
803 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804{
805 uint8_t pdr[size];
806 uint8_t *start = pdr;
807
808 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
809 hdr->version = 1;
810 hdr->record_handle = 0;
811 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
812 hdr->record_change_num = 0;
813 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
814 start += sizeof(struct pldm_pdr_hdr);
815
816 uint16_t *container_id = (uint16_t *)start;
817 *container_id = htole16(curr->first_child->entity.entity_container_id);
818 start += sizeof(uint16_t);
819 *start = association_type;
820 start += sizeof(uint8_t);
821
822 pldm_entity *entity = (pldm_entity *)start;
823 entity->entity_type = htole16(curr->entity.entity_type);
824 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
825 entity->entity_container_id = htole16(curr->entity.entity_container_id);
826 start += sizeof(pldm_entity);
827
828 *start = contained_count;
829 start += sizeof(uint8_t);
830
831 pldm_entity_node *node = curr->first_child;
832 while (node != NULL) {
833 if (node->association_type == association_type) {
834 pldm_entity *entity = (pldm_entity *)start;
835 entity->entity_type = htole16(node->entity.entity_type);
836 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930837 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930840 start += sizeof(pldm_entity);
841 }
842 node = node->next_sibling;
843 }
844
Andrew Jeffery65945992023-07-17 15:04:21 +0930845 return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
846 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847}
848
Andrew Jeffery65945992023-07-17 15:04:21 +0930849static int entity_association_pdr_add_entry(pldm_entity_node *curr,
850 pldm_pdr *repo, bool is_remote,
851 uint16_t terminus_handle,
852 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930854 uint8_t num_logical_children = pldm_entity_get_num_children(
855 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
856 uint8_t num_physical_children = pldm_entity_get_num_children(
857 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930858 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859
860 if (num_logical_children) {
861 uint16_t logical_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_logical_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, logical_pdr_size, num_logical_children,
868 PLDM_ENTITY_ASSOCIAION_LOGICAL, 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 }
874
875 if (num_physical_children) {
876 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930877 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
878 sizeof(uint8_t) + sizeof(pldm_entity) +
879 sizeof(uint8_t) +
880 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930881 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930882 curr, repo, physical_pdr_size, num_physical_children,
883 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500884 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930885 if (rc < 0) {
886 return rc;
887 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930888 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930889
890 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891}
892
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930893LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
895{
896 if (entities == NULL || num_entities == 0) {
897 return true;
898 }
899 size_t i = 0;
900 while (i < num_entities) {
901 if ((*entities + i)->entity_type == entity.entity_type) {
902 return true;
903 }
904 i++;
905 }
906 return false;
907}
908
Andrew Jeffery65945992023-07-17 15:04:21 +0930909static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
910 pldm_entity **entities,
911 size_t num_entities, bool is_remote,
912 uint16_t terminus_handle,
913 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914{
Andrew Jeffery65945992023-07-17 15:04:21 +0930915 int rc;
916
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930918 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930920
921 if (is_present(curr->entity, entities, num_entities)) {
922 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500923 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930924 if (rc) {
925 return rc;
926 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930928
929 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
930 num_entities, is_remote,
931 terminus_handle, record_handle);
932 if (rc) {
933 return rc;
934 }
935
936 return entity_association_pdr_add(curr->first_child, repo, entities,
937 num_entities, is_remote,
938 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930939}
940
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930941LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
943 pldm_pdr *repo, bool is_remote,
944 uint16_t terminus_handle)
945{
Andrew Jeffery65945992023-07-17 15:04:21 +0930946 int rc = pldm_entity_association_pdr_add_check(tree, repo, is_remote,
947 terminus_handle);
948 (void)rc;
949 assert(!rc);
950}
951
952LIBPLDM_ABI_TESTING
953int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
954 pldm_pdr *repo, bool is_remote,
955 uint16_t terminus_handle)
956{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930957 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930958 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930959 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960
Andrew Jeffery65945992023-07-17 15:04:21 +0930961 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
962 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930963}
964
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930965LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930966void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930967 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
968 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969{
Andrew Jefferycc394522023-07-03 12:49:31 +0930970 int rc = pldm_entity_association_pdr_add_from_node_check(
971 node, repo, entities, num_entities, is_remote, terminus_handle);
972 (void)rc;
973 assert(!rc);
974}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930976LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930977int pldm_entity_association_pdr_add_from_node_check(
978 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
979 size_t num_entities, bool is_remote, uint16_t terminus_handle)
980{
981 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500982 node, repo, entities, num_entities, is_remote, terminus_handle,
983 0);
984}
985
986LIBPLDM_ABI_TESTING
987int pldm_entity_association_pdr_add_from_node_with_record_handle(
988 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
989 size_t num_entities, bool is_remote, uint16_t terminus_handle,
990 uint32_t record_handle)
991{
992 if (!node || !repo || !entities) {
993 return -EINVAL;
994 }
995
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500997 is_remote, terminus_handle, record_handle);
998
999 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000}
1001
Andrew Jefferybfeb65e2023-06-30 16:02:15 +09301002LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301003void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
1004 pldm_entity_node **node)
1005{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001006 bool is_entity_container_id;
1007 bool is_entity_instance_num;
1008 bool is_type;
1009
Andrew Jeffery9c766792022-08-10 23:12:49 +09301010 if (tree_node == NULL) {
1011 return;
1012 }
1013
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001014 is_type = tree_node->entity.entity_type == entity.entity_type;
1015 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1016 entity.entity_instance_num;
1017 is_entity_container_id = tree_node->entity.entity_container_id ==
1018 entity.entity_container_id;
1019
1020 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301021 *node = tree_node;
1022 return;
1023 }
1024
1025 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1026 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1027}
1028
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301029LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301030void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1031 pldm_entity entity, pldm_entity_node **node)
1032{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301033 if (!tree || !node) {
1034 return;
1035 }
1036
Andrew Jeffery9c766792022-08-10 23:12:49 +09301037 find_entity_ref_in_tree(tree->root, entity, node);
1038}
1039
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301040LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1042 uint16_t terminus_handle)
1043{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301044 if (!repo) {
1045 return;
1046 }
1047
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048 bool removed = false;
1049
1050 pldm_pdr_record *record = repo->first;
1051 pldm_pdr_record *prev = NULL;
1052 while (record != NULL) {
1053 pldm_pdr_record *next = record->next;
1054 if (record->terminus_handle == terminus_handle) {
1055 if (repo->first == record) {
1056 repo->first = next;
1057 } else {
1058 prev->next = next;
1059 }
1060 if (repo->last == record) {
1061 repo->last = prev;
1062 }
1063 if (record->data) {
1064 free(record->data);
1065 }
1066 --repo->record_count;
1067 repo->size -= record->size;
1068 free(record);
1069 removed = true;
1070 } else {
1071 prev = record;
1072 }
1073 record = next;
1074 }
1075
1076 if (removed == true) {
1077 record = repo->first;
1078 uint32_t record_handle = 0;
1079 while (record != NULL) {
1080 record->record_handle = ++record_handle;
1081 if (record->data != NULL) {
1082 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301083 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301085 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301086 }
1087 record = record->next;
1088 }
1089 }
1090}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301091
1092LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301093void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1094{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301095 if (!repo) {
1096 return;
1097 }
1098
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099 bool removed = false;
1100
1101 pldm_pdr_record *record = repo->first;
1102 pldm_pdr_record *prev = NULL;
1103 while (record != NULL) {
1104 pldm_pdr_record *next = record->next;
1105 if (record->is_remote == true) {
1106 if (repo->first == record) {
1107 repo->first = next;
1108 } else {
1109 prev->next = next;
1110 }
1111 if (repo->last == record) {
1112 repo->last = prev;
1113 }
1114 if (record->data) {
1115 free(record->data);
1116 }
1117 --repo->record_count;
1118 repo->size -= record->size;
1119 free(record);
1120 removed = true;
1121 } else {
1122 prev = record;
1123 }
1124 record = next;
1125 }
1126
1127 if (removed == true) {
1128 record = repo->first;
1129 uint32_t record_handle = 0;
1130 while (record != NULL) {
1131 record->record_handle = ++record_handle;
1132 if (record->data != NULL) {
1133 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301134 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301136 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137 }
1138 record = record->next;
1139 }
1140 }
1141}
1142
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001143LIBPLDM_ABI_TESTING
1144pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1145 uint32_t first, uint32_t last)
1146{
1147 pldm_pdr_record *record = NULL;
1148 pldm_pdr_record *curr;
1149
1150 if (!repo) {
1151 return NULL;
1152 }
1153 for (curr = repo->first; curr; curr = curr->next) {
1154 if (first > curr->record_handle || last < curr->record_handle) {
1155 continue;
1156 }
1157 if (!record || curr->record_handle > record->record_handle) {
1158 record = curr;
1159 }
1160 }
1161
1162 return record;
1163}
1164
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001165static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1166 pldm_entity *entity,
1167 pldm_entity_node **out,
1168 bool is_remote)
1169{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001170 if (node == NULL) {
1171 return;
1172 }
1173 bool is_entity_type;
1174 bool is_entity_instance_num;
1175
1176 is_entity_type = node->entity.entity_type == entity->entity_type;
1177 is_entity_instance_num = node->entity.entity_instance_num ==
1178 entity->entity_instance_num;
1179
1180 if (!is_remote ||
1181 node->remote_container_id == entity->entity_container_id) {
1182 if (is_entity_type && is_entity_instance_num) {
1183 entity->entity_container_id =
1184 node->entity.entity_container_id;
1185 *out = node;
1186 return;
1187 }
1188 }
1189 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1190 is_remote);
1191 entity_association_tree_find_if_remote(node->first_child, entity, out,
1192 is_remote);
1193}
1194
1195LIBPLDM_ABI_TESTING
1196pldm_entity_node *
1197pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1198 pldm_entity *entity, bool is_remote)
1199{
1200 if (!tree || !entity) {
1201 return NULL;
1202 }
1203 pldm_entity_node *node = NULL;
1204 entity_association_tree_find_if_remote(tree->root, entity, &node,
1205 is_remote);
1206 return node;
1207}
1208
Andrew Jeffery7f589312023-07-03 12:03:25 +09301209LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301210void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1211 pldm_entity_node **out)
1212{
1213 if (node == NULL) {
1214 return;
1215 }
1216
1217 if (node->entity.entity_type == entity->entity_type &&
1218 node->entity.entity_instance_num == entity->entity_instance_num) {
1219 entity->entity_container_id = node->entity.entity_container_id;
1220 *out = node;
1221 return;
1222 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223 entity_association_tree_find(node->next_sibling, entity, out);
1224 entity_association_tree_find(node->first_child, entity, out);
1225}
1226
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301227LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228pldm_entity_node *
1229pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1230 pldm_entity *entity)
1231{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301232 if (!tree || !entity) {
1233 return NULL;
1234 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235
1236 pldm_entity_node *node = NULL;
1237 entity_association_tree_find(tree->root, entity, &node);
1238 return node;
1239}
1240
1241static void entity_association_tree_copy(pldm_entity_node *org_node,
1242 pldm_entity_node **new_node)
1243{
1244 if (org_node == NULL) {
1245 return;
1246 }
1247 *new_node = malloc(sizeof(pldm_entity_node));
1248 (*new_node)->parent = org_node->parent;
1249 (*new_node)->entity = org_node->entity;
1250 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001251 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301252 (*new_node)->first_child = NULL;
1253 (*new_node)->next_sibling = NULL;
1254 entity_association_tree_copy(org_node->first_child,
1255 &((*new_node)->first_child));
1256 entity_association_tree_copy(org_node->next_sibling,
1257 &((*new_node)->next_sibling));
1258}
1259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301260LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301261void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301262 pldm_entity_association_tree *org_tree,
1263 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301264{
1265 new_tree->last_used_container_id = org_tree->last_used_container_id;
1266 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1267}
1268
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301269LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301270void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301271 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301272{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301273 if (!tree) {
1274 return;
1275 }
1276
Andrew Jeffery9c766792022-08-10 23:12:49 +09301277 entity_association_tree_destroy(tree->root);
1278 tree->last_used_container_id = 0;
1279 tree->root = NULL;
1280}
1281
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301282LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301283bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1284{
1285 return ((tree->root == NULL) ? true : false);
1286}
1287
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301288LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1290 size_t *num_entities,
1291 pldm_entity **entities)
1292{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301293 if (!pdr || !num_entities || !entities) {
1294 return;
1295 }
1296#define PDR_MIN_SIZE \
1297 (sizeof(struct pldm_pdr_hdr) + \
1298 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301299 if (pdr_len < PDR_MIN_SIZE) {
1300 return;
1301 }
1302#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301303
1304 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301305 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1306 return;
1307 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301308
1309 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301310 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301311 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301312 start += sizeof(struct pldm_pdr_hdr);
1313 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301314 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301315 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301316 if (l_num_entities < 2) {
1317 return;
1318 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301319 if (start + sizeof(struct pldm_pdr_entity_association) +
1320 sizeof(pldm_entity) * (l_num_entities - 2) !=
1321 end) {
1322 return;
1323 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301324 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301325 if (!l_entities) {
1326 return;
1327 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301328 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301329 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301330 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301331 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301332 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301333 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301334 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301335 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1336 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1337 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301338 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301339 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301340 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301341 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301342
1343 *num_entities = l_num_entities;
1344 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301345}