blob: 45f1d867bb6e876a8ac851204c2a64ab62d1709e [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery860a43d2024-08-23 01:21:58 +00002#include "compiler.h"
Varsha Kaverappa37552b92024-02-12 05:06:06 -06003#include "msgbuf.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10304#include <libpldm/pdr.h>
5#include <libpldm/platform.h>
6
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05308#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09309#include <stdlib.h>
10#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060011#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093012
Varsha Kaverappa37552b92024-02-12 05:06:06 -060013#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
14 (sizeof(struct pldm_pdr_hdr) + \
15 sizeof(struct pldm_pdr_entity_association))
16
Andrew Jeffery9c766792022-08-10 23:12:49 +093017typedef struct pldm_pdr_record {
18 uint32_t record_handle;
19 uint32_t size;
20 uint8_t *data;
21 struct pldm_pdr_record *next;
22 bool is_remote;
23 uint16_t terminus_handle;
24} pldm_pdr_record;
25
26typedef struct pldm_pdr {
27 uint32_t record_count;
28 uint32_t size;
29 pldm_pdr_record *first;
30 pldm_pdr_record *last;
31} pldm_pdr;
32
33static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
34 const pldm_pdr_record *record)
35{
36 assert(repo != NULL);
37 assert(record != NULL);
38
39 if (record == repo->last) {
40 return 0;
41 }
42 return record->next->record_handle;
43}
44
Andrew Jefferyca248ce2023-07-07 10:38:30 +093045LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000046int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
47 bool is_remote, uint16_t terminus_handle,
48 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093049{
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093050 uint32_t curr;
51
Andrew Jeffery3b93d092023-07-17 13:01:50 +093052 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093053 return -EINVAL;
54 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093055
Andrew Jeffery3b93d092023-07-17 13:01:50 +093056 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093057 curr = *record_handle;
58 } else if (repo->last) {
59 curr = repo->last->record_handle;
60 if (curr == UINT32_MAX) {
61 return -EOVERFLOW;
62 }
63 curr += 1;
64 } else {
65 curr = 1;
66 }
67
Andrew Jeffery9c766792022-08-10 23:12:49 +093068 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093069 if (!record) {
70 return -ENOMEM;
71 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093072
Andrew Jeffery572a3952023-07-03 13:19:28 +093073 if (data) {
74 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093075 if (!record->data) {
76 free(record);
77 return -ENOMEM;
78 }
79 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093080 }
81
Andrew Jeffery9c766792022-08-10 23:12:49 +093082 record->size = size;
83 record->is_remote = is_remote;
84 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093085 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093086
Andrew Jeffery3b93d092023-07-17 13:01:50 +093087 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093088 /* If record handle is 0, that is an indication for this API to
89 * compute a new handle. For that reason, the computed handle
90 * needs to be populated in the PDR header. For a case where the
91 * caller supplied the record handle, it would exist in the
92 * header already.
93 */
94 struct pldm_pdr_hdr *hdr = (void *)record->data;
95 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093096 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093097
Andrew Jeffery9c766792022-08-10 23:12:49 +093098 record->next = NULL;
99
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930100 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930101 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930102 repo->first = record;
103 repo->last = record;
104 } else {
105 repo->last->next = record;
106 repo->last = record;
107 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930108
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930109 repo->size += record->size;
110 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930111
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930112 if (record_handle) {
113 *record_handle = record->record_handle;
114 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930115
116 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930117}
118
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930119LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930120pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121{
122 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930123 if (!repo) {
124 return NULL;
125 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930126 repo->record_count = 0;
127 repo->size = 0;
128 repo->first = NULL;
129 repo->last = NULL;
130
131 return repo;
132}
133
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930134LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930135void pldm_pdr_destroy(pldm_pdr *repo)
136{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930137 if (!repo) {
138 return;
139 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930140
141 pldm_pdr_record *record = repo->first;
142 while (record != NULL) {
143 pldm_pdr_record *next = record->next;
144 if (record->data) {
145 free(record->data);
146 record->data = NULL;
147 }
148 free(record);
149 record = next;
150 }
151 free(repo);
152}
153
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930154LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930155const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
156 uint32_t record_handle,
157 uint8_t **data, uint32_t *size,
158 uint32_t *next_record_handle)
159{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930160 if (!repo || !data || !size || !next_record_handle) {
161 return NULL;
162 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930163
164 if (!record_handle && (repo->first != NULL)) {
165 record_handle = repo->first->record_handle;
166 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930167
Andrew Jeffery9c766792022-08-10 23:12:49 +0930168 pldm_pdr_record *record = repo->first;
169 while (record != NULL) {
170 if (record->record_handle == record_handle) {
171 *size = record->size;
172 *data = record->data;
173 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930174 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930175 return record;
176 }
177 record = record->next;
178 }
179
180 *size = 0;
181 *next_record_handle = 0;
182 return NULL;
183}
184
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930185LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930186const pldm_pdr_record *
187pldm_pdr_get_next_record(const pldm_pdr *repo,
188 const pldm_pdr_record *curr_record, uint8_t **data,
189 uint32_t *size, uint32_t *next_record_handle)
190{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930191 if (!repo || !curr_record || !data || !size || !next_record_handle) {
192 return NULL;
193 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930194
195 if (curr_record == repo->last) {
196 *data = NULL;
197 *size = 0;
198 *next_record_handle = get_next_record_handle(repo, curr_record);
199 return NULL;
200 }
201
202 *next_record_handle = get_next_record_handle(repo, curr_record->next);
203 *data = curr_record->next->data;
204 *size = curr_record->next->size;
205 return curr_record->next;
206}
207
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930208LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930209const pldm_pdr_record *
210pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
211 const pldm_pdr_record *curr_record, uint8_t **data,
212 uint32_t *size)
213{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930214 if (!repo) {
215 return NULL;
216 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930217
218 pldm_pdr_record *record = repo->first;
219 if (curr_record != NULL) {
220 record = curr_record->next;
221 }
222 while (record != NULL) {
223 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
224 if (hdr->type == pdr_type) {
225 if (data && size) {
226 *size = record->size;
227 *data = record->data;
228 }
229 return record;
230 }
231 record = record->next;
232 }
233
234 if (size) {
235 *size = 0;
236 }
237 return NULL;
238}
239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930241uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
242{
243 assert(repo != NULL);
244
245 return repo->record_count;
246}
247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930248LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930249uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
250{
251 assert(repo != NULL);
252
253 return repo->size;
254}
255
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930256LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000257uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_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
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000267uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530268 const pldm_pdr_record *record)
269{
270 assert(repo != NULL);
271 assert(record != NULL);
272
273 return record->terminus_handle;
274}
275
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930276LIBPLDM_ABI_STABLE
277bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930278{
279 assert(record != NULL);
280
281 return record->is_remote;
282}
283
Andrew Jefferya2c69112023-07-07 10:41:38 +0930284LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930285int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
286 uint16_t fru_rsi, uint16_t entity_type,
287 uint16_t entity_instance_num,
288 uint16_t container_id,
289 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930290{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930291 if (!repo || !bmc_record_handle) {
292 return -EINVAL;
293 }
294
Andrew Jeffery9c766792022-08-10 23:12:49 +0930295 uint32_t size = sizeof(struct pldm_pdr_hdr) +
296 sizeof(struct pldm_pdr_fru_record_set);
297 uint8_t data[size];
298
299 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
300 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930301 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302 hdr->type = PLDM_PDR_FRU_RECORD_SET;
303 hdr->record_change_num = 0;
304 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
305 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930306 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
307 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308 fru->terminus_handle = htole16(terminus_handle);
309 fru->fru_rsi = htole16(fru_rsi);
310 fru->entity_type = htole16(entity_type);
311 fru->entity_instance_num = htole16(entity_instance_num);
312 fru->container_id = htole16(container_id);
313
Andrew Jefferyfae36412024-06-20 06:35:51 +0000314 return pldm_pdr_add(repo, data, size, false, terminus_handle,
315 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316}
317
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930318LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930319const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
321 uint16_t *entity_type, uint16_t *entity_instance_num,
322 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930324 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
325 !container_id) {
326 return NULL;
327 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328
329 uint8_t *data = NULL;
330 uint32_t size = 0;
331 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930332 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333 while (curr_record != NULL) {
334 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930335 (struct pldm_pdr_fru_record_set
336 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 if (fru->fru_rsi == htole16(fru_rsi)) {
338 *terminus_handle = le16toh(fru->terminus_handle);
339 *entity_type = le16toh(fru->entity_type);
340 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 *container_id = le16toh(fru->container_id);
343 return curr_record;
344 }
345 data = NULL;
346 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930347 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
348 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349 }
350
351 *terminus_handle = 0;
352 *entity_type = 0;
353 *entity_instance_num = 0;
354 *container_id = 0;
355
356 return NULL;
357}
358
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930359LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930360/* NOLINTNEXTLINE(readability-identifier-naming) */
361void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
362 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930364 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 uint32_t size = 0;
366 const pldm_pdr_record *record;
367 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930368 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369
370 do {
371 if (record != NULL) {
372 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930375 (struct pldm_terminus_locator_type_mctp_eid *)
376 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 if (pdr->terminus_handle == terminus_handle &&
378 pdr->tid == tid && value->eid == tl_eid) {
379 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 break;
381 }
382 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930383 record = pldm_pdr_find_record_by_type(repo,
384 PLDM_TERMINUS_LOCATOR_PDR,
385 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930386 } while (record);
387}
388
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500389static bool pldm_record_handle_in_range(uint32_t record_handle,
390 uint32_t first_record_handle,
391 uint32_t last_record_handle)
392{
393 return record_handle >= first_record_handle &&
394 record_handle <= last_record_handle;
395}
396
397LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500398int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500399 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500400 uint8_t child_index, uint32_t range_exclude_start_handle,
401 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500402{
403 pldm_pdr_record *record;
404 if (!repo) {
405 return -EINVAL;
406 }
407
408 for (record = repo->first; record; record = record->next) {
409 bool is_container_entity_instance_number;
410 struct pldm_pdr_entity_association *pdr;
411 bool is_container_entity_type;
412 struct pldm_entity *child;
413 struct pldm_pdr_hdr *hdr;
414 bool in_range;
415
416 // pldm_pdr_add() takes only uint8_t* data as an argument.
417 // The expectation here is the pldm_pdr_hdr is the first field of the record data
418 hdr = (struct pldm_pdr_hdr *)record->data;
419 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
420 continue;
421 }
422 in_range = pldm_record_handle_in_range(
423 record->record_handle, range_exclude_start_handle,
424 range_exclude_end_handle);
425 if (in_range) {
426 continue;
427 }
428
429 // this cast is valid with respect to alignment because
430 // struct pldm_pdr_hdr is declared with __attribute__((packed))
431 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500432 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500433 continue;
434 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500435
436 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500437 is_container_entity_type = pdr->container.entity_type ==
438 entity_type;
439 is_container_entity_instance_number =
440 pdr->container.entity_instance_num == entity_instance;
441 if (is_container_entity_type &&
442 is_container_entity_instance_number) {
443 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500444 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500445 }
446 }
447 return -ENOKEY;
448}
449
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450typedef struct pldm_entity_association_tree {
451 pldm_entity_node *root;
452 uint16_t last_used_container_id;
453} pldm_entity_association_tree;
454
455typedef struct pldm_entity_node {
456 pldm_entity entity;
457 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600458 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459 pldm_entity_node *first_child;
460 pldm_entity_node *next_sibling;
461 uint8_t association_type;
462} pldm_entity_node;
463
464static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
465{
466 assert(tree != NULL);
467 assert(tree->last_used_container_id != UINT16_MAX);
468
469 return ++tree->last_used_container_id;
470}
471
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930472LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930473pldm_entity pldm_entity_extract(pldm_entity_node *node)
474{
475 assert(node != NULL);
476
477 return node->entity;
478}
479
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500480LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930481uint16_t
482pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600483{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930484 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600485
Andrew Jeffery15b88182023-06-30 13:29:17 +0930486 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600487}
488
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930489LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930490pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930491{
492 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930493 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930494 if (!tree) {
495 return NULL;
496 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930497 tree->root = NULL;
498 tree->last_used_container_id = 0;
499
500 return tree;
501}
502
503static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
504 uint16_t entity_type)
505{
506 assert(start != NULL);
507
508 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530509 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930510 */
511 while (start->next_sibling != NULL) {
512 uint16_t this_type = start->entity.entity_type;
513 pldm_entity_node *next = start->next_sibling;
514 if (this_type == entity_type &&
515 (this_type != next->entity.entity_type)) {
516 break;
517 }
518 start = start->next_sibling;
519 }
520
521 return start;
522}
523
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930524LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930525pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930526 pldm_entity_association_tree *tree, pldm_entity *entity,
527 uint16_t entity_instance_number, pldm_entity_node *parent,
528 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930529{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500530 return pldm_entity_association_tree_add_entity(tree, entity,
531 entity_instance_number,
532 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600533 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500534}
535
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500536LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500537pldm_entity_node *pldm_entity_association_tree_add_entity(
538 pldm_entity_association_tree *tree, pldm_entity *entity,
539 uint16_t entity_instance_number, pldm_entity_node *parent,
540 uint8_t association_type, bool is_remote, bool is_update_container_id,
541 uint16_t container_id)
542{
543 if ((!tree) || (!entity)) {
544 return NULL;
545 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930546
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600547 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 pldm_entity node;
549 node.entity_type = entity->entity_type;
550 node.entity_instance_num = entity_instance_number;
551 if (pldm_is_current_parent_child(parent, &node)) {
552 return NULL;
553 }
554 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500555 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
556 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
557 return NULL;
558 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930559 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500560 if (!node) {
561 return NULL;
562 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 node->first_child = NULL;
564 node->next_sibling = NULL;
565 node->parent.entity_type = 0;
566 node->parent.entity_instance_num = 0;
567 node->parent.entity_container_id = 0;
568 node->entity.entity_type = entity->entity_type;
569 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600570 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600572 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500574 if (parent != NULL) {
575 free(node);
576 return NULL;
577 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578 tree->root = node;
579 /* container_id 0 here indicates this is the top-most entry */
580 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600581 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930583 /* Ensure next_container_id() will yield a valid ID */
584 if (tree->last_used_container_id == UINT16_MAX) {
585 free(node);
586 return NULL;
587 }
588
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589 parent->first_child = node;
590 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500591
592 if (is_remote) {
593 node->remote_container_id = entity->entity_container_id;
594 }
595 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600596 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500597 node->entity.entity_container_id = container_id;
598 } else {
599 node->entity.entity_container_id =
600 next_container_id(tree);
601 }
602 } else {
603 node->entity.entity_container_id =
604 entity->entity_container_id;
605 }
606
607 if (!is_remote) {
608 node->remote_container_id =
609 node->entity.entity_container_id;
610 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930612 pldm_entity_node *start = parent == NULL ? tree->root :
613 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930615 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500616 if (!prev) {
617 free(node);
618 return NULL;
619 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 pldm_entity_node *next = prev->next_sibling;
621 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500622 if (prev->entity.entity_instance_num == UINT16_MAX) {
623 free(node);
624 return NULL;
625 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930626 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600627 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930628 entity_instance_number :
629 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930630 }
631 prev->next_sibling = node;
632 node->parent = prev->parent;
633 node->next_sibling = next;
634 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930635 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600636 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637 }
638 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500639 if (is_update_container_id) {
640 entity->entity_container_id = node->entity.entity_container_id;
641 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930642 return node;
643}
644
645static void get_num_nodes(pldm_entity_node *node, size_t *num)
646{
647 if (node == NULL) {
648 return;
649 }
650
651 ++(*num);
652 get_num_nodes(node->next_sibling, num);
653 get_num_nodes(node->first_child, num);
654}
655
656static void entity_association_tree_visit(pldm_entity_node *node,
657 pldm_entity *entities, size_t *index)
658{
659 if (node == NULL) {
660 return;
661 }
662
663 pldm_entity *entity = &entities[*index];
664 ++(*index);
665 entity->entity_type = node->entity.entity_type;
666 entity->entity_instance_num = node->entity.entity_instance_num;
667 entity->entity_container_id = node->entity.entity_container_id;
668
669 entity_association_tree_visit(node->next_sibling, entities, index);
670 entity_association_tree_visit(node->first_child, entities, index);
671}
672
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930673LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
675 pldm_entity **entities, size_t *size)
676{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930677 if (!tree || !entities || !size) {
678 return;
679 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680
681 *size = 0;
682 if (tree->root == NULL) {
683 return;
684 }
685
686 get_num_nodes(tree->root, size);
687 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930688 if (!entities) {
689 return;
690 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930691 size_t index = 0;
692 entity_association_tree_visit(tree->root, *entities, &index);
693}
694
695static void entity_association_tree_destroy(pldm_entity_node *node)
696{
697 if (node == NULL) {
698 return;
699 }
700
701 entity_association_tree_destroy(node->next_sibling);
702 entity_association_tree_destroy(node->first_child);
703 free(node);
704}
705
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930706LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
708{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930709 if (!tree) {
710 return;
711 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930712
713 entity_association_tree_destroy(tree->root);
714 free(tree);
715}
716
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930717LIBPLDM_ABI_STABLE
718bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930719{
720 assert(node != NULL);
721
722 return node->first_child != NULL;
723}
724
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930725LIBPLDM_ABI_STABLE
726pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930727{
728 assert(node != NULL);
729
730 return node->parent;
731}
732
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930733LIBPLDM_ABI_STABLE
734bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735{
736 assert(node != NULL);
737
738 if (node->parent.entity_type == 0 &&
739 node->parent.entity_instance_num == 0 &&
740 node->parent.entity_container_id == 0) {
741 return false;
742 }
743
744 return true;
745}
746
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930747LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
749 uint8_t association_type)
750{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930751 if (!node) {
752 return 0;
753 }
754
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930755 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
756 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
757 return 0;
758 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759
760 size_t count = 0;
761 pldm_entity_node *curr = node->first_child;
762 while (curr != NULL) {
763 if (curr->association_type == association_type) {
764 ++count;
765 }
766 curr = curr->next_sibling;
767 }
768
769 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930770 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771}
772
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930773LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930774bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
775{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930776 if (!parent || !node) {
777 return false;
778 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930779
780 pldm_entity_node *curr = parent->first_child;
781 while (curr != NULL) {
782 if (node->entity_type == curr->entity.entity_type &&
783 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930784 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930785 return true;
786 }
787 curr = curr->next_sibling;
788 }
789
790 return false;
791}
792
Andrew Jeffery65945992023-07-17 15:04:21 +0930793static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500794 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
795 uint8_t contained_count, uint8_t association_type, bool is_remote,
796 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930797{
798 uint8_t pdr[size];
799 uint8_t *start = pdr;
800
801 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
802 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600803 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
805 hdr->record_change_num = 0;
806 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
807 start += sizeof(struct pldm_pdr_hdr);
808
809 uint16_t *container_id = (uint16_t *)start;
810 *container_id = htole16(curr->first_child->entity.entity_container_id);
811 start += sizeof(uint16_t);
812 *start = association_type;
813 start += sizeof(uint8_t);
814
815 pldm_entity *entity = (pldm_entity *)start;
816 entity->entity_type = htole16(curr->entity.entity_type);
817 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
818 entity->entity_container_id = htole16(curr->entity.entity_container_id);
819 start += sizeof(pldm_entity);
820
821 *start = contained_count;
822 start += sizeof(uint8_t);
823
824 pldm_entity_node *node = curr->first_child;
825 while (node != NULL) {
826 if (node->association_type == association_type) {
827 pldm_entity *entity = (pldm_entity *)start;
828 entity->entity_type = htole16(node->entity.entity_type);
829 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930830 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930831 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930832 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930833 start += sizeof(pldm_entity);
834 }
835 node = node->next_sibling;
836 }
837
Andrew Jefferyfae36412024-06-20 06:35:51 +0000838 return pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
839 &record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930840}
841
Andrew Jeffery65945992023-07-17 15:04:21 +0930842static int entity_association_pdr_add_entry(pldm_entity_node *curr,
843 pldm_pdr *repo, bool is_remote,
844 uint16_t terminus_handle,
845 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930847 uint8_t num_logical_children = pldm_entity_get_num_children(
848 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
849 uint8_t num_physical_children = pldm_entity_get_num_children(
850 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930851 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930852
853 if (num_logical_children) {
854 uint16_t logical_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_logical_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, logical_pdr_size, num_logical_children,
861 PLDM_ENTITY_ASSOCIAION_LOGICAL, 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 }
867
868 if (num_physical_children) {
869 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930870 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
871 sizeof(uint8_t) + sizeof(pldm_entity) +
872 sizeof(uint8_t) +
873 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930874 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930875 curr, repo, physical_pdr_size, num_physical_children,
876 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500877 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930878 if (rc < 0) {
879 return rc;
880 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930881 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930882
883 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930884}
885
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930886static bool is_present(pldm_entity entity, pldm_entity **entities,
887 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930888{
889 if (entities == NULL || num_entities == 0) {
890 return true;
891 }
892 size_t i = 0;
893 while (i < num_entities) {
894 if ((*entities + i)->entity_type == entity.entity_type) {
895 return true;
896 }
897 i++;
898 }
899 return false;
900}
901
Andrew Jeffery65945992023-07-17 15:04:21 +0930902static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
903 pldm_entity **entities,
904 size_t num_entities, bool is_remote,
905 uint16_t terminus_handle,
906 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930907{
Andrew Jeffery65945992023-07-17 15:04:21 +0930908 int rc;
909
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930911 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930912 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930913
914 if (is_present(curr->entity, entities, num_entities)) {
915 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500916 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930917 if (rc) {
918 return rc;
919 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930920 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930921
922 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
923 num_entities, is_remote,
924 terminus_handle, record_handle);
925 if (rc) {
926 return rc;
927 }
928
929 return entity_association_pdr_add(curr->first_child, repo, entities,
930 num_entities, is_remote,
931 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930932}
933
Andrew Jeffery096685b2023-07-17 17:36:14 +0930934LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +0930935int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
936 pldm_pdr *repo, bool is_remote,
937 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +0930938{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930939 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930940 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930941 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942
Andrew Jeffery65945992023-07-17 15:04:21 +0930943 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
944 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930945}
946
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930947LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +0930948int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +0930949 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
950 size_t num_entities, bool is_remote, uint16_t terminus_handle)
951{
952 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500953 node, repo, entities, num_entities, is_remote, terminus_handle,
954 0);
955}
956
Pavithra Barithaya3a267052023-11-13 05:01:36 -0600957LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500958int pldm_entity_association_pdr_add_from_node_with_record_handle(
959 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
960 size_t num_entities, bool is_remote, uint16_t terminus_handle,
961 uint32_t record_handle)
962{
963 if (!node || !repo || !entities) {
964 return -EINVAL;
965 }
966
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500968 is_remote, terminus_handle, record_handle);
969
970 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930971}
972
Andrew Jeffery643c4432023-07-17 15:36:03 +0930973static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
974 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600976 bool is_entity_container_id;
977 bool is_entity_instance_num;
978 bool is_type;
979
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980 if (tree_node == NULL) {
981 return;
982 }
983
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600984 is_type = tree_node->entity.entity_type == entity.entity_type;
985 is_entity_instance_num = tree_node->entity.entity_instance_num ==
986 entity.entity_instance_num;
987 is_entity_container_id = tree_node->entity.entity_container_id ==
988 entity.entity_container_id;
989
990 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991 *node = tree_node;
992 return;
993 }
994
995 find_entity_ref_in_tree(tree_node->first_child, entity, node);
996 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
997}
998
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930999LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301000void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1001 pldm_entity entity, pldm_entity_node **node)
1002{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301003 if (!tree || !node) {
1004 return;
1005 }
1006
Andrew Jeffery9c766792022-08-10 23:12:49 +09301007 find_entity_ref_in_tree(tree->root, entity, node);
1008}
1009
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301010LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301011void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1012 uint16_t terminus_handle)
1013{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301014 if (!repo) {
1015 return;
1016 }
1017
Andrew Jeffery9c766792022-08-10 23:12:49 +09301018 bool removed = false;
1019
1020 pldm_pdr_record *record = repo->first;
1021 pldm_pdr_record *prev = NULL;
1022 while (record != NULL) {
1023 pldm_pdr_record *next = record->next;
1024 if (record->terminus_handle == terminus_handle) {
1025 if (repo->first == record) {
1026 repo->first = next;
1027 } else {
1028 prev->next = next;
1029 }
1030 if (repo->last == record) {
1031 repo->last = prev;
1032 }
1033 if (record->data) {
1034 free(record->data);
1035 }
1036 --repo->record_count;
1037 repo->size -= record->size;
1038 free(record);
1039 removed = true;
1040 } else {
1041 prev = record;
1042 }
1043 record = next;
1044 }
1045
1046 if (removed == true) {
1047 record = repo->first;
1048 uint32_t record_handle = 0;
1049 while (record != NULL) {
1050 record->record_handle = ++record_handle;
1051 if (record->data != NULL) {
1052 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301053 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301055 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301056 }
1057 record = record->next;
1058 }
1059 }
1060}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301061
1062LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1064{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301065 if (!repo) {
1066 return;
1067 }
1068
Andrew Jeffery9c766792022-08-10 23:12:49 +09301069 bool removed = false;
1070
1071 pldm_pdr_record *record = repo->first;
1072 pldm_pdr_record *prev = NULL;
1073 while (record != NULL) {
1074 pldm_pdr_record *next = record->next;
1075 if (record->is_remote == true) {
1076 if (repo->first == record) {
1077 repo->first = next;
1078 } else {
1079 prev->next = next;
1080 }
1081 if (repo->last == record) {
1082 repo->last = prev;
1083 }
1084 if (record->data) {
1085 free(record->data);
1086 }
1087 --repo->record_count;
1088 repo->size -= record->size;
1089 free(record);
1090 removed = true;
1091 } else {
1092 prev = record;
1093 }
1094 record = next;
1095 }
1096
1097 if (removed == true) {
1098 record = repo->first;
1099 uint32_t record_handle = 0;
1100 while (record != NULL) {
1101 record->record_handle = ++record_handle;
1102 if (record->data != NULL) {
1103 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301104 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301105 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301106 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301107 }
1108 record = record->next;
1109 }
1110 }
1111}
1112
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001113LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001114pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1115 uint32_t first, uint32_t last)
1116{
1117 pldm_pdr_record *record = NULL;
1118 pldm_pdr_record *curr;
1119
1120 if (!repo) {
1121 return NULL;
1122 }
1123 for (curr = repo->first; curr; curr = curr->next) {
1124 if (first > curr->record_handle || last < curr->record_handle) {
1125 continue;
1126 }
1127 if (!record || curr->record_handle > record->record_handle) {
1128 record = curr;
1129 }
1130 }
1131
1132 return record;
1133}
1134
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001135static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1136 pldm_entity *entity,
1137 pldm_entity_node **out,
1138 bool is_remote)
1139{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001140 if (node == NULL) {
1141 return;
1142 }
1143 bool is_entity_type;
1144 bool is_entity_instance_num;
1145
1146 is_entity_type = node->entity.entity_type == entity->entity_type;
1147 is_entity_instance_num = node->entity.entity_instance_num ==
1148 entity->entity_instance_num;
1149
1150 if (!is_remote ||
1151 node->remote_container_id == entity->entity_container_id) {
1152 if (is_entity_type && is_entity_instance_num) {
1153 entity->entity_container_id =
1154 node->entity.entity_container_id;
1155 *out = node;
1156 return;
1157 }
1158 }
1159 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1160 is_remote);
1161 entity_association_tree_find_if_remote(node->first_child, entity, out,
1162 is_remote);
1163}
1164
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001165LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001166pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1167 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001168{
1169 if (!tree || !entity) {
1170 return NULL;
1171 }
1172 pldm_entity_node *node = NULL;
1173 entity_association_tree_find_if_remote(tree->root, entity, &node,
1174 is_remote);
1175 return node;
1176}
1177
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301178static void entity_association_tree_find(pldm_entity_node *node,
1179 pldm_entity *entity,
1180 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301181{
1182 if (node == NULL) {
1183 return;
1184 }
1185
1186 if (node->entity.entity_type == entity->entity_type &&
1187 node->entity.entity_instance_num == entity->entity_instance_num) {
1188 entity->entity_container_id = node->entity.entity_container_id;
1189 *out = node;
1190 return;
1191 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301192 entity_association_tree_find(node->next_sibling, entity, out);
1193 entity_association_tree_find(node->first_child, entity, out);
1194}
1195
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301196LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301197pldm_entity_node *
1198pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1199 pldm_entity *entity)
1200{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301201 if (!tree || !entity) {
1202 return NULL;
1203 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301204
1205 pldm_entity_node *node = NULL;
1206 entity_association_tree_find(tree->root, entity, &node);
1207 return node;
1208}
1209
1210static void entity_association_tree_copy(pldm_entity_node *org_node,
1211 pldm_entity_node **new_node)
1212{
1213 if (org_node == NULL) {
1214 return;
1215 }
1216 *new_node = malloc(sizeof(pldm_entity_node));
1217 (*new_node)->parent = org_node->parent;
1218 (*new_node)->entity = org_node->entity;
1219 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001220 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221 (*new_node)->first_child = NULL;
1222 (*new_node)->next_sibling = NULL;
1223 entity_association_tree_copy(org_node->first_child,
1224 &((*new_node)->first_child));
1225 entity_association_tree_copy(org_node->next_sibling,
1226 &((*new_node)->next_sibling));
1227}
1228
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301229LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301231 pldm_entity_association_tree *org_tree,
1232 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233{
George Liuc6c391d2023-11-09 10:13:34 +08001234 assert(org_tree != NULL);
1235 assert(new_tree != NULL);
1236
Andrew Jeffery9c766792022-08-10 23:12:49 +09301237 new_tree->last_used_container_id = org_tree->last_used_container_id;
1238 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1239}
1240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301242void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301243 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301245 if (!tree) {
1246 return;
1247 }
1248
Andrew Jeffery9c766792022-08-10 23:12:49 +09301249 entity_association_tree_destroy(tree->root);
1250 tree->last_used_container_id = 0;
1251 tree->root = NULL;
1252}
1253
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301254LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301255bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1256{
1257 return ((tree->root == NULL) ? true : false);
1258}
1259
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301260LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301261void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1262 size_t *num_entities,
1263 pldm_entity **entities)
1264{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301265 if (!pdr || !num_entities || !entities) {
1266 return;
1267 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001268 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301269 return;
1270 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271
1272 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301273 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1274 return;
1275 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301276
1277 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery860a43d2024-08-23 01:21:58 +00001278 const uint8_t *end LIBPLDM_CC_UNUSED =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301279 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 start += sizeof(struct pldm_pdr_hdr);
1281 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301282 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301283 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301284 if (l_num_entities < 2) {
1285 return;
1286 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301287 if (start + sizeof(struct pldm_pdr_entity_association) +
1288 sizeof(pldm_entity) * (l_num_entities - 2) !=
1289 end) {
1290 return;
1291 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301292 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301293 if (!l_entities) {
1294 return;
1295 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301296 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301297 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301298 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301299 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301300 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301301 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301302 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301303 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1304 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1305 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301306 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301307 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301308 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301309 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301310
1311 *num_entities = l_num_entities;
1312 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001314
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301315/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001316 * the same position.
1317 */
1318static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1319 pldm_pdr_record *prev,
1320 pldm_pdr_record *new_record)
1321{
1322 assert(repo);
1323 assert(record);
1324 assert(prev);
1325 assert(new_record);
1326
1327 if (repo->size < record->size) {
1328 return -EOVERFLOW;
1329 }
1330
1331 if (repo->size + new_record->size < new_record->size) {
1332 return -EOVERFLOW;
1333 }
1334
1335 if (repo->first == record) {
1336 repo->first = new_record;
1337 } else {
1338 prev->next = new_record;
1339 }
1340 new_record->next = record->next;
1341
1342 if (repo->last == record) {
1343 repo->last = new_record;
1344 }
1345
1346 repo->size = (repo->size - record->size) + new_record->size;
1347 return 0;
1348}
1349
1350/* Insert a new record to pldm_pdr repo to a position that comes after
1351 * pldm_pdr_record record.
1352 */
1353static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1354 pldm_pdr_record *new_record)
1355{
1356 assert(repo);
1357 assert(record);
1358 assert(new_record);
1359
1360 if (repo->size + new_record->size < new_record->size) {
1361 return -EOVERFLOW;
1362 }
1363
1364 if (repo->record_count == UINT32_MAX) {
1365 return -EOVERFLOW;
1366 }
1367
1368 new_record->next = record->next;
1369 record->next = new_record;
1370
1371 if (repo->last == record) {
1372 repo->last = new_record;
1373 }
1374
1375 repo->size = repo->size + new_record->size;
1376 ++repo->record_count;
1377 return 0;
1378}
1379
1380/* Find the position of PDR when its record handle is known
1381 */
1382static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1383 pldm_pdr_record **prev,
1384 uint32_t record_handle)
1385{
1386 assert(record);
1387 assert(prev);
1388
1389 while (*record != NULL) {
1390 if ((*record)->record_handle == record_handle) {
1391 return true;
1392 }
1393 *prev = *record;
1394 *record = (*record)->next;
1395 }
1396 return false;
1397}
1398
1399LIBPLDM_ABI_TESTING
1400int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1401 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1402{
1403 if (!repo || !entity) {
1404 return -EINVAL;
1405 }
1406
1407 pldm_pdr_record *record = repo->first;
1408 pldm_pdr_record *prev = repo->first;
1409 int rc = 0;
1410 uint16_t header_length = 0;
1411 uint8_t num_children = 0;
1412 struct pldm_msgbuf _src;
1413 struct pldm_msgbuf *src = &_src;
1414 struct pldm_msgbuf _dst;
1415 struct pldm_msgbuf *dst = &_dst;
1416
1417 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1418
1419 if (!record) {
1420 return -EINVAL;
1421 }
1422 // Initialize msg buffer for record and record->data
1423 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1424 record->data, record->size);
1425 if (rc) {
1426 return rc;
1427 }
1428
1429 // check if adding another entity to record causes overflow before
1430 // allocating memory for new_record.
1431 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1432 return -EOVERFLOW;
1433 }
1434 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1435 if (!new_record) {
1436 return -ENOMEM;
1437 }
1438
1439 new_record->data = malloc(record->size + sizeof(pldm_entity));
1440 if (!new_record->data) {
1441 rc = -ENOMEM;
1442 goto cleanup_new_record;
1443 }
1444
1445 new_record->record_handle = record->record_handle;
1446 new_record->size = record->size + sizeof(struct pldm_entity);
1447 new_record->is_remote = record->is_remote;
1448
1449 // Initialize new PDR record with data from original PDR record.
1450 // Start with adding the header of original PDR
1451 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1452 new_record->data, new_record->size);
1453 if (rc) {
1454 goto cleanup_new_record_data;
1455 }
1456
1457 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1458 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1459 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1460 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1461 // extract the header length from record and increment size with
1462 // size of pldm_entity before inserting the value into new_record.
1463 rc = pldm_msgbuf_extract(src, header_length);
1464 if (rc) {
1465 goto cleanup_new_record_data;
1466 }
1467 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1468 "Fix the following bounds check.");
1469 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1470 rc = -EOVERFLOW;
1471 goto cleanup_new_record_data;
1472 }
1473 header_length += sizeof(pldm_entity);
1474 pldm_msgbuf_insert(dst, header_length);
1475 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1476 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1477 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1478 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1479 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1480 // extract value of number of children from record and increment it
1481 // by 1 before insert the value to new record.
1482 rc = pldm_msgbuf_extract(src, num_children);
1483 if (rc) {
1484 goto cleanup_new_record_data;
1485 }
1486 if (num_children == UINT8_MAX) {
1487 rc = -EOVERFLOW;
1488 goto cleanup_new_record_data;
1489 }
1490 num_children += 1;
1491 pldm_msgbuf_insert(dst, num_children);
1492 //Add all children of original PDR to new PDR
1493 for (int i = 0; i < num_children - 1; i++) {
1494 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1495 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1496 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1497 }
1498
1499 // Add new contained entity as a child of new PDR
1500 rc = pldm_msgbuf_destroy(src);
1501 if (rc) {
1502 goto cleanup_new_record_data;
1503 }
1504 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1505 sizeof(struct pldm_entity));
1506 if (rc) {
1507 goto cleanup_new_record_data;
1508 }
1509 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1510 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1511 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1512
1513 rc = pldm_msgbuf_destroy(src);
1514 if (rc) {
1515 goto cleanup_new_record_data;
1516 }
1517 rc = pldm_msgbuf_destroy(dst);
1518 if (rc) {
1519 goto cleanup_new_record_data;
1520 }
1521
1522 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1523 if (rc) {
1524 goto cleanup_new_record_data;
1525 }
1526
1527 free(record->data);
1528 free(record);
1529 return rc;
1530cleanup_new_record_data:
1531 free(new_record->data);
1532cleanup_new_record:
1533 free(new_record);
1534 return rc;
1535}
1536
1537LIBPLDM_ABI_TESTING
1538int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1539 uint32_t pdr_record_handle,
1540 pldm_entity *parent,
1541 pldm_entity *entity,
1542 uint32_t *entity_record_handle)
1543{
1544 if (!repo || !parent || !entity || !entity_record_handle) {
1545 return -EINVAL;
1546 }
1547
1548 if (pdr_record_handle == UINT32_MAX) {
1549 return -EOVERFLOW;
1550 }
1551
1552 bool pdr_added = false;
1553 uint16_t new_pdr_size;
1554 uint16_t container_id = 0;
1555 uint8_t *container_id_addr = NULL;
1556 struct pldm_msgbuf _dst;
1557 struct pldm_msgbuf *dst = &_dst;
1558 struct pldm_msgbuf _src_p;
1559 struct pldm_msgbuf *src_p = &_src_p;
1560 struct pldm_msgbuf _src_c;
1561 struct pldm_msgbuf *src_c = &_src_c;
1562 int rc = 0;
1563
1564 pldm_pdr_record *prev = repo->first;
1565 pldm_pdr_record *record = repo->first;
1566 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1567 pdr_record_handle);
1568 if (!pdr_added) {
1569 return -ENOENT;
1570 }
1571
1572 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1573 "Truncation ahead");
1574 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1575 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1576 if (!new_record) {
1577 return -ENOMEM;
1578 }
1579
1580 new_record->data = malloc(new_pdr_size);
1581 if (!new_record->data) {
1582 rc = -ENOMEM;
1583 goto cleanup_new_record;
1584 }
1585
1586 // Initialise new PDR to be added with the header, size and handle.
1587 // Set the position of new PDR
1588 *entity_record_handle = pdr_record_handle + 1;
1589 new_record->record_handle = *entity_record_handle;
1590 new_record->size = new_pdr_size;
1591 new_record->is_remote = false;
1592
1593 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1594 new_record->data, new_record->size);
1595 if (rc) {
1596 goto cleanup_new_record_data;
1597 }
1598
1599 // header record handle
1600 pldm_msgbuf_insert(dst, *entity_record_handle);
1601 // header version
1602 pldm_msgbuf_insert_uint8(dst, 1);
1603 // header type
1604 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1605 // header change number
1606 pldm_msgbuf_insert_uint16(dst, 0);
1607 // header length
1608 pldm_msgbuf_insert_uint16(dst,
1609 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1610
1611 // Data for new PDR is obtained from parent PDR and new contained entity
1612 // is added as the child
1613 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1614 sizeof(*parent));
1615 if (rc) {
1616 goto cleanup_new_record_data;
1617 }
1618
1619 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1620 sizeof(*entity));
1621 if (rc) {
1622 goto cleanup_new_record_data;
1623 }
1624
1625 // extract pointer for container ID and save the address
1626 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1627 (void **)&container_id_addr);
1628 if (rc) {
1629 goto cleanup_new_record_data;
1630 }
1631 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1632 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1633 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1634 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1635 // number of children
1636 pldm_msgbuf_insert_uint8(dst, 1);
1637
1638 // Add new entity as child
1639 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1640 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1641 // Extract and insert child entity container ID and add same value to
1642 // container ID of entity
1643 pldm_msgbuf_extract(src_c, container_id);
1644 pldm_msgbuf_insert(dst, container_id);
1645 container_id = htole16(container_id);
1646 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1647
1648 rc = pldm_msgbuf_destroy(dst);
1649 if (rc) {
1650 goto cleanup_new_record_data;
1651 }
1652 rc = pldm_msgbuf_destroy(src_p);
1653 if (rc) {
1654 goto cleanup_new_record_data;
1655 }
1656 rc = pldm_msgbuf_destroy(src_c);
1657 if (rc) {
1658 goto cleanup_new_record_data;
1659 }
1660
1661 rc = pldm_pdr_insert_record(repo, record, new_record);
1662 if (rc) {
1663 goto cleanup_new_record_data;
1664 }
1665
1666 return rc;
1667cleanup_new_record_data:
1668 free(new_record->data);
1669cleanup_new_record:
1670 free(new_record);
1671 return rc;
1672}