blob: ee699c74b820d5048c59fdd6f0d605a1e2a776d6 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery9c766792022-08-10 23:12:49 +09302#include "pdr.h"
3#include "platform.h"
4#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05305#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09306#include <stdlib.h>
7#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06008#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09309
10typedef struct pldm_pdr_record {
11 uint32_t record_handle;
12 uint32_t size;
13 uint8_t *data;
14 struct pldm_pdr_record *next;
15 bool is_remote;
16 uint16_t terminus_handle;
17} pldm_pdr_record;
18
19typedef struct pldm_pdr {
20 uint32_t record_count;
21 uint32_t size;
22 pldm_pdr_record *first;
23 pldm_pdr_record *last;
24} pldm_pdr;
25
26static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
27 const pldm_pdr_record *record)
28{
29 assert(repo != NULL);
30 assert(record != NULL);
31
32 if (record == repo->last) {
33 return 0;
34 }
35 return record->next->record_handle;
36}
37
Andrew Jefferyca248ce2023-07-07 10:38:30 +093038LIBPLDM_ABI_STABLE
Andrew Jeffery572a3952023-07-03 13:19:28 +093039int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
40 bool is_remote, uint16_t terminus_handle,
41 uint32_t *record_handle)
42{
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093043 uint32_t curr;
44
Andrew Jeffery3b93d092023-07-17 13:01:50 +093045 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093046 return -EINVAL;
47 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093048
Andrew Jeffery3b93d092023-07-17 13:01:50 +093049 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093050 curr = *record_handle;
51 } else if (repo->last) {
52 curr = repo->last->record_handle;
53 if (curr == UINT32_MAX) {
54 return -EOVERFLOW;
55 }
56 curr += 1;
57 } else {
58 curr = 1;
59 }
60
Andrew Jeffery9c766792022-08-10 23:12:49 +093061 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093062 if (!record) {
63 return -ENOMEM;
64 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093065
Andrew Jeffery572a3952023-07-03 13:19:28 +093066 if (data) {
67 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093068 if (!record->data) {
69 free(record);
70 return -ENOMEM;
71 }
72 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093073 }
74
Andrew Jeffery9c766792022-08-10 23:12:49 +093075 record->size = size;
76 record->is_remote = is_remote;
77 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093078 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093079
Andrew Jeffery3b93d092023-07-17 13:01:50 +093080 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093081 /* If record handle is 0, that is an indication for this API to
82 * compute a new handle. For that reason, the computed handle
83 * needs to be populated in the PDR header. For a case where the
84 * caller supplied the record handle, it would exist in the
85 * header already.
86 */
87 struct pldm_pdr_hdr *hdr = (void *)record->data;
88 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093089 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093090
Andrew Jeffery9c766792022-08-10 23:12:49 +093091 record->next = NULL;
92
Andrew Jeffery8d231da2023-07-04 11:28:46 +093093 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093094 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +093095 repo->first = record;
96 repo->last = record;
97 } else {
98 repo->last->next = record;
99 repo->last = record;
100 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930101
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930102 repo->size += record->size;
103 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930104
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930105 if (record_handle) {
106 *record_handle = record->record_handle;
107 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930108
109 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930110}
111
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930112LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930113pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930114{
115 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930116 if (!repo) {
117 return NULL;
118 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119 repo->record_count = 0;
120 repo->size = 0;
121 repo->first = NULL;
122 repo->last = NULL;
123
124 return repo;
125}
126
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930127LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128void pldm_pdr_destroy(pldm_pdr *repo)
129{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930130 if (!repo) {
131 return;
132 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930133
134 pldm_pdr_record *record = repo->first;
135 while (record != NULL) {
136 pldm_pdr_record *next = record->next;
137 if (record->data) {
138 free(record->data);
139 record->data = NULL;
140 }
141 free(record);
142 record = next;
143 }
144 free(repo);
145}
146
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930147LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930148const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
149 uint32_t record_handle,
150 uint8_t **data, uint32_t *size,
151 uint32_t *next_record_handle)
152{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930153 if (!repo || !data || !size || !next_record_handle) {
154 return NULL;
155 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930156
157 if (!record_handle && (repo->first != NULL)) {
158 record_handle = repo->first->record_handle;
159 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930160
Andrew Jeffery9c766792022-08-10 23:12:49 +0930161 pldm_pdr_record *record = repo->first;
162 while (record != NULL) {
163 if (record->record_handle == record_handle) {
164 *size = record->size;
165 *data = record->data;
166 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930167 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168 return record;
169 }
170 record = record->next;
171 }
172
173 *size = 0;
174 *next_record_handle = 0;
175 return NULL;
176}
177
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930178LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179const pldm_pdr_record *
180pldm_pdr_get_next_record(const pldm_pdr *repo,
181 const pldm_pdr_record *curr_record, uint8_t **data,
182 uint32_t *size, uint32_t *next_record_handle)
183{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930184 if (!repo || !curr_record || !data || !size || !next_record_handle) {
185 return NULL;
186 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187
188 if (curr_record == repo->last) {
189 *data = NULL;
190 *size = 0;
191 *next_record_handle = get_next_record_handle(repo, curr_record);
192 return NULL;
193 }
194
195 *next_record_handle = get_next_record_handle(repo, curr_record->next);
196 *data = curr_record->next->data;
197 *size = curr_record->next->size;
198 return curr_record->next;
199}
200
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930201LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930202const pldm_pdr_record *
203pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
204 const pldm_pdr_record *curr_record, uint8_t **data,
205 uint32_t *size)
206{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930207 if (!repo) {
208 return NULL;
209 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930210
211 pldm_pdr_record *record = repo->first;
212 if (curr_record != NULL) {
213 record = curr_record->next;
214 }
215 while (record != NULL) {
216 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
217 if (hdr->type == pdr_type) {
218 if (data && size) {
219 *size = record->size;
220 *data = record->data;
221 }
222 return record;
223 }
224 record = record->next;
225 }
226
227 if (size) {
228 *size = 0;
229 }
230 return NULL;
231}
232
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930233LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930234uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
235{
236 assert(repo != NULL);
237
238 return repo->record_count;
239}
240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930242uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
243{
244 assert(repo != NULL);
245
246 return repo->size;
247}
248
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930249LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930250uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
251 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252 const pldm_pdr_record *record)
253{
254 assert(repo != NULL);
255 assert(record != NULL);
256
257 return record->record_handle;
258}
259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930260LIBPLDM_ABI_STABLE
261bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930262{
263 assert(record != NULL);
264
265 return record->is_remote;
266}
267
Andrew Jefferya2c69112023-07-07 10:41:38 +0930268LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930269int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
270 uint16_t fru_rsi, uint16_t entity_type,
271 uint16_t entity_instance_num,
272 uint16_t container_id,
273 uint32_t *bmc_record_handle)
274{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930275 if (!repo || !bmc_record_handle) {
276 return -EINVAL;
277 }
278
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279 uint32_t size = sizeof(struct pldm_pdr_hdr) +
280 sizeof(struct pldm_pdr_fru_record_set);
281 uint8_t data[size];
282
283 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
284 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930285 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930286 hdr->type = PLDM_PDR_FRU_RECORD_SET;
287 hdr->record_change_num = 0;
288 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
289 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930290 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
291 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930292 fru->terminus_handle = htole16(terminus_handle);
293 fru->fru_rsi = htole16(fru_rsi);
294 fru->entity_type = htole16(entity_type);
295 fru->entity_instance_num = htole16(entity_instance_num);
296 fru->container_id = htole16(container_id);
297
Andrew Jefferyc821a702023-07-03 13:32:11 +0930298 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
299 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930300}
301
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930302LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930304 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
305 uint16_t *entity_type, uint16_t *entity_instance_num,
306 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930308 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
309 !container_id) {
310 return NULL;
311 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312
313 uint8_t *data = NULL;
314 uint32_t size = 0;
315 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930316 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 while (curr_record != NULL) {
318 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930319 (struct pldm_pdr_fru_record_set
320 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930321 if (fru->fru_rsi == htole16(fru_rsi)) {
322 *terminus_handle = le16toh(fru->terminus_handle);
323 *entity_type = le16toh(fru->entity_type);
324 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930325 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326 *container_id = le16toh(fru->container_id);
327 return curr_record;
328 }
329 data = NULL;
330 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930331 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
332 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333 }
334
335 *terminus_handle = 0;
336 *entity_type = 0;
337 *entity_instance_num = 0;
338 *container_id = 0;
339
340 return NULL;
341}
342
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930343LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930344/* NOLINTNEXTLINE(readability-identifier-naming) */
345void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
346 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930348 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349 uint32_t size = 0;
350 const pldm_pdr_record *record;
351 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930352 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930353
354 do {
355 if (record != NULL) {
356 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930357 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930358 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930359 (struct pldm_terminus_locator_type_mctp_eid *)
360 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930361 if (pdr->terminus_handle == terminus_handle &&
362 pdr->tid == tid && value->eid == tl_eid) {
363 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930364 break;
365 }
366 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930367 record = pldm_pdr_find_record_by_type(repo,
368 PLDM_TERMINUS_LOCATOR_PDR,
369 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370 } while (record);
371}
372
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500373static bool pldm_record_handle_in_range(uint32_t record_handle,
374 uint32_t first_record_handle,
375 uint32_t last_record_handle)
376{
377 return record_handle >= first_record_handle &&
378 record_handle <= last_record_handle;
379}
380
381LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500382int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500383 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500384 uint8_t child_index, uint32_t range_exclude_start_handle,
385 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500386{
387 pldm_pdr_record *record;
388 if (!repo) {
389 return -EINVAL;
390 }
391
392 for (record = repo->first; record; record = record->next) {
393 bool is_container_entity_instance_number;
394 struct pldm_pdr_entity_association *pdr;
395 bool is_container_entity_type;
396 struct pldm_entity *child;
397 struct pldm_pdr_hdr *hdr;
398 bool in_range;
399
400 // pldm_pdr_add() takes only uint8_t* data as an argument.
401 // The expectation here is the pldm_pdr_hdr is the first field of the record data
402 hdr = (struct pldm_pdr_hdr *)record->data;
403 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
404 continue;
405 }
406 in_range = pldm_record_handle_in_range(
407 record->record_handle, range_exclude_start_handle,
408 range_exclude_end_handle);
409 if (in_range) {
410 continue;
411 }
412
413 // this cast is valid with respect to alignment because
414 // struct pldm_pdr_hdr is declared with __attribute__((packed))
415 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500416 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500417 continue;
418 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500419
420 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500421 is_container_entity_type = pdr->container.entity_type ==
422 entity_type;
423 is_container_entity_instance_number =
424 pdr->container.entity_instance_num == entity_instance;
425 if (is_container_entity_type &&
426 is_container_entity_instance_number) {
427 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500428 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500429 }
430 }
431 return -ENOKEY;
432}
433
Andrew Jeffery9c766792022-08-10 23:12:49 +0930434typedef struct pldm_entity_association_tree {
435 pldm_entity_node *root;
436 uint16_t last_used_container_id;
437} pldm_entity_association_tree;
438
439typedef struct pldm_entity_node {
440 pldm_entity entity;
441 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600442 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930443 pldm_entity_node *first_child;
444 pldm_entity_node *next_sibling;
445 uint8_t association_type;
446} pldm_entity_node;
447
448static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
449{
450 assert(tree != NULL);
451 assert(tree->last_used_container_id != UINT16_MAX);
452
453 return ++tree->last_used_container_id;
454}
455
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930456LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930457pldm_entity pldm_entity_extract(pldm_entity_node *node)
458{
459 assert(node != NULL);
460
461 return node->entity;
462}
463
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500464LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930465uint16_t
466pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600467{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930468 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600469
Andrew Jeffery15b88182023-06-30 13:29:17 +0930470 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600471}
472
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930473LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930474pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930475{
476 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930477 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930478 if (!tree) {
479 return NULL;
480 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930481 tree->root = NULL;
482 tree->last_used_container_id = 0;
483
484 return tree;
485}
486
487static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
488 uint16_t entity_type)
489{
490 assert(start != NULL);
491
492 /* Insert after the the last node that matches the input entity type, or
493 * at the end if no such match occurrs
494 */
495 while (start->next_sibling != NULL) {
496 uint16_t this_type = start->entity.entity_type;
497 pldm_entity_node *next = start->next_sibling;
498 if (this_type == entity_type &&
499 (this_type != next->entity.entity_type)) {
500 break;
501 }
502 start = start->next_sibling;
503 }
504
505 return start;
506}
507
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930508LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930509pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930510 pldm_entity_association_tree *tree, pldm_entity *entity,
511 uint16_t entity_instance_number, pldm_entity_node *parent,
512 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930513{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500514 return pldm_entity_association_tree_add_entity(tree, entity,
515 entity_instance_number,
516 parent, association_type,
517 false, true, 0xFFFF);
518}
519
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500520LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500521pldm_entity_node *pldm_entity_association_tree_add_entity(
522 pldm_entity_association_tree *tree, pldm_entity *entity,
523 uint16_t entity_instance_number, pldm_entity_node *parent,
524 uint8_t association_type, bool is_remote, bool is_update_container_id,
525 uint16_t container_id)
526{
527 if ((!tree) || (!entity)) {
528 return NULL;
529 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930530
531 if (entity_instance_number != 0xFFFF && parent != NULL) {
532 pldm_entity node;
533 node.entity_type = entity->entity_type;
534 node.entity_instance_num = entity_instance_number;
535 if (pldm_is_current_parent_child(parent, &node)) {
536 return NULL;
537 }
538 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500539 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
540 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
541 return NULL;
542 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930543 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500544 if (!node) {
545 return NULL;
546 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930547 node->first_child = NULL;
548 node->next_sibling = NULL;
549 node->parent.entity_type = 0;
550 node->parent.entity_instance_num = 0;
551 node->parent.entity_container_id = 0;
552 node->entity.entity_type = entity->entity_type;
553 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930554 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930555 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600556 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930557 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500558 if (parent != NULL) {
559 free(node);
560 return NULL;
561 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 tree->root = node;
563 /* container_id 0 here indicates this is the top-most entry */
564 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600565 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930566 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930567 /* Ensure next_container_id() will yield a valid ID */
568 if (tree->last_used_container_id == UINT16_MAX) {
569 free(node);
570 return NULL;
571 }
572
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 parent->first_child = node;
574 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500575
576 if (is_remote) {
577 node->remote_container_id = entity->entity_container_id;
578 }
579 if (is_update_container_id) {
580 if (container_id != 0xFFFF) {
581 node->entity.entity_container_id = container_id;
582 } else {
583 node->entity.entity_container_id =
584 next_container_id(tree);
585 }
586 } else {
587 node->entity.entity_container_id =
588 entity->entity_container_id;
589 }
590
591 if (!is_remote) {
592 node->remote_container_id =
593 node->entity.entity_container_id;
594 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930595 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930596 pldm_entity_node *start = parent == NULL ? tree->root :
597 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930598 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930599 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500600 if (!prev) {
601 free(node);
602 return NULL;
603 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930604 pldm_entity_node *next = prev->next_sibling;
605 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500606 if (prev->entity.entity_instance_num == UINT16_MAX) {
607 free(node);
608 return NULL;
609 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930610 node->entity.entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930611 entity_instance_number != 0xFFFF ?
612 entity_instance_number :
613 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614 }
615 prev->next_sibling = node;
616 node->parent = prev->parent;
617 node->next_sibling = next;
618 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930619 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600620 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930621 }
622 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500623 if (is_update_container_id) {
624 entity->entity_container_id = node->entity.entity_container_id;
625 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626 return node;
627}
628
629static void get_num_nodes(pldm_entity_node *node, size_t *num)
630{
631 if (node == NULL) {
632 return;
633 }
634
635 ++(*num);
636 get_num_nodes(node->next_sibling, num);
637 get_num_nodes(node->first_child, num);
638}
639
640static void entity_association_tree_visit(pldm_entity_node *node,
641 pldm_entity *entities, size_t *index)
642{
643 if (node == NULL) {
644 return;
645 }
646
647 pldm_entity *entity = &entities[*index];
648 ++(*index);
649 entity->entity_type = node->entity.entity_type;
650 entity->entity_instance_num = node->entity.entity_instance_num;
651 entity->entity_container_id = node->entity.entity_container_id;
652
653 entity_association_tree_visit(node->next_sibling, entities, index);
654 entity_association_tree_visit(node->first_child, entities, index);
655}
656
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930657LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930658void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
659 pldm_entity **entities, size_t *size)
660{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930661 if (!tree || !entities || !size) {
662 return;
663 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930664
665 *size = 0;
666 if (tree->root == NULL) {
667 return;
668 }
669
670 get_num_nodes(tree->root, size);
671 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930672 if (!entities) {
673 return;
674 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675 size_t index = 0;
676 entity_association_tree_visit(tree->root, *entities, &index);
677}
678
679static void entity_association_tree_destroy(pldm_entity_node *node)
680{
681 if (node == NULL) {
682 return;
683 }
684
685 entity_association_tree_destroy(node->next_sibling);
686 entity_association_tree_destroy(node->first_child);
687 free(node);
688}
689
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930690LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
692{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930693 if (!tree) {
694 return;
695 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696
697 entity_association_tree_destroy(tree->root);
698 free(tree);
699}
700
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930701LIBPLDM_ABI_STABLE
702bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930703{
704 assert(node != NULL);
705
706 return node->first_child != NULL;
707}
708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930709LIBPLDM_ABI_STABLE
710pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930711{
712 assert(node != NULL);
713
714 return node->parent;
715}
716
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930717LIBPLDM_ABI_STABLE
718bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719{
720 assert(node != NULL);
721
722 if (node->parent.entity_type == 0 &&
723 node->parent.entity_instance_num == 0 &&
724 node->parent.entity_container_id == 0) {
725 return false;
726 }
727
728 return true;
729}
730
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930731LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930732uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
733 uint8_t association_type)
734{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930735 if (!node) {
736 return 0;
737 }
738
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930739 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
740 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
741 return 0;
742 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743
744 size_t count = 0;
745 pldm_entity_node *curr = node->first_child;
746 while (curr != NULL) {
747 if (curr->association_type == association_type) {
748 ++count;
749 }
750 curr = curr->next_sibling;
751 }
752
753 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930754 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755}
756
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930757LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930758bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
759{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930760 if (!parent || !node) {
761 return false;
762 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930763
764 pldm_entity_node *curr = parent->first_child;
765 while (curr != NULL) {
766 if (node->entity_type == curr->entity.entity_type &&
767 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930768 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930769 return true;
770 }
771 curr = curr->next_sibling;
772 }
773
774 return false;
775}
776
Andrew Jeffery65945992023-07-17 15:04:21 +0930777static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500778 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
779 uint8_t contained_count, uint8_t association_type, bool is_remote,
780 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781{
782 uint8_t pdr[size];
783 uint8_t *start = pdr;
784
785 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
786 hdr->version = 1;
787 hdr->record_handle = 0;
788 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
789 hdr->record_change_num = 0;
790 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
791 start += sizeof(struct pldm_pdr_hdr);
792
793 uint16_t *container_id = (uint16_t *)start;
794 *container_id = htole16(curr->first_child->entity.entity_container_id);
795 start += sizeof(uint16_t);
796 *start = association_type;
797 start += sizeof(uint8_t);
798
799 pldm_entity *entity = (pldm_entity *)start;
800 entity->entity_type = htole16(curr->entity.entity_type);
801 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
802 entity->entity_container_id = htole16(curr->entity.entity_container_id);
803 start += sizeof(pldm_entity);
804
805 *start = contained_count;
806 start += sizeof(uint8_t);
807
808 pldm_entity_node *node = curr->first_child;
809 while (node != NULL) {
810 if (node->association_type == association_type) {
811 pldm_entity *entity = (pldm_entity *)start;
812 entity->entity_type = htole16(node->entity.entity_type);
813 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930814 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930815 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930816 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817 start += sizeof(pldm_entity);
818 }
819 node = node->next_sibling;
820 }
821
Andrew Jeffery65945992023-07-17 15:04:21 +0930822 return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
823 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824}
825
Andrew Jeffery65945992023-07-17 15:04:21 +0930826static int entity_association_pdr_add_entry(pldm_entity_node *curr,
827 pldm_pdr *repo, bool is_remote,
828 uint16_t terminus_handle,
829 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930831 uint8_t num_logical_children = pldm_entity_get_num_children(
832 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
833 uint8_t num_physical_children = pldm_entity_get_num_children(
834 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930835 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836
837 if (num_logical_children) {
838 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930839 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
840 sizeof(uint8_t) + sizeof(pldm_entity) +
841 sizeof(uint8_t) +
842 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930843 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930844 curr, repo, logical_pdr_size, num_logical_children,
845 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500846 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930847 if (rc < 0) {
848 return rc;
849 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930850 }
851
852 if (num_physical_children) {
853 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930854 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
855 sizeof(uint8_t) + sizeof(pldm_entity) +
856 sizeof(uint8_t) +
857 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930858 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930859 curr, repo, physical_pdr_size, num_physical_children,
860 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500861 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930862 if (rc < 0) {
863 return rc;
864 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930866
867 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930868}
869
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930870static bool is_present(pldm_entity entity, pldm_entity **entities,
871 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872{
873 if (entities == NULL || num_entities == 0) {
874 return true;
875 }
876 size_t i = 0;
877 while (i < num_entities) {
878 if ((*entities + i)->entity_type == entity.entity_type) {
879 return true;
880 }
881 i++;
882 }
883 return false;
884}
885
Andrew Jeffery65945992023-07-17 15:04:21 +0930886static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
887 pldm_entity **entities,
888 size_t num_entities, bool is_remote,
889 uint16_t terminus_handle,
890 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891{
Andrew Jeffery65945992023-07-17 15:04:21 +0930892 int rc;
893
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930895 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930896 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930897
898 if (is_present(curr->entity, entities, num_entities)) {
899 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500900 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930901 if (rc) {
902 return rc;
903 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930905
906 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
907 num_entities, is_remote,
908 terminus_handle, record_handle);
909 if (rc) {
910 return rc;
911 }
912
913 return entity_association_pdr_add(curr->first_child, repo, entities,
914 num_entities, is_remote,
915 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916}
917
Andrew Jeffery096685b2023-07-17 17:36:14 +0930918LIBPLDM_ABI_STABLE
Andrew Jeffery65945992023-07-17 15:04:21 +0930919int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
920 pldm_pdr *repo, bool is_remote,
921 uint16_t terminus_handle)
922{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930923 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930924 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930925 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926
Andrew Jeffery65945992023-07-17 15:04:21 +0930927 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
928 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930929}
930
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930931LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930932int pldm_entity_association_pdr_add_from_node_check(
933 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
934 size_t num_entities, bool is_remote, uint16_t terminus_handle)
935{
936 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500937 node, repo, entities, num_entities, is_remote, terminus_handle,
938 0);
939}
940
941LIBPLDM_ABI_TESTING
942int pldm_entity_association_pdr_add_from_node_with_record_handle(
943 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
944 size_t num_entities, bool is_remote, uint16_t terminus_handle,
945 uint32_t record_handle)
946{
947 if (!node || !repo || !entities) {
948 return -EINVAL;
949 }
950
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500952 is_remote, terminus_handle, record_handle);
953
954 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930955}
956
Andrew Jeffery643c4432023-07-17 15:36:03 +0930957static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
958 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930959{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600960 bool is_entity_container_id;
961 bool is_entity_instance_num;
962 bool is_type;
963
Andrew Jeffery9c766792022-08-10 23:12:49 +0930964 if (tree_node == NULL) {
965 return;
966 }
967
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600968 is_type = tree_node->entity.entity_type == entity.entity_type;
969 is_entity_instance_num = tree_node->entity.entity_instance_num ==
970 entity.entity_instance_num;
971 is_entity_container_id = tree_node->entity.entity_container_id ==
972 entity.entity_container_id;
973
974 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975 *node = tree_node;
976 return;
977 }
978
979 find_entity_ref_in_tree(tree_node->first_child, entity, node);
980 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
981}
982
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930983LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930984void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
985 pldm_entity entity, pldm_entity_node **node)
986{
Andrew Jefferyba47e832023-07-03 11:41:03 +0930987 if (!tree || !node) {
988 return;
989 }
990
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991 find_entity_ref_in_tree(tree->root, entity, node);
992}
993
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930994LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
996 uint16_t terminus_handle)
997{
Andrew Jeffery438dd492023-07-03 11:51:43 +0930998 if (!repo) {
999 return;
1000 }
1001
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002 bool removed = false;
1003
1004 pldm_pdr_record *record = repo->first;
1005 pldm_pdr_record *prev = NULL;
1006 while (record != NULL) {
1007 pldm_pdr_record *next = record->next;
1008 if (record->terminus_handle == terminus_handle) {
1009 if (repo->first == record) {
1010 repo->first = next;
1011 } else {
1012 prev->next = next;
1013 }
1014 if (repo->last == record) {
1015 repo->last = prev;
1016 }
1017 if (record->data) {
1018 free(record->data);
1019 }
1020 --repo->record_count;
1021 repo->size -= record->size;
1022 free(record);
1023 removed = true;
1024 } else {
1025 prev = record;
1026 }
1027 record = next;
1028 }
1029
1030 if (removed == true) {
1031 record = repo->first;
1032 uint32_t record_handle = 0;
1033 while (record != NULL) {
1034 record->record_handle = ++record_handle;
1035 if (record->data != NULL) {
1036 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301037 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301038 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301039 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301040 }
1041 record = record->next;
1042 }
1043 }
1044}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301045
1046LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301047void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1048{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301049 if (!repo) {
1050 return;
1051 }
1052
Andrew Jeffery9c766792022-08-10 23:12:49 +09301053 bool removed = false;
1054
1055 pldm_pdr_record *record = repo->first;
1056 pldm_pdr_record *prev = NULL;
1057 while (record != NULL) {
1058 pldm_pdr_record *next = record->next;
1059 if (record->is_remote == true) {
1060 if (repo->first == record) {
1061 repo->first = next;
1062 } else {
1063 prev->next = next;
1064 }
1065 if (repo->last == record) {
1066 repo->last = prev;
1067 }
1068 if (record->data) {
1069 free(record->data);
1070 }
1071 --repo->record_count;
1072 repo->size -= record->size;
1073 free(record);
1074 removed = true;
1075 } else {
1076 prev = record;
1077 }
1078 record = next;
1079 }
1080
1081 if (removed == true) {
1082 record = repo->first;
1083 uint32_t record_handle = 0;
1084 while (record != NULL) {
1085 record->record_handle = ++record_handle;
1086 if (record->data != NULL) {
1087 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301088 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301089 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301090 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301091 }
1092 record = record->next;
1093 }
1094 }
1095}
1096
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001097LIBPLDM_ABI_TESTING
1098pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1099 uint32_t first, uint32_t last)
1100{
1101 pldm_pdr_record *record = NULL;
1102 pldm_pdr_record *curr;
1103
1104 if (!repo) {
1105 return NULL;
1106 }
1107 for (curr = repo->first; curr; curr = curr->next) {
1108 if (first > curr->record_handle || last < curr->record_handle) {
1109 continue;
1110 }
1111 if (!record || curr->record_handle > record->record_handle) {
1112 record = curr;
1113 }
1114 }
1115
1116 return record;
1117}
1118
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001119static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1120 pldm_entity *entity,
1121 pldm_entity_node **out,
1122 bool is_remote)
1123{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001124 if (node == NULL) {
1125 return;
1126 }
1127 bool is_entity_type;
1128 bool is_entity_instance_num;
1129
1130 is_entity_type = node->entity.entity_type == entity->entity_type;
1131 is_entity_instance_num = node->entity.entity_instance_num ==
1132 entity->entity_instance_num;
1133
1134 if (!is_remote ||
1135 node->remote_container_id == entity->entity_container_id) {
1136 if (is_entity_type && is_entity_instance_num) {
1137 entity->entity_container_id =
1138 node->entity.entity_container_id;
1139 *out = node;
1140 return;
1141 }
1142 }
1143 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1144 is_remote);
1145 entity_association_tree_find_if_remote(node->first_child, entity, out,
1146 is_remote);
1147}
1148
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001149LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001150pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1151 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001152{
1153 if (!tree || !entity) {
1154 return NULL;
1155 }
1156 pldm_entity_node *node = NULL;
1157 entity_association_tree_find_if_remote(tree->root, entity, &node,
1158 is_remote);
1159 return node;
1160}
1161
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301162static void entity_association_tree_find(pldm_entity_node *node,
1163 pldm_entity *entity,
1164 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301165{
1166 if (node == NULL) {
1167 return;
1168 }
1169
1170 if (node->entity.entity_type == entity->entity_type &&
1171 node->entity.entity_instance_num == entity->entity_instance_num) {
1172 entity->entity_container_id = node->entity.entity_container_id;
1173 *out = node;
1174 return;
1175 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301176 entity_association_tree_find(node->next_sibling, entity, out);
1177 entity_association_tree_find(node->first_child, entity, out);
1178}
1179
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301180LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181pldm_entity_node *
1182pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1183 pldm_entity *entity)
1184{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301185 if (!tree || !entity) {
1186 return NULL;
1187 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301188
1189 pldm_entity_node *node = NULL;
1190 entity_association_tree_find(tree->root, entity, &node);
1191 return node;
1192}
1193
1194static void entity_association_tree_copy(pldm_entity_node *org_node,
1195 pldm_entity_node **new_node)
1196{
1197 if (org_node == NULL) {
1198 return;
1199 }
1200 *new_node = malloc(sizeof(pldm_entity_node));
1201 (*new_node)->parent = org_node->parent;
1202 (*new_node)->entity = org_node->entity;
1203 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001204 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205 (*new_node)->first_child = NULL;
1206 (*new_node)->next_sibling = NULL;
1207 entity_association_tree_copy(org_node->first_child,
1208 &((*new_node)->first_child));
1209 entity_association_tree_copy(org_node->next_sibling,
1210 &((*new_node)->next_sibling));
1211}
1212
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301213LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301214void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301215 pldm_entity_association_tree *org_tree,
1216 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301217{
1218 new_tree->last_used_container_id = org_tree->last_used_container_id;
1219 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1220}
1221
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301222LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301224 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301225{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301226 if (!tree) {
1227 return;
1228 }
1229
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230 entity_association_tree_destroy(tree->root);
1231 tree->last_used_container_id = 0;
1232 tree->root = NULL;
1233}
1234
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301235LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301236bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1237{
1238 return ((tree->root == NULL) ? true : false);
1239}
1240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301242void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1243 size_t *num_entities,
1244 pldm_entity **entities)
1245{
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))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301252 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;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301258 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1259 return;
1260 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301261
1262 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301263 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301264 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301265 start += sizeof(struct pldm_pdr_hdr);
1266 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301267 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301268 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301269 if (l_num_entities < 2) {
1270 return;
1271 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301272 if (start + sizeof(struct pldm_pdr_entity_association) +
1273 sizeof(pldm_entity) * (l_num_entities - 2) !=
1274 end) {
1275 return;
1276 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301277 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301278 if (!l_entities) {
1279 return;
1280 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301281 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301282 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301283 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301284 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301285 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301287 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301288 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1289 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1290 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301291 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301292 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301293 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301295
1296 *num_entities = l_num_entities;
1297 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301298}