blob: bf63ecf8376c6c2ac5a84d39215d029ba81eb414 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Varsha Kaverappa37552b92024-02-12 05:06:06 -06002#include "msgbuf.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10303#include <libpldm/pdr.h>
4#include <libpldm/platform.h>
5
Andrew Jeffery9c766792022-08-10 23:12:49 +09306#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05307#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09308#include <stdlib.h>
9#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060010#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093011
Varsha Kaverappa37552b92024-02-12 05:06:06 -060012#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
13 (sizeof(struct pldm_pdr_hdr) + \
14 sizeof(struct pldm_pdr_entity_association))
15
Andrew Jeffery9c766792022-08-10 23:12:49 +093016typedef struct pldm_pdr_record {
17 uint32_t record_handle;
18 uint32_t size;
19 uint8_t *data;
20 struct pldm_pdr_record *next;
21 bool is_remote;
22 uint16_t terminus_handle;
23} pldm_pdr_record;
24
25typedef struct pldm_pdr {
26 uint32_t record_count;
27 uint32_t size;
28 pldm_pdr_record *first;
29 pldm_pdr_record *last;
30} pldm_pdr;
31
32static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
33 const pldm_pdr_record *record)
34{
35 assert(repo != NULL);
36 assert(record != NULL);
37
38 if (record == repo->last) {
39 return 0;
40 }
41 return record->next->record_handle;
42}
43
Andrew Jefferyca248ce2023-07-07 10:38:30 +093044LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000045int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
46 bool is_remote, uint16_t terminus_handle,
47 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093048{
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093049 uint32_t curr;
50
Andrew Jeffery3b93d092023-07-17 13:01:50 +093051 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093052 return -EINVAL;
53 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093054
Andrew Jeffery3b93d092023-07-17 13:01:50 +093055 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093056 curr = *record_handle;
57 } else if (repo->last) {
58 curr = repo->last->record_handle;
59 if (curr == UINT32_MAX) {
60 return -EOVERFLOW;
61 }
62 curr += 1;
63 } else {
64 curr = 1;
65 }
66
Andrew Jeffery9c766792022-08-10 23:12:49 +093067 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093068 if (!record) {
69 return -ENOMEM;
70 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093071
Andrew Jeffery572a3952023-07-03 13:19:28 +093072 if (data) {
73 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093074 if (!record->data) {
75 free(record);
76 return -ENOMEM;
77 }
78 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093079 }
80
Andrew Jeffery9c766792022-08-10 23:12:49 +093081 record->size = size;
82 record->is_remote = is_remote;
83 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093084 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093085
Andrew Jeffery3b93d092023-07-17 13:01:50 +093086 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093087 /* If record handle is 0, that is an indication for this API to
88 * compute a new handle. For that reason, the computed handle
89 * needs to be populated in the PDR header. For a case where the
90 * caller supplied the record handle, it would exist in the
91 * header already.
92 */
93 struct pldm_pdr_hdr *hdr = (void *)record->data;
94 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093095 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093096
Andrew Jeffery9c766792022-08-10 23:12:49 +093097 record->next = NULL;
98
Andrew Jeffery8d231da2023-07-04 11:28:46 +093099 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930100 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930101 repo->first = record;
102 repo->last = record;
103 } else {
104 repo->last->next = record;
105 repo->last = record;
106 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930107
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930108 repo->size += record->size;
109 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930110
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930111 if (record_handle) {
112 *record_handle = record->record_handle;
113 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930114
115 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930116}
117
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930118LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930119pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930120{
121 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930122 if (!repo) {
123 return NULL;
124 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930125 repo->record_count = 0;
126 repo->size = 0;
127 repo->first = NULL;
128 repo->last = NULL;
129
130 return repo;
131}
132
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930133LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930134void pldm_pdr_destroy(pldm_pdr *repo)
135{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930136 if (!repo) {
137 return;
138 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930139
140 pldm_pdr_record *record = repo->first;
141 while (record != NULL) {
142 pldm_pdr_record *next = record->next;
143 if (record->data) {
144 free(record->data);
145 record->data = NULL;
146 }
147 free(record);
148 record = next;
149 }
150 free(repo);
151}
152
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930153LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930154const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
155 uint32_t record_handle,
156 uint8_t **data, uint32_t *size,
157 uint32_t *next_record_handle)
158{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930159 if (!repo || !data || !size || !next_record_handle) {
160 return NULL;
161 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930162
163 if (!record_handle && (repo->first != NULL)) {
164 record_handle = repo->first->record_handle;
165 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930166
Andrew Jeffery9c766792022-08-10 23:12:49 +0930167 pldm_pdr_record *record = repo->first;
168 while (record != NULL) {
169 if (record->record_handle == record_handle) {
170 *size = record->size;
171 *data = record->data;
172 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930173 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930174 return record;
175 }
176 record = record->next;
177 }
178
179 *size = 0;
180 *next_record_handle = 0;
181 return NULL;
182}
183
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930184LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185const pldm_pdr_record *
186pldm_pdr_get_next_record(const pldm_pdr *repo,
187 const pldm_pdr_record *curr_record, uint8_t **data,
188 uint32_t *size, uint32_t *next_record_handle)
189{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930190 if (!repo || !curr_record || !data || !size || !next_record_handle) {
191 return NULL;
192 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930193
194 if (curr_record == repo->last) {
195 *data = NULL;
196 *size = 0;
197 *next_record_handle = get_next_record_handle(repo, curr_record);
198 return NULL;
199 }
200
201 *next_record_handle = get_next_record_handle(repo, curr_record->next);
202 *data = curr_record->next->data;
203 *size = curr_record->next->size;
204 return curr_record->next;
205}
206
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930207LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930208const pldm_pdr_record *
209pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
210 const pldm_pdr_record *curr_record, uint8_t **data,
211 uint32_t *size)
212{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930213 if (!repo) {
214 return NULL;
215 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930216
217 pldm_pdr_record *record = repo->first;
218 if (curr_record != NULL) {
219 record = curr_record->next;
220 }
221 while (record != NULL) {
222 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
223 if (hdr->type == pdr_type) {
224 if (data && size) {
225 *size = record->size;
226 *data = record->data;
227 }
228 return record;
229 }
230 record = record->next;
231 }
232
233 if (size) {
234 *size = 0;
235 }
236 return NULL;
237}
238
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930239LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930240uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
241{
242 assert(repo != NULL);
243
244 return repo->record_count;
245}
246
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930247LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930248uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
249{
250 assert(repo != NULL);
251
252 return repo->size;
253}
254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930255LIBPLDM_ABI_STABLE
Andrew Jeffery5565fcd2023-06-30 13:21:32 +0930256uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo
257 __attribute__((unused)),
Andrew Jeffery9c766792022-08-10 23:12:49 +0930258 const pldm_pdr_record *record)
259{
260 assert(repo != NULL);
261 assert(record != NULL);
262
263 return record->record_handle;
264}
265
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530266LIBPLDM_ABI_TESTING
267uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo
268 __attribute__((unused)),
269 const pldm_pdr_record *record)
270{
271 assert(repo != NULL);
272 assert(record != NULL);
273
274 return record->terminus_handle;
275}
276
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930277LIBPLDM_ABI_STABLE
278bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279{
280 assert(record != NULL);
281
282 return record->is_remote;
283}
284
Andrew Jefferya2c69112023-07-07 10:41:38 +0930285LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930286int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
287 uint16_t fru_rsi, uint16_t entity_type,
288 uint16_t entity_instance_num,
289 uint16_t container_id,
290 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930291{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930292 if (!repo || !bmc_record_handle) {
293 return -EINVAL;
294 }
295
Andrew Jeffery9c766792022-08-10 23:12:49 +0930296 uint32_t size = sizeof(struct pldm_pdr_hdr) +
297 sizeof(struct pldm_pdr_fru_record_set);
298 uint8_t data[size];
299
300 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
301 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930302 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303 hdr->type = PLDM_PDR_FRU_RECORD_SET;
304 hdr->record_change_num = 0;
305 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
306 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930307 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
308 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930309 fru->terminus_handle = htole16(terminus_handle);
310 fru->fru_rsi = htole16(fru_rsi);
311 fru->entity_type = htole16(entity_type);
312 fru->entity_instance_num = htole16(entity_instance_num);
313 fru->container_id = htole16(container_id);
314
Andrew Jefferyfae36412024-06-20 06:35:51 +0000315 return pldm_pdr_add(repo, data, size, false, terminus_handle,
316 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317}
318
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930319LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930320const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
322 uint16_t *entity_type, uint16_t *entity_instance_num,
323 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930325 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
326 !container_id) {
327 return NULL;
328 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329
330 uint8_t *data = NULL;
331 uint32_t size = 0;
332 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334 while (curr_record != NULL) {
335 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930336 (struct pldm_pdr_fru_record_set
337 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338 if (fru->fru_rsi == htole16(fru_rsi)) {
339 *terminus_handle = le16toh(fru->terminus_handle);
340 *entity_type = le16toh(fru->entity_type);
341 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930342 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343 *container_id = le16toh(fru->container_id);
344 return curr_record;
345 }
346 data = NULL;
347 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
349 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930350 }
351
352 *terminus_handle = 0;
353 *entity_type = 0;
354 *entity_instance_num = 0;
355 *container_id = 0;
356
357 return NULL;
358}
359
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930360LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930361/* NOLINTNEXTLINE(readability-identifier-naming) */
362void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
363 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930364{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930365 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 uint32_t size = 0;
367 const pldm_pdr_record *record;
368 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370
371 do {
372 if (record != NULL) {
373 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930374 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930375 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930376 (struct pldm_terminus_locator_type_mctp_eid *)
377 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930378 if (pdr->terminus_handle == terminus_handle &&
379 pdr->tid == tid && value->eid == tl_eid) {
380 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930381 break;
382 }
383 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930384 record = pldm_pdr_find_record_by_type(repo,
385 PLDM_TERMINUS_LOCATOR_PDR,
386 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930387 } while (record);
388}
389
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500390static bool pldm_record_handle_in_range(uint32_t record_handle,
391 uint32_t first_record_handle,
392 uint32_t last_record_handle)
393{
394 return record_handle >= first_record_handle &&
395 record_handle <= last_record_handle;
396}
397
398LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500399int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500400 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500401 uint8_t child_index, uint32_t range_exclude_start_handle,
402 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500403{
404 pldm_pdr_record *record;
405 if (!repo) {
406 return -EINVAL;
407 }
408
409 for (record = repo->first; record; record = record->next) {
410 bool is_container_entity_instance_number;
411 struct pldm_pdr_entity_association *pdr;
412 bool is_container_entity_type;
413 struct pldm_entity *child;
414 struct pldm_pdr_hdr *hdr;
415 bool in_range;
416
417 // pldm_pdr_add() takes only uint8_t* data as an argument.
418 // The expectation here is the pldm_pdr_hdr is the first field of the record data
419 hdr = (struct pldm_pdr_hdr *)record->data;
420 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
421 continue;
422 }
423 in_range = pldm_record_handle_in_range(
424 record->record_handle, range_exclude_start_handle,
425 range_exclude_end_handle);
426 if (in_range) {
427 continue;
428 }
429
430 // this cast is valid with respect to alignment because
431 // struct pldm_pdr_hdr is declared with __attribute__((packed))
432 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500433 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500434 continue;
435 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500436
437 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500438 is_container_entity_type = pdr->container.entity_type ==
439 entity_type;
440 is_container_entity_instance_number =
441 pdr->container.entity_instance_num == entity_instance;
442 if (is_container_entity_type &&
443 is_container_entity_instance_number) {
444 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500445 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500446 }
447 }
448 return -ENOKEY;
449}
450
Andrew Jeffery9c766792022-08-10 23:12:49 +0930451typedef struct pldm_entity_association_tree {
452 pldm_entity_node *root;
453 uint16_t last_used_container_id;
454} pldm_entity_association_tree;
455
456typedef struct pldm_entity_node {
457 pldm_entity entity;
458 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600459 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930460 pldm_entity_node *first_child;
461 pldm_entity_node *next_sibling;
462 uint8_t association_type;
463} pldm_entity_node;
464
465static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
466{
467 assert(tree != NULL);
468 assert(tree->last_used_container_id != UINT16_MAX);
469
470 return ++tree->last_used_container_id;
471}
472
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930473LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474pldm_entity pldm_entity_extract(pldm_entity_node *node)
475{
476 assert(node != NULL);
477
478 return node->entity;
479}
480
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500481LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930482uint16_t
483pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600484{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930485 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600486
Andrew Jeffery15b88182023-06-30 13:29:17 +0930487 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600488}
489
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930490LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930491pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930492{
493 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930494 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930495 if (!tree) {
496 return NULL;
497 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930498 tree->root = NULL;
499 tree->last_used_container_id = 0;
500
501 return tree;
502}
503
504static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
505 uint16_t entity_type)
506{
507 assert(start != NULL);
508
509 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530510 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930511 */
512 while (start->next_sibling != NULL) {
513 uint16_t this_type = start->entity.entity_type;
514 pldm_entity_node *next = start->next_sibling;
515 if (this_type == entity_type &&
516 (this_type != next->entity.entity_type)) {
517 break;
518 }
519 start = start->next_sibling;
520 }
521
522 return start;
523}
524
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930525LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930526pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930527 pldm_entity_association_tree *tree, pldm_entity *entity,
528 uint16_t entity_instance_number, pldm_entity_node *parent,
529 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930530{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500531 return pldm_entity_association_tree_add_entity(tree, entity,
532 entity_instance_number,
533 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600534 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500535}
536
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500537LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500538pldm_entity_node *pldm_entity_association_tree_add_entity(
539 pldm_entity_association_tree *tree, pldm_entity *entity,
540 uint16_t entity_instance_number, pldm_entity_node *parent,
541 uint8_t association_type, bool is_remote, bool is_update_container_id,
542 uint16_t container_id)
543{
544 if ((!tree) || (!entity)) {
545 return NULL;
546 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930547
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600548 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930549 pldm_entity node;
550 node.entity_type = entity->entity_type;
551 node.entity_instance_num = entity_instance_number;
552 if (pldm_is_current_parent_child(parent, &node)) {
553 return NULL;
554 }
555 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500556 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
557 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
558 return NULL;
559 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930560 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500561 if (!node) {
562 return NULL;
563 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 node->first_child = NULL;
565 node->next_sibling = NULL;
566 node->parent.entity_type = 0;
567 node->parent.entity_instance_num = 0;
568 node->parent.entity_container_id = 0;
569 node->entity.entity_type = entity->entity_type;
570 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600571 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930572 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600573 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500575 if (parent != NULL) {
576 free(node);
577 return NULL;
578 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930579 tree->root = node;
580 /* container_id 0 here indicates this is the top-most entry */
581 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600582 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930583 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930584 /* Ensure next_container_id() will yield a valid ID */
585 if (tree->last_used_container_id == UINT16_MAX) {
586 free(node);
587 return NULL;
588 }
589
Andrew Jeffery9c766792022-08-10 23:12:49 +0930590 parent->first_child = node;
591 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500592
593 if (is_remote) {
594 node->remote_container_id = entity->entity_container_id;
595 }
596 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600597 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500598 node->entity.entity_container_id = container_id;
599 } else {
600 node->entity.entity_container_id =
601 next_container_id(tree);
602 }
603 } else {
604 node->entity.entity_container_id =
605 entity->entity_container_id;
606 }
607
608 if (!is_remote) {
609 node->remote_container_id =
610 node->entity.entity_container_id;
611 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930613 pldm_entity_node *start = parent == NULL ? tree->root :
614 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930616 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500617 if (!prev) {
618 free(node);
619 return NULL;
620 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930621 pldm_entity_node *next = prev->next_sibling;
622 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500623 if (prev->entity.entity_instance_num == UINT16_MAX) {
624 free(node);
625 return NULL;
626 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930627 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600628 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930629 entity_instance_number :
630 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930631 }
632 prev->next_sibling = node;
633 node->parent = prev->parent;
634 node->next_sibling = next;
635 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930636 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600637 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930638 }
639 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500640 if (is_update_container_id) {
641 entity->entity_container_id = node->entity.entity_container_id;
642 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643 return node;
644}
645
646static void get_num_nodes(pldm_entity_node *node, size_t *num)
647{
648 if (node == NULL) {
649 return;
650 }
651
652 ++(*num);
653 get_num_nodes(node->next_sibling, num);
654 get_num_nodes(node->first_child, num);
655}
656
657static void entity_association_tree_visit(pldm_entity_node *node,
658 pldm_entity *entities, size_t *index)
659{
660 if (node == NULL) {
661 return;
662 }
663
664 pldm_entity *entity = &entities[*index];
665 ++(*index);
666 entity->entity_type = node->entity.entity_type;
667 entity->entity_instance_num = node->entity.entity_instance_num;
668 entity->entity_container_id = node->entity.entity_container_id;
669
670 entity_association_tree_visit(node->next_sibling, entities, index);
671 entity_association_tree_visit(node->first_child, entities, index);
672}
673
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930674LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
676 pldm_entity **entities, size_t *size)
677{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930678 if (!tree || !entities || !size) {
679 return;
680 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681
682 *size = 0;
683 if (tree->root == NULL) {
684 return;
685 }
686
687 get_num_nodes(tree->root, size);
688 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930689 if (!entities) {
690 return;
691 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692 size_t index = 0;
693 entity_association_tree_visit(tree->root, *entities, &index);
694}
695
696static void entity_association_tree_destroy(pldm_entity_node *node)
697{
698 if (node == NULL) {
699 return;
700 }
701
702 entity_association_tree_destroy(node->next_sibling);
703 entity_association_tree_destroy(node->first_child);
704 free(node);
705}
706
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930707LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930708void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
709{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930710 if (!tree) {
711 return;
712 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713
714 entity_association_tree_destroy(tree->root);
715 free(tree);
716}
717
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930718LIBPLDM_ABI_STABLE
719bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930720{
721 assert(node != NULL);
722
723 return node->first_child != NULL;
724}
725
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930726LIBPLDM_ABI_STABLE
727pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930728{
729 assert(node != NULL);
730
731 return node->parent;
732}
733
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930734LIBPLDM_ABI_STABLE
735bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736{
737 assert(node != NULL);
738
739 if (node->parent.entity_type == 0 &&
740 node->parent.entity_instance_num == 0 &&
741 node->parent.entity_container_id == 0) {
742 return false;
743 }
744
745 return true;
746}
747
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930748LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930749uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
750 uint8_t association_type)
751{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930752 if (!node) {
753 return 0;
754 }
755
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930756 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
757 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
758 return 0;
759 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760
761 size_t count = 0;
762 pldm_entity_node *curr = node->first_child;
763 while (curr != NULL) {
764 if (curr->association_type == association_type) {
765 ++count;
766 }
767 curr = curr->next_sibling;
768 }
769
770 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930771 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930772}
773
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930774LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
776{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930777 if (!parent || !node) {
778 return false;
779 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930780
781 pldm_entity_node *curr = parent->first_child;
782 while (curr != NULL) {
783 if (node->entity_type == curr->entity.entity_type &&
784 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930785 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930786 return true;
787 }
788 curr = curr->next_sibling;
789 }
790
791 return false;
792}
793
Andrew Jeffery65945992023-07-17 15:04:21 +0930794static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500795 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
796 uint8_t contained_count, uint8_t association_type, bool is_remote,
797 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930798{
799 uint8_t pdr[size];
800 uint8_t *start = pdr;
801
802 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
803 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600804 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
806 hdr->record_change_num = 0;
807 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
808 start += sizeof(struct pldm_pdr_hdr);
809
810 uint16_t *container_id = (uint16_t *)start;
811 *container_id = htole16(curr->first_child->entity.entity_container_id);
812 start += sizeof(uint16_t);
813 *start = association_type;
814 start += sizeof(uint8_t);
815
816 pldm_entity *entity = (pldm_entity *)start;
817 entity->entity_type = htole16(curr->entity.entity_type);
818 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
819 entity->entity_container_id = htole16(curr->entity.entity_container_id);
820 start += sizeof(pldm_entity);
821
822 *start = contained_count;
823 start += sizeof(uint8_t);
824
825 pldm_entity_node *node = curr->first_child;
826 while (node != NULL) {
827 if (node->association_type == association_type) {
828 pldm_entity *entity = (pldm_entity *)start;
829 entity->entity_type = htole16(node->entity.entity_type);
830 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930831 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930832 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930833 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930834 start += sizeof(pldm_entity);
835 }
836 node = node->next_sibling;
837 }
838
Andrew Jefferyfae36412024-06-20 06:35:51 +0000839 return pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
840 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930841}
842
Andrew Jeffery65945992023-07-17 15:04:21 +0930843static int entity_association_pdr_add_entry(pldm_entity_node *curr,
844 pldm_pdr *repo, bool is_remote,
845 uint16_t terminus_handle,
846 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930848 uint8_t num_logical_children = pldm_entity_get_num_children(
849 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
850 uint8_t num_physical_children = pldm_entity_get_num_children(
851 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930852 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853
854 if (num_logical_children) {
855 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930856 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
857 sizeof(uint8_t) + sizeof(pldm_entity) +
858 sizeof(uint8_t) +
859 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930860 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930861 curr, repo, logical_pdr_size, num_logical_children,
862 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500863 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930864 if (rc < 0) {
865 return rc;
866 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930867 }
868
869 if (num_physical_children) {
870 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930871 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
872 sizeof(uint8_t) + sizeof(pldm_entity) +
873 sizeof(uint8_t) +
874 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930875 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930876 curr, repo, physical_pdr_size, num_physical_children,
877 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500878 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930879 if (rc < 0) {
880 return rc;
881 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930883
884 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930885}
886
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930887static bool is_present(pldm_entity entity, pldm_entity **entities,
888 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930889{
890 if (entities == NULL || num_entities == 0) {
891 return true;
892 }
893 size_t i = 0;
894 while (i < num_entities) {
895 if ((*entities + i)->entity_type == entity.entity_type) {
896 return true;
897 }
898 i++;
899 }
900 return false;
901}
902
Andrew Jeffery65945992023-07-17 15:04:21 +0930903static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
904 pldm_entity **entities,
905 size_t num_entities, bool is_remote,
906 uint16_t terminus_handle,
907 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930908{
Andrew Jeffery65945992023-07-17 15:04:21 +0930909 int rc;
910
Andrew Jeffery9c766792022-08-10 23:12:49 +0930911 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930912 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930914
915 if (is_present(curr->entity, entities, num_entities)) {
916 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500917 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930918 if (rc) {
919 return rc;
920 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930921 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930922
923 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
924 num_entities, is_remote,
925 terminus_handle, record_handle);
926 if (rc) {
927 return rc;
928 }
929
930 return entity_association_pdr_add(curr->first_child, repo, entities,
931 num_entities, is_remote,
932 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930933}
934
Andrew Jeffery096685b2023-07-17 17:36:14 +0930935LIBPLDM_ABI_STABLE
Andrew Jeffery65945992023-07-17 15:04:21 +0930936int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
937 pldm_pdr *repo, bool is_remote,
938 uint16_t terminus_handle)
939{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930940 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930941 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930942 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930943
Andrew Jeffery65945992023-07-17 15:04:21 +0930944 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
945 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946}
947
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930948LIBPLDM_ABI_STABLE
Andrew Jefferycc394522023-07-03 12:49:31 +0930949int pldm_entity_association_pdr_add_from_node_check(
950 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
951 size_t num_entities, bool is_remote, uint16_t terminus_handle)
952{
953 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500954 node, repo, entities, num_entities, is_remote, terminus_handle,
955 0);
956}
957
Pavithra Barithaya3a267052023-11-13 05:01:36 -0600958LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500959int pldm_entity_association_pdr_add_from_node_with_record_handle(
960 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
961 size_t num_entities, bool is_remote, uint16_t terminus_handle,
962 uint32_t record_handle)
963{
964 if (!node || !repo || !entities) {
965 return -EINVAL;
966 }
967
Andrew Jeffery9c766792022-08-10 23:12:49 +0930968 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500969 is_remote, terminus_handle, record_handle);
970
971 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930972}
973
Andrew Jeffery643c4432023-07-17 15:36:03 +0930974static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
975 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930976{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600977 bool is_entity_container_id;
978 bool is_entity_instance_num;
979 bool is_type;
980
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981 if (tree_node == NULL) {
982 return;
983 }
984
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600985 is_type = tree_node->entity.entity_type == entity.entity_type;
986 is_entity_instance_num = tree_node->entity.entity_instance_num ==
987 entity.entity_instance_num;
988 is_entity_container_id = tree_node->entity.entity_container_id ==
989 entity.entity_container_id;
990
991 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930992 *node = tree_node;
993 return;
994 }
995
996 find_entity_ref_in_tree(tree_node->first_child, entity, node);
997 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
998}
999
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301000LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1002 pldm_entity entity, pldm_entity_node **node)
1003{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301004 if (!tree || !node) {
1005 return;
1006 }
1007
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008 find_entity_ref_in_tree(tree->root, entity, node);
1009}
1010
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301011LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301012void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1013 uint16_t terminus_handle)
1014{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301015 if (!repo) {
1016 return;
1017 }
1018
Andrew Jeffery9c766792022-08-10 23:12:49 +09301019 bool removed = false;
1020
1021 pldm_pdr_record *record = repo->first;
1022 pldm_pdr_record *prev = NULL;
1023 while (record != NULL) {
1024 pldm_pdr_record *next = record->next;
1025 if (record->terminus_handle == terminus_handle) {
1026 if (repo->first == record) {
1027 repo->first = next;
1028 } else {
1029 prev->next = next;
1030 }
1031 if (repo->last == record) {
1032 repo->last = prev;
1033 }
1034 if (record->data) {
1035 free(record->data);
1036 }
1037 --repo->record_count;
1038 repo->size -= record->size;
1039 free(record);
1040 removed = true;
1041 } else {
1042 prev = record;
1043 }
1044 record = next;
1045 }
1046
1047 if (removed == true) {
1048 record = repo->first;
1049 uint32_t record_handle = 0;
1050 while (record != NULL) {
1051 record->record_handle = ++record_handle;
1052 if (record->data != NULL) {
1053 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301054 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301055 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301056 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301057 }
1058 record = record->next;
1059 }
1060 }
1061}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301062
1063LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301064void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1065{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301066 if (!repo) {
1067 return;
1068 }
1069
Andrew Jeffery9c766792022-08-10 23:12:49 +09301070 bool removed = false;
1071
1072 pldm_pdr_record *record = repo->first;
1073 pldm_pdr_record *prev = NULL;
1074 while (record != NULL) {
1075 pldm_pdr_record *next = record->next;
1076 if (record->is_remote == true) {
1077 if (repo->first == record) {
1078 repo->first = next;
1079 } else {
1080 prev->next = next;
1081 }
1082 if (repo->last == record) {
1083 repo->last = prev;
1084 }
1085 if (record->data) {
1086 free(record->data);
1087 }
1088 --repo->record_count;
1089 repo->size -= record->size;
1090 free(record);
1091 removed = true;
1092 } else {
1093 prev = record;
1094 }
1095 record = next;
1096 }
1097
1098 if (removed == true) {
1099 record = repo->first;
1100 uint32_t record_handle = 0;
1101 while (record != NULL) {
1102 record->record_handle = ++record_handle;
1103 if (record->data != NULL) {
1104 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301105 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301107 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301108 }
1109 record = record->next;
1110 }
1111 }
1112}
1113
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001114LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001115pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1116 uint32_t first, uint32_t last)
1117{
1118 pldm_pdr_record *record = NULL;
1119 pldm_pdr_record *curr;
1120
1121 if (!repo) {
1122 return NULL;
1123 }
1124 for (curr = repo->first; curr; curr = curr->next) {
1125 if (first > curr->record_handle || last < curr->record_handle) {
1126 continue;
1127 }
1128 if (!record || curr->record_handle > record->record_handle) {
1129 record = curr;
1130 }
1131 }
1132
1133 return record;
1134}
1135
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001136static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1137 pldm_entity *entity,
1138 pldm_entity_node **out,
1139 bool is_remote)
1140{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001141 if (node == NULL) {
1142 return;
1143 }
1144 bool is_entity_type;
1145 bool is_entity_instance_num;
1146
1147 is_entity_type = node->entity.entity_type == entity->entity_type;
1148 is_entity_instance_num = node->entity.entity_instance_num ==
1149 entity->entity_instance_num;
1150
1151 if (!is_remote ||
1152 node->remote_container_id == entity->entity_container_id) {
1153 if (is_entity_type && is_entity_instance_num) {
1154 entity->entity_container_id =
1155 node->entity.entity_container_id;
1156 *out = node;
1157 return;
1158 }
1159 }
1160 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1161 is_remote);
1162 entity_association_tree_find_if_remote(node->first_child, entity, out,
1163 is_remote);
1164}
1165
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001166LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001167pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1168 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001169{
1170 if (!tree || !entity) {
1171 return NULL;
1172 }
1173 pldm_entity_node *node = NULL;
1174 entity_association_tree_find_if_remote(tree->root, entity, &node,
1175 is_remote);
1176 return node;
1177}
1178
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301179static void entity_association_tree_find(pldm_entity_node *node,
1180 pldm_entity *entity,
1181 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301182{
1183 if (node == NULL) {
1184 return;
1185 }
1186
1187 if (node->entity.entity_type == entity->entity_type &&
1188 node->entity.entity_instance_num == entity->entity_instance_num) {
1189 entity->entity_container_id = node->entity.entity_container_id;
1190 *out = node;
1191 return;
1192 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301193 entity_association_tree_find(node->next_sibling, entity, out);
1194 entity_association_tree_find(node->first_child, entity, out);
1195}
1196
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301197LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198pldm_entity_node *
1199pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1200 pldm_entity *entity)
1201{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301202 if (!tree || !entity) {
1203 return NULL;
1204 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301205
1206 pldm_entity_node *node = NULL;
1207 entity_association_tree_find(tree->root, entity, &node);
1208 return node;
1209}
1210
1211static void entity_association_tree_copy(pldm_entity_node *org_node,
1212 pldm_entity_node **new_node)
1213{
1214 if (org_node == NULL) {
1215 return;
1216 }
1217 *new_node = malloc(sizeof(pldm_entity_node));
1218 (*new_node)->parent = org_node->parent;
1219 (*new_node)->entity = org_node->entity;
1220 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001221 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222 (*new_node)->first_child = NULL;
1223 (*new_node)->next_sibling = NULL;
1224 entity_association_tree_copy(org_node->first_child,
1225 &((*new_node)->first_child));
1226 entity_association_tree_copy(org_node->next_sibling,
1227 &((*new_node)->next_sibling));
1228}
1229
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301230LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301231void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301232 pldm_entity_association_tree *org_tree,
1233 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301234{
George Liuc6c391d2023-11-09 10:13:34 +08001235 assert(org_tree != NULL);
1236 assert(new_tree != NULL);
1237
Andrew Jeffery9c766792022-08-10 23:12:49 +09301238 new_tree->last_used_container_id = org_tree->last_used_container_id;
1239 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1240}
1241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301243void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301244 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301245{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301246 if (!tree) {
1247 return;
1248 }
1249
Andrew Jeffery9c766792022-08-10 23:12:49 +09301250 entity_association_tree_destroy(tree->root);
1251 tree->last_used_container_id = 0;
1252 tree->root = NULL;
1253}
1254
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301255LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301256bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1257{
1258 return ((tree->root == NULL) ? true : false);
1259}
1260
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301261LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1263 size_t *num_entities,
1264 pldm_entity **entities)
1265{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301266 if (!pdr || !num_entities || !entities) {
1267 return;
1268 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001269 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301270 return;
1271 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301272
1273 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301274 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1275 return;
1276 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301277
1278 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301279 const uint8_t *end __attribute__((unused)) =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301280 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301281 start += sizeof(struct pldm_pdr_hdr);
1282 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301283 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301284 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301285 if (l_num_entities < 2) {
1286 return;
1287 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301288 if (start + sizeof(struct pldm_pdr_entity_association) +
1289 sizeof(pldm_entity) * (l_num_entities - 2) !=
1290 end) {
1291 return;
1292 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301293 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301294 if (!l_entities) {
1295 return;
1296 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301297 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301298 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301299 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301300 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301301 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301302 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301303 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301304 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1305 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1306 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301307 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301308 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301309 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301310 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301311
1312 *num_entities = l_num_entities;
1313 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301314}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001315
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301316/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001317 * the same position.
1318 */
1319static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1320 pldm_pdr_record *prev,
1321 pldm_pdr_record *new_record)
1322{
1323 assert(repo);
1324 assert(record);
1325 assert(prev);
1326 assert(new_record);
1327
1328 if (repo->size < record->size) {
1329 return -EOVERFLOW;
1330 }
1331
1332 if (repo->size + new_record->size < new_record->size) {
1333 return -EOVERFLOW;
1334 }
1335
1336 if (repo->first == record) {
1337 repo->first = new_record;
1338 } else {
1339 prev->next = new_record;
1340 }
1341 new_record->next = record->next;
1342
1343 if (repo->last == record) {
1344 repo->last = new_record;
1345 }
1346
1347 repo->size = (repo->size - record->size) + new_record->size;
1348 return 0;
1349}
1350
1351/* Insert a new record to pldm_pdr repo to a position that comes after
1352 * pldm_pdr_record record.
1353 */
1354static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1355 pldm_pdr_record *new_record)
1356{
1357 assert(repo);
1358 assert(record);
1359 assert(new_record);
1360
1361 if (repo->size + new_record->size < new_record->size) {
1362 return -EOVERFLOW;
1363 }
1364
1365 if (repo->record_count == UINT32_MAX) {
1366 return -EOVERFLOW;
1367 }
1368
1369 new_record->next = record->next;
1370 record->next = new_record;
1371
1372 if (repo->last == record) {
1373 repo->last = new_record;
1374 }
1375
1376 repo->size = repo->size + new_record->size;
1377 ++repo->record_count;
1378 return 0;
1379}
1380
1381/* Find the position of PDR when its record handle is known
1382 */
1383static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1384 pldm_pdr_record **prev,
1385 uint32_t record_handle)
1386{
1387 assert(record);
1388 assert(prev);
1389
1390 while (*record != NULL) {
1391 if ((*record)->record_handle == record_handle) {
1392 return true;
1393 }
1394 *prev = *record;
1395 *record = (*record)->next;
1396 }
1397 return false;
1398}
1399
1400LIBPLDM_ABI_TESTING
1401int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1402 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1403{
1404 if (!repo || !entity) {
1405 return -EINVAL;
1406 }
1407
1408 pldm_pdr_record *record = repo->first;
1409 pldm_pdr_record *prev = repo->first;
1410 int rc = 0;
1411 uint16_t header_length = 0;
1412 uint8_t num_children = 0;
1413 struct pldm_msgbuf _src;
1414 struct pldm_msgbuf *src = &_src;
1415 struct pldm_msgbuf _dst;
1416 struct pldm_msgbuf *dst = &_dst;
1417
1418 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1419
1420 if (!record) {
1421 return -EINVAL;
1422 }
1423 // Initialize msg buffer for record and record->data
1424 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1425 record->data, record->size);
1426 if (rc) {
1427 return rc;
1428 }
1429
1430 // check if adding another entity to record causes overflow before
1431 // allocating memory for new_record.
1432 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1433 return -EOVERFLOW;
1434 }
1435 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1436 if (!new_record) {
1437 return -ENOMEM;
1438 }
1439
1440 new_record->data = malloc(record->size + sizeof(pldm_entity));
1441 if (!new_record->data) {
1442 rc = -ENOMEM;
1443 goto cleanup_new_record;
1444 }
1445
1446 new_record->record_handle = record->record_handle;
1447 new_record->size = record->size + sizeof(struct pldm_entity);
1448 new_record->is_remote = record->is_remote;
1449
1450 // Initialize new PDR record with data from original PDR record.
1451 // Start with adding the header of original PDR
1452 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1453 new_record->data, new_record->size);
1454 if (rc) {
1455 goto cleanup_new_record_data;
1456 }
1457
1458 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1459 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1460 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1461 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1462 // extract the header length from record and increment size with
1463 // size of pldm_entity before inserting the value into new_record.
1464 rc = pldm_msgbuf_extract(src, header_length);
1465 if (rc) {
1466 goto cleanup_new_record_data;
1467 }
1468 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1469 "Fix the following bounds check.");
1470 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1471 rc = -EOVERFLOW;
1472 goto cleanup_new_record_data;
1473 }
1474 header_length += sizeof(pldm_entity);
1475 pldm_msgbuf_insert(dst, header_length);
1476 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1477 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1478 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1479 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1480 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1481 // extract value of number of children from record and increment it
1482 // by 1 before insert the value to new record.
1483 rc = pldm_msgbuf_extract(src, num_children);
1484 if (rc) {
1485 goto cleanup_new_record_data;
1486 }
1487 if (num_children == UINT8_MAX) {
1488 rc = -EOVERFLOW;
1489 goto cleanup_new_record_data;
1490 }
1491 num_children += 1;
1492 pldm_msgbuf_insert(dst, num_children);
1493 //Add all children of original PDR to new PDR
1494 for (int i = 0; i < num_children - 1; i++) {
1495 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1496 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1497 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1498 }
1499
1500 // Add new contained entity as a child of new PDR
1501 rc = pldm_msgbuf_destroy(src);
1502 if (rc) {
1503 goto cleanup_new_record_data;
1504 }
1505 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1506 sizeof(struct pldm_entity));
1507 if (rc) {
1508 goto cleanup_new_record_data;
1509 }
1510 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1511 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1512 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1513
1514 rc = pldm_msgbuf_destroy(src);
1515 if (rc) {
1516 goto cleanup_new_record_data;
1517 }
1518 rc = pldm_msgbuf_destroy(dst);
1519 if (rc) {
1520 goto cleanup_new_record_data;
1521 }
1522
1523 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1524 if (rc) {
1525 goto cleanup_new_record_data;
1526 }
1527
1528 free(record->data);
1529 free(record);
1530 return rc;
1531cleanup_new_record_data:
1532 free(new_record->data);
1533cleanup_new_record:
1534 free(new_record);
1535 return rc;
1536}
1537
1538LIBPLDM_ABI_TESTING
1539int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1540 uint32_t pdr_record_handle,
1541 pldm_entity *parent,
1542 pldm_entity *entity,
1543 uint32_t *entity_record_handle)
1544{
1545 if (!repo || !parent || !entity || !entity_record_handle) {
1546 return -EINVAL;
1547 }
1548
1549 if (pdr_record_handle == UINT32_MAX) {
1550 return -EOVERFLOW;
1551 }
1552
1553 bool pdr_added = false;
1554 uint16_t new_pdr_size;
1555 uint16_t container_id = 0;
1556 uint8_t *container_id_addr = NULL;
1557 struct pldm_msgbuf _dst;
1558 struct pldm_msgbuf *dst = &_dst;
1559 struct pldm_msgbuf _src_p;
1560 struct pldm_msgbuf *src_p = &_src_p;
1561 struct pldm_msgbuf _src_c;
1562 struct pldm_msgbuf *src_c = &_src_c;
1563 int rc = 0;
1564
1565 pldm_pdr_record *prev = repo->first;
1566 pldm_pdr_record *record = repo->first;
1567 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1568 pdr_record_handle);
1569 if (!pdr_added) {
1570 return -ENOENT;
1571 }
1572
1573 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1574 "Truncation ahead");
1575 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1576 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1577 if (!new_record) {
1578 return -ENOMEM;
1579 }
1580
1581 new_record->data = malloc(new_pdr_size);
1582 if (!new_record->data) {
1583 rc = -ENOMEM;
1584 goto cleanup_new_record;
1585 }
1586
1587 // Initialise new PDR to be added with the header, size and handle.
1588 // Set the position of new PDR
1589 *entity_record_handle = pdr_record_handle + 1;
1590 new_record->record_handle = *entity_record_handle;
1591 new_record->size = new_pdr_size;
1592 new_record->is_remote = false;
1593
1594 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1595 new_record->data, new_record->size);
1596 if (rc) {
1597 goto cleanup_new_record_data;
1598 }
1599
1600 // header record handle
1601 pldm_msgbuf_insert(dst, *entity_record_handle);
1602 // header version
1603 pldm_msgbuf_insert_uint8(dst, 1);
1604 // header type
1605 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1606 // header change number
1607 pldm_msgbuf_insert_uint16(dst, 0);
1608 // header length
1609 pldm_msgbuf_insert_uint16(dst,
1610 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1611
1612 // Data for new PDR is obtained from parent PDR and new contained entity
1613 // is added as the child
1614 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1615 sizeof(*parent));
1616 if (rc) {
1617 goto cleanup_new_record_data;
1618 }
1619
1620 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1621 sizeof(*entity));
1622 if (rc) {
1623 goto cleanup_new_record_data;
1624 }
1625
1626 // extract pointer for container ID and save the address
1627 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1628 (void **)&container_id_addr);
1629 if (rc) {
1630 goto cleanup_new_record_data;
1631 }
1632 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1633 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1634 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1635 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1636 // number of children
1637 pldm_msgbuf_insert_uint8(dst, 1);
1638
1639 // Add new entity as child
1640 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1641 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1642 // Extract and insert child entity container ID and add same value to
1643 // container ID of entity
1644 pldm_msgbuf_extract(src_c, container_id);
1645 pldm_msgbuf_insert(dst, container_id);
1646 container_id = htole16(container_id);
1647 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1648
1649 rc = pldm_msgbuf_destroy(dst);
1650 if (rc) {
1651 goto cleanup_new_record_data;
1652 }
1653 rc = pldm_msgbuf_destroy(src_p);
1654 if (rc) {
1655 goto cleanup_new_record_data;
1656 }
1657 rc = pldm_msgbuf_destroy(src_c);
1658 if (rc) {
1659 goto cleanup_new_record_data;
1660 }
1661
1662 rc = pldm_pdr_insert_record(repo, record, new_record);
1663 if (rc) {
1664 goto cleanup_new_record_data;
1665 }
1666
1667 return rc;
1668cleanup_new_record_data:
1669 free(new_record->data);
1670cleanup_new_record:
1671 free(new_record);
1672 return rc;
1673}