blob: 56c07b530c54b5bd44d68c832e34b956c997e9d2 [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
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500800static void entity_association_pdr_add_children(
801 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
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500845 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
846 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847}
848
849static void entity_association_pdr_add_entry(pldm_entity_node *curr,
850 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500851 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 Jeffery9c766792022-08-10 23:12:49 +0930858
859 if (num_logical_children) {
860 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930861 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
862 sizeof(uint8_t) + sizeof(pldm_entity) +
863 sizeof(uint8_t) +
864 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930865 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930866 curr, repo, logical_pdr_size, num_logical_children,
867 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500868 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869 }
870
871 if (num_physical_children) {
872 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930873 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
874 sizeof(uint8_t) + sizeof(pldm_entity) +
875 sizeof(uint8_t) +
876 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930877 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930878 curr, repo, physical_pdr_size, num_physical_children,
879 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500880 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930881 }
882}
883
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930884LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
886{
887 if (entities == NULL || num_entities == 0) {
888 return true;
889 }
890 size_t i = 0;
891 while (i < num_entities) {
892 if ((*entities + i)->entity_type == entity.entity_type) {
893 return true;
894 }
895 i++;
896 }
897 return false;
898}
899
900static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
901 pldm_entity **entities,
902 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500903 uint16_t terminus_handle,
904 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905{
906 if (curr == NULL) {
907 return;
908 }
909 bool to_add = true;
910 to_add = is_present(curr->entity, entities, num_entities);
911 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500912 entity_association_pdr_add_entry(
913 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914 }
915 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500916 num_entities, is_remote, terminus_handle,
917 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500919 num_entities, is_remote, terminus_handle,
920 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921}
922
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930923LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930924void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
925 pldm_pdr *repo, bool is_remote,
926 uint16_t terminus_handle)
927{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930928 if (!tree || !repo) {
929 return;
930 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931
932 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500933 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934}
935
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930936LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930938 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
939 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940{
Andrew Jefferycc394522023-07-03 12:49:31 +0930941 int rc = pldm_entity_association_pdr_add_from_node_check(
942 node, repo, entities, num_entities, is_remote, terminus_handle);
943 (void)rc;
944 assert(!rc);
945}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930947LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930948int pldm_entity_association_pdr_add_from_node_check(
949 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
950 size_t num_entities, bool is_remote, uint16_t terminus_handle)
951{
952 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500953 node, repo, entities, num_entities, is_remote, terminus_handle,
954 0);
955}
956
957LIBPLDM_ABI_TESTING
958int pldm_entity_association_pdr_add_from_node_with_record_handle(
959 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
960 size_t num_entities, bool is_remote, uint16_t terminus_handle,
961 uint32_t record_handle)
962{
963 if (!node || !repo || !entities) {
964 return -EINVAL;
965 }
966
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500968 is_remote, terminus_handle, record_handle);
969
970 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971}
972
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930973LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930974void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
975 pldm_entity_node **node)
976{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600977 bool is_entity_container_id;
978 bool is_entity_instance_num;
979 bool is_type;
980
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 if (tree_node == NULL) {
982 return;
983 }
984
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600985 is_type = tree_node->entity.entity_type == entity.entity_type;
986 is_entity_instance_num = tree_node->entity.entity_instance_num ==
987 entity.entity_instance_num;
988 is_entity_container_id = tree_node->entity.entity_container_id ==
989 entity.entity_container_id;
990
991 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930992 *node = tree_node;
993 return;
994 }
995
996 find_entity_ref_in_tree(tree_node->first_child, entity, node);
997 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
998}
999
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1002 pldm_entity entity, pldm_entity_node **node)
1003{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301004 if (!tree || !node) {
1005 return;
1006 }
1007
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008 find_entity_ref_in_tree(tree->root, entity, node);
1009}
1010
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301011LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301012void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1013 uint16_t terminus_handle)
1014{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301015 if (!repo) {
1016 return;
1017 }
1018
Andrew Jeffery9c766792022-08-10 23:12:49 +09301019 bool removed = false;
1020
1021 pldm_pdr_record *record = repo->first;
1022 pldm_pdr_record *prev = NULL;
1023 while (record != NULL) {
1024 pldm_pdr_record *next = record->next;
1025 if (record->terminus_handle == terminus_handle) {
1026 if (repo->first == record) {
1027 repo->first = next;
1028 } else {
1029 prev->next = next;
1030 }
1031 if (repo->last == record) {
1032 repo->last = prev;
1033 }
1034 if (record->data) {
1035 free(record->data);
1036 }
1037 --repo->record_count;
1038 repo->size -= record->size;
1039 free(record);
1040 removed = true;
1041 } else {
1042 prev = record;
1043 }
1044 record = next;
1045 }
1046
1047 if (removed == true) {
1048 record = repo->first;
1049 uint32_t record_handle = 0;
1050 while (record != NULL) {
1051 record->record_handle = ++record_handle;
1052 if (record->data != NULL) {
1053 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301054 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301056 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 }
1058 record = record->next;
1059 }
1060 }
1061}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301062
1063LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301064void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1065{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301066 if (!repo) {
1067 return;
1068 }
1069
Andrew Jeffery9c766792022-08-10 23:12:49 +09301070 bool removed = false;
1071
1072 pldm_pdr_record *record = repo->first;
1073 pldm_pdr_record *prev = NULL;
1074 while (record != NULL) {
1075 pldm_pdr_record *next = record->next;
1076 if (record->is_remote == true) {
1077 if (repo->first == record) {
1078 repo->first = next;
1079 } else {
1080 prev->next = next;
1081 }
1082 if (repo->last == record) {
1083 repo->last = prev;
1084 }
1085 if (record->data) {
1086 free(record->data);
1087 }
1088 --repo->record_count;
1089 repo->size -= record->size;
1090 free(record);
1091 removed = true;
1092 } else {
1093 prev = record;
1094 }
1095 record = next;
1096 }
1097
1098 if (removed == true) {
1099 record = repo->first;
1100 uint32_t record_handle = 0;
1101 while (record != NULL) {
1102 record->record_handle = ++record_handle;
1103 if (record->data != NULL) {
1104 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301105 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301107 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301108 }
1109 record = record->next;
1110 }
1111 }
1112}
1113
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001114LIBPLDM_ABI_TESTING
1115pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1116 uint32_t first, uint32_t last)
1117{
1118 pldm_pdr_record *record = NULL;
1119 pldm_pdr_record *curr;
1120
1121 if (!repo) {
1122 return NULL;
1123 }
1124 for (curr = repo->first; curr; curr = curr->next) {
1125 if (first > curr->record_handle || last < curr->record_handle) {
1126 continue;
1127 }
1128 if (!record || curr->record_handle > record->record_handle) {
1129 record = curr;
1130 }
1131 }
1132
1133 return record;
1134}
1135
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001136static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1137 pldm_entity *entity,
1138 pldm_entity_node **out,
1139 bool is_remote)
1140{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001141 if (node == NULL) {
1142 return;
1143 }
1144 bool is_entity_type;
1145 bool is_entity_instance_num;
1146
1147 is_entity_type = node->entity.entity_type == entity->entity_type;
1148 is_entity_instance_num = node->entity.entity_instance_num ==
1149 entity->entity_instance_num;
1150
1151 if (!is_remote ||
1152 node->remote_container_id == entity->entity_container_id) {
1153 if (is_entity_type && is_entity_instance_num) {
1154 entity->entity_container_id =
1155 node->entity.entity_container_id;
1156 *out = node;
1157 return;
1158 }
1159 }
1160 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1161 is_remote);
1162 entity_association_tree_find_if_remote(node->first_child, entity, out,
1163 is_remote);
1164}
1165
1166LIBPLDM_ABI_TESTING
1167pldm_entity_node *
1168pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1169 pldm_entity *entity, bool is_remote)
1170{
1171 if (!tree || !entity) {
1172 return NULL;
1173 }
1174 pldm_entity_node *node = NULL;
1175 entity_association_tree_find_if_remote(tree->root, entity, &node,
1176 is_remote);
1177 return node;
1178}
1179
Andrew Jeffery7f589312023-07-03 12:03:25 +09301180LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1182 pldm_entity_node **out)
1183{
1184 if (node == NULL) {
1185 return;
1186 }
1187
1188 if (node->entity.entity_type == entity->entity_type &&
1189 node->entity.entity_instance_num == entity->entity_instance_num) {
1190 entity->entity_container_id = node->entity.entity_container_id;
1191 *out = node;
1192 return;
1193 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301194 entity_association_tree_find(node->next_sibling, entity, out);
1195 entity_association_tree_find(node->first_child, entity, out);
1196}
1197
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301198LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199pldm_entity_node *
1200pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1201 pldm_entity *entity)
1202{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301203 if (!tree || !entity) {
1204 return NULL;
1205 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206
1207 pldm_entity_node *node = NULL;
1208 entity_association_tree_find(tree->root, entity, &node);
1209 return node;
1210}
1211
1212static void entity_association_tree_copy(pldm_entity_node *org_node,
1213 pldm_entity_node **new_node)
1214{
1215 if (org_node == NULL) {
1216 return;
1217 }
1218 *new_node = malloc(sizeof(pldm_entity_node));
1219 (*new_node)->parent = org_node->parent;
1220 (*new_node)->entity = org_node->entity;
1221 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001222 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223 (*new_node)->first_child = NULL;
1224 (*new_node)->next_sibling = NULL;
1225 entity_association_tree_copy(org_node->first_child,
1226 &((*new_node)->first_child));
1227 entity_association_tree_copy(org_node->next_sibling,
1228 &((*new_node)->next_sibling));
1229}
1230
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301231LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301233 pldm_entity_association_tree *org_tree,
1234 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235{
1236 new_tree->last_used_container_id = org_tree->last_used_container_id;
1237 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1238}
1239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301241void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301242 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301243{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301244 if (!tree) {
1245 return;
1246 }
1247
Andrew Jeffery9c766792022-08-10 23:12:49 +09301248 entity_association_tree_destroy(tree->root);
1249 tree->last_used_container_id = 0;
1250 tree->root = NULL;
1251}
1252
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301253LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301254bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1255{
1256 return ((tree->root == NULL) ? true : false);
1257}
1258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301259LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301260void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1261 size_t *num_entities,
1262 pldm_entity **entities)
1263{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301264 if (!pdr || !num_entities || !entities) {
1265 return;
1266 }
1267#define PDR_MIN_SIZE \
1268 (sizeof(struct pldm_pdr_hdr) + \
1269 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301270 if (pdr_len < PDR_MIN_SIZE) {
1271 return;
1272 }
1273#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301274
1275 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301276 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1277 return;
1278 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301279
1280 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301281 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301282 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301283 start += sizeof(struct pldm_pdr_hdr);
1284 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301285 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301286 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301287 if (l_num_entities < 2) {
1288 return;
1289 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301290 if (start + sizeof(struct pldm_pdr_entity_association) +
1291 sizeof(pldm_entity) * (l_num_entities - 2) !=
1292 end) {
1293 return;
1294 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301295 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301296 if (!l_entities) {
1297 return;
1298 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301299 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301300 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301301 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301302 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301303 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301304 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301305 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301306 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1307 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1308 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301309 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301310 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301311 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301312 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301313
1314 *num_entities = l_num_entities;
1315 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301316}