blob: 571321627e13e472ac2ad7a3d4e9a982362197dc [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 Jeffery572a3952023-07-03 13:19:28 +093042 int rc = pldm_pdr_add_check(repo, data, size, is_remote,
43 terminus_handle, &record_handle);
44 (void)rc;
45 assert(!rc);
46 return record_handle;
47}
48
Andrew Jefferyca248ce2023-07-07 10:38:30 +093049LIBPLDM_ABI_STABLE
Andrew Jeffery572a3952023-07-03 13:19:28 +093050int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
51 bool is_remote, uint16_t terminus_handle,
52 uint32_t *record_handle)
53{
Andrew Jeffery9c766792022-08-10 23:12:49 +093054 assert(repo != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093055 assert(data != NULL);
Andrew Jeffery9c766792022-08-10 23:12:49 +093056 assert(size != 0);
Andrew Jeffery572a3952023-07-03 13:19:28 +093057 assert(record_handle != NULL);
58 if (!repo || !data || !size || !record_handle) {
59 return -EINVAL;
60 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093061
62 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
63 assert(record != NULL);
Andrew Jeffery572a3952023-07-03 13:19:28 +093064 if (!record) {
65 return -ENOMEM;
66 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093067
Andrew Jeffery572a3952023-07-03 13:19:28 +093068 if (data) {
69 record->data = malloc(size);
70 assert(record->data != NULL);
71 if (!record->data) {
72 free(record);
73 return -ENOMEM;
74 }
75 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093076 }
77
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 record->size = size;
79 record->is_remote = is_remote;
80 record->terminus_handle = terminus_handle;
Andrew Jeffery572a3952023-07-03 13:19:28 +093081
82 if (*record_handle) {
83 record->record_handle = *record_handle;
84 } else {
85 uint32_t curr = repo->last ? repo->last->record_handle : 0;
86 assert(curr != UINT32_MAX);
87 if (curr == UINT32_MAX) {
88 return -EOVERFLOW;
89 }
90 record->record_handle = curr + 1;
91
92 if (data != NULL) {
93 /* If record handle is 0, that is an indication for this API to
94 * compute a new handle. For that reason, the computed handle
95 * needs to be populated in the PDR header. For a case where the
96 * caller supplied the record handle, it would exist in the
97 * header already.
98 */
99 struct pldm_pdr_hdr *hdr = (void *)record->data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100 hdr->record_handle = htole32(record->record_handle);
101 }
102 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930103
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104 record->next = NULL;
105
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930106 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930107 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930108 repo->first = record;
109 repo->last = record;
110 } else {
111 repo->last->next = record;
112 repo->last = record;
113 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930115 repo->size += record->size;
116 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117
Andrew Jeffery572a3952023-07-03 13:19:28 +0930118 *record_handle = record->record_handle;
119
120 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121}
122
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930123LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930124pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930125{
126 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930127 if (!repo) {
128 return NULL;
129 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930130 repo->record_count = 0;
131 repo->size = 0;
132 repo->first = NULL;
133 repo->last = NULL;
134
135 return repo;
136}
137
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930138LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930139void pldm_pdr_destroy(pldm_pdr *repo)
140{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930141 if (!repo) {
142 return;
143 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930144
145 pldm_pdr_record *record = repo->first;
146 while (record != NULL) {
147 pldm_pdr_record *next = record->next;
148 if (record->data) {
149 free(record->data);
150 record->data = NULL;
151 }
152 free(record);
153 record = next;
154 }
155 free(repo);
156}
157
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930158LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930159const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
160 uint32_t record_handle,
161 uint8_t **data, uint32_t *size,
162 uint32_t *next_record_handle)
163{
164 assert(repo != NULL);
165 assert(data != NULL);
166 assert(size != NULL);
167 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168 if (!repo || !data || !size || !next_record_handle) {
169 return NULL;
170 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930171
172 if (!record_handle && (repo->first != NULL)) {
173 record_handle = repo->first->record_handle;
174 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930175
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 pldm_pdr_record *record = repo->first;
177 while (record != NULL) {
178 if (record->record_handle == record_handle) {
179 *size = record->size;
180 *data = record->data;
181 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930182 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930183 return record;
184 }
185 record = record->next;
186 }
187
188 *size = 0;
189 *next_record_handle = 0;
190 return NULL;
191}
192
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930193LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930194const pldm_pdr_record *
195pldm_pdr_get_next_record(const pldm_pdr *repo,
196 const pldm_pdr_record *curr_record, uint8_t **data,
197 uint32_t *size, uint32_t *next_record_handle)
198{
199 assert(repo != NULL);
200 assert(curr_record != NULL);
201 assert(data != NULL);
202 assert(size != NULL);
203 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930204 if (!repo || !curr_record || !data || !size || !next_record_handle) {
205 return NULL;
206 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930207
208 if (curr_record == repo->last) {
209 *data = NULL;
210 *size = 0;
211 *next_record_handle = get_next_record_handle(repo, curr_record);
212 return NULL;
213 }
214
215 *next_record_handle = get_next_record_handle(repo, curr_record->next);
216 *data = curr_record->next->data;
217 *size = curr_record->next->size;
218 return curr_record->next;
219}
220
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930221LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930222const pldm_pdr_record *
223pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
224 const pldm_pdr_record *curr_record, uint8_t **data,
225 uint32_t *size)
226{
227 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930228 if (!repo) {
229 return NULL;
230 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930231
232 pldm_pdr_record *record = repo->first;
233 if (curr_record != NULL) {
234 record = curr_record->next;
235 }
236 while (record != NULL) {
237 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
238 if (hdr->type == pdr_type) {
239 if (data && size) {
240 *size = record->size;
241 *data = record->data;
242 }
243 return record;
244 }
245 record = record->next;
246 }
247
248 if (size) {
249 *size = 0;
250 }
251 return NULL;
252}
253
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930254LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930255uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
256{
257 assert(repo != NULL);
258
259 return repo->record_count;
260}
261
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930262LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930263uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
264{
265 assert(repo != NULL);
266
267 return repo->size;
268}
269
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930270LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930271uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
272 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930273 const pldm_pdr_record *record)
274{
275 assert(repo != NULL);
276 assert(record != NULL);
277
278 return record->record_handle;
279}
280
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930281LIBPLDM_ABI_STABLE
282bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283{
284 assert(record != NULL);
285
286 return record->is_remote;
287}
288
Andrew Jefferya2c69112023-07-07 10:41:38 +0930289LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930290uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
291 uint16_t fru_rsi, uint16_t entity_type,
292 uint16_t entity_instance_num,
293 uint16_t container_id,
294 uint32_t bmc_record_handle)
295{
Andrew Jefferyc821a702023-07-03 13:32:11 +0930296 int rc = pldm_pdr_add_fru_record_set_check(
297 repo, terminus_handle, fru_rsi, entity_type,
298 entity_instance_num, container_id, &bmc_record_handle);
299 (void)rc;
300 assert(!rc);
301 return bmc_record_handle;
302}
303
Andrew Jefferya2c69112023-07-07 10:41:38 +0930304LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930305int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
306 uint16_t fru_rsi, uint16_t entity_type,
307 uint16_t entity_instance_num,
308 uint16_t container_id,
309 uint32_t *bmc_record_handle)
310{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311 uint32_t size = sizeof(struct pldm_pdr_hdr) +
312 sizeof(struct pldm_pdr_fru_record_set);
313 uint8_t data[size];
314
315 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
316 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930317 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930318 hdr->type = PLDM_PDR_FRU_RECORD_SET;
319 hdr->record_change_num = 0;
320 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
321 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930322 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
323 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324 fru->terminus_handle = htole16(terminus_handle);
325 fru->fru_rsi = htole16(fru_rsi);
326 fru->entity_type = htole16(entity_type);
327 fru->entity_instance_num = htole16(entity_instance_num);
328 fru->container_id = htole16(container_id);
329
Andrew Jefferyc821a702023-07-03 13:32:11 +0930330 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
331 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332}
333
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930334LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930335const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930336 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
337 uint16_t *entity_type, uint16_t *entity_instance_num,
338 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930339{
340 assert(terminus_handle != NULL);
341 assert(entity_type != NULL);
342 assert(entity_instance_num != NULL);
343 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930344 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
345 !container_id) {
346 return NULL;
347 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348
349 uint8_t *data = NULL;
350 uint32_t size = 0;
351 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353 while (curr_record != NULL) {
354 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930355 (struct pldm_pdr_fru_record_set
356 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930357 if (fru->fru_rsi == htole16(fru_rsi)) {
358 *terminus_handle = le16toh(fru->terminus_handle);
359 *entity_type = le16toh(fru->entity_type);
360 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930361 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930362 *container_id = le16toh(fru->container_id);
363 return curr_record;
364 }
365 data = NULL;
366 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930367 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
368 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369 }
370
371 *terminus_handle = 0;
372 *entity_type = 0;
373 *entity_instance_num = 0;
374 *container_id = 0;
375
376 return NULL;
377}
378
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930379LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930380/* NOLINTNEXTLINE(readability-identifier-naming) */
381void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
382 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930384 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930385 uint32_t size = 0;
386 const pldm_pdr_record *record;
387 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930388 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389
390 do {
391 if (record != NULL) {
392 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930393 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930394 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930395 (struct pldm_terminus_locator_type_mctp_eid *)
396 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930397 if (pdr->terminus_handle == terminus_handle &&
398 pdr->tid == tid && value->eid == tl_eid) {
399 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930400 break;
401 }
402 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930403 record = pldm_pdr_find_record_by_type(repo,
404 PLDM_TERMINUS_LOCATOR_PDR,
405 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930406 } while (record);
407}
408
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500409static bool pldm_record_handle_in_range(uint32_t record_handle,
410 uint32_t first_record_handle,
411 uint32_t last_record_handle)
412{
413 return record_handle >= first_record_handle &&
414 record_handle <= last_record_handle;
415}
416
417LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500418int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500419 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500420 uint8_t child_index, uint32_t range_exclude_start_handle,
421 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500422{
423 pldm_pdr_record *record;
424 if (!repo) {
425 return -EINVAL;
426 }
427
428 for (record = repo->first; record; record = record->next) {
429 bool is_container_entity_instance_number;
430 struct pldm_pdr_entity_association *pdr;
431 bool is_container_entity_type;
432 struct pldm_entity *child;
433 struct pldm_pdr_hdr *hdr;
434 bool in_range;
435
436 // pldm_pdr_add() takes only uint8_t* data as an argument.
437 // The expectation here is the pldm_pdr_hdr is the first field of the record data
438 hdr = (struct pldm_pdr_hdr *)record->data;
439 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
440 continue;
441 }
442 in_range = pldm_record_handle_in_range(
443 record->record_handle, range_exclude_start_handle,
444 range_exclude_end_handle);
445 if (in_range) {
446 continue;
447 }
448
449 // this cast is valid with respect to alignment because
450 // struct pldm_pdr_hdr is declared with __attribute__((packed))
451 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500452 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500453 continue;
454 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500455
456 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500457 is_container_entity_type = pdr->container.entity_type ==
458 entity_type;
459 is_container_entity_instance_number =
460 pdr->container.entity_instance_num == entity_instance;
461 if (is_container_entity_type &&
462 is_container_entity_instance_number) {
463 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500464 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500465 }
466 }
467 return -ENOKEY;
468}
469
Andrew Jeffery9c766792022-08-10 23:12:49 +0930470typedef struct pldm_entity_association_tree {
471 pldm_entity_node *root;
472 uint16_t last_used_container_id;
473} pldm_entity_association_tree;
474
475typedef struct pldm_entity_node {
476 pldm_entity entity;
477 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600478 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930479 pldm_entity_node *first_child;
480 pldm_entity_node *next_sibling;
481 uint8_t association_type;
482} pldm_entity_node;
483
484static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
485{
486 assert(tree != NULL);
487 assert(tree->last_used_container_id != UINT16_MAX);
488
489 return ++tree->last_used_container_id;
490}
491
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930492LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930493pldm_entity pldm_entity_extract(pldm_entity_node *node)
494{
495 assert(node != NULL);
496
497 return node->entity;
498}
499
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600500LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930501uint16_t
502pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600503{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930504 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600505
Andrew Jeffery15b88182023-06-30 13:29:17 +0930506 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600507}
508
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930509LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930510pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930511{
512 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930513 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930514 if (!tree) {
515 return NULL;
516 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930517 tree->root = NULL;
518 tree->last_used_container_id = 0;
519
520 return tree;
521}
522
523static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
524 uint16_t entity_type)
525{
526 assert(start != NULL);
527
528 /* Insert after the the last node that matches the input entity type, or
529 * at the end if no such match occurrs
530 */
531 while (start->next_sibling != NULL) {
532 uint16_t this_type = start->entity.entity_type;
533 pldm_entity_node *next = start->next_sibling;
534 if (this_type == entity_type &&
535 (this_type != next->entity.entity_type)) {
536 break;
537 }
538 start = start->next_sibling;
539 }
540
541 return start;
542}
543
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930544LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930545pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930546 pldm_entity_association_tree *tree, pldm_entity *entity,
547 uint16_t entity_instance_number, pldm_entity_node *parent,
548 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930549{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500550 return pldm_entity_association_tree_add_entity(tree, entity,
551 entity_instance_number,
552 parent, association_type,
553 false, true, 0xFFFF);
554}
555
556LIBPLDM_ABI_TESTING
557pldm_entity_node *pldm_entity_association_tree_add_entity(
558 pldm_entity_association_tree *tree, pldm_entity *entity,
559 uint16_t entity_instance_number, pldm_entity_node *parent,
560 uint8_t association_type, bool is_remote, bool is_update_container_id,
561 uint16_t container_id)
562{
563 if ((!tree) || (!entity)) {
564 return NULL;
565 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930566
567 if (entity_instance_number != 0xFFFF && parent != NULL) {
568 pldm_entity node;
569 node.entity_type = entity->entity_type;
570 node.entity_instance_num = entity_instance_number;
571 if (pldm_is_current_parent_child(parent, &node)) {
572 return NULL;
573 }
574 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500575 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
576 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
577 return NULL;
578 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930579 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500580 if (!node) {
581 return NULL;
582 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583 node->first_child = NULL;
584 node->next_sibling = NULL;
585 node->parent.entity_type = 0;
586 node->parent.entity_instance_num = 0;
587 node->parent.entity_container_id = 0;
588 node->entity.entity_type = entity->entity_type;
589 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930590 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930591 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600592 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930593 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500594 if (parent != NULL) {
595 free(node);
596 return NULL;
597 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930598 tree->root = node;
599 /* container_id 0 here indicates this is the top-most entry */
600 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600601 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930602 } else if (parent != NULL && parent->first_child == NULL) {
603 parent->first_child = node;
604 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500605
606 if (is_remote) {
607 node->remote_container_id = entity->entity_container_id;
608 }
609 if (is_update_container_id) {
610 if (container_id != 0xFFFF) {
611 node->entity.entity_container_id = container_id;
612 } else {
613 node->entity.entity_container_id =
614 next_container_id(tree);
615 }
616 } else {
617 node->entity.entity_container_id =
618 entity->entity_container_id;
619 }
620
621 if (!is_remote) {
622 node->remote_container_id =
623 node->entity.entity_container_id;
624 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930626 pldm_entity_node *start = parent == NULL ? tree->root :
627 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930628 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930629 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500630 if (!prev) {
631 free(node);
632 return NULL;
633 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930634 pldm_entity_node *next = prev->next_sibling;
635 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500636 if (prev->entity.entity_instance_num == UINT16_MAX) {
637 free(node);
638 return NULL;
639 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930640 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930641 entity_instance_number != 0xFFFF ?
642 entity_instance_number :
643 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930644 }
645 prev->next_sibling = node;
646 node->parent = prev->parent;
647 node->next_sibling = next;
648 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930649 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600650 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930651 }
652 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500653 if (is_update_container_id) {
654 entity->entity_container_id = node->entity.entity_container_id;
655 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930656 return node;
657}
658
659static void get_num_nodes(pldm_entity_node *node, size_t *num)
660{
661 if (node == NULL) {
662 return;
663 }
664
665 ++(*num);
666 get_num_nodes(node->next_sibling, num);
667 get_num_nodes(node->first_child, num);
668}
669
670static void entity_association_tree_visit(pldm_entity_node *node,
671 pldm_entity *entities, size_t *index)
672{
673 if (node == NULL) {
674 return;
675 }
676
677 pldm_entity *entity = &entities[*index];
678 ++(*index);
679 entity->entity_type = node->entity.entity_type;
680 entity->entity_instance_num = node->entity.entity_instance_num;
681 entity->entity_container_id = node->entity.entity_container_id;
682
683 entity_association_tree_visit(node->next_sibling, entities, index);
684 entity_association_tree_visit(node->first_child, entities, index);
685}
686
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930687LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930688void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
689 pldm_entity **entities, size_t *size)
690{
691 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930692 if (!tree || !entities || !size) {
693 return;
694 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930695
696 *size = 0;
697 if (tree->root == NULL) {
698 return;
699 }
700
701 get_num_nodes(tree->root, size);
702 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930703 if (!entities) {
704 return;
705 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706 size_t index = 0;
707 entity_association_tree_visit(tree->root, *entities, &index);
708}
709
710static void entity_association_tree_destroy(pldm_entity_node *node)
711{
712 if (node == NULL) {
713 return;
714 }
715
716 entity_association_tree_destroy(node->next_sibling);
717 entity_association_tree_destroy(node->first_child);
718 free(node);
719}
720
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930721LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
723{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930724 if (!tree) {
725 return;
726 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727
728 entity_association_tree_destroy(tree->root);
729 free(tree);
730}
731
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930732LIBPLDM_ABI_STABLE
733bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734{
735 assert(node != NULL);
736
737 return node->first_child != NULL;
738}
739
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930740LIBPLDM_ABI_STABLE
741pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742{
743 assert(node != NULL);
744
745 return node->parent;
746}
747
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930748LIBPLDM_ABI_STABLE
749bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750{
751 assert(node != NULL);
752
753 if (node->parent.entity_type == 0 &&
754 node->parent.entity_instance_num == 0 &&
755 node->parent.entity_container_id == 0) {
756 return false;
757 }
758
759 return true;
760}
761
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930762LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
764 uint8_t association_type)
765{
766 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930767 if (!node) {
768 return 0;
769 }
770
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
772 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930773 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
774 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
775 return 0;
776 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777
778 size_t count = 0;
779 pldm_entity_node *curr = node->first_child;
780 while (curr != NULL) {
781 if (curr->association_type == association_type) {
782 ++count;
783 }
784 curr = curr->next_sibling;
785 }
786
787 assert(count < UINT8_MAX);
788 return count;
789}
790
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930791LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930792bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
793{
794 assert(parent != NULL);
795 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930796 if (!parent || !node) {
797 return false;
798 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930799
800 pldm_entity_node *curr = parent->first_child;
801 while (curr != NULL) {
802 if (node->entity_type == curr->entity.entity_type &&
803 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930804 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805 return true;
806 }
807 curr = curr->next_sibling;
808 }
809
810 return false;
811}
812
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500813static void entity_association_pdr_add_children(
814 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
815 uint8_t contained_count, uint8_t association_type, bool is_remote,
816 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817{
818 uint8_t pdr[size];
819 uint8_t *start = pdr;
820
821 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
822 hdr->version = 1;
823 hdr->record_handle = 0;
824 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
825 hdr->record_change_num = 0;
826 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
827 start += sizeof(struct pldm_pdr_hdr);
828
829 uint16_t *container_id = (uint16_t *)start;
830 *container_id = htole16(curr->first_child->entity.entity_container_id);
831 start += sizeof(uint16_t);
832 *start = association_type;
833 start += sizeof(uint8_t);
834
835 pldm_entity *entity = (pldm_entity *)start;
836 entity->entity_type = htole16(curr->entity.entity_type);
837 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
838 entity->entity_container_id = htole16(curr->entity.entity_container_id);
839 start += sizeof(pldm_entity);
840
841 *start = contained_count;
842 start += sizeof(uint8_t);
843
844 pldm_entity_node *node = curr->first_child;
845 while (node != NULL) {
846 if (node->association_type == association_type) {
847 pldm_entity *entity = (pldm_entity *)start;
848 entity->entity_type = htole16(node->entity.entity_type);
849 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930850 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930851 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930852 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853 start += sizeof(pldm_entity);
854 }
855 node = node->next_sibling;
856 }
857
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500858 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
859 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930860}
861
862static void entity_association_pdr_add_entry(pldm_entity_node *curr,
863 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500864 uint16_t terminus_handle,
865 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930866{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 uint8_t num_logical_children = pldm_entity_get_num_children(
868 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
869 uint8_t num_physical_children = pldm_entity_get_num_children(
870 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871
872 if (num_logical_children) {
873 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930874 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
875 sizeof(uint8_t) + sizeof(pldm_entity) +
876 sizeof(uint8_t) +
877 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930878 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930879 curr, repo, logical_pdr_size, num_logical_children,
880 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500881 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882 }
883
884 if (num_physical_children) {
885 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930886 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
887 sizeof(uint8_t) + sizeof(pldm_entity) +
888 sizeof(uint8_t) +
889 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930890 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930891 curr, repo, physical_pdr_size, num_physical_children,
892 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500893 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 }
895}
896
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930897LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930898bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
899{
900 if (entities == NULL || num_entities == 0) {
901 return true;
902 }
903 size_t i = 0;
904 while (i < num_entities) {
905 if ((*entities + i)->entity_type == entity.entity_type) {
906 return true;
907 }
908 i++;
909 }
910 return false;
911}
912
913static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
914 pldm_entity **entities,
915 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500916 uint16_t terminus_handle,
917 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918{
919 if (curr == NULL) {
920 return;
921 }
922 bool to_add = true;
923 to_add = is_present(curr->entity, entities, num_entities);
924 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500925 entity_association_pdr_add_entry(
926 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927 }
928 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500929 num_entities, is_remote, terminus_handle,
930 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500932 num_entities, is_remote, terminus_handle,
933 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934}
935
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930936LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
938 pldm_pdr *repo, bool is_remote,
939 uint16_t terminus_handle)
940{
941 assert(tree != NULL);
942 assert(repo != NULL);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930943 if (!tree || !repo) {
944 return;
945 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946
947 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500948 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949}
950
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930951LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930953 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
954 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955{
Andrew Jefferycc394522023-07-03 12:49:31 +0930956 int rc = pldm_entity_association_pdr_add_from_node_check(
957 node, repo, entities, num_entities, is_remote, terminus_handle);
958 (void)rc;
959 assert(!rc);
960}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930961
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930962LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930963int pldm_entity_association_pdr_add_from_node_check(
964 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
965 size_t num_entities, bool is_remote, uint16_t terminus_handle)
966{
967 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500968 node, repo, entities, num_entities, is_remote, terminus_handle,
969 0);
970}
971
972LIBPLDM_ABI_TESTING
973int pldm_entity_association_pdr_add_from_node_with_record_handle(
974 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
975 size_t num_entities, bool is_remote, uint16_t terminus_handle,
976 uint32_t record_handle)
977{
978 if (!node || !repo || !entities) {
979 return -EINVAL;
980 }
981
Andrew Jeffery9c766792022-08-10 23:12:49 +0930982 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500983 is_remote, terminus_handle, record_handle);
984
985 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930986}
987
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930988LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930989void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
990 pldm_entity_node **node)
991{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600992 bool is_entity_container_id;
993 bool is_entity_instance_num;
994 bool is_type;
995
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996 if (tree_node == NULL) {
997 return;
998 }
999
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001000 is_type = tree_node->entity.entity_type == entity.entity_type;
1001 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1002 entity.entity_instance_num;
1003 is_entity_container_id = tree_node->entity.entity_container_id ==
1004 entity.entity_container_id;
1005
1006 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 *node = tree_node;
1008 return;
1009 }
1010
1011 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1012 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1013}
1014
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301015LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301016void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1017 pldm_entity entity, pldm_entity_node **node)
1018{
1019 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +09301020 if (!tree || !node) {
1021 return;
1022 }
1023
Andrew Jeffery9c766792022-08-10 23:12:49 +09301024 find_entity_ref_in_tree(tree->root, entity, node);
1025}
1026
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301027LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301028void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1029 uint16_t terminus_handle)
1030{
1031 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +09301032 if (!repo) {
1033 return;
1034 }
1035
Andrew Jeffery9c766792022-08-10 23:12:49 +09301036 bool removed = false;
1037
1038 pldm_pdr_record *record = repo->first;
1039 pldm_pdr_record *prev = NULL;
1040 while (record != NULL) {
1041 pldm_pdr_record *next = record->next;
1042 if (record->terminus_handle == terminus_handle) {
1043 if (repo->first == record) {
1044 repo->first = next;
1045 } else {
1046 prev->next = next;
1047 }
1048 if (repo->last == record) {
1049 repo->last = prev;
1050 }
1051 if (record->data) {
1052 free(record->data);
1053 }
1054 --repo->record_count;
1055 repo->size -= record->size;
1056 free(record);
1057 removed = true;
1058 } else {
1059 prev = record;
1060 }
1061 record = next;
1062 }
1063
1064 if (removed == true) {
1065 record = repo->first;
1066 uint32_t record_handle = 0;
1067 while (record != NULL) {
1068 record->record_handle = ++record_handle;
1069 if (record->data != NULL) {
1070 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301071 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301072 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301073 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301074 }
1075 record = record->next;
1076 }
1077 }
1078}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301079
1080LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301081void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1082{
1083 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301084 if (!repo) {
1085 return;
1086 }
1087
Andrew Jeffery9c766792022-08-10 23:12:49 +09301088 bool removed = false;
1089
1090 pldm_pdr_record *record = repo->first;
1091 pldm_pdr_record *prev = NULL;
1092 while (record != NULL) {
1093 pldm_pdr_record *next = record->next;
1094 if (record->is_remote == true) {
1095 if (repo->first == record) {
1096 repo->first = next;
1097 } else {
1098 prev->next = next;
1099 }
1100 if (repo->last == record) {
1101 repo->last = prev;
1102 }
1103 if (record->data) {
1104 free(record->data);
1105 }
1106 --repo->record_count;
1107 repo->size -= record->size;
1108 free(record);
1109 removed = true;
1110 } else {
1111 prev = record;
1112 }
1113 record = next;
1114 }
1115
1116 if (removed == true) {
1117 record = repo->first;
1118 uint32_t record_handle = 0;
1119 while (record != NULL) {
1120 record->record_handle = ++record_handle;
1121 if (record->data != NULL) {
1122 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301123 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301124 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301125 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126 }
1127 record = record->next;
1128 }
1129 }
1130}
1131
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001132LIBPLDM_ABI_TESTING
1133pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1134 uint32_t first, uint32_t last)
1135{
1136 pldm_pdr_record *record = NULL;
1137 pldm_pdr_record *curr;
1138
1139 if (!repo) {
1140 return NULL;
1141 }
1142 for (curr = repo->first; curr; curr = curr->next) {
1143 if (first > curr->record_handle || last < curr->record_handle) {
1144 continue;
1145 }
1146 if (!record || curr->record_handle > record->record_handle) {
1147 record = curr;
1148 }
1149 }
1150
1151 return record;
1152}
1153
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001154static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1155 pldm_entity *entity,
1156 pldm_entity_node **out,
1157 bool is_remote)
1158{
1159 assert(out != NULL && *out == NULL);
1160 if (node == NULL) {
1161 return;
1162 }
1163 bool is_entity_type;
1164 bool is_entity_instance_num;
1165
1166 is_entity_type = node->entity.entity_type == entity->entity_type;
1167 is_entity_instance_num = node->entity.entity_instance_num ==
1168 entity->entity_instance_num;
1169
1170 if (!is_remote ||
1171 node->remote_container_id == entity->entity_container_id) {
1172 if (is_entity_type && is_entity_instance_num) {
1173 entity->entity_container_id =
1174 node->entity.entity_container_id;
1175 *out = node;
1176 return;
1177 }
1178 }
1179 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1180 is_remote);
1181 entity_association_tree_find_if_remote(node->first_child, entity, out,
1182 is_remote);
1183}
1184
1185LIBPLDM_ABI_TESTING
1186pldm_entity_node *
1187pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1188 pldm_entity *entity, bool is_remote)
1189{
1190 if (!tree || !entity) {
1191 return NULL;
1192 }
1193 pldm_entity_node *node = NULL;
1194 entity_association_tree_find_if_remote(tree->root, entity, &node,
1195 is_remote);
1196 return node;
1197}
1198
Andrew Jeffery7f589312023-07-03 12:03:25 +09301199LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301200void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1201 pldm_entity_node **out)
1202{
1203 if (node == NULL) {
1204 return;
1205 }
1206
1207 if (node->entity.entity_type == entity->entity_type &&
1208 node->entity.entity_instance_num == entity->entity_instance_num) {
1209 entity->entity_container_id = node->entity.entity_container_id;
1210 *out = node;
1211 return;
1212 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301213 entity_association_tree_find(node->next_sibling, entity, out);
1214 entity_association_tree_find(node->first_child, entity, out);
1215}
1216
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301217LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218pldm_entity_node *
1219pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1220 pldm_entity *entity)
1221{
1222 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301223 if (!tree || !entity) {
1224 return NULL;
1225 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301226
1227 pldm_entity_node *node = NULL;
1228 entity_association_tree_find(tree->root, entity, &node);
1229 return node;
1230}
1231
1232static void entity_association_tree_copy(pldm_entity_node *org_node,
1233 pldm_entity_node **new_node)
1234{
1235 if (org_node == NULL) {
1236 return;
1237 }
1238 *new_node = malloc(sizeof(pldm_entity_node));
1239 (*new_node)->parent = org_node->parent;
1240 (*new_node)->entity = org_node->entity;
1241 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001242 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301243 (*new_node)->first_child = NULL;
1244 (*new_node)->next_sibling = NULL;
1245 entity_association_tree_copy(org_node->first_child,
1246 &((*new_node)->first_child));
1247 entity_association_tree_copy(org_node->next_sibling,
1248 &((*new_node)->next_sibling));
1249}
1250
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301251LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301252void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301253 pldm_entity_association_tree *org_tree,
1254 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301255{
1256 new_tree->last_used_container_id = org_tree->last_used_container_id;
1257 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1258}
1259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301260LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301261void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301262 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301263{
1264 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301265 if (!tree) {
1266 return;
1267 }
1268
Andrew Jeffery9c766792022-08-10 23:12:49 +09301269 entity_association_tree_destroy(tree->root);
1270 tree->last_used_container_id = 0;
1271 tree->root = NULL;
1272}
1273
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301274LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301275bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1276{
1277 return ((tree->root == NULL) ? true : false);
1278}
1279
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301280LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301281void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1282 size_t *num_entities,
1283 pldm_entity **entities)
1284{
1285 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301286 if (!pdr || !num_entities || !entities) {
1287 return;
1288 }
1289#define PDR_MIN_SIZE \
1290 (sizeof(struct pldm_pdr_hdr) + \
1291 sizeof(struct pldm_pdr_entity_association))
1292 assert(pdr_len >= PDR_MIN_SIZE);
1293 if (pdr_len < PDR_MIN_SIZE) {
1294 return;
1295 }
1296#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297
1298 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1299 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1300
1301 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301302 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301303 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301304 start += sizeof(struct pldm_pdr_hdr);
1305 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301306 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301307 *num_entities = entity_association_pdr->num_children + 1;
1308 assert(*num_entities >= 2);
1309 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1310 assert(*entities != NULL);
1311 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301312 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313 end);
Andrew Jeffery975f0aa2023-07-11 16:49:39 +09301314 (*entities)[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301315 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery975f0aa2023-07-11 16:49:39 +09301316 (*entities)[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301317 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery975f0aa2023-07-11 16:49:39 +09301318 (*entities)[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301319 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301320 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jefferya6e1ae92023-07-11 16:45:03 +09301321 for (size_t i = 1; i < *num_entities; i++, curr_entity++) {
Andrew Jeffery975f0aa2023-07-11 16:49:39 +09301322 (*entities)[i].entity_type = le16toh(curr_entity->entity_type);
1323 (*entities)[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301324 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery975f0aa2023-07-11 16:49:39 +09301325 (*entities)[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301326 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301327 }
1328}