blob: cd7857ab3eeb0d06749923564be82a3dc312dbc6 [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);
Andrew Jeffery164ec2d2023-06-28 22:14:57 +093040 uint32_t last_used_hdl = repo->last ? repo->last->record_handle : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +093041 assert(last_used_hdl != UINT32_MAX);
42
43 return last_used_hdl + 1;
44}
45
Andrew Jefferya51ccc22023-06-28 21:57:46 +093046LIBPLDM_ABI_STABLE
47uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
48 uint32_t record_handle, bool is_remote,
49 uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +093050{
51 assert(repo != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093052 assert(data != NULL);
Andrew Jeffery9c766792022-08-10 23:12:49 +093053 assert(size != 0);
54
55 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
56 assert(record != NULL);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093057
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093058 record->record_handle = record_handle == 0 ?
59 get_new_record_handle(repo) :
60 record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +093061 record->size = size;
62 record->is_remote = is_remote;
63 record->terminus_handle = terminus_handle;
64 if (data != NULL) {
65 record->data = malloc(size);
66 assert(record->data != NULL);
67 memcpy(record->data, data, size);
68 /* If record handle is 0, that is an indication for this API to
69 * compute a new handle. For that reason, the computed handle
70 * needs to be populated in the PDR header. For a case where the
71 * caller supplied the record handle, it would exist in the
72 * header already.
73 */
74 if (!record_handle) {
75 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +093076 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +093077 hdr->record_handle = htole32(record->record_handle);
78 }
79 }
80 record->next = NULL;
81
Andrew Jeffery8d231da2023-07-04 11:28:46 +093082 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093083 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +093084 repo->first = record;
85 repo->last = record;
86 } else {
87 repo->last->next = record;
88 repo->last = record;
89 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093090
Andrew Jefferya51ccc22023-06-28 21:57:46 +093091 repo->size += record->size;
92 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +093093
94 return record->record_handle;
95}
96
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +093097LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +093098pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +093099{
100 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930101 if (!repo) {
102 return NULL;
103 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104 repo->record_count = 0;
105 repo->size = 0;
106 repo->first = NULL;
107 repo->last = NULL;
108
109 return repo;
110}
111
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930112LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930113void pldm_pdr_destroy(pldm_pdr *repo)
114{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930115 if (!repo) {
116 return;
117 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118
119 pldm_pdr_record *record = repo->first;
120 while (record != NULL) {
121 pldm_pdr_record *next = record->next;
122 if (record->data) {
123 free(record->data);
124 record->data = NULL;
125 }
126 free(record);
127 record = next;
128 }
129 free(repo);
130}
131
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930132LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930133const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
134 uint32_t record_handle,
135 uint8_t **data, uint32_t *size,
136 uint32_t *next_record_handle)
137{
138 assert(repo != NULL);
139 assert(data != NULL);
140 assert(size != NULL);
141 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930142 if (!repo || !data || !size || !next_record_handle) {
143 return NULL;
144 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145
146 if (!record_handle && (repo->first != NULL)) {
147 record_handle = repo->first->record_handle;
148 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930149
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150 pldm_pdr_record *record = repo->first;
151 while (record != NULL) {
152 if (record->record_handle == record_handle) {
153 *size = record->size;
154 *data = record->data;
155 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930156 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930157 return record;
158 }
159 record = record->next;
160 }
161
162 *size = 0;
163 *next_record_handle = 0;
164 return NULL;
165}
166
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930167LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168const pldm_pdr_record *
169pldm_pdr_get_next_record(const pldm_pdr *repo,
170 const pldm_pdr_record *curr_record, uint8_t **data,
171 uint32_t *size, uint32_t *next_record_handle)
172{
173 assert(repo != NULL);
174 assert(curr_record != NULL);
175 assert(data != NULL);
176 assert(size != NULL);
177 assert(next_record_handle != NULL);
Andrew Jeffery68b51302023-06-28 21:29:42 +0930178 if (!repo || !curr_record || !data || !size || !next_record_handle) {
179 return NULL;
180 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930181
182 if (curr_record == repo->last) {
183 *data = NULL;
184 *size = 0;
185 *next_record_handle = get_next_record_handle(repo, curr_record);
186 return NULL;
187 }
188
189 *next_record_handle = get_next_record_handle(repo, curr_record->next);
190 *data = curr_record->next->data;
191 *size = curr_record->next->size;
192 return curr_record->next;
193}
194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196const pldm_pdr_record *
197pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
198 const pldm_pdr_record *curr_record, uint8_t **data,
199 uint32_t *size)
200{
201 assert(repo != NULL);
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930202 if (!repo) {
203 return NULL;
204 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205
206 pldm_pdr_record *record = repo->first;
207 if (curr_record != NULL) {
208 record = curr_record->next;
209 }
210 while (record != NULL) {
211 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
212 if (hdr->type == pdr_type) {
213 if (data && size) {
214 *size = record->size;
215 *data = record->data;
216 }
217 return record;
218 }
219 record = record->next;
220 }
221
222 if (size) {
223 *size = 0;
224 }
225 return NULL;
226}
227
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930228LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930229uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
230{
231 assert(repo != NULL);
232
233 return repo->record_count;
234}
235
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930236LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930237uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
238{
239 assert(repo != NULL);
240
241 return repo->size;
242}
243
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930244LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930245uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
246 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930247 const pldm_pdr_record *record)
248{
249 assert(repo != NULL);
250 assert(record != NULL);
251
252 return record->record_handle;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
256bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930257{
258 assert(record != NULL);
259
260 return record->is_remote;
261}
262
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930263LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930264uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
265 uint16_t fru_rsi, uint16_t entity_type,
266 uint16_t entity_instance_num,
267 uint16_t container_id,
268 uint32_t bmc_record_handle)
269{
270 uint32_t size = sizeof(struct pldm_pdr_hdr) +
271 sizeof(struct pldm_pdr_fru_record_set);
272 uint8_t data[size];
273
274 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
275 hdr->version = 1;
276 hdr->record_handle = bmc_record_handle;
277 hdr->type = PLDM_PDR_FRU_RECORD_SET;
278 hdr->record_change_num = 0;
279 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
280 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930281 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
282 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930283 fru->terminus_handle = htole16(terminus_handle);
284 fru->fru_rsi = htole16(fru_rsi);
285 fru->entity_type = htole16(entity_type);
286 fru->entity_instance_num = htole16(entity_instance_num);
287 fru->container_id = htole16(container_id);
288
289 return pldm_pdr_add(repo, data, size, bmc_record_handle, false,
290 terminus_handle);
291}
292
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930293LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930294const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930295 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
296 uint16_t *entity_type, uint16_t *entity_instance_num,
297 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298{
299 assert(terminus_handle != NULL);
300 assert(entity_type != NULL);
301 assert(entity_instance_num != NULL);
302 assert(container_id != NULL);
Andrew Jeffery01425e92023-06-30 13:47:40 +0930303 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
304 !container_id) {
305 return NULL;
306 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307
308 uint8_t *data = NULL;
309 uint32_t size = 0;
310 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930311 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312 while (curr_record != NULL) {
313 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930314 (struct pldm_pdr_fru_record_set
315 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316 if (fru->fru_rsi == htole16(fru_rsi)) {
317 *terminus_handle = le16toh(fru->terminus_handle);
318 *entity_type = le16toh(fru->entity_type);
319 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 *container_id = le16toh(fru->container_id);
322 return curr_record;
323 }
324 data = NULL;
325 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930326 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
327 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328 }
329
330 *terminus_handle = 0;
331 *entity_type = 0;
332 *entity_instance_num = 0;
333 *container_id = 0;
334
335 return NULL;
336}
337
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930338LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930339/* NOLINTNEXTLINE(readability-identifier-naming) */
340void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
341 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930343 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930344 uint32_t size = 0;
345 const pldm_pdr_record *record;
346 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930347 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348
349 do {
350 if (record != NULL) {
351 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930352 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930354 (struct pldm_terminus_locator_type_mctp_eid *)
355 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930356 if (pdr->terminus_handle == terminus_handle &&
357 pdr->tid == tid && value->eid == tl_eid) {
358 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 break;
360 }
361 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930362 record = pldm_pdr_find_record_by_type(repo,
363 PLDM_TERMINUS_LOCATOR_PDR,
364 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 } while (record);
366}
367
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500368static bool pldm_record_handle_in_range(uint32_t record_handle,
369 uint32_t first_record_handle,
370 uint32_t last_record_handle)
371{
372 return record_handle >= first_record_handle &&
373 record_handle <= last_record_handle;
374}
375
376LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500377int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500378 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500379 uint8_t child_index, uint32_t range_exclude_start_handle,
380 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500381{
382 pldm_pdr_record *record;
383 if (!repo) {
384 return -EINVAL;
385 }
386
387 for (record = repo->first; record; record = record->next) {
388 bool is_container_entity_instance_number;
389 struct pldm_pdr_entity_association *pdr;
390 bool is_container_entity_type;
391 struct pldm_entity *child;
392 struct pldm_pdr_hdr *hdr;
393 bool in_range;
394
395 // pldm_pdr_add() takes only uint8_t* data as an argument.
396 // The expectation here is the pldm_pdr_hdr is the first field of the record data
397 hdr = (struct pldm_pdr_hdr *)record->data;
398 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
399 continue;
400 }
401 in_range = pldm_record_handle_in_range(
402 record->record_handle, range_exclude_start_handle,
403 range_exclude_end_handle);
404 if (in_range) {
405 continue;
406 }
407
408 // this cast is valid with respect to alignment because
409 // struct pldm_pdr_hdr is declared with __attribute__((packed))
410 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500411 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500412 continue;
413 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500414
415 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500416 is_container_entity_type = pdr->container.entity_type ==
417 entity_type;
418 is_container_entity_instance_number =
419 pdr->container.entity_instance_num == entity_instance;
420 if (is_container_entity_type &&
421 is_container_entity_instance_number) {
422 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500423 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500424 }
425 }
426 return -ENOKEY;
427}
428
Andrew Jeffery9c766792022-08-10 23:12:49 +0930429typedef struct pldm_entity_association_tree {
430 pldm_entity_node *root;
431 uint16_t last_used_container_id;
432} pldm_entity_association_tree;
433
434typedef struct pldm_entity_node {
435 pldm_entity entity;
436 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600437 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930438 pldm_entity_node *first_child;
439 pldm_entity_node *next_sibling;
440 uint8_t association_type;
441} pldm_entity_node;
442
443static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
444{
445 assert(tree != NULL);
446 assert(tree->last_used_container_id != UINT16_MAX);
447
448 return ++tree->last_used_container_id;
449}
450
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930451LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930452pldm_entity pldm_entity_extract(pldm_entity_node *node)
453{
454 assert(node != NULL);
455
456 return node->entity;
457}
458
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600459LIBPLDM_ABI_TESTING
Andrew Jeffery15b88182023-06-30 13:29:17 +0930460uint16_t
461pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600462{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930463 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600464
Andrew Jeffery15b88182023-06-30 13:29:17 +0930465 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600466}
467
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930468LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930469pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930470{
471 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930472 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930473 if (!tree) {
474 return NULL;
475 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476 tree->root = NULL;
477 tree->last_used_container_id = 0;
478
479 return tree;
480}
481
482static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
483 uint16_t entity_type)
484{
485 assert(start != NULL);
486
487 /* Insert after the the last node that matches the input entity type, or
488 * at the end if no such match occurrs
489 */
490 while (start->next_sibling != NULL) {
491 uint16_t this_type = start->entity.entity_type;
492 pldm_entity_node *next = start->next_sibling;
493 if (this_type == entity_type &&
494 (this_type != next->entity.entity_type)) {
495 break;
496 }
497 start = start->next_sibling;
498 }
499
500 return start;
501}
502
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930503LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930504pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930505 pldm_entity_association_tree *tree, pldm_entity *entity,
506 uint16_t entity_instance_number, pldm_entity_node *parent,
507 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500509 return pldm_entity_association_tree_add_entity(tree, entity,
510 entity_instance_number,
511 parent, association_type,
512 false, true, 0xFFFF);
513}
514
515LIBPLDM_ABI_TESTING
516pldm_entity_node *pldm_entity_association_tree_add_entity(
517 pldm_entity_association_tree *tree, pldm_entity *entity,
518 uint16_t entity_instance_number, pldm_entity_node *parent,
519 uint8_t association_type, bool is_remote, bool is_update_container_id,
520 uint16_t container_id)
521{
522 if ((!tree) || (!entity)) {
523 return NULL;
524 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930525
526 if (entity_instance_number != 0xFFFF && parent != NULL) {
527 pldm_entity node;
528 node.entity_type = entity->entity_type;
529 node.entity_instance_num = entity_instance_number;
530 if (pldm_is_current_parent_child(parent, &node)) {
531 return NULL;
532 }
533 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500534 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
535 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
536 return NULL;
537 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500539 if (!node) {
540 return NULL;
541 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930542 node->first_child = NULL;
543 node->next_sibling = NULL;
544 node->parent.entity_type = 0;
545 node->parent.entity_instance_num = 0;
546 node->parent.entity_container_id = 0;
547 node->entity.entity_type = entity->entity_type;
548 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930549 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600551 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930552 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500553 if (parent != NULL) {
554 free(node);
555 return NULL;
556 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 tree->root = node;
558 /* container_id 0 here indicates this is the top-most entry */
559 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600560 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930561 } else if (parent != NULL && parent->first_child == NULL) {
562 parent->first_child = node;
563 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500564
565 if (is_remote) {
566 node->remote_container_id = entity->entity_container_id;
567 }
568 if (is_update_container_id) {
569 if (container_id != 0xFFFF) {
570 node->entity.entity_container_id = container_id;
571 } else {
572 node->entity.entity_container_id =
573 next_container_id(tree);
574 }
575 } else {
576 node->entity.entity_container_id =
577 entity->entity_container_id;
578 }
579
580 if (!is_remote) {
581 node->remote_container_id =
582 node->entity.entity_container_id;
583 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930584 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930585 pldm_entity_node *start = parent == NULL ? tree->root :
586 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930587 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930588 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500589 if (!prev) {
590 free(node);
591 return NULL;
592 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930593 pldm_entity_node *next = prev->next_sibling;
594 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500595 if (prev->entity.entity_instance_num == UINT16_MAX) {
596 free(node);
597 return NULL;
598 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930600 entity_instance_number != 0xFFFF ?
601 entity_instance_number :
602 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 }
604 prev->next_sibling = node;
605 node->parent = prev->parent;
606 node->next_sibling = next;
607 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930608 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600609 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610 }
611 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500612 if (is_update_container_id) {
613 entity->entity_container_id = node->entity.entity_container_id;
614 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 return node;
616}
617
618static void get_num_nodes(pldm_entity_node *node, size_t *num)
619{
620 if (node == NULL) {
621 return;
622 }
623
624 ++(*num);
625 get_num_nodes(node->next_sibling, num);
626 get_num_nodes(node->first_child, num);
627}
628
629static void entity_association_tree_visit(pldm_entity_node *node,
630 pldm_entity *entities, size_t *index)
631{
632 if (node == NULL) {
633 return;
634 }
635
636 pldm_entity *entity = &entities[*index];
637 ++(*index);
638 entity->entity_type = node->entity.entity_type;
639 entity->entity_instance_num = node->entity.entity_instance_num;
640 entity->entity_container_id = node->entity.entity_container_id;
641
642 entity_association_tree_visit(node->next_sibling, entities, index);
643 entity_association_tree_visit(node->first_child, entities, index);
644}
645
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930646LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
648 pldm_entity **entities, size_t *size)
649{
650 assert(tree != NULL);
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930651 if (!tree || !entities || !size) {
652 return;
653 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654
655 *size = 0;
656 if (tree->root == NULL) {
657 return;
658 }
659
660 get_num_nodes(tree->root, size);
661 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930662 if (!entities) {
663 return;
664 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930665 size_t index = 0;
666 entity_association_tree_visit(tree->root, *entities, &index);
667}
668
669static void entity_association_tree_destroy(pldm_entity_node *node)
670{
671 if (node == NULL) {
672 return;
673 }
674
675 entity_association_tree_destroy(node->next_sibling);
676 entity_association_tree_destroy(node->first_child);
677 free(node);
678}
679
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930680LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
682{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930683 if (!tree) {
684 return;
685 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686
687 entity_association_tree_destroy(tree->root);
688 free(tree);
689}
690
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930691LIBPLDM_ABI_STABLE
692bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693{
694 assert(node != NULL);
695
696 return node->first_child != NULL;
697}
698
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930699LIBPLDM_ABI_STABLE
700pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701{
702 assert(node != NULL);
703
704 return node->parent;
705}
706
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930707LIBPLDM_ABI_STABLE
708bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930709{
710 assert(node != NULL);
711
712 if (node->parent.entity_type == 0 &&
713 node->parent.entity_instance_num == 0 &&
714 node->parent.entity_container_id == 0) {
715 return false;
716 }
717
718 return true;
719}
720
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930721LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
723 uint8_t association_type)
724{
725 assert(node != NULL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930726 if (!node) {
727 return 0;
728 }
729
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
731 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930732 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
733 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
734 return 0;
735 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736
737 size_t count = 0;
738 pldm_entity_node *curr = node->first_child;
739 while (curr != NULL) {
740 if (curr->association_type == association_type) {
741 ++count;
742 }
743 curr = curr->next_sibling;
744 }
745
746 assert(count < UINT8_MAX);
747 return count;
748}
749
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930750LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
752{
753 assert(parent != NULL);
754 assert(node != NULL);
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930755 if (!parent || !node) {
756 return false;
757 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758
759 pldm_entity_node *curr = parent->first_child;
760 while (curr != NULL) {
761 if (node->entity_type == curr->entity.entity_type &&
762 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930763 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930764 return true;
765 }
766 curr = curr->next_sibling;
767 }
768
769 return false;
770}
771
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500772static void entity_association_pdr_add_children(
773 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
774 uint8_t contained_count, uint8_t association_type, bool is_remote,
775 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930776{
777 uint8_t pdr[size];
778 uint8_t *start = pdr;
779
780 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
781 hdr->version = 1;
782 hdr->record_handle = 0;
783 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
784 hdr->record_change_num = 0;
785 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
786 start += sizeof(struct pldm_pdr_hdr);
787
788 uint16_t *container_id = (uint16_t *)start;
789 *container_id = htole16(curr->first_child->entity.entity_container_id);
790 start += sizeof(uint16_t);
791 *start = association_type;
792 start += sizeof(uint8_t);
793
794 pldm_entity *entity = (pldm_entity *)start;
795 entity->entity_type = htole16(curr->entity.entity_type);
796 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
797 entity->entity_container_id = htole16(curr->entity.entity_container_id);
798 start += sizeof(pldm_entity);
799
800 *start = contained_count;
801 start += sizeof(uint8_t);
802
803 pldm_entity_node *node = curr->first_child;
804 while (node != NULL) {
805 if (node->association_type == association_type) {
806 pldm_entity *entity = (pldm_entity *)start;
807 entity->entity_type = htole16(node->entity.entity_type);
808 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930809 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930810 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930811 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812 start += sizeof(pldm_entity);
813 }
814 node = node->next_sibling;
815 }
816
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500817 pldm_pdr_add(repo, pdr, size, record_handle, is_remote,
818 terminus_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819}
820
821static void entity_association_pdr_add_entry(pldm_entity_node *curr,
822 pldm_pdr *repo, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500823 uint16_t terminus_handle,
824 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 uint8_t num_logical_children = pldm_entity_get_num_children(
827 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
828 uint8_t num_physical_children = pldm_entity_get_num_children(
829 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830
831 if (num_logical_children) {
832 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930833 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
834 sizeof(uint8_t) + sizeof(pldm_entity) +
835 sizeof(uint8_t) +
836 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930837 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930838 curr, repo, logical_pdr_size, num_logical_children,
839 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500840 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930841 }
842
843 if (num_physical_children) {
844 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930845 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
846 sizeof(uint8_t) + sizeof(pldm_entity) +
847 sizeof(uint8_t) +
848 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery4edb7082023-04-05 19:09:52 +0930849 entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930850 curr, repo, physical_pdr_size, num_physical_children,
851 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500852 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853 }
854}
855
Andrew Jefferyd11bf9f2023-06-30 15:47:41 +0930856LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930857bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
858{
859 if (entities == NULL || num_entities == 0) {
860 return true;
861 }
862 size_t i = 0;
863 while (i < num_entities) {
864 if ((*entities + i)->entity_type == entity.entity_type) {
865 return true;
866 }
867 i++;
868 }
869 return false;
870}
871
872static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
873 pldm_entity **entities,
874 size_t num_entities, bool is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500875 uint16_t terminus_handle,
876 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930877{
878 if (curr == NULL) {
879 return;
880 }
881 bool to_add = true;
882 to_add = is_present(curr->entity, entities, num_entities);
883 if (to_add) {
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500884 entity_association_pdr_add_entry(
885 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886 }
887 entity_association_pdr_add(curr->next_sibling, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500888 num_entities, is_remote, terminus_handle,
889 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890 entity_association_pdr_add(curr->first_child, repo, entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500891 num_entities, is_remote, terminus_handle,
892 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893}
894
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930895LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
897 pldm_pdr *repo, bool is_remote,
898 uint16_t terminus_handle)
899{
900 assert(tree != NULL);
901 assert(repo != NULL);
Andrew Jefferyc7883482023-06-30 15:52:04 +0930902 if (!tree || !repo) {
903 return;
904 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905
906 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500907 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930908}
909
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930910LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930911void pldm_entity_association_pdr_add_from_node(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930912 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
913 size_t num_entities, bool is_remote, uint16_t terminus_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914{
Andrew Jefferycc394522023-07-03 12:49:31 +0930915 int rc = pldm_entity_association_pdr_add_from_node_check(
916 node, repo, entities, num_entities, is_remote, terminus_handle);
917 (void)rc;
918 assert(!rc);
919}
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920
Andrew Jefferycc394522023-07-03 12:49:31 +0930921LIBPLDM_ABI_TESTING
922int pldm_entity_association_pdr_add_from_node_check(
923 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
924 size_t num_entities, bool is_remote, uint16_t terminus_handle)
925{
926 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500927 node, repo, entities, num_entities, is_remote, terminus_handle,
928 0);
929}
930
931LIBPLDM_ABI_TESTING
932int pldm_entity_association_pdr_add_from_node_with_record_handle(
933 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
934 size_t num_entities, bool is_remote, uint16_t terminus_handle,
935 uint32_t record_handle)
936{
937 if (!node || !repo || !entities) {
938 return -EINVAL;
939 }
940
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500942 is_remote, terminus_handle, record_handle);
943
944 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945}
946
Andrew Jefferybfeb65e2023-06-30 16:02:15 +0930947LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
949 pldm_entity_node **node)
950{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600951 bool is_entity_container_id;
952 bool is_entity_instance_num;
953 bool is_type;
954
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955 if (tree_node == NULL) {
956 return;
957 }
958
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600959 is_type = tree_node->entity.entity_type == entity.entity_type;
960 is_entity_instance_num = tree_node->entity.entity_instance_num ==
961 entity.entity_instance_num;
962 is_entity_container_id = tree_node->entity.entity_container_id ==
963 entity.entity_container_id;
964
965 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930966 *node = tree_node;
967 return;
968 }
969
970 find_entity_ref_in_tree(tree_node->first_child, entity, node);
971 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
972}
973
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930974LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
976 pldm_entity entity, pldm_entity_node **node)
977{
978 assert(tree != NULL);
Andrew Jefferyba47e832023-07-03 11:41:03 +0930979 if (!tree || !node) {
980 return;
981 }
982
Andrew Jeffery9c766792022-08-10 23:12:49 +0930983 find_entity_ref_in_tree(tree->root, entity, node);
984}
985
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930986LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930987void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
988 uint16_t terminus_handle)
989{
990 assert(repo != NULL);
Andrew Jeffery438dd492023-07-03 11:51:43 +0930991 if (!repo) {
992 return;
993 }
994
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995 bool removed = false;
996
997 pldm_pdr_record *record = repo->first;
998 pldm_pdr_record *prev = NULL;
999 while (record != NULL) {
1000 pldm_pdr_record *next = record->next;
1001 if (record->terminus_handle == terminus_handle) {
1002 if (repo->first == record) {
1003 repo->first = next;
1004 } else {
1005 prev->next = next;
1006 }
1007 if (repo->last == record) {
1008 repo->last = prev;
1009 }
1010 if (record->data) {
1011 free(record->data);
1012 }
1013 --repo->record_count;
1014 repo->size -= record->size;
1015 free(record);
1016 removed = true;
1017 } else {
1018 prev = record;
1019 }
1020 record = next;
1021 }
1022
1023 if (removed == true) {
1024 record = repo->first;
1025 uint32_t record_handle = 0;
1026 while (record != NULL) {
1027 record->record_handle = ++record_handle;
1028 if (record->data != NULL) {
1029 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301030 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301031 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301032 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301033 }
1034 record = record->next;
1035 }
1036 }
1037}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301038
1039LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1041{
1042 assert(repo != NULL);
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301043 if (!repo) {
1044 return;
1045 }
1046
Andrew Jeffery9c766792022-08-10 23:12:49 +09301047 bool removed = false;
1048
1049 pldm_pdr_record *record = repo->first;
1050 pldm_pdr_record *prev = NULL;
1051 while (record != NULL) {
1052 pldm_pdr_record *next = record->next;
1053 if (record->is_remote == true) {
1054 if (repo->first == record) {
1055 repo->first = next;
1056 } else {
1057 prev->next = next;
1058 }
1059 if (repo->last == record) {
1060 repo->last = prev;
1061 }
1062 if (record->data) {
1063 free(record->data);
1064 }
1065 --repo->record_count;
1066 repo->size -= record->size;
1067 free(record);
1068 removed = true;
1069 } else {
1070 prev = record;
1071 }
1072 record = next;
1073 }
1074
1075 if (removed == true) {
1076 record = repo->first;
1077 uint32_t record_handle = 0;
1078 while (record != NULL) {
1079 record->record_handle = ++record_handle;
1080 if (record->data != NULL) {
1081 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301082 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301083 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301084 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301085 }
1086 record = record->next;
1087 }
1088 }
1089}
1090
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001091LIBPLDM_ABI_TESTING
1092pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1093 uint32_t first, uint32_t last)
1094{
1095 pldm_pdr_record *record = NULL;
1096 pldm_pdr_record *curr;
1097
1098 if (!repo) {
1099 return NULL;
1100 }
1101 for (curr = repo->first; curr; curr = curr->next) {
1102 if (first > curr->record_handle || last < curr->record_handle) {
1103 continue;
1104 }
1105 if (!record || curr->record_handle > record->record_handle) {
1106 record = curr;
1107 }
1108 }
1109
1110 return record;
1111}
1112
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001113static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1114 pldm_entity *entity,
1115 pldm_entity_node **out,
1116 bool is_remote)
1117{
1118 assert(out != NULL && *out == NULL);
1119 if (node == NULL) {
1120 return;
1121 }
1122 bool is_entity_type;
1123 bool is_entity_instance_num;
1124
1125 is_entity_type = node->entity.entity_type == entity->entity_type;
1126 is_entity_instance_num = node->entity.entity_instance_num ==
1127 entity->entity_instance_num;
1128
1129 if (!is_remote ||
1130 node->remote_container_id == entity->entity_container_id) {
1131 if (is_entity_type && is_entity_instance_num) {
1132 entity->entity_container_id =
1133 node->entity.entity_container_id;
1134 *out = node;
1135 return;
1136 }
1137 }
1138 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1139 is_remote);
1140 entity_association_tree_find_if_remote(node->first_child, entity, out,
1141 is_remote);
1142}
1143
1144LIBPLDM_ABI_TESTING
1145pldm_entity_node *
1146pldm_entity_association_tree_find_if_remote(pldm_entity_association_tree *tree,
1147 pldm_entity *entity, bool is_remote)
1148{
1149 if (!tree || !entity) {
1150 return NULL;
1151 }
1152 pldm_entity_node *node = NULL;
1153 entity_association_tree_find_if_remote(tree->root, entity, &node,
1154 is_remote);
1155 return node;
1156}
1157
Andrew Jeffery7f589312023-07-03 12:03:25 +09301158LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
1160 pldm_entity_node **out)
1161{
1162 if (node == NULL) {
1163 return;
1164 }
1165
1166 if (node->entity.entity_type == entity->entity_type &&
1167 node->entity.entity_instance_num == entity->entity_instance_num) {
1168 entity->entity_container_id = node->entity.entity_container_id;
1169 *out = node;
1170 return;
1171 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301172 entity_association_tree_find(node->next_sibling, entity, out);
1173 entity_association_tree_find(node->first_child, entity, out);
1174}
1175
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301176LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301177pldm_entity_node *
1178pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1179 pldm_entity *entity)
1180{
1181 assert(tree != NULL);
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301182 if (!tree || !entity) {
1183 return NULL;
1184 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301185
1186 pldm_entity_node *node = NULL;
1187 entity_association_tree_find(tree->root, entity, &node);
1188 return node;
1189}
1190
1191static void entity_association_tree_copy(pldm_entity_node *org_node,
1192 pldm_entity_node **new_node)
1193{
1194 if (org_node == NULL) {
1195 return;
1196 }
1197 *new_node = malloc(sizeof(pldm_entity_node));
1198 (*new_node)->parent = org_node->parent;
1199 (*new_node)->entity = org_node->entity;
1200 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001201 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301202 (*new_node)->first_child = NULL;
1203 (*new_node)->next_sibling = NULL;
1204 entity_association_tree_copy(org_node->first_child,
1205 &((*new_node)->first_child));
1206 entity_association_tree_copy(org_node->next_sibling,
1207 &((*new_node)->next_sibling));
1208}
1209
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301210LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301211void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301212 pldm_entity_association_tree *org_tree,
1213 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214{
1215 new_tree->last_used_container_id = org_tree->last_used_container_id;
1216 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1217}
1218
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301219LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301221 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222{
1223 assert(tree != NULL);
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301224 if (!tree) {
1225 return;
1226 }
1227
Andrew Jeffery9c766792022-08-10 23:12:49 +09301228 entity_association_tree_destroy(tree->root);
1229 tree->last_used_container_id = 0;
1230 tree->root = NULL;
1231}
1232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301233LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301234bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1235{
1236 return ((tree->root == NULL) ? true : false);
1237}
1238
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301239LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1241 size_t *num_entities,
1242 pldm_entity **entities)
1243{
1244 assert(pdr != NULL);
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301245 if (!pdr || !num_entities || !entities) {
1246 return;
1247 }
1248#define PDR_MIN_SIZE \
1249 (sizeof(struct pldm_pdr_hdr) + \
1250 sizeof(struct pldm_pdr_entity_association))
1251 assert(pdr_len >= PDR_MIN_SIZE);
1252 if (pdr_len < PDR_MIN_SIZE) {
1253 return;
1254 }
1255#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301256
1257 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
1258 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
1259
1260 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301261 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301262 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301263 start += sizeof(struct pldm_pdr_hdr);
1264 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301265 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301266 *num_entities = entity_association_pdr->num_children + 1;
1267 assert(*num_entities >= 2);
1268 *entities = malloc(sizeof(pldm_entity) * *num_entities);
1269 assert(*entities != NULL);
1270 assert(start + sizeof(struct pldm_pdr_entity_association) +
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301271 sizeof(pldm_entity) * (*num_entities - 2) ==
Andrew Jeffery9c766792022-08-10 23:12:49 +09301272 end);
1273 (*entities)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301274 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301275 (*entities)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301276 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301277 (*entities)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301278 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301279 pldm_entity *curr_entity = entity_association_pdr->children;
1280 size_t i = 1;
1281 while (i < *num_entities) {
1282 (*entities + i)->entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 le16toh(curr_entity->entity_type);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284 (*entities + i)->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301285 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301286 (*entities + i)->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301287 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301288 ++curr_entity;
1289 ++i;
1290 }
1291}