blob: 5109d6aa950abcec9679ab63a5cffa7248741fd0 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10302#include <libpldm/pdr.h>
3#include <libpldm/platform.h>
4
Andrew Jeffery9c766792022-08-10 23:12:49 +09305#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05306#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <stdlib.h>
8#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06009#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010
11typedef struct pldm_pdr_record {
12 uint32_t record_handle;
13 uint32_t size;
14 uint8_t *data;
15 struct pldm_pdr_record *next;
16 bool is_remote;
17 uint16_t terminus_handle;
18} pldm_pdr_record;
19
20typedef struct pldm_pdr {
21 uint32_t record_count;
22 uint32_t size;
23 pldm_pdr_record *first;
24 pldm_pdr_record *last;
25} pldm_pdr;
26
27static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
28 const pldm_pdr_record *record)
29{
30 assert(repo != NULL);
31 assert(record != NULL);
32
33 if (record == repo->last) {
34 return 0;
35 }
36 return record->next->record_handle;
37}
38
Andrew Jefferyca248ce2023-07-07 10:38:30 +093039LIBPLDM_ABI_STABLE
Andrew Jeffery572a3952023-07-03 13:19:28 +093040int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
41 bool is_remote, uint16_t terminus_handle,
42 uint32_t *record_handle)
43{
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093044 uint32_t curr;
45
Andrew Jeffery3b93d092023-07-17 13:01:50 +093046 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093047 return -EINVAL;
48 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093049
Andrew Jeffery3b93d092023-07-17 13:01:50 +093050 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093051 curr = *record_handle;
52 } else if (repo->last) {
53 curr = repo->last->record_handle;
54 if (curr == UINT32_MAX) {
55 return -EOVERFLOW;
56 }
57 curr += 1;
58 } else {
59 curr = 1;
60 }
61
Andrew Jeffery9c766792022-08-10 23:12:49 +093062 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093063 if (!record) {
64 return -ENOMEM;
65 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093066
Andrew Jeffery572a3952023-07-03 13:19:28 +093067 if (data) {
68 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093069 if (!record->data) {
70 free(record);
71 return -ENOMEM;
72 }
73 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093074 }
75
Andrew Jeffery9c766792022-08-10 23:12:49 +093076 record->size = size;
77 record->is_remote = is_remote;
78 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093079 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093080
Andrew Jeffery3b93d092023-07-17 13:01:50 +093081 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093082 /* If record handle is 0, that is an indication for this API to
83 * compute a new handle. For that reason, the computed handle
84 * needs to be populated in the PDR header. For a case where the
85 * caller supplied the record handle, it would exist in the
86 * header already.
87 */
88 struct pldm_pdr_hdr *hdr = (void *)record->data;
89 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093090 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093091
Andrew Jeffery9c766792022-08-10 23:12:49 +093092 record->next = NULL;
93
Andrew Jeffery8d231da2023-07-04 11:28:46 +093094 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +093095 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +093096 repo->first = record;
97 repo->last = record;
98 } else {
99 repo->last->next = record;
100 repo->last = record;
101 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930102
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930103 repo->size += record->size;
104 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930105
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930106 if (record_handle) {
107 *record_handle = record->record_handle;
108 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930109
110 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111}
112
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930113LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930114pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930115{
116 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930117 if (!repo) {
118 return NULL;
119 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930120 repo->record_count = 0;
121 repo->size = 0;
122 repo->first = NULL;
123 repo->last = NULL;
124
125 return repo;
126}
127
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930128LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930129void pldm_pdr_destroy(pldm_pdr *repo)
130{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930131 if (!repo) {
132 return;
133 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930134
135 pldm_pdr_record *record = repo->first;
136 while (record != NULL) {
137 pldm_pdr_record *next = record->next;
138 if (record->data) {
139 free(record->data);
140 record->data = NULL;
141 }
142 free(record);
143 record = next;
144 }
145 free(repo);
146}
147
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930148LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930149const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
150 uint32_t record_handle,
151 uint8_t **data, uint32_t *size,
152 uint32_t *next_record_handle)
153{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930154 if (!repo || !data || !size || !next_record_handle) {
155 return NULL;
156 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930157
158 if (!record_handle && (repo->first != NULL)) {
159 record_handle = repo->first->record_handle;
160 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930161
Andrew Jeffery9c766792022-08-10 23:12:49 +0930162 pldm_pdr_record *record = repo->first;
163 while (record != NULL) {
164 if (record->record_handle == record_handle) {
165 *size = record->size;
166 *data = record->data;
167 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930168 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 return record;
170 }
171 record = record->next;
172 }
173
174 *size = 0;
175 *next_record_handle = 0;
176 return NULL;
177}
178
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930179LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930180const pldm_pdr_record *
181pldm_pdr_get_next_record(const pldm_pdr *repo,
182 const pldm_pdr_record *curr_record, uint8_t **data,
183 uint32_t *size, uint32_t *next_record_handle)
184{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930185 if (!repo || !curr_record || !data || !size || !next_record_handle) {
186 return NULL;
187 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930188
189 if (curr_record == repo->last) {
190 *data = NULL;
191 *size = 0;
192 *next_record_handle = get_next_record_handle(repo, curr_record);
193 return NULL;
194 }
195
196 *next_record_handle = get_next_record_handle(repo, curr_record->next);
197 *data = curr_record->next->data;
198 *size = curr_record->next->size;
199 return curr_record->next;
200}
201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930202LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930203const pldm_pdr_record *
204pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
205 const pldm_pdr_record *curr_record, uint8_t **data,
206 uint32_t *size)
207{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930208 if (!repo) {
209 return NULL;
210 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930211
212 pldm_pdr_record *record = repo->first;
213 if (curr_record != NULL) {
214 record = curr_record->next;
215 }
216 while (record != NULL) {
217 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
218 if (hdr->type == pdr_type) {
219 if (data && size) {
220 *size = record->size;
221 *data = record->data;
222 }
223 return record;
224 }
225 record = record->next;
226 }
227
228 if (size) {
229 *size = 0;
230 }
231 return NULL;
232}
233
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930234LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930235uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
236{
237 assert(repo != NULL);
238
239 return repo->record_count;
240}
241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
244{
245 assert(repo != NULL);
246
247 return repo->size;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930251uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
252 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930253 const pldm_pdr_record *record)
254{
255 assert(repo != NULL);
256 assert(record != NULL);
257
258 return record->record_handle;
259}
260
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930261LIBPLDM_ABI_STABLE
262bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930263{
264 assert(record != NULL);
265
266 return record->is_remote;
267}
268
Andrew Jefferya2c69112023-07-07 10:41:38 +0930269LIBPLDM_ABI_STABLE
Andrew Jefferyc821a702023-07-03 13:32:11 +0930270int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
271 uint16_t fru_rsi, uint16_t entity_type,
272 uint16_t entity_instance_num,
273 uint16_t container_id,
274 uint32_t *bmc_record_handle)
275{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930276 if (!repo || !bmc_record_handle) {
277 return -EINVAL;
278 }
279
Andrew Jeffery9c766792022-08-10 23:12:49 +0930280 uint32_t size = sizeof(struct pldm_pdr_hdr) +
281 sizeof(struct pldm_pdr_fru_record_set);
282 uint8_t data[size];
283
284 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
285 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930286 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930287 hdr->type = PLDM_PDR_FRU_RECORD_SET;
288 hdr->record_change_num = 0;
289 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
290 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930291 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
292 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930293 fru->terminus_handle = htole16(terminus_handle);
294 fru->fru_rsi = htole16(fru_rsi);
295 fru->entity_type = htole16(entity_type);
296 fru->entity_instance_num = htole16(entity_instance_num);
297 fru->container_id = htole16(container_id);
298
Andrew Jefferyc821a702023-07-03 13:32:11 +0930299 return pldm_pdr_add_check(repo, data, size, false, terminus_handle,
300 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930301}
302
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930303LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930304const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930305 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
306 uint16_t *entity_type, uint16_t *entity_instance_num,
307 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930309 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
310 !container_id) {
311 return NULL;
312 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930313
314 uint8_t *data = NULL;
315 uint32_t size = 0;
316 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930317 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930318 while (curr_record != NULL) {
319 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 (struct pldm_pdr_fru_record_set
321 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930322 if (fru->fru_rsi == htole16(fru_rsi)) {
323 *terminus_handle = le16toh(fru->terminus_handle);
324 *entity_type = le16toh(fru->entity_type);
325 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930326 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930327 *container_id = le16toh(fru->container_id);
328 return curr_record;
329 }
330 data = NULL;
331 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930332 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
333 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334 }
335
336 *terminus_handle = 0;
337 *entity_type = 0;
338 *entity_instance_num = 0;
339 *container_id = 0;
340
341 return NULL;
342}
343
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930344LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930345/* NOLINTNEXTLINE(readability-identifier-naming) */
346void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
347 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930348{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930349 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930350 uint32_t size = 0;
351 const pldm_pdr_record *record;
352 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930353 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930354
355 do {
356 if (record != NULL) {
357 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930358 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930360 (struct pldm_terminus_locator_type_mctp_eid *)
361 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930362 if (pdr->terminus_handle == terminus_handle &&
363 pdr->tid == tid && value->eid == tl_eid) {
364 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 break;
366 }
367 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930368 record = pldm_pdr_find_record_by_type(repo,
369 PLDM_TERMINUS_LOCATOR_PDR,
370 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930371 } while (record);
372}
373
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500374static bool pldm_record_handle_in_range(uint32_t record_handle,
375 uint32_t first_record_handle,
376 uint32_t last_record_handle)
377{
378 return record_handle >= first_record_handle &&
379 record_handle <= last_record_handle;
380}
381
382LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500383int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500384 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500385 uint8_t child_index, uint32_t range_exclude_start_handle,
386 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500387{
388 pldm_pdr_record *record;
389 if (!repo) {
390 return -EINVAL;
391 }
392
393 for (record = repo->first; record; record = record->next) {
394 bool is_container_entity_instance_number;
395 struct pldm_pdr_entity_association *pdr;
396 bool is_container_entity_type;
397 struct pldm_entity *child;
398 struct pldm_pdr_hdr *hdr;
399 bool in_range;
400
401 // pldm_pdr_add() takes only uint8_t* data as an argument.
402 // The expectation here is the pldm_pdr_hdr is the first field of the record data
403 hdr = (struct pldm_pdr_hdr *)record->data;
404 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
405 continue;
406 }
407 in_range = pldm_record_handle_in_range(
408 record->record_handle, range_exclude_start_handle,
409 range_exclude_end_handle);
410 if (in_range) {
411 continue;
412 }
413
414 // this cast is valid with respect to alignment because
415 // struct pldm_pdr_hdr is declared with __attribute__((packed))
416 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500417 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500418 continue;
419 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500420
421 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500422 is_container_entity_type = pdr->container.entity_type ==
423 entity_type;
424 is_container_entity_instance_number =
425 pdr->container.entity_instance_num == entity_instance;
426 if (is_container_entity_type &&
427 is_container_entity_instance_number) {
428 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500429 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500430 }
431 }
432 return -ENOKEY;
433}
434
Andrew Jeffery9c766792022-08-10 23:12:49 +0930435typedef struct pldm_entity_association_tree {
436 pldm_entity_node *root;
437 uint16_t last_used_container_id;
438} pldm_entity_association_tree;
439
440typedef struct pldm_entity_node {
441 pldm_entity entity;
442 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600443 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930444 pldm_entity_node *first_child;
445 pldm_entity_node *next_sibling;
446 uint8_t association_type;
447} pldm_entity_node;
448
449static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
450{
451 assert(tree != NULL);
452 assert(tree->last_used_container_id != UINT16_MAX);
453
454 return ++tree->last_used_container_id;
455}
456
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930457LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930458pldm_entity pldm_entity_extract(pldm_entity_node *node)
459{
460 assert(node != NULL);
461
462 return node->entity;
463}
464
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500465LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930466uint16_t
467pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600468{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930469 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600470
Andrew Jeffery15b88182023-06-30 13:29:17 +0930471 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600472}
473
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930474LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930475pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930476{
477 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930478 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930479 if (!tree) {
480 return NULL;
481 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930482 tree->root = NULL;
483 tree->last_used_container_id = 0;
484
485 return tree;
486}
487
488static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
489 uint16_t entity_type)
490{
491 assert(start != NULL);
492
493 /* Insert after the the last node that matches the input entity type, or
494 * at the end if no such match occurrs
495 */
496 while (start->next_sibling != NULL) {
497 uint16_t this_type = start->entity.entity_type;
498 pldm_entity_node *next = start->next_sibling;
499 if (this_type == entity_type &&
500 (this_type != next->entity.entity_type)) {
501 break;
502 }
503 start = start->next_sibling;
504 }
505
506 return start;
507}
508
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930509LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930510pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930511 pldm_entity_association_tree *tree, pldm_entity *entity,
512 uint16_t entity_instance_number, pldm_entity_node *parent,
513 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930514{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500515 return pldm_entity_association_tree_add_entity(tree, entity,
516 entity_instance_number,
517 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600518 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500519}
520
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500521LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500522pldm_entity_node *pldm_entity_association_tree_add_entity(
523 pldm_entity_association_tree *tree, pldm_entity *entity,
524 uint16_t entity_instance_number, pldm_entity_node *parent,
525 uint8_t association_type, bool is_remote, bool is_update_container_id,
526 uint16_t container_id)
527{
528 if ((!tree) || (!entity)) {
529 return NULL;
530 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930531
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600532 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930533 pldm_entity node;
534 node.entity_type = entity->entity_type;
535 node.entity_instance_num = entity_instance_number;
536 if (pldm_is_current_parent_child(parent, &node)) {
537 return NULL;
538 }
539 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500540 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
541 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
542 return NULL;
543 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930544 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500545 if (!node) {
546 return NULL;
547 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 node->first_child = NULL;
549 node->next_sibling = NULL;
550 node->parent.entity_type = 0;
551 node->parent.entity_instance_num = 0;
552 node->parent.entity_container_id = 0;
553 node->entity.entity_type = entity->entity_type;
554 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600555 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930556 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600557 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930558 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500559 if (parent != NULL) {
560 free(node);
561 return NULL;
562 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 tree->root = node;
564 /* container_id 0 here indicates this is the top-most entry */
565 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600566 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930567 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930568 /* Ensure next_container_id() will yield a valid ID */
569 if (tree->last_used_container_id == UINT16_MAX) {
570 free(node);
571 return NULL;
572 }
573
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 parent->first_child = node;
575 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500576
577 if (is_remote) {
578 node->remote_container_id = entity->entity_container_id;
579 }
580 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600581 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500582 node->entity.entity_container_id = container_id;
583 } else {
584 node->entity.entity_container_id =
585 next_container_id(tree);
586 }
587 } else {
588 node->entity.entity_container_id =
589 entity->entity_container_id;
590 }
591
592 if (!is_remote) {
593 node->remote_container_id =
594 node->entity.entity_container_id;
595 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930596 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930597 pldm_entity_node *start = parent == NULL ? tree->root :
598 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930600 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500601 if (!prev) {
602 free(node);
603 return NULL;
604 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930605 pldm_entity_node *next = prev->next_sibling;
606 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500607 if (prev->entity.entity_instance_num == UINT16_MAX) {
608 free(node);
609 return NULL;
610 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600612 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930613 entity_instance_number :
614 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 }
616 prev->next_sibling = node;
617 node->parent = prev->parent;
618 node->next_sibling = next;
619 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930620 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600621 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 }
623 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500624 if (is_update_container_id) {
625 entity->entity_container_id = node->entity.entity_container_id;
626 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627 return node;
628}
629
630static void get_num_nodes(pldm_entity_node *node, size_t *num)
631{
632 if (node == NULL) {
633 return;
634 }
635
636 ++(*num);
637 get_num_nodes(node->next_sibling, num);
638 get_num_nodes(node->first_child, num);
639}
640
641static void entity_association_tree_visit(pldm_entity_node *node,
642 pldm_entity *entities, size_t *index)
643{
644 if (node == NULL) {
645 return;
646 }
647
648 pldm_entity *entity = &entities[*index];
649 ++(*index);
650 entity->entity_type = node->entity.entity_type;
651 entity->entity_instance_num = node->entity.entity_instance_num;
652 entity->entity_container_id = node->entity.entity_container_id;
653
654 entity_association_tree_visit(node->next_sibling, entities, index);
655 entity_association_tree_visit(node->first_child, entities, index);
656}
657
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930658LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930659void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
660 pldm_entity **entities, size_t *size)
661{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930662 if (!tree || !entities || !size) {
663 return;
664 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930665
666 *size = 0;
667 if (tree->root == NULL) {
668 return;
669 }
670
671 get_num_nodes(tree->root, size);
672 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930673 if (!entities) {
674 return;
675 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930676 size_t index = 0;
677 entity_association_tree_visit(tree->root, *entities, &index);
678}
679
680static void entity_association_tree_destroy(pldm_entity_node *node)
681{
682 if (node == NULL) {
683 return;
684 }
685
686 entity_association_tree_destroy(node->next_sibling);
687 entity_association_tree_destroy(node->first_child);
688 free(node);
689}
690
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930691LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
693{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930694 if (!tree) {
695 return;
696 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697
698 entity_association_tree_destroy(tree->root);
699 free(tree);
700}
701
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930702LIBPLDM_ABI_STABLE
703bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930704{
705 assert(node != NULL);
706
707 return node->first_child != NULL;
708}
709
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930710LIBPLDM_ABI_STABLE
711pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712{
713 assert(node != NULL);
714
715 return node->parent;
716}
717
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930718LIBPLDM_ABI_STABLE
719bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720{
721 assert(node != NULL);
722
723 if (node->parent.entity_type == 0 &&
724 node->parent.entity_instance_num == 0 &&
725 node->parent.entity_container_id == 0) {
726 return false;
727 }
728
729 return true;
730}
731
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930732LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
734 uint8_t association_type)
735{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930736 if (!node) {
737 return 0;
738 }
739
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930740 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
741 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
742 return 0;
743 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744
745 size_t count = 0;
746 pldm_entity_node *curr = node->first_child;
747 while (curr != NULL) {
748 if (curr->association_type == association_type) {
749 ++count;
750 }
751 curr = curr->next_sibling;
752 }
753
754 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930755 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930756}
757
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930758LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
760{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930761 if (!parent || !node) {
762 return false;
763 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930764
765 pldm_entity_node *curr = parent->first_child;
766 while (curr != NULL) {
767 if (node->entity_type == curr->entity.entity_type &&
768 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930769 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770 return true;
771 }
772 curr = curr->next_sibling;
773 }
774
775 return false;
776}
777
Andrew Jeffery65945992023-07-17 15:04:21 +0930778static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500779 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
780 uint8_t contained_count, uint8_t association_type, bool is_remote,
781 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930782{
783 uint8_t pdr[size];
784 uint8_t *start = pdr;
785
786 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
787 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600788 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930789 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
790 hdr->record_change_num = 0;
791 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
792 start += sizeof(struct pldm_pdr_hdr);
793
794 uint16_t *container_id = (uint16_t *)start;
795 *container_id = htole16(curr->first_child->entity.entity_container_id);
796 start += sizeof(uint16_t);
797 *start = association_type;
798 start += sizeof(uint8_t);
799
800 pldm_entity *entity = (pldm_entity *)start;
801 entity->entity_type = htole16(curr->entity.entity_type);
802 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
803 entity->entity_container_id = htole16(curr->entity.entity_container_id);
804 start += sizeof(pldm_entity);
805
806 *start = contained_count;
807 start += sizeof(uint8_t);
808
809 pldm_entity_node *node = curr->first_child;
810 while (node != NULL) {
811 if (node->association_type == association_type) {
812 pldm_entity *entity = (pldm_entity *)start;
813 entity->entity_type = htole16(node->entity.entity_type);
814 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930815 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930817 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818 start += sizeof(pldm_entity);
819 }
820 node = node->next_sibling;
821 }
822
Andrew Jeffery65945992023-07-17 15:04:21 +0930823 return pldm_pdr_add_check(repo, pdr, size, is_remote, terminus_handle,
824 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930825}
826
Andrew Jeffery65945992023-07-17 15:04:21 +0930827static int entity_association_pdr_add_entry(pldm_entity_node *curr,
828 pldm_pdr *repo, bool is_remote,
829 uint16_t terminus_handle,
830 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930832 uint8_t num_logical_children = pldm_entity_get_num_children(
833 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
834 uint8_t num_physical_children = pldm_entity_get_num_children(
835 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930836 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837
838 if (num_logical_children) {
839 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930840 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
841 sizeof(uint8_t) + sizeof(pldm_entity) +
842 sizeof(uint8_t) +
843 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930844 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930845 curr, repo, logical_pdr_size, num_logical_children,
846 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500847 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930848 if (rc < 0) {
849 return rc;
850 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930851 }
852
853 if (num_physical_children) {
854 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930855 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
856 sizeof(uint8_t) + sizeof(pldm_entity) +
857 sizeof(uint8_t) +
858 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930859 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930860 curr, repo, physical_pdr_size, num_physical_children,
861 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500862 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930863 if (rc < 0) {
864 return rc;
865 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930866 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930867
868 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930869}
870
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930871static bool is_present(pldm_entity entity, pldm_entity **entities,
872 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873{
874 if (entities == NULL || num_entities == 0) {
875 return true;
876 }
877 size_t i = 0;
878 while (i < num_entities) {
879 if ((*entities + i)->entity_type == entity.entity_type) {
880 return true;
881 }
882 i++;
883 }
884 return false;
885}
886
Andrew Jeffery65945992023-07-17 15:04:21 +0930887static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
888 pldm_entity **entities,
889 size_t num_entities, bool is_remote,
890 uint16_t terminus_handle,
891 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930892{
Andrew Jeffery65945992023-07-17 15:04:21 +0930893 int rc;
894
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930896 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930897 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930898
899 if (is_present(curr->entity, entities, num_entities)) {
900 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500901 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930902 if (rc) {
903 return rc;
904 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930905 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930906
907 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
908 num_entities, is_remote,
909 terminus_handle, record_handle);
910 if (rc) {
911 return rc;
912 }
913
914 return entity_association_pdr_add(curr->first_child, repo, entities,
915 num_entities, is_remote,
916 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917}
918
Andrew Jeffery096685b2023-07-17 17:36:14 +0930919LIBPLDM_ABI_STABLE
Andrew Jeffery65945992023-07-17 15:04:21 +0930920int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
921 pldm_pdr *repo, bool is_remote,
922 uint16_t terminus_handle)
923{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930924 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930925 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930926 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927
Andrew Jeffery65945992023-07-17 15:04:21 +0930928 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
929 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930}
931
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930932LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930933int pldm_entity_association_pdr_add_from_node_check(
934 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
935 size_t num_entities, bool is_remote, uint16_t terminus_handle)
936{
937 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500938 node, repo, entities, num_entities, is_remote, terminus_handle,
939 0);
940}
941
Pavithra Barithaya3a267052023-11-13 05:01:36 -0600942LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500943int pldm_entity_association_pdr_add_from_node_with_record_handle(
944 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
945 size_t num_entities, bool is_remote, uint16_t terminus_handle,
946 uint32_t record_handle)
947{
948 if (!node || !repo || !entities) {
949 return -EINVAL;
950 }
951
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500953 is_remote, terminus_handle, record_handle);
954
955 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930956}
957
Andrew Jeffery643c4432023-07-17 15:36:03 +0930958static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
959 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600961 bool is_entity_container_id;
962 bool is_entity_instance_num;
963 bool is_type;
964
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965 if (tree_node == NULL) {
966 return;
967 }
968
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600969 is_type = tree_node->entity.entity_type == entity.entity_type;
970 is_entity_instance_num = tree_node->entity.entity_instance_num ==
971 entity.entity_instance_num;
972 is_entity_container_id = tree_node->entity.entity_container_id ==
973 entity.entity_container_id;
974
975 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930976 *node = tree_node;
977 return;
978 }
979
980 find_entity_ref_in_tree(tree_node->first_child, entity, node);
981 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
982}
983
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930984LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930985void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
986 pldm_entity entity, pldm_entity_node **node)
987{
Andrew Jefferyba47e832023-07-03 11:41:03 +0930988 if (!tree || !node) {
989 return;
990 }
991
Andrew Jeffery9c766792022-08-10 23:12:49 +0930992 find_entity_ref_in_tree(tree->root, entity, node);
993}
994
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930995LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930996void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
997 uint16_t terminus_handle)
998{
Andrew Jeffery438dd492023-07-03 11:51:43 +0930999 if (!repo) {
1000 return;
1001 }
1002
Andrew Jeffery9c766792022-08-10 23:12:49 +09301003 bool removed = false;
1004
1005 pldm_pdr_record *record = repo->first;
1006 pldm_pdr_record *prev = NULL;
1007 while (record != NULL) {
1008 pldm_pdr_record *next = record->next;
1009 if (record->terminus_handle == terminus_handle) {
1010 if (repo->first == record) {
1011 repo->first = next;
1012 } else {
1013 prev->next = next;
1014 }
1015 if (repo->last == record) {
1016 repo->last = prev;
1017 }
1018 if (record->data) {
1019 free(record->data);
1020 }
1021 --repo->record_count;
1022 repo->size -= record->size;
1023 free(record);
1024 removed = true;
1025 } else {
1026 prev = record;
1027 }
1028 record = next;
1029 }
1030
1031 if (removed == true) {
1032 record = repo->first;
1033 uint32_t record_handle = 0;
1034 while (record != NULL) {
1035 record->record_handle = ++record_handle;
1036 if (record->data != NULL) {
1037 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301038 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301039 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301040 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301041 }
1042 record = record->next;
1043 }
1044 }
1045}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301046
1047LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301048void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1049{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301050 if (!repo) {
1051 return;
1052 }
1053
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 bool removed = false;
1055
1056 pldm_pdr_record *record = repo->first;
1057 pldm_pdr_record *prev = NULL;
1058 while (record != NULL) {
1059 pldm_pdr_record *next = record->next;
1060 if (record->is_remote == true) {
1061 if (repo->first == record) {
1062 repo->first = next;
1063 } else {
1064 prev->next = next;
1065 }
1066 if (repo->last == record) {
1067 repo->last = prev;
1068 }
1069 if (record->data) {
1070 free(record->data);
1071 }
1072 --repo->record_count;
1073 repo->size -= record->size;
1074 free(record);
1075 removed = true;
1076 } else {
1077 prev = record;
1078 }
1079 record = next;
1080 }
1081
1082 if (removed == true) {
1083 record = repo->first;
1084 uint32_t record_handle = 0;
1085 while (record != NULL) {
1086 record->record_handle = ++record_handle;
1087 if (record->data != NULL) {
1088 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301089 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301090 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301091 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301092 }
1093 record = record->next;
1094 }
1095 }
1096}
1097
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001098LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001099pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1100 uint32_t first, uint32_t last)
1101{
1102 pldm_pdr_record *record = NULL;
1103 pldm_pdr_record *curr;
1104
1105 if (!repo) {
1106 return NULL;
1107 }
1108 for (curr = repo->first; curr; curr = curr->next) {
1109 if (first > curr->record_handle || last < curr->record_handle) {
1110 continue;
1111 }
1112 if (!record || curr->record_handle > record->record_handle) {
1113 record = curr;
1114 }
1115 }
1116
1117 return record;
1118}
1119
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001120static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1121 pldm_entity *entity,
1122 pldm_entity_node **out,
1123 bool is_remote)
1124{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001125 if (node == NULL) {
1126 return;
1127 }
1128 bool is_entity_type;
1129 bool is_entity_instance_num;
1130
1131 is_entity_type = node->entity.entity_type == entity->entity_type;
1132 is_entity_instance_num = node->entity.entity_instance_num ==
1133 entity->entity_instance_num;
1134
1135 if (!is_remote ||
1136 node->remote_container_id == entity->entity_container_id) {
1137 if (is_entity_type && is_entity_instance_num) {
1138 entity->entity_container_id =
1139 node->entity.entity_container_id;
1140 *out = node;
1141 return;
1142 }
1143 }
1144 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1145 is_remote);
1146 entity_association_tree_find_if_remote(node->first_child, entity, out,
1147 is_remote);
1148}
1149
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001150LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001151pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1152 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001153{
1154 if (!tree || !entity) {
1155 return NULL;
1156 }
1157 pldm_entity_node *node = NULL;
1158 entity_association_tree_find_if_remote(tree->root, entity, &node,
1159 is_remote);
1160 return node;
1161}
1162
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301163static void entity_association_tree_find(pldm_entity_node *node,
1164 pldm_entity *entity,
1165 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166{
1167 if (node == NULL) {
1168 return;
1169 }
1170
1171 if (node->entity.entity_type == entity->entity_type &&
1172 node->entity.entity_instance_num == entity->entity_instance_num) {
1173 entity->entity_container_id = node->entity.entity_container_id;
1174 *out = node;
1175 return;
1176 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301177 entity_association_tree_find(node->next_sibling, entity, out);
1178 entity_association_tree_find(node->first_child, entity, out);
1179}
1180
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301181LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182pldm_entity_node *
1183pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1184 pldm_entity *entity)
1185{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301186 if (!tree || !entity) {
1187 return NULL;
1188 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301189
1190 pldm_entity_node *node = NULL;
1191 entity_association_tree_find(tree->root, entity, &node);
1192 return node;
1193}
1194
1195static void entity_association_tree_copy(pldm_entity_node *org_node,
1196 pldm_entity_node **new_node)
1197{
1198 if (org_node == NULL) {
1199 return;
1200 }
1201 *new_node = malloc(sizeof(pldm_entity_node));
1202 (*new_node)->parent = org_node->parent;
1203 (*new_node)->entity = org_node->entity;
1204 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001205 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301206 (*new_node)->first_child = NULL;
1207 (*new_node)->next_sibling = NULL;
1208 entity_association_tree_copy(org_node->first_child,
1209 &((*new_node)->first_child));
1210 entity_association_tree_copy(org_node->next_sibling,
1211 &((*new_node)->next_sibling));
1212}
1213
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301214LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301216 pldm_entity_association_tree *org_tree,
1217 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218{
George Liuc6c391d2023-11-09 10:13:34 +08001219 assert(org_tree != NULL);
1220 assert(new_tree != NULL);
1221
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222 new_tree->last_used_container_id = org_tree->last_used_container_id;
1223 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1224}
1225
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301226LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301227void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301228 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301230 if (!tree) {
1231 return;
1232 }
1233
Andrew Jeffery9c766792022-08-10 23:12:49 +09301234 entity_association_tree_destroy(tree->root);
1235 tree->last_used_container_id = 0;
1236 tree->root = NULL;
1237}
1238
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301239LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1241{
1242 return ((tree->root == NULL) ? true : false);
1243}
1244
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301245LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301246void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1247 size_t *num_entities,
1248 pldm_entity **entities)
1249{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301250 if (!pdr || !num_entities || !entities) {
1251 return;
1252 }
1253#define PDR_MIN_SIZE \
1254 (sizeof(struct pldm_pdr_hdr) + \
1255 sizeof(struct pldm_pdr_entity_association))
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301256 if (pdr_len < PDR_MIN_SIZE) {
1257 return;
1258 }
1259#undef PDR_MIN_SIZE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301260
1261 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301262 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1263 return;
1264 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301265
1266 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301267 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301268 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301269 start += sizeof(struct pldm_pdr_hdr);
1270 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301271 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301272 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301273 if (l_num_entities < 2) {
1274 return;
1275 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301276 if (start + sizeof(struct pldm_pdr_entity_association) +
1277 sizeof(pldm_entity) * (l_num_entities - 2) !=
1278 end) {
1279 return;
1280 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301281 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301282 if (!l_entities) {
1283 return;
1284 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301285 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301286 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301287 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301288 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301289 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301290 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301291 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301292 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1293 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1294 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301295 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301296 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301297 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301298 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301299
1300 *num_entities = l_num_entities;
1301 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301302}