blob: 094e1c6b2eb9b62f0058fef9e50ab2694770eb59 [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 Jeffery9c766792022-08-10 23:12:49 +093037static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
38{
39 assert(repo != NULL);
40 uint32_t last_used_hdl =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093041 repo->last != NULL ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093042 assert(last_used_hdl != UINT32_MAX);
43
44 return last_used_hdl + 1;
45}
46
Andrew Jefferya51ccc22023-06-28 21:57:46 +093047LIBPLDM_ABI_STABLE
48uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
49 uint32_t record_handle, bool is_remote,
50 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +093051{
52 assert(repo != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093053 assert(data != NULL);
Andrew Jeffery9c766792022-08-10 23:12:49 +093054 assert(size != 0);
55
56 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
57 assert(record != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093058
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093059 record->record_handle = record_handle == 0 ?
60 get_new_record_handle(repo) :
61 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093062 record->size = size;
63 record->is_remote = is_remote;
64 record->terminus_handle = terminus_handle;
65 if (data != NULL) {
66 record->data = malloc(size);
67 assert(record->data != NULL);
68 memcpy(record->data, data, size);
69 /* If record handle is 0, that is an indication for this API to
70 * compute a new handle. For that reason, the computed handle
71 * needs to be populated in the PDR header. For a case where the
72 * caller supplied the record handle, it would exist in the
73 * header already.
74 */
75 if (!record_handle) {
76 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093077 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 hdr->record_handle = htole32(record->record_handle);
79 }
80 }
81 record->next = NULL;
82
Andrew Jefferya51ccc22023-06-28 21:57:46 +093083 if (repo->first == NULL) {
84 assert(repo->last == NULL);
85 repo->first = record;
86 repo->last = record;
87 } else {
88 repo->last->next = record;
89 repo->last = record;
90 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093091
Andrew Jefferya51ccc22023-06-28 21:57:46 +093092 repo->size += record->size;
93 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +093094
95 return record->record_handle;
96}
97
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093098LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +093099pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100{
101 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930102 if (!repo) {
103 return NULL;
104 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930105 repo->record_count = 0;
106 repo->size = 0;
107 repo->first = NULL;
108 repo->last = NULL;
109
110 return repo;
111}
112
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930113LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114void pldm_pdr_destroy(pldm_pdr *repo)
115{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930116 if (!repo) {
117 return;
118 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119
120 pldm_pdr_record *record = repo->first;
121 while (record != NULL) {
122 pldm_pdr_record *next = record->next;
123 if (record->data) {
124 free(record->data);
125 record->data = NULL;
126 }
127 free(record);
128 record = next;
129 }
130 free(repo);
131}
132
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930133LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930134const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
135 uint32_t record_handle,
136 uint8_t **data, uint32_t *size,
137 uint32_t *next_record_handle)
138{
139 assert(repo != NULL);
140 assert(data != NULL);
141 assert(size != NULL);
142 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930143 if (!repo || !data || !size || !next_record_handle) {
144 return NULL;
145 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930146
147 if (!record_handle && (repo->first != NULL)) {
148 record_handle = repo->first->record_handle;
149 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930150
Andrew Jeffery9c766792022-08-10 23:12:49 +0930151 pldm_pdr_record *record = repo->first;
152 while (record != NULL) {
153 if (record->record_handle == record_handle) {
154 *size = record->size;
155 *data = record->data;
156 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930157 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930158 return record;
159 }
160 record = record->next;
161 }
162
163 *size = 0;
164 *next_record_handle = 0;
165 return NULL;
166}
167
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930168LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169const pldm_pdr_record *
170pldm_pdr_get_next_record(const pldm_pdr *repo,
171 const pldm_pdr_record *curr_record, uint8_t **data,
172 uint32_t *size, uint32_t *next_record_handle)
173{
174 assert(repo != NULL);
175 assert(curr_record != NULL);
176 assert(data != NULL);
177 assert(size != NULL);
178 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930179 if (!repo || !curr_record || !data || !size || !next_record_handle) {
180 return NULL;
181 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930182
183 if (curr_record == repo->last) {
184 *data = NULL;
185 *size = 0;
186 *next_record_handle = get_next_record_handle(repo, curr_record);
187 return NULL;
188 }
189
190 *next_record_handle = get_next_record_handle(repo, curr_record->next);
191 *data = curr_record->next->data;
192 *size = curr_record->next->size;
193 return curr_record->next;
194}
195
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930196LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930197const pldm_pdr_record *
198pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
199 const pldm_pdr_record *curr_record, uint8_t **data,
200 uint32_t *size)
201{
202 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930203 if (!repo) {
204 return NULL;
205 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930206
207 pldm_pdr_record *record = repo->first;
208 if (curr_record != NULL) {
209 record = curr_record->next;
210 }
211 while (record != NULL) {
212 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
213 if (hdr->type == pdr_type) {
214 if (data && size) {
215 *size = record->size;
216 *data = record->data;
217 }
218 return record;
219 }
220 record = record->next;
221 }
222
223 if (size) {
224 *size = 0;
225 }
226 return NULL;
227}
228
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930229LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930230uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
231{
232 assert(repo != NULL);
233
234 return repo->record_count;
235}
236
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930237LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930238uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
239{
240 assert(repo != NULL);
241
242 return repo->size;
243}
244
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930245LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930246uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
247 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248 const pldm_pdr_record *record)
249{
250 assert(repo != NULL);
251 assert(record != NULL);
252
253 return record->record_handle;
254}
255
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930256LIBPLDM_ABI_STABLE
257bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930258{
259 assert(record != NULL);
260
261 return record->is_remote;
262}
263
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930264LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930265uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
266 uint16_t fru_rsi, uint16_t entity_type,
267 uint16_t entity_instance_num,
268 uint16_t container_id,
269 uint32_t bmc_record_handle)
270{
271 uint32_t size = sizeof(struct pldm_pdr_hdr) +
272 sizeof(struct pldm_pdr_fru_record_set);
273 uint8_t data[size];
274
275 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
276 hdr->version = 1;
277 hdr->record_handle = bmc_record_handle;
278 hdr->type = PLDM_PDR_FRU_RECORD_SET;
279 hdr->record_change_num = 0;
280 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
281 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930282 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
283 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930284 fru->terminus_handle = htole16(terminus_handle);
285 fru->fru_rsi = htole16(fru_rsi);
286 fru->entity_type = htole16(entity_type);
287 fru->entity_instance_num = htole16(entity_instance_num);
288 fru->container_id = htole16(container_id);
289
290 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
291 terminus_handle);
292}
293
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930294LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930295const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930296 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
297 uint16_t *entity_type, uint16_t *entity_instance_num,
298 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299{
300 assert(terminus_handle != NULL);
301 assert(entity_type != NULL);
302 assert(entity_instance_num != NULL);
303 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930304 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
305 !container_id) {
306 return NULL;
307 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308
309 uint8_t *data = NULL;
310 uint32_t size = 0;
311 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930312 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313 while (curr_record != NULL) {
314 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 (struct pldm_pdr_fru_record_set
316 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 if (fru->fru_rsi == htole16(fru_rsi)) {
318 *terminus_handle = le16toh(fru->terminus_handle);
319 *entity_type = le16toh(fru->entity_type);
320 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930322 *container_id = le16toh(fru->container_id);
323 return curr_record;
324 }
325 data = NULL;
326 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930327 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
328 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329 }
330
331 *terminus_handle = 0;
332 *entity_type = 0;
333 *entity_instance_num = 0;
334 *container_id = 0;
335
336 return NULL;
337}
338
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930339LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930340/* NOLINTNEXTLINE(readability-identifier-naming) */
341void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
342 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930344 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930345 uint32_t size = 0;
346 const pldm_pdr_record *record;
347 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930348 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349
350 do {
351 if (record != NULL) {
352 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930353 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930355 (struct pldm_terminus_locator_type_mctp_eid *)
356 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930357 if (pdr->terminus_handle == terminus_handle &&
358 pdr->tid == tid && value->eid == tl_eid) {
359 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930360 break;
361 }
362 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930363 record = pldm_pdr_find_record_by_type(repo,
364 PLDM_TERMINUS_LOCATOR_PDR,
365 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 } while (record);
367}
368
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500369static bool pldm_record_handle_in_range(uint32_t record_handle,
370 uint32_t first_record_handle,
371 uint32_t last_record_handle)
372{
373 return record_handle >= first_record_handle &&
374 record_handle <= last_record_handle;
375}
376
377LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500378int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500379 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500380 uint8_t child_index, uint32_t range_exclude_start_handle,
381 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500382{
383 pldm_pdr_record *record;
384 if (!repo) {
385 return -EINVAL;
386 }
387
388 for (record = repo->first; record; record = record->next) {
389 bool is_container_entity_instance_number;
390 struct pldm_pdr_entity_association *pdr;
391 bool is_container_entity_type;
392 struct pldm_entity *child;
393 struct pldm_pdr_hdr *hdr;
394 bool in_range;
395
396 // pldm_pdr_add() takes only uint8_t* data as an argument.
397 // The expectation here is the pldm_pdr_hdr is the first field of the record data
398 hdr = (struct pldm_pdr_hdr *)record->data;
399 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
400 continue;
401 }
402 in_range = pldm_record_handle_in_range(
403 record->record_handle, range_exclude_start_handle,
404 range_exclude_end_handle);
405 if (in_range) {
406 continue;
407 }
408
409 // this cast is valid with respect to alignment because
410 // struct pldm_pdr_hdr is declared with __attribute__((packed))
411 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500412 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500413 continue;
414 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500415
416 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500417 is_container_entity_type = pdr->container.entity_type ==
418 entity_type;
419 is_container_entity_instance_number =
420 pdr->container.entity_instance_num == entity_instance;
421 if (is_container_entity_type &&
422 is_container_entity_instance_number) {
423 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500424 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500425 }
426 }
427 return -ENOKEY;
428}
429
Andrew Jeffery9c766792022-08-10 23:12:49 +0930430typedef struct pldm_entity_association_tree {
431 pldm_entity_node *root;
432 uint16_t last_used_container_id;
433} pldm_entity_association_tree;
434
435typedef struct pldm_entity_node {
436 pldm_entity entity;
437 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600438 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930439 pldm_entity_node *first_child;
440 pldm_entity_node *next_sibling;
441 uint8_t association_type;
442} pldm_entity_node;
443
444static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
445{
446 assert(tree != NULL);
447 assert(tree->last_used_container_id != UINT16_MAX);
448
449 return ++tree->last_used_container_id;
450}
451
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930452LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930453pldm_entity pldm_entity_extract(pldm_entity_node *node)
454{
455 assert(node != NULL);
456
457 return node->entity;
458}
459
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600460LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930461uint16_t
462pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600463{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930464 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600465
Andrew Jeffery15b88182023-06-30 13:29:17 +0930466 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600467}
468
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930469LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930470pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930471{
472 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930473 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930474 if (!tree) {
475 return NULL;
476 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930477 tree->root = NULL;
478 tree->last_used_container_id = 0;
479
480 return tree;
481}
482
483static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
484 uint16_t entity_type)
485{
486 assert(start != NULL);
487
488 /* Insert after the the last node that matches the input entity type, or
489 * at the end if no such match occurrs
490 */
491 while (start->next_sibling != NULL) {
492 uint16_t this_type = start->entity.entity_type;
493 pldm_entity_node *next = start->next_sibling;
494 if (this_type == entity_type &&
495 (this_type != next->entity.entity_type)) {
496 break;
497 }
498 start = start->next_sibling;
499 }
500
501 return start;
502}
503
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930504LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930505pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930506 pldm_entity_association_tree *tree, pldm_entity *entity,
507 uint16_t entity_instance_number, pldm_entity_node *parent,
508 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930509{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500510 return pldm_entity_association_tree_add_entity(tree, entity,
511 entity_instance_number,
512 parent, association_type,
513 false, true, 0xFFFF);
514}
515
516LIBPLDM_ABI_TESTING
517pldm_entity_node *pldm_entity_association_tree_add_entity(
518 pldm_entity_association_tree *tree, pldm_entity *entity,
519 uint16_t entity_instance_number, pldm_entity_node *parent,
520 uint8_t association_type, bool is_remote, bool is_update_container_id,
521 uint16_t container_id)
522{
523 if ((!tree) || (!entity)) {
524 return NULL;
525 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930526
527 if (entity_instance_number != 0xFFFF && parent != NULL) {
528 pldm_entity node;
529 node.entity_type = entity->entity_type;
530 node.entity_instance_num = entity_instance_number;
531 if (pldm_is_current_parent_child(parent, &node)) {
532 return NULL;
533 }
534 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500535 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
536 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
537 return NULL;
538 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930539 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500540 if (!node) {
541 return NULL;
542 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543 node->first_child = NULL;
544 node->next_sibling = NULL;
545 node->parent.entity_type = 0;
546 node->parent.entity_instance_num = 0;
547 node->parent.entity_container_id = 0;
548 node->entity.entity_type = entity->entity_type;
549 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930550 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600552 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930553 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500554 if (parent != NULL) {
555 free(node);
556 return NULL;
557 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 tree->root = node;
559 /* container_id 0 here indicates this is the top-most entry */
560 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600561 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 } else if (parent != NULL && parent->first_child == NULL) {
563 parent->first_child = node;
564 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500565
566 if (is_remote) {
567 node->remote_container_id = entity->entity_container_id;
568 }
569 if (is_update_container_id) {
570 if (container_id != 0xFFFF) {
571 node->entity.entity_container_id = container_id;
572 } else {
573 node->entity.entity_container_id =
574 next_container_id(tree);
575 }
576 } else {
577 node->entity.entity_container_id =
578 entity->entity_container_id;
579 }
580
581 if (!is_remote) {
582 node->remote_container_id =
583 node->entity.entity_container_id;
584 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930585 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930586 pldm_entity_node *start = parent == NULL ? tree->root :
587 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930589 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500590 if (!prev) {
591 free(node);
592 return NULL;
593 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930594 pldm_entity_node *next = prev->next_sibling;
595 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500596 if (prev->entity.entity_instance_num == UINT16_MAX) {
597 free(node);
598 return NULL;
599 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930600 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930601 entity_instance_number != 0xFFFF ?
602 entity_instance_number :
603 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604 }
605 prev->next_sibling = node;
606 node->parent = prev->parent;
607 node->next_sibling = next;
608 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930609 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600610 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 }
612 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500613 if (is_update_container_id) {
614 entity->entity_container_id = node->entity.entity_container_id;
615 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930616 return node;
617}
618
619static void get_num_nodes(pldm_entity_node *node, size_t *num)
620{
621 if (node == NULL) {
622 return;
623 }
624
625 ++(*num);
626 get_num_nodes(node->next_sibling, num);
627 get_num_nodes(node->first_child, num);
628}
629
630static void entity_association_tree_visit(pldm_entity_node *node,
631 pldm_entity *entities, size_t *index)
632{
633 if (node == NULL) {
634 return;
635 }
636
637 pldm_entity *entity = &entities[*index];
638 ++(*index);
639 entity->entity_type = node->entity.entity_type;
640 entity->entity_instance_num = node->entity.entity_instance_num;
641 entity->entity_container_id = node->entity.entity_container_id;
642
643 entity_association_tree_visit(node->next_sibling, entities, index);
644 entity_association_tree_visit(node->first_child, entities, index);
645}
646
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930647LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
649 pldm_entity **entities, size_t *size)
650{
651 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930652 if (!tree || !entities || !size) {
653 return;
654 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930655
656 *size = 0;
657 if (tree->root == NULL) {
658 return;
659 }
660
661 get_num_nodes(tree->root, size);
662 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930663 if (!entities) {
664 return;
665 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930666 size_t index = 0;
667 entity_association_tree_visit(tree->root, *entities, &index);
668}
669
670static void entity_association_tree_destroy(pldm_entity_node *node)
671{
672 if (node == NULL) {
673 return;
674 }
675
676 entity_association_tree_destroy(node->next_sibling);
677 entity_association_tree_destroy(node->first_child);
678 free(node);
679}
680
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930681LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930682void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
683{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930684 if (!tree) {
685 return;
686 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687
688 entity_association_tree_destroy(tree->root);
689 free(tree);
690}
691
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930692LIBPLDM_ABI_STABLE
693bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694{
695 assert(node != NULL);
696
697 return node->first_child != NULL;
698}
699
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930700LIBPLDM_ABI_STABLE
701pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702{
703 assert(node != NULL);
704
705 return node->parent;
706}
707
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930708LIBPLDM_ABI_STABLE
709bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930710{
711 assert(node != NULL);
712
713 if (node->parent.entity_type == 0 &&
714 node->parent.entity_instance_num == 0 &&
715 node->parent.entity_container_id == 0) {
716 return false;
717 }
718
719 return true;
720}
721
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930722LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
724 uint8_t association_type)
725{
726 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930727 if (!node) {
728 return 0;
729 }
730
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
732 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930733 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
734 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
735 return 0;
736 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737
738 size_t count = 0;
739 pldm_entity_node *curr = node->first_child;
740 while (curr != NULL) {
741 if (curr->association_type == association_type) {
742 ++count;
743 }
744 curr = curr->next_sibling;
745 }
746
747 assert(count < UINT8_MAX);
748 return count;
749}
750
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930751LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
753{
754 assert(parent != NULL);
755 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930756 if (!parent || !node) {
757 return false;
758 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759
760 pldm_entity_node *curr = parent->first_child;
761 while (curr != NULL) {
762 if (node->entity_type == curr->entity.entity_type &&
763 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930764 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930765 return true;
766 }
767 curr = curr->next_sibling;
768 }
769
770 return false;
771}
772
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500773static void entity_association_pdr_add_children(
774 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
775 uint8_t contained_count, uint8_t association_type, bool is_remote,
776 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777{
778 uint8_t pdr[size];
779 uint8_t *start = pdr;
780
781 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
782 hdr->version = 1;
783 hdr->record_handle = 0;
784 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
785 hdr->record_change_num = 0;
786 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
787 start += sizeof(struct pldm_pdr_hdr);
788
789 uint16_t *container_id = (uint16_t *)start;
790 *container_id = htole16(curr->first_child->entity.entity_container_id);
791 start += sizeof(uint16_t);
792 *start = association_type;
793 start += sizeof(uint8_t);
794
795 pldm_entity *entity = (pldm_entity *)start;
796 entity->entity_type = htole16(curr->entity.entity_type);
797 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
798 entity->entity_container_id = htole16(curr->entity.entity_container_id);
799 start += sizeof(pldm_entity);
800
801 *start = contained_count;
802 start += sizeof(uint8_t);
803
804 pldm_entity_node *node = curr->first_child;
805 while (node != NULL) {
806 if (node->association_type == association_type) {
807 pldm_entity *entity = (pldm_entity *)start;
808 entity->entity_type = htole16(node->entity.entity_type);
809 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930810 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930811 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930812 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813 start += sizeof(pldm_entity);
814 }
815 node = node->next_sibling;
816 }
817
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500818 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
819 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930820}
821
822static void entity_association_pdr_add_entry(pldm_entity_node *curr,
823 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500824 uint16_t terminus_handle,
825 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930826{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930827 uint8_t num_logical_children = pldm_entity_get_num_children(
828 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
829 uint8_t num_physical_children = pldm_entity_get_num_children(
830 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831
832 if (num_logical_children) {
833 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930834 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
835 sizeof(uint8_t) + sizeof(pldm_entity) +
836 sizeof(uint8_t) +
837 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930838 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 curr, repo, logical_pdr_size, num_logical_children,
840 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500841 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842 }
843
844 if (num_physical_children) {
845 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930846 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
847 sizeof(uint8_t) + sizeof(pldm_entity) +
848 sizeof(uint8_t) +
849 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930850 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930851 curr, repo, physical_pdr_size, num_physical_children,
852 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500853 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930854 }
855}
856
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930857LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930858bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
859{
860 if (entities == NULL || num_entities == 0) {
861 return true;
862 }
863 size_t i = 0;
864 while (i < num_entities) {
865 if ((*entities + i)->entity_type == entity.entity_type) {
866 return true;
867 }
868 i++;
869 }
870 return false;
871}
872
873static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
874 pldm_entity **entities,
875 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500876 uint16_t terminus_handle,
877 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878{
879 if (curr == NULL) {
880 return;
881 }
882 bool to_add = true;
883 to_add = is_present(curr->entity, entities, num_entities);
884 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500885 entity_association_pdr_add_entry(
886 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887 }
888 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500889 num_entities, is_remote, terminus_handle,
890 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500892 num_entities, is_remote, terminus_handle,
893 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894}
895
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930896LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930897void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
898 pldm_pdr *repo, bool is_remote,
899 uint16_t terminus_handle)
900{
901 assert(tree != NULL);
902 assert(repo != NULL);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930903 if (!tree || !repo) {
904 return;
905 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930906
907 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500908 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930909}
910
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930911LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930913 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
914 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930915{
Andrew Jefferycc394522023-07-03 12:49:31 +0930916 int rc = pldm_entity_association_pdr_add_from_node_check(
917 node, repo, entities, num_entities, is_remote, terminus_handle);
918 (void)rc;
919 assert(!rc);
920}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921
Andrew Jefferycc394522023-07-03 12:49:31 +0930922LIBPLDM_ABI_TESTING
923int pldm_entity_association_pdr_add_from_node_check(
924 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
925 size_t num_entities, bool is_remote, uint16_t terminus_handle)
926{
927 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500928 node, repo, entities, num_entities, is_remote, terminus_handle,
929 0);
930}
931
932LIBPLDM_ABI_TESTING
933int pldm_entity_association_pdr_add_from_node_with_record_handle(
934 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
935 size_t num_entities, bool is_remote, uint16_t terminus_handle,
936 uint32_t record_handle)
937{
938 if (!node || !repo || !entities) {
939 return -EINVAL;
940 }
941
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500943 is_remote, terminus_handle, record_handle);
944
945 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946}
947
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930948LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
950 pldm_entity_node **node)
951{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600952 bool is_entity_container_id;
953 bool is_entity_instance_num;
954 bool is_type;
955
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956 if (tree_node == NULL) {
957 return;
958 }
959
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600960 is_type = tree_node->entity.entity_type == entity.entity_type;
961 is_entity_instance_num = tree_node->entity.entity_instance_num ==
962 entity.entity_instance_num;
963 is_entity_container_id = tree_node->entity.entity_container_id ==
964 entity.entity_container_id;
965
966 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 *node = tree_node;
968 return;
969 }
970
971 find_entity_ref_in_tree(tree_node->first_child, entity, node);
972 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
973}
974
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930975LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930976void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
977 pldm_entity entity, pldm_entity_node **node)
978{
979 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +0930980 if (!tree || !node) {
981 return;
982 }
983
Andrew Jeffery9c766792022-08-10 23:12:49 +0930984 find_entity_ref_in_tree(tree->root, entity, node);
985}
986
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930987LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930988void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
989 uint16_t terminus_handle)
990{
991 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +0930992 if (!repo) {
993 return;
994 }
995
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996 bool removed = false;
997
998 pldm_pdr_record *record = repo->first;
999 pldm_pdr_record *prev = NULL;
1000 while (record != NULL) {
1001 pldm_pdr_record *next = record->next;
1002 if (record->terminus_handle == terminus_handle) {
1003 if (repo->first == record) {
1004 repo->first = next;
1005 } else {
1006 prev->next = next;
1007 }
1008 if (repo->last == record) {
1009 repo->last = prev;
1010 }
1011 if (record->data) {
1012 free(record->data);
1013 }
1014 --repo->record_count;
1015 repo->size -= record->size;
1016 free(record);
1017 removed = true;
1018 } else {
1019 prev = record;
1020 }
1021 record = next;
1022 }
1023
1024 if (removed == true) {
1025 record = repo->first;
1026 uint32_t record_handle = 0;
1027 while (record != NULL) {
1028 record->record_handle = ++record_handle;
1029 if (record->data != NULL) {
1030 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301031 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301032 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301033 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 }
1035 record = record->next;
1036 }
1037 }
1038}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301039
1040LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1042{
1043 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301044 if (!repo) {
1045 return;
1046 }
1047
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048 bool removed = false;
1049
1050 pldm_pdr_record *record = repo->first;
1051 pldm_pdr_record *prev = NULL;
1052 while (record != NULL) {
1053 pldm_pdr_record *next = record->next;
1054 if (record->is_remote == true) {
1055 if (repo->first == record) {
1056 repo->first = next;
1057 } else {
1058 prev->next = next;
1059 }
1060 if (repo->last == record) {
1061 repo->last = prev;
1062 }
1063 if (record->data) {
1064 free(record->data);
1065 }
1066 --repo->record_count;
1067 repo->size -= record->size;
1068 free(record);
1069 removed = true;
1070 } else {
1071 prev = record;
1072 }
1073 record = next;
1074 }
1075
1076 if (removed == true) {
1077 record = repo->first;
1078 uint32_t record_handle = 0;
1079 while (record != NULL) {
1080 record->record_handle = ++record_handle;
1081 if (record->data != NULL) {
1082 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301083 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301084 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301085 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301086 }
1087 record = record->next;
1088 }
1089 }
1090}
1091
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001092LIBPLDM_ABI_TESTING
1093pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1094 uint32_t first, uint32_t last)
1095{
1096 pldm_pdr_record *record = NULL;
1097 pldm_pdr_record *curr;
1098
1099 if (!repo) {
1100 return NULL;
1101 }
1102 for (curr = repo->first; curr; curr = curr->next) {
1103 if (first > curr->record_handle || last < curr->record_handle) {
1104 continue;
1105 }
1106 if (!record || curr->record_handle > record->record_handle) {
1107 record = curr;
1108 }
1109 }
1110
1111 return record;
1112}
1113
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001114static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1115 pldm_entity *entity,
1116 pldm_entity_node **out,
1117 bool is_remote)
1118{
1119 assert(out != NULL && *out == NULL);
1120 if (node == NULL) {
1121 return;
1122 }
1123 bool is_entity_type;
1124 bool is_entity_instance_num;
1125
1126 is_entity_type = node->entity.entity_type == entity->entity_type;
1127 is_entity_instance_num = node->entity.entity_instance_num ==
1128 entity->entity_instance_num;
1129
1130 if (!is_remote ||
1131 node->remote_container_id == entity->entity_container_id) {
1132 if (is_entity_type && is_entity_instance_num) {
1133 entity->entity_container_id =
1134 node->entity.entity_container_id;
1135 *out = node;
1136 return;
1137 }
1138 }
1139 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1140 is_remote);
1141 entity_association_tree_find_if_remote(node->first_child, entity, out,
1142 is_remote);
1143}
1144
1145LIBPLDM_ABI_TESTING
1146pldm_entity_node *
1147pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1148 pldm_entity *entity, bool is_remote)
1149{
1150 if (!tree || !entity) {
1151 return NULL;
1152 }
1153 pldm_entity_node *node = NULL;
1154 entity_association_tree_find_if_remote(tree->root, entity, &node,
1155 is_remote);
1156 return node;
1157}
1158
Andrew Jeffery7f589312023-07-03 12:03:25 +09301159LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301160void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1161 pldm_entity_node **out)
1162{
1163 if (node == NULL) {
1164 return;
1165 }
1166
1167 if (node->entity.entity_type == entity->entity_type &&
1168 node->entity.entity_instance_num == entity->entity_instance_num) {
1169 entity->entity_container_id = node->entity.entity_container_id;
1170 *out = node;
1171 return;
1172 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173 entity_association_tree_find(node->next_sibling, entity, out);
1174 entity_association_tree_find(node->first_child, entity, out);
1175}
1176
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301177LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301178pldm_entity_node *
1179pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1180 pldm_entity *entity)
1181{
1182 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301183 if (!tree || !entity) {
1184 return NULL;
1185 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301186
1187 pldm_entity_node *node = NULL;
1188 entity_association_tree_find(tree->root, entity, &node);
1189 return node;
1190}
1191
1192static void entity_association_tree_copy(pldm_entity_node *org_node,
1193 pldm_entity_node **new_node)
1194{
1195 if (org_node == NULL) {
1196 return;
1197 }
1198 *new_node = malloc(sizeof(pldm_entity_node));
1199 (*new_node)->parent = org_node->parent;
1200 (*new_node)->entity = org_node->entity;
1201 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001202 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203 (*new_node)->first_child = NULL;
1204 (*new_node)->next_sibling = NULL;
1205 entity_association_tree_copy(org_node->first_child,
1206 &((*new_node)->first_child));
1207 entity_association_tree_copy(org_node->next_sibling,
1208 &((*new_node)->next_sibling));
1209}
1210
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301211LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301213 pldm_entity_association_tree *org_tree,
1214 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215{
1216 new_tree->last_used_container_id = org_tree->last_used_container_id;
1217 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1218}
1219
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301220LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301222 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223{
1224 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301225 if (!tree) {
1226 return;
1227 }
1228
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229 entity_association_tree_destroy(tree->root);
1230 tree->last_used_container_id = 0;
1231 tree->root = NULL;
1232}
1233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301234LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1236{
1237 return ((tree->root == NULL) ? true : false);
1238}
1239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301241void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1242 size_t *num_entities,
1243 pldm_entity **entities)
1244{
1245 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301246 if (!pdr || !num_entities || !entities) {
1247 return;
1248 }
1249#define PDR_MIN_SIZE \
1250 (sizeof(struct pldm_pdr_hdr) + \
1251 sizeof(struct pldm_pdr_entity_association))
1252 assert(pdr_len >= PDR_MIN_SIZE);
1253 if (pdr_len < PDR_MIN_SIZE) {
1254 return;
1255 }
1256#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301257
1258 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1259 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1260
1261 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301262 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301263 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301264 start += sizeof(struct pldm_pdr_hdr);
1265 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301266 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301267 *num_entities = entity_association_pdr->num_children + 1;
1268 assert(*num_entities >= 2);
1269 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1270 assert(*entities != NULL);
1271 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301272 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273 end);
1274 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301275 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301276 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301277 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301278 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 pldm_entity *curr_entity = entity_association_pdr->children;
1281 size_t i = 1;
1282 while (i < *num_entities) {
1283 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301284 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301285 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301287 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289 ++curr_entity;
1290 ++i;
1291 }
1292}