blob: e549fbbcbd9b474aed888cc5000b0d6c1fb8d575 [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 Jeffery9e566592024-10-02 16:38:51 +09309#include <stdint.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010#include <stdlib.h>
11#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060012#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093013
Varsha Kaverappa37552b92024-02-12 05:06:06 -060014#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
15 (sizeof(struct pldm_pdr_hdr) + \
16 sizeof(struct pldm_pdr_entity_association))
17
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050018#define PDR_FRU_RECORD_SET_MIN_SIZE \
19 (sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
20
Andrew Jeffery9c766792022-08-10 23:12:49 +093021typedef struct pldm_pdr_record {
22 uint32_t record_handle;
23 uint32_t size;
24 uint8_t *data;
25 struct pldm_pdr_record *next;
26 bool is_remote;
27 uint16_t terminus_handle;
28} pldm_pdr_record;
29
30typedef struct pldm_pdr {
31 uint32_t record_count;
32 uint32_t size;
33 pldm_pdr_record *first;
34 pldm_pdr_record *last;
35} pldm_pdr;
36
Andrew Jeffery890d37a2024-09-22 20:50:53 +093037LIBPLDM_CC_NONNULL
Archana Kakani94e2d752024-12-12 08:22:55 -060038static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
39 pldm_pdr_record *record);
40
41LIBPLDM_CC_NONNULL_ARGS(1, 2)
42static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
43 pldm_pdr_record *prev);
44
45LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +093046static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
47 const pldm_pdr_record *record)
48{
Andrew Jeffery9c766792022-08-10 23:12:49 +093049 if (record == repo->last) {
50 return 0;
51 }
52 return record->next->record_handle;
53}
54
Andrew Jefferyca248ce2023-07-07 10:38:30 +093055LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000056int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
57 bool is_remote, uint16_t terminus_handle,
58 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093059{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050060 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093061
Andrew Jeffery3b93d092023-07-17 13:01:50 +093062 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093063 return -EINVAL;
64 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093065
Andrew Jeffery3b93d092023-07-17 13:01:50 +093066 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093067 curr = *record_handle;
68 } else if (repo->last) {
69 curr = repo->last->record_handle;
70 if (curr == UINT32_MAX) {
71 return -EOVERFLOW;
72 }
73 curr += 1;
74 } else {
75 curr = 1;
76 }
77
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093079 if (!record) {
80 return -ENOMEM;
81 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093082
Andrew Jeffery572a3952023-07-03 13:19:28 +093083 if (data) {
84 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093085 if (!record->data) {
86 free(record);
87 return -ENOMEM;
88 }
89 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093090 }
91
Andrew Jeffery9c766792022-08-10 23:12:49 +093092 record->size = size;
93 record->is_remote = is_remote;
94 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093095 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093096
Andrew Jeffery3b93d092023-07-17 13:01:50 +093097 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093098 /* If record handle is 0, that is an indication for this API to
99 * compute a new handle. For that reason, the computed handle
100 * needs to be populated in the PDR header. For a case where the
101 * caller supplied the record handle, it would exist in the
102 * header already.
103 */
104 struct pldm_pdr_hdr *hdr = (void *)record->data;
105 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930106 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930107
Andrew Jeffery9c766792022-08-10 23:12:49 +0930108 record->next = NULL;
109
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930110 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930111 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930112 repo->first = record;
113 repo->last = record;
114 } else {
115 repo->last->next = record;
116 repo->last = record;
117 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930119 repo->size += record->size;
120 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930122 if (record_handle) {
123 *record_handle = record->record_handle;
124 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930125
126 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930130pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930131{
132 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930133 if (!repo) {
134 return NULL;
135 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136 repo->record_count = 0;
137 repo->size = 0;
138 repo->first = NULL;
139 repo->last = NULL;
140
141 return repo;
142}
143
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930144LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145void pldm_pdr_destroy(pldm_pdr *repo)
146{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930147 if (!repo) {
148 return;
149 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150
151 pldm_pdr_record *record = repo->first;
152 while (record != NULL) {
153 pldm_pdr_record *next = record->next;
154 if (record->data) {
155 free(record->data);
156 record->data = NULL;
157 }
158 free(record);
159 record = next;
160 }
161 free(repo);
162}
163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
166 uint32_t record_handle,
167 uint8_t **data, uint32_t *size,
168 uint32_t *next_record_handle)
169{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930170 if (!repo || !data || !size || !next_record_handle) {
171 return NULL;
172 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173
174 if (!record_handle && (repo->first != NULL)) {
175 record_handle = repo->first->record_handle;
176 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930177
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178 pldm_pdr_record *record = repo->first;
179 while (record != NULL) {
180 if (record->record_handle == record_handle) {
181 *size = record->size;
182 *data = record->data;
183 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930184 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185 return record;
186 }
187 record = record->next;
188 }
189
190 *size = 0;
191 *next_record_handle = 0;
192 return NULL;
193}
194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196const pldm_pdr_record *
197pldm_pdr_get_next_record(const pldm_pdr *repo,
198 const pldm_pdr_record *curr_record, uint8_t **data,
199 uint32_t *size, uint32_t *next_record_handle)
200{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930201 if (!repo || !curr_record || !data || !size || !next_record_handle) {
202 return NULL;
203 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204
205 if (curr_record == repo->last) {
206 *data = NULL;
207 *size = 0;
208 *next_record_handle = get_next_record_handle(repo, curr_record);
209 return NULL;
210 }
211
212 *next_record_handle = get_next_record_handle(repo, curr_record->next);
213 *data = curr_record->next->data;
214 *size = curr_record->next->size;
215 return curr_record->next;
216}
217
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930218LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219const pldm_pdr_record *
220pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
221 const pldm_pdr_record *curr_record, uint8_t **data,
222 uint32_t *size)
223{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930224 if (!repo) {
225 return NULL;
226 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930227
228 pldm_pdr_record *record = repo->first;
229 if (curr_record != NULL) {
230 record = curr_record->next;
231 }
232 while (record != NULL) {
233 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
234 if (hdr->type == pdr_type) {
235 if (data && size) {
236 *size = record->size;
237 *data = record->data;
238 }
239 return record;
240 }
241 record = record->next;
242 }
243
244 if (size) {
245 *size = 0;
246 }
247 return NULL;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
252{
253 assert(repo != NULL);
254
255 return repo->record_count;
256}
257
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930258LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
260{
261 assert(repo != NULL);
262
263 return repo->size;
264}
265
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000267uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268 const pldm_pdr_record *record)
269{
270 assert(repo != NULL);
271 assert(record != NULL);
272
273 return record->record_handle;
274}
275
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530276LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000277uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530278 const pldm_pdr_record *record)
279{
280 assert(repo != NULL);
281 assert(record != NULL);
282
283 return record->terminus_handle;
284}
285
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930286LIBPLDM_ABI_STABLE
287bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288{
289 assert(record != NULL);
290
291 return record->is_remote;
292}
293
Andrew Jefferya2c69112023-07-07 10:41:38 +0930294LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930295int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
296 uint16_t fru_rsi, uint16_t entity_type,
297 uint16_t entity_instance_num,
298 uint16_t container_id,
299 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930300{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930301 if (!repo || !bmc_record_handle) {
302 return -EINVAL;
303 }
304
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930305 uint8_t data[sizeof(struct pldm_pdr_hdr) +
306 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307
308 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
309 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930310 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311 hdr->type = PLDM_PDR_FRU_RECORD_SET;
312 hdr->record_change_num = 0;
313 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
314 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
316 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 fru->terminus_handle = htole16(terminus_handle);
318 fru->fru_rsi = htole16(fru_rsi);
319 fru->entity_type = htole16(entity_type);
320 fru->entity_instance_num = htole16(entity_instance_num);
321 fru->container_id = htole16(container_id);
322
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930323 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000324 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325}
326
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930327LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930329 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
330 uint16_t *entity_type, uint16_t *entity_instance_num,
331 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930333 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
334 !container_id) {
335 return NULL;
336 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337
338 uint8_t *data = NULL;
339 uint32_t size = 0;
340 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 while (curr_record != NULL) {
343 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344 (struct pldm_pdr_fru_record_set
345 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346 if (fru->fru_rsi == htole16(fru_rsi)) {
347 *terminus_handle = le16toh(fru->terminus_handle);
348 *entity_type = le16toh(fru->entity_type);
349 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930350 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 *container_id = le16toh(fru->container_id);
352 return curr_record;
353 }
354 data = NULL;
355 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930356 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
357 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930358 }
359
360 *terminus_handle = 0;
361 *entity_type = 0;
362 *entity_instance_num = 0;
363 *container_id = 0;
364
365 return NULL;
366}
367
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930368LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369/* NOLINTNEXTLINE(readability-identifier-naming) */
370void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
371 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930373 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 uint32_t size = 0;
375 const pldm_pdr_record *record;
376 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378
379 do {
380 if (record != NULL) {
381 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930382 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930384 (struct pldm_terminus_locator_type_mctp_eid *)
385 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930386 if (pdr->terminus_handle == terminus_handle &&
387 pdr->tid == tid && value->eid == tl_eid) {
388 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389 break;
390 }
391 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930392 record = pldm_pdr_find_record_by_type(repo,
393 PLDM_TERMINUS_LOCATOR_PDR,
394 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930395 } while (record);
396}
397
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500398static bool pldm_record_handle_in_range(uint32_t record_handle,
399 uint32_t first_record_handle,
400 uint32_t last_record_handle)
401{
402 return record_handle >= first_record_handle &&
403 record_handle <= last_record_handle;
404}
405
406LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500407int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500408 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500409 uint8_t child_index, uint32_t range_exclude_start_handle,
410 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500411{
412 pldm_pdr_record *record;
413 if (!repo) {
414 return -EINVAL;
415 }
416
417 for (record = repo->first; record; record = record->next) {
418 bool is_container_entity_instance_number;
419 struct pldm_pdr_entity_association *pdr;
420 bool is_container_entity_type;
421 struct pldm_entity *child;
422 struct pldm_pdr_hdr *hdr;
423 bool in_range;
424
425 // pldm_pdr_add() takes only uint8_t* data as an argument.
426 // The expectation here is the pldm_pdr_hdr is the first field of the record data
427 hdr = (struct pldm_pdr_hdr *)record->data;
428 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
429 continue;
430 }
431 in_range = pldm_record_handle_in_range(
432 record->record_handle, range_exclude_start_handle,
433 range_exclude_end_handle);
434 if (in_range) {
435 continue;
436 }
437
438 // this cast is valid with respect to alignment because
439 // struct pldm_pdr_hdr is declared with __attribute__((packed))
440 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500441 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500442 continue;
443 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500444
445 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500446 is_container_entity_type = pdr->container.entity_type ==
447 entity_type;
448 is_container_entity_instance_number =
449 pdr->container.entity_instance_num == entity_instance;
450 if (is_container_entity_type &&
451 is_container_entity_instance_number) {
452 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500453 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500454 }
455 }
Matt Johnstonae05d5e2024-10-11 14:51:12 +0800456 return -ENOENT;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500457}
458
Pavithra Barithaya8cfeb472025-02-25 10:43:34 +0530459LIBPLDM_CC_NONNULL
460static int decode_pldm_state_effecter_pdr(uint8_t *data, uint32_t size,
461 struct pldm_state_effecter_pdr *pdr)
462{
463 PLDM_MSGBUF_DEFINE_P(buf);
464 int rc = 0;
465 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_effecter_pdr),
466 (uint8_t *)data, size);
467 if (rc) {
468 return rc;
469 }
470
471 pldm_msgbuf_extract(buf, pdr->hdr.record_handle);
472 pldm_msgbuf_extract(buf, pdr->hdr.version);
473 pldm_msgbuf_extract(buf, pdr->hdr.type);
474 pldm_msgbuf_extract(buf, pdr->hdr.record_change_num);
475 pldm_msgbuf_extract(buf, pdr->hdr.length);
476 pldm_msgbuf_extract(buf, pdr->terminus_handle);
477 pldm_msgbuf_extract(buf, pdr->effecter_id);
478 pldm_msgbuf_extract(buf, pdr->entity_type);
479 pldm_msgbuf_extract(buf, pdr->entity_instance);
480 pldm_msgbuf_extract(buf, pdr->container_id);
481 pldm_msgbuf_extract(buf, pdr->effecter_semantic_id);
482 pldm_msgbuf_extract(buf, pdr->effecter_init);
483 pldm_msgbuf_extract(buf, pdr->has_description_pdr);
484 pldm_msgbuf_extract(buf, pdr->composite_effecter_count);
485
486 return pldm_msgbuf_complete(buf);
487}
488
489LIBPLDM_ABI_TESTING
490int pldm_pdr_delete_by_effecter_id(pldm_pdr *repo, uint16_t effecter_id,
491 bool is_remote, uint32_t *record_handle)
492{
493 pldm_pdr_record *record;
494 pldm_pdr_record *prev = NULL;
495 int rc = 0;
496 int found;
497 struct pldm_state_effecter_pdr pdr;
498
499 if (!repo) {
500 return -EINVAL;
501 }
502 record = repo->first;
503
504 while (record != NULL) {
505 if (!record->data) {
506 continue;
507 }
508
509 rc = decode_pldm_state_effecter_pdr(record->data, record->size,
510 &pdr);
511 if (rc) {
512 return rc;
513 }
514
515 if (record->is_remote != is_remote ||
516 pdr.hdr.type != PLDM_STATE_EFFECTER_PDR) {
517 record = record->next;
518 continue;
519 }
520 found = pdr.effecter_id == effecter_id;
521 if (found) {
522 if (record_handle) {
523 *record_handle = record->record_handle;
524 }
525 prev = pldm_pdr_get_prev_record(repo, record);
526 return pldm_pdr_remove_record(repo, record, prev);
527 }
528 record = record->next;
529 }
530 return rc;
531}
532
Pavithra Barithaya869c2872025-04-30 14:32:18 +0530533LIBPLDM_ABI_STABLE
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530534int pldm_pdr_delete_by_record_handle(pldm_pdr *repo, uint32_t record_handle,
535 bool is_remote)
536{
537 pldm_pdr_record *record;
538 pldm_pdr_record *prev = NULL;
539 int rc = 0;
540 uint16_t rec_handle = 0;
541
542 if (!repo) {
543 return -EINVAL;
544 }
545 record = repo->first;
546
547 while (record != NULL) {
548 struct pldm_msgbuf _buf;
549 struct pldm_msgbuf *buf = &_buf;
550 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
551 record->data, record->size);
552
553 if (rc) {
554 return rc;
555 }
556 if ((rc = pldm_msgbuf_extract(buf, rec_handle))) {
557 return rc;
558 }
559 if (record->is_remote == is_remote &&
560 rec_handle == record_handle) {
561 prev = pldm_pdr_get_prev_record(repo, record);
562 return pldm_pdr_remove_record(repo, record, prev);
563 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030564 rc = pldm_msgbuf_complete(buf);
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530565 if (rc) {
566 return rc;
567 }
568 record = record->next;
569 }
570 return -ENOENT;
571}
572
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573typedef struct pldm_entity_association_tree {
574 pldm_entity_node *root;
575 uint16_t last_used_container_id;
576} pldm_entity_association_tree;
577
578typedef struct pldm_entity_node {
579 pldm_entity entity;
580 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600581 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582 pldm_entity_node *first_child;
583 pldm_entity_node *next_sibling;
584 uint8_t association_type;
585} pldm_entity_node;
586
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930587LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588pldm_entity pldm_entity_extract(pldm_entity_node *node)
589{
590 assert(node != NULL);
591
592 return node->entity;
593}
594
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500595LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930596uint16_t
597pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600598{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930599 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600600
Andrew Jeffery15b88182023-06-30 13:29:17 +0930601 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600602}
603
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930604LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930605pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606{
607 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930608 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930609 if (!tree) {
610 return NULL;
611 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930612 tree->root = NULL;
613 tree->last_used_container_id = 0;
614
615 return tree;
616}
617
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930618LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930619static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
620 uint16_t entity_type)
621{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530623 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624 */
625 while (start->next_sibling != NULL) {
626 uint16_t this_type = start->entity.entity_type;
627 pldm_entity_node *next = start->next_sibling;
628 if (this_type == entity_type &&
629 (this_type != next->entity.entity_type)) {
630 break;
631 }
632 start = start->next_sibling;
633 }
634
635 return start;
636}
637
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930638LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930639pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930640 pldm_entity_association_tree *tree, pldm_entity *entity,
641 uint16_t entity_instance_number, pldm_entity_node *parent,
642 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930643{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500644 return pldm_entity_association_tree_add_entity(tree, entity,
645 entity_instance_number,
646 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600647 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500648}
649
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500650LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500651pldm_entity_node *pldm_entity_association_tree_add_entity(
652 pldm_entity_association_tree *tree, pldm_entity *entity,
653 uint16_t entity_instance_number, pldm_entity_node *parent,
654 uint8_t association_type, bool is_remote, bool is_update_container_id,
655 uint16_t container_id)
656{
657 if ((!tree) || (!entity)) {
658 return NULL;
659 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930660
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600661 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930662 pldm_entity node;
663 node.entity_type = entity->entity_type;
664 node.entity_instance_num = entity_instance_number;
665 if (pldm_is_current_parent_child(parent, &node)) {
666 return NULL;
667 }
668 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500669 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
670 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
671 return NULL;
672 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500674 if (!node) {
675 return NULL;
676 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677 node->first_child = NULL;
678 node->next_sibling = NULL;
679 node->parent.entity_type = 0;
680 node->parent.entity_instance_num = 0;
681 node->parent.entity_container_id = 0;
682 node->entity.entity_type = entity->entity_type;
683 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600684 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600686 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500688 if (parent != NULL) {
689 free(node);
690 return NULL;
691 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930692 tree->root = node;
693 /* container_id 0 here indicates this is the top-most entry */
694 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600695 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930697 /* Ensure next_container_id() will yield a valid ID */
698 if (tree->last_used_container_id == UINT16_MAX) {
699 free(node);
700 return NULL;
701 }
702
Andrew Jeffery9c766792022-08-10 23:12:49 +0930703 parent->first_child = node;
704 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500705
706 if (is_remote) {
707 node->remote_container_id = entity->entity_container_id;
708 }
709 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600710 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500711 node->entity.entity_container_id = container_id;
712 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930713 /* We will have returned above */
714 assert(tree->last_used_container_id !=
715 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500716 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930717 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500718 }
719 } else {
720 node->entity.entity_container_id =
721 entity->entity_container_id;
722 }
723
724 if (!is_remote) {
725 node->remote_container_id =
726 node->entity.entity_container_id;
727 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930728 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930729 pldm_entity_node *start = parent == NULL ? tree->root :
730 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930731 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930732 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500733 if (!prev) {
734 free(node);
735 return NULL;
736 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737 pldm_entity_node *next = prev->next_sibling;
738 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500739 if (prev->entity.entity_instance_num == UINT16_MAX) {
740 free(node);
741 return NULL;
742 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930743 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600744 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930745 entity_instance_number :
746 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747 }
748 prev->next_sibling = node;
749 node->parent = prev->parent;
750 node->next_sibling = next;
751 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930752 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600753 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930754 }
755 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500756 if (is_update_container_id) {
757 entity->entity_container_id = node->entity.entity_container_id;
758 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759 return node;
760}
761
762static void get_num_nodes(pldm_entity_node *node, size_t *num)
763{
764 if (node == NULL) {
765 return;
766 }
767
768 ++(*num);
769 get_num_nodes(node->next_sibling, num);
770 get_num_nodes(node->first_child, num);
771}
772
773static void entity_association_tree_visit(pldm_entity_node *node,
774 pldm_entity *entities, size_t *index)
775{
776 if (node == NULL) {
777 return;
778 }
779
780 pldm_entity *entity = &entities[*index];
781 ++(*index);
782 entity->entity_type = node->entity.entity_type;
783 entity->entity_instance_num = node->entity.entity_instance_num;
784 entity->entity_container_id = node->entity.entity_container_id;
785
786 entity_association_tree_visit(node->next_sibling, entities, index);
787 entity_association_tree_visit(node->first_child, entities, index);
788}
789
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930790LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930791void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
792 pldm_entity **entities, size_t *size)
793{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930794 if (!tree || !entities || !size) {
795 return;
796 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930797
798 *size = 0;
799 if (tree->root == NULL) {
800 return;
801 }
802
803 get_num_nodes(tree->root, size);
804 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930805 if (!entities) {
806 return;
807 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 size_t index = 0;
809 entity_association_tree_visit(tree->root, *entities, &index);
810}
811
812static void entity_association_tree_destroy(pldm_entity_node *node)
813{
814 if (node == NULL) {
815 return;
816 }
817
818 entity_association_tree_destroy(node->next_sibling);
819 entity_association_tree_destroy(node->first_child);
820 free(node);
821}
822
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930823LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
825{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930826 if (!tree) {
827 return;
828 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829
830 entity_association_tree_destroy(tree->root);
831 free(tree);
832}
833
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930834LIBPLDM_ABI_STABLE
835bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836{
837 assert(node != NULL);
838
839 return node->first_child != NULL;
840}
841
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930842LIBPLDM_ABI_STABLE
843pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844{
845 assert(node != NULL);
846
847 return node->parent;
848}
849
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930850LIBPLDM_ABI_STABLE
851bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930852{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930853 if (!node) {
854 return false;
855 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930856
857 if (node->parent.entity_type == 0 &&
858 node->parent.entity_instance_num == 0 &&
859 node->parent.entity_container_id == 0) {
860 return false;
861 }
862
863 return true;
864}
865
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930866LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930867uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
868 uint8_t association_type)
869{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930870 if (!node) {
871 return 0;
872 }
873
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930874 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
875 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
876 return 0;
877 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930878
879 size_t count = 0;
880 pldm_entity_node *curr = node->first_child;
881 while (curr != NULL) {
882 if (curr->association_type == association_type) {
883 ++count;
884 }
885 curr = curr->next_sibling;
886 }
887
888 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930889 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890}
891
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930892LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930893bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
894{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930895 if (!parent || !node) {
896 return false;
897 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930898
899 pldm_entity_node *curr = parent->first_child;
900 while (curr != NULL) {
901 if (node->entity_type == curr->entity.entity_type &&
902 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930903 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904 return true;
905 }
906 curr = curr->next_sibling;
907 }
908
909 return false;
910}
911
Archana Kakanibc40dd52024-08-02 00:10:44 -0500912static int64_t entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500913 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
914 uint8_t contained_count, uint8_t association_type, bool is_remote,
915 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930917 uint8_t *start;
918 uint8_t *pdr;
Archana Kakanibc40dd52024-08-02 00:10:44 -0500919 int64_t rc;
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930920
921 pdr = calloc(1, size);
922 if (!pdr) {
923 return -ENOMEM;
924 }
925
926 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927
928 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
929 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600930 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
932 hdr->record_change_num = 0;
933 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
934 start += sizeof(struct pldm_pdr_hdr);
935
936 uint16_t *container_id = (uint16_t *)start;
937 *container_id = htole16(curr->first_child->entity.entity_container_id);
938 start += sizeof(uint16_t);
939 *start = association_type;
940 start += sizeof(uint8_t);
941
942 pldm_entity *entity = (pldm_entity *)start;
943 entity->entity_type = htole16(curr->entity.entity_type);
944 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
945 entity->entity_container_id = htole16(curr->entity.entity_container_id);
946 start += sizeof(pldm_entity);
947
948 *start = contained_count;
949 start += sizeof(uint8_t);
950
951 pldm_entity_node *node = curr->first_child;
952 while (node != NULL) {
953 if (node->association_type == association_type) {
954 pldm_entity *entity = (pldm_entity *)start;
955 entity->entity_type = htole16(node->entity.entity_type);
956 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930957 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930959 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930960 start += sizeof(pldm_entity);
961 }
962 node = node->next_sibling;
963 }
964
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930965 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
966 &record_handle);
967 free(pdr);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500968 return (rc < 0) ? rc : record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930969}
970
Archana Kakanibc40dd52024-08-02 00:10:44 -0500971static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
972 pldm_pdr *repo, bool is_remote,
973 uint16_t terminus_handle,
974 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930975{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930976 uint8_t num_logical_children = pldm_entity_get_num_children(
977 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
978 uint8_t num_physical_children = pldm_entity_get_num_children(
979 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500980 int64_t rc;
981
982 if (!num_logical_children && !num_physical_children) {
983 if (record_handle == 0) {
984 return -EINVAL;
985 }
986 return record_handle - 1;
987 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930988
989 if (num_logical_children) {
990 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930991 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
992 sizeof(uint8_t) + sizeof(pldm_entity) +
993 sizeof(uint8_t) +
994 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930995 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930996 curr, repo, logical_pdr_size, num_logical_children,
997 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500998 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930999 if (rc < 0) {
1000 return rc;
1001 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001002 if (num_physical_children) {
1003 if (rc >= UINT32_MAX) {
1004 return -EOVERFLOW;
1005 }
1006 record_handle = rc + 1;
1007 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301008 }
1009
1010 if (num_physical_children) {
1011 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301012 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
1013 sizeof(uint8_t) + sizeof(pldm_entity) +
1014 sizeof(uint8_t) +
1015 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +09301016 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301017 curr, repo, physical_pdr_size, num_physical_children,
1018 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001019 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +09301020 if (rc < 0) {
1021 return rc;
1022 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001023 record_handle = rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301024 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301025
Archana Kakanibc40dd52024-08-02 00:10:44 -05001026 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027}
1028
Andrew Jefferyd09b1af2023-07-17 12:39:16 +09301029static bool is_present(pldm_entity entity, pldm_entity **entities,
1030 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301031{
1032 if (entities == NULL || num_entities == 0) {
1033 return true;
1034 }
1035 size_t i = 0;
1036 while (i < num_entities) {
1037 if ((*entities + i)->entity_type == entity.entity_type) {
1038 return true;
1039 }
1040 i++;
1041 }
1042 return false;
1043}
1044
Archana Kakanibc40dd52024-08-02 00:10:44 -05001045static int64_t entity_association_pdr_add(pldm_entity_node *curr,
1046 pldm_pdr *repo,
1047 pldm_entity **entities,
1048 size_t num_entities, bool is_remote,
1049 uint16_t terminus_handle,
1050 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301051{
Archana Kakanibc40dd52024-08-02 00:10:44 -05001052 int64_t rc;
Andrew Jeffery65945992023-07-17 15:04:21 +09301053
Andrew Jeffery9c766792022-08-10 23:12:49 +09301054 if (curr == NULL) {
Archana Kakanibc40dd52024-08-02 00:10:44 -05001055 // entity_association_pdr_add function gets called
1056 // recursively for the siblings and children of the
1057 // entity. This causes NULL current entity node, and the
1058 // record handle is returned
1059 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301061
1062 if (is_present(curr->entity, entities, num_entities)) {
1063 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001064 curr, repo, is_remote, terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001065 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301066 return rc;
1067 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001068 if (rc >= UINT32_MAX) {
1069 return -EOVERFLOW;
1070 }
1071 record_handle = rc + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301072 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301073
1074 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
1075 num_entities, is_remote,
1076 terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001077 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301078 return rc;
1079 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001080 // entity_association_pdr_add return record handle in success
1081 // case. If the pdr gets added to the repo, new record handle
1082 // will be returned. Below check confirms if the pdr is added
1083 // to the repo and increments the record handle
1084 if (record_handle != rc) {
1085 if (rc >= UINT32_MAX) {
1086 return -EOVERFLOW;
1087 }
1088 record_handle = rc + 1;
1089 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301090
Archana Kakanibc40dd52024-08-02 00:10:44 -05001091 rc = entity_association_pdr_add(curr->first_child, repo, entities,
1092 num_entities, is_remote,
1093 terminus_handle, record_handle);
1094 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301095}
1096
Andrew Jeffery096685b2023-07-17 17:36:14 +09301097LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +09301098int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
1099 pldm_pdr *repo, bool is_remote,
1100 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +09301101{
Andrew Jefferyc7883482023-06-30 15:52:04 +09301102 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301103 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +09301104 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001105 int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
1106 is_remote, terminus_handle, 0);
1107 assert(rc >= INT_MIN);
1108 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301109}
1110
Andrew Jeffery1354a6e2023-07-07 10:34:38 +09301111LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +09301112int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +09301113 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1114 size_t num_entities, bool is_remote, uint16_t terminus_handle)
1115{
1116 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001117 node, repo, entities, num_entities, is_remote, terminus_handle,
1118 0);
1119}
1120
Pavithra Barithaya3a267052023-11-13 05:01:36 -06001121LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001122int pldm_entity_association_pdr_add_from_node_with_record_handle(
1123 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1124 size_t num_entities, bool is_remote, uint16_t terminus_handle,
1125 uint32_t record_handle)
1126{
1127 if (!node || !repo || !entities) {
1128 return -EINVAL;
1129 }
1130
Archana Kakanibc40dd52024-08-02 00:10:44 -05001131 int64_t rc = entity_association_pdr_add(node, repo, entities,
1132 num_entities, is_remote,
1133 terminus_handle, record_handle);
1134
1135 assert(rc >= INT_MIN);
1136 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301137}
1138
Andrew Jeffery643c4432023-07-17 15:36:03 +09301139static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
1140 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301141{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001142 bool is_entity_container_id;
1143 bool is_entity_instance_num;
1144 bool is_type;
1145
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146 if (tree_node == NULL) {
1147 return;
1148 }
1149
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001150 is_type = tree_node->entity.entity_type == entity.entity_type;
1151 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1152 entity.entity_instance_num;
1153 is_entity_container_id = tree_node->entity.entity_container_id ==
1154 entity.entity_container_id;
1155
1156 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157 *node = tree_node;
1158 return;
1159 }
1160
1161 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1162 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1163}
1164
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301165LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301166void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1167 pldm_entity entity, pldm_entity_node **node)
1168{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301169 if (!tree || !node) {
1170 return;
1171 }
1172
Andrew Jeffery9c766792022-08-10 23:12:49 +09301173 find_entity_ref_in_tree(tree->root, entity, node);
1174}
1175
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301176LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301177void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1178 uint16_t terminus_handle)
1179{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301180 if (!repo) {
1181 return;
1182 }
1183
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184 bool removed = false;
1185
1186 pldm_pdr_record *record = repo->first;
1187 pldm_pdr_record *prev = NULL;
1188 while (record != NULL) {
1189 pldm_pdr_record *next = record->next;
1190 if (record->terminus_handle == terminus_handle) {
1191 if (repo->first == record) {
1192 repo->first = next;
1193 } else {
1194 prev->next = next;
1195 }
1196 if (repo->last == record) {
1197 repo->last = prev;
1198 }
1199 if (record->data) {
1200 free(record->data);
1201 }
1202 --repo->record_count;
1203 repo->size -= record->size;
1204 free(record);
1205 removed = true;
1206 } else {
1207 prev = record;
1208 }
1209 record = next;
1210 }
1211
1212 if (removed == true) {
1213 record = repo->first;
1214 uint32_t record_handle = 0;
1215 while (record != NULL) {
1216 record->record_handle = ++record_handle;
1217 if (record->data != NULL) {
1218 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301219 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301221 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301222 }
1223 record = record->next;
1224 }
1225 }
1226}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301227
1228LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301229void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1230{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301231 if (!repo) {
1232 return;
1233 }
1234
Andrew Jeffery9c766792022-08-10 23:12:49 +09301235 bool removed = false;
1236
1237 pldm_pdr_record *record = repo->first;
1238 pldm_pdr_record *prev = NULL;
1239 while (record != NULL) {
1240 pldm_pdr_record *next = record->next;
1241 if (record->is_remote == true) {
1242 if (repo->first == record) {
1243 repo->first = next;
1244 } else {
1245 prev->next = next;
1246 }
1247 if (repo->last == record) {
1248 repo->last = prev;
1249 }
1250 if (record->data) {
1251 free(record->data);
1252 }
1253 --repo->record_count;
1254 repo->size -= record->size;
1255 free(record);
1256 removed = true;
1257 } else {
1258 prev = record;
1259 }
1260 record = next;
1261 }
1262
1263 if (removed == true) {
1264 record = repo->first;
1265 uint32_t record_handle = 0;
1266 while (record != NULL) {
1267 record->record_handle = ++record_handle;
1268 if (record->data != NULL) {
1269 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301270 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301272 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273 }
1274 record = record->next;
1275 }
1276 }
1277}
1278
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001279LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001280pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1281 uint32_t first, uint32_t last)
1282{
1283 pldm_pdr_record *record = NULL;
1284 pldm_pdr_record *curr;
1285
1286 if (!repo) {
1287 return NULL;
1288 }
1289 for (curr = repo->first; curr; curr = curr->next) {
1290 if (first > curr->record_handle || last < curr->record_handle) {
1291 continue;
1292 }
1293 if (!record || curr->record_handle > record->record_handle) {
1294 record = curr;
1295 }
1296 }
1297
1298 return record;
1299}
1300
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001301static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1302 pldm_entity *entity,
1303 pldm_entity_node **out,
1304 bool is_remote)
1305{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001306 if (node == NULL) {
1307 return;
1308 }
1309 bool is_entity_type;
1310 bool is_entity_instance_num;
1311
1312 is_entity_type = node->entity.entity_type == entity->entity_type;
1313 is_entity_instance_num = node->entity.entity_instance_num ==
1314 entity->entity_instance_num;
1315
1316 if (!is_remote ||
1317 node->remote_container_id == entity->entity_container_id) {
1318 if (is_entity_type && is_entity_instance_num) {
1319 entity->entity_container_id =
1320 node->entity.entity_container_id;
1321 *out = node;
1322 return;
1323 }
1324 }
1325 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1326 is_remote);
1327 entity_association_tree_find_if_remote(node->first_child, entity, out,
1328 is_remote);
1329}
1330
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001331LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001332pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1333 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001334{
1335 if (!tree || !entity) {
1336 return NULL;
1337 }
1338 pldm_entity_node *node = NULL;
1339 entity_association_tree_find_if_remote(tree->root, entity, &node,
1340 is_remote);
1341 return node;
1342}
1343
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301344static void entity_association_tree_find(pldm_entity_node *node,
1345 pldm_entity *entity,
1346 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301347{
1348 if (node == NULL) {
1349 return;
1350 }
1351
1352 if (node->entity.entity_type == entity->entity_type &&
1353 node->entity.entity_instance_num == entity->entity_instance_num) {
1354 entity->entity_container_id = node->entity.entity_container_id;
1355 *out = node;
1356 return;
1357 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301358 entity_association_tree_find(node->next_sibling, entity, out);
1359 entity_association_tree_find(node->first_child, entity, out);
1360}
1361
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301362LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301363pldm_entity_node *
1364pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1365 pldm_entity *entity)
1366{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301367 if (!tree || !entity) {
1368 return NULL;
1369 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301370
1371 pldm_entity_node *node = NULL;
1372 entity_association_tree_find(tree->root, entity, &node);
1373 return node;
1374}
1375
Andrew Jeffery60582152024-09-22 21:16:38 +09301376static int entity_association_tree_copy(pldm_entity_node *org_node,
1377 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301378{
Andrew Jeffery60582152024-09-22 21:16:38 +09301379 int rc;
1380
Andrew Jeffery9c766792022-08-10 23:12:49 +09301381 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301382 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301383 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301384
Andrew Jeffery9c766792022-08-10 23:12:49 +09301385 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301386 if (!*new_node) {
1387 return -ENOMEM;
1388 }
1389
Andrew Jeffery9c766792022-08-10 23:12:49 +09301390 (*new_node)->parent = org_node->parent;
1391 (*new_node)->entity = org_node->entity;
1392 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001393 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301394 (*new_node)->first_child = NULL;
1395 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301396
1397 rc = entity_association_tree_copy(org_node->first_child,
1398 &((*new_node)->first_child));
1399 if (rc) {
1400 goto cleanup;
1401 }
1402
1403 rc = entity_association_tree_copy(org_node->next_sibling,
1404 &((*new_node)->next_sibling));
1405 if (rc) {
1406 entity_association_tree_destroy((*new_node)->first_child);
1407 goto cleanup;
1408 }
1409
1410 return 0;
1411
1412cleanup:
1413 free(*new_node);
1414 *new_node = NULL;
1415 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301416}
1417
Andrew Jeffery36324f62024-09-25 13:41:41 +09301418LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301419void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301420 pldm_entity_association_tree *org_tree,
1421 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301422{
George Liuc6c391d2023-11-09 10:13:34 +08001423 assert(org_tree != NULL);
1424 assert(new_tree != NULL);
1425
Andrew Jeffery9c766792022-08-10 23:12:49 +09301426 new_tree->last_used_container_id = org_tree->last_used_container_id;
1427 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1428}
1429
Andrew Jeffery60582152024-09-22 21:16:38 +09301430LIBPLDM_ABI_TESTING
1431int pldm_entity_association_tree_copy_root_check(
1432 pldm_entity_association_tree *org_tree,
1433 pldm_entity_association_tree *new_tree)
1434{
1435 if (!org_tree || !new_tree) {
1436 return -EINVAL;
1437 }
1438
1439 new_tree->last_used_container_id = org_tree->last_used_container_id;
1440 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1441}
1442
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301443LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301444void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301445 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301446{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301447 if (!tree) {
1448 return;
1449 }
1450
Andrew Jeffery9c766792022-08-10 23:12:49 +09301451 entity_association_tree_destroy(tree->root);
1452 tree->last_used_container_id = 0;
1453 tree->root = NULL;
1454}
1455
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301456LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301457bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1458{
1459 return ((tree->root == NULL) ? true : false);
1460}
1461
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301462LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301463void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1464 size_t *num_entities,
1465 pldm_entity **entities)
1466{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301467 if (!pdr || !num_entities || !entities) {
1468 return;
1469 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001470 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301471 return;
1472 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301473
1474 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301475 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1476 return;
1477 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301478
1479 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301480
1481 if (UINTPTR_MAX - (uintptr_t)start <
1482 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1483 return;
1484 }
1485
1486 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1487 return;
1488 }
1489
1490 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301491 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301492 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301493
1494 if ((uintptr_t)end - (uintptr_t)start <
1495 sizeof(struct pldm_pdr_entity_association)) {
1496 return;
1497 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001498
Andrew Jeffery9c766792022-08-10 23:12:49 +09301499 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301500 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301501
Archana Kakanibc40dd52024-08-02 00:10:44 -05001502 size_t l_num_entities = entity_association_pdr->num_children;
1503
1504 if (l_num_entities == 0) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301505 return;
1506 }
Andrew Jeffery8f33a1d2024-10-11 18:01:19 +10301507
Archana Kakanibc40dd52024-08-02 00:10:44 -05001508 if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1509 l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301510 return;
1511 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301512
Archana Kakanibc40dd52024-08-02 00:10:44 -05001513 if (l_num_entities >= (size_t)UINT8_MAX) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301514 return;
1515 }
1516
Archana Kakanibc40dd52024-08-02 00:10:44 -05001517 l_num_entities++;
1518
Andrew Jeffery9e566592024-10-02 16:38:51 +09301519 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301520 if (!l_entities) {
1521 return;
1522 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301523 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301524 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301525 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301526 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301527 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301528 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301529 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301530 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1531 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1532 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301533 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301534 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301535 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301536 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301537
1538 *num_entities = l_num_entities;
1539 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301540}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001541
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301542/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001543 * the same position.
1544 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301545LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001546static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1547 pldm_pdr_record *prev,
1548 pldm_pdr_record *new_record)
1549{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001550 if (repo->size < record->size) {
1551 return -EOVERFLOW;
1552 }
1553
1554 if (repo->size + new_record->size < new_record->size) {
1555 return -EOVERFLOW;
1556 }
1557
1558 if (repo->first == record) {
1559 repo->first = new_record;
1560 } else {
1561 prev->next = new_record;
1562 }
1563 new_record->next = record->next;
1564
1565 if (repo->last == record) {
1566 repo->last = new_record;
1567 }
1568
1569 repo->size = (repo->size - record->size) + new_record->size;
1570 return 0;
1571}
1572
1573/* Insert a new record to pldm_pdr repo to a position that comes after
1574 * pldm_pdr_record record.
1575 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301576LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001577static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1578 pldm_pdr_record *new_record)
1579{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001580 if (repo->size + new_record->size < new_record->size) {
1581 return -EOVERFLOW;
1582 }
1583
1584 if (repo->record_count == UINT32_MAX) {
1585 return -EOVERFLOW;
1586 }
1587
1588 new_record->next = record->next;
1589 record->next = new_record;
1590
1591 if (repo->last == record) {
1592 repo->last = new_record;
1593 }
1594
1595 repo->size = repo->size + new_record->size;
1596 ++repo->record_count;
1597 return 0;
1598}
1599
1600/* Find the position of PDR when its record handle is known
1601 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301602LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001603static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1604 pldm_pdr_record **prev,
1605 uint32_t record_handle)
1606{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001607 while (*record != NULL) {
1608 if ((*record)->record_handle == record_handle) {
1609 return true;
1610 }
1611 *prev = *record;
1612 *record = (*record)->next;
1613 }
1614 return false;
1615}
1616
1617LIBPLDM_ABI_TESTING
1618int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1619 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1620{
1621 if (!repo || !entity) {
1622 return -EINVAL;
1623 }
1624
1625 pldm_pdr_record *record = repo->first;
1626 pldm_pdr_record *prev = repo->first;
1627 int rc = 0;
1628 uint16_t header_length = 0;
1629 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10301630 PLDM_MSGBUF_DEFINE_P(src);
1631 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001632
1633 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1634
1635 if (!record) {
1636 return -EINVAL;
1637 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001638
1639 // check if adding another entity to record causes overflow before
1640 // allocating memory for new_record.
1641 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1642 return -EOVERFLOW;
1643 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301644
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001645 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1646 if (!new_record) {
1647 return -ENOMEM;
1648 }
1649
1650 new_record->data = malloc(record->size + sizeof(pldm_entity));
1651 if (!new_record->data) {
1652 rc = -ENOMEM;
1653 goto cleanup_new_record;
1654 }
1655
1656 new_record->record_handle = record->record_handle;
1657 new_record->size = record->size + sizeof(struct pldm_entity);
1658 new_record->is_remote = record->is_remote;
1659
Andrew Jefferya1896962025-03-03 21:41:25 +10301660 // Initialize msg buffer for record and record->data
1661 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1662 record->data, record->size);
1663 if (rc) {
1664 goto cleanup_new_record_data;
1665 }
1666
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001667 // Initialize new PDR record with data from original PDR record.
1668 // Start with adding the header of original PDR
1669 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1670 new_record->data, new_record->size);
1671 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301672 goto cleanup_src_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001673 }
1674
1675 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1676 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1677 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1678 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1679 // extract the header length from record and increment size with
1680 // size of pldm_entity before inserting the value into new_record.
1681 rc = pldm_msgbuf_extract(src, header_length);
1682 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301683 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001684 }
1685 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1686 "Fix the following bounds check.");
1687 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1688 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301689 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001690 }
1691 header_length += sizeof(pldm_entity);
1692 pldm_msgbuf_insert(dst, header_length);
1693 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1694 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1695 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1696 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1697 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1698 // extract value of number of children from record and increment it
1699 // by 1 before insert the value to new record.
1700 rc = pldm_msgbuf_extract(src, num_children);
1701 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301702 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001703 }
1704 if (num_children == UINT8_MAX) {
1705 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301706 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001707 }
1708 num_children += 1;
1709 pldm_msgbuf_insert(dst, num_children);
1710 //Add all children of original PDR to new PDR
1711 for (int i = 0; i < num_children - 1; i++) {
1712 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1713 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1714 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1715 }
1716
1717 // Add new contained entity as a child of new PDR
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301718 rc = pldm_msgbuf_complete(src);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001719 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301720 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001721 goto cleanup_new_record_data;
1722 }
1723 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1724 sizeof(struct pldm_entity));
1725 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301726 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001727 goto cleanup_new_record_data;
1728 }
1729 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1730 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1731 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1732
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301733 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001734 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301735 goto cleanup_src_msgbuf;
1736 }
1737 rc = pldm_msgbuf_complete(src);
1738 if (rc) {
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001739 goto cleanup_new_record_data;
1740 }
1741
1742 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1743 if (rc) {
1744 goto cleanup_new_record_data;
1745 }
1746
1747 free(record->data);
1748 free(record);
1749 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301750cleanup_dst_msgbuf:
1751 rc = pldm_msgbuf_discard(dst, rc);
1752cleanup_src_msgbuf:
1753 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001754cleanup_new_record_data:
1755 free(new_record->data);
1756cleanup_new_record:
1757 free(new_record);
1758 return rc;
1759}
1760
1761LIBPLDM_ABI_TESTING
1762int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1763 uint32_t pdr_record_handle,
1764 pldm_entity *parent,
1765 pldm_entity *entity,
1766 uint32_t *entity_record_handle)
1767{
1768 if (!repo || !parent || !entity || !entity_record_handle) {
1769 return -EINVAL;
1770 }
1771
1772 if (pdr_record_handle == UINT32_MAX) {
1773 return -EOVERFLOW;
1774 }
1775
1776 bool pdr_added = false;
1777 uint16_t new_pdr_size;
1778 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001779 void *container_id_addr;
Andrew Jefferya1896962025-03-03 21:41:25 +10301780 PLDM_MSGBUF_DEFINE_P(dst);
1781 PLDM_MSGBUF_DEFINE_P(src_p);
1782 PLDM_MSGBUF_DEFINE_P(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001783 int rc = 0;
1784
1785 pldm_pdr_record *prev = repo->first;
1786 pldm_pdr_record *record = repo->first;
1787 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1788 pdr_record_handle);
1789 if (!pdr_added) {
1790 return -ENOENT;
1791 }
1792
1793 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1794 "Truncation ahead");
1795 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1796 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1797 if (!new_record) {
1798 return -ENOMEM;
1799 }
1800
1801 new_record->data = malloc(new_pdr_size);
1802 if (!new_record->data) {
1803 rc = -ENOMEM;
1804 goto cleanup_new_record;
1805 }
1806
1807 // Initialise new PDR to be added with the header, size and handle.
1808 // Set the position of new PDR
1809 *entity_record_handle = pdr_record_handle + 1;
1810 new_record->record_handle = *entity_record_handle;
1811 new_record->size = new_pdr_size;
1812 new_record->is_remote = false;
1813
1814 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1815 new_record->data, new_record->size);
1816 if (rc) {
1817 goto cleanup_new_record_data;
1818 }
1819
1820 // header record handle
1821 pldm_msgbuf_insert(dst, *entity_record_handle);
1822 // header version
1823 pldm_msgbuf_insert_uint8(dst, 1);
1824 // header type
1825 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1826 // header change number
1827 pldm_msgbuf_insert_uint16(dst, 0);
1828 // header length
1829 pldm_msgbuf_insert_uint16(dst,
1830 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1831
1832 // Data for new PDR is obtained from parent PDR and new contained entity
1833 // is added as the child
1834 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1835 sizeof(*parent));
1836 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301837 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001838 }
1839
1840 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1841 sizeof(*entity));
1842 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301843 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001844 }
1845
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001846 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001847 // extract pointer for container ID and save the address
1848 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1849 (void **)&container_id_addr);
1850 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301851 goto cleanup_msgbuf_src_c;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001852 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001853 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001854 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1855 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1856 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1857 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1858 // number of children
1859 pldm_msgbuf_insert_uint8(dst, 1);
1860
1861 // Add new entity as child
1862 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1863 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1864 // Extract and insert child entity container ID and add same value to
1865 // container ID of entity
1866 pldm_msgbuf_extract(src_c, container_id);
1867 pldm_msgbuf_insert(dst, container_id);
1868 container_id = htole16(container_id);
1869 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1870
Andrew Jefferya1896962025-03-03 21:41:25 +10301871 rc = pldm_msgbuf_complete(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001872 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301873 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001874 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301875 rc = pldm_msgbuf_complete(src_p);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001876 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301877 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001878 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301879 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001880 if (rc) {
1881 goto cleanup_new_record_data;
1882 }
1883
1884 rc = pldm_pdr_insert_record(repo, record, new_record);
1885 if (rc) {
1886 goto cleanup_new_record_data;
1887 }
1888
1889 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301890cleanup_msgbuf_src_c:
1891 rc = pldm_msgbuf_discard(src_c, rc);
1892cleanup_msgbuf_src_p:
1893 rc = pldm_msgbuf_discard(src_p, rc);
1894cleanup_msgbuf_dst:
1895 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001896cleanup_new_record_data:
1897 free(new_record->data);
1898cleanup_new_record:
1899 free(new_record);
1900 return rc;
1901}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001902
1903LIBPLDM_CC_NONNULL
1904static bool pldm_entity_cmp(const struct pldm_entity *l,
1905 const struct pldm_entity *r)
1906{
1907 return l->entity_type == r->entity_type &&
1908 l->entity_instance_num == r->entity_instance_num &&
1909 l->entity_container_id == r->entity_container_id;
1910}
1911
1912/* Find record handle of a PDR record from PDR repo and
1913 * entity
1914 */
1915LIBPLDM_CC_NONNULL
1916static int pldm_entity_association_find_record_handle_by_entity(
1917 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1918 uint32_t *record_handle)
1919{
1920 uint8_t num_children = 0;
1921 uint8_t hdr_type = 0;
1922 int rc = 0;
1923 size_t skip_data_size = 0;
1924 pldm_pdr_record *record = repo->first;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001925
1926 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301927 PLDM_MSGBUF_DEFINE_P(dst);
1928
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001929 rc = pldm_msgbuf_init_errno(dst,
1930 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1931 record->data, record->size);
1932 if (rc) {
1933 return rc;
1934 }
1935 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1936 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10301937 rc = pldm_msgbuf_extract(dst, hdr_type);
1938 if (rc) {
1939 return pldm_msgbuf_discard(dst, rc);
1940 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001941 if (record->is_remote != is_remote ||
1942 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1943 goto cleanup;
1944 }
1945 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1946 sizeof(uint16_t) + sizeof(uint8_t) +
1947 sizeof(struct pldm_entity);
1948 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10301949 rc = pldm_msgbuf_extract(dst, num_children);
1950 if (rc) {
1951 return pldm_msgbuf_discard(dst, rc);
1952 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001953 for (int i = 0; i < num_children; ++i) {
1954 struct pldm_entity e;
1955
1956 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1957 (rc = pldm_msgbuf_extract(dst,
1958 e.entity_instance_num)) ||
1959 (rc = pldm_msgbuf_extract(dst,
1960 e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301961 return pldm_msgbuf_discard(dst, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001962 }
1963
1964 if (pldm_entity_cmp(entity, &e)) {
1965 *record_handle = record->record_handle;
Andrew Jefferya1896962025-03-03 21:41:25 +10301966 return pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001967 }
1968 }
1969 cleanup:
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301970 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001971 if (rc) {
1972 return rc;
1973 }
1974 record = record->next;
1975 }
1976 return 0;
1977}
1978
1979LIBPLDM_ABI_TESTING
1980int pldm_entity_association_pdr_remove_contained_entity(
1981 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1982 uint32_t *pdr_record_handle)
1983{
1984 uint16_t header_length = 0;
1985 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10301986 PLDM_MSGBUF_DEFINE_P(src);
1987 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001988 int rc;
1989 pldm_pdr_record *record;
1990 pldm_pdr_record *prev;
1991
1992 if (!repo || !entity || !pdr_record_handle) {
1993 return -EINVAL;
1994 }
1995 record = repo->first;
1996 prev = repo->first;
1997
1998 rc = pldm_entity_association_find_record_handle_by_entity(
1999 repo, entity, is_remote, pdr_record_handle);
2000 if (rc) {
2001 return rc;
2002 }
2003 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
2004 if (!record) {
2005 return -EINVAL;
2006 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002007 // check if removing an entity from record causes overflow before
2008 // allocating memory for new_record.
2009 if (record->size < sizeof(pldm_entity)) {
2010 return -EOVERFLOW;
2011 }
2012 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
2013 if (!new_record) {
2014 return -ENOMEM;
2015 }
2016 new_record->data = malloc(record->size - sizeof(pldm_entity));
2017 if (!new_record->data) {
2018 rc = -ENOMEM;
2019 goto cleanup_new_record;
2020 }
2021 new_record->record_handle = record->record_handle;
2022 new_record->size = record->size - sizeof(struct pldm_entity);
2023 new_record->is_remote = record->is_remote;
2024
Andrew Jefferya1896962025-03-03 21:41:25 +10302025 // Initialize msg buffer for record and record->data
2026 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
2027 record->data, record->size);
2028 if (rc) {
2029 goto cleanup_new_record_data;
2030 }
2031
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002032 // Initialize new PDR record with data from original PDR record.
2033 // Start with adding the header of original PDR
Archana Kakani94e2d752024-12-12 08:22:55 -06002034 rc = pldm_msgbuf_init_errno(
2035 dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
2036 new_record->data, new_record->size);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002037 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302038 goto cleanup_msgbuf_src;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002039 }
2040 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
2041 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
2042 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
2043 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
2044 // extract the header length from record and decrement size with
2045 // size of pldm_entity before inserting the value into new_record.
2046 rc = pldm_msgbuf_extract(src, header_length);
2047 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302048 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002049 }
2050 if (header_length < sizeof(pldm_entity)) {
2051 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302052 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002053 }
2054 header_length -= sizeof(pldm_entity);
2055 pldm_msgbuf_insert(dst, header_length);
2056 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
2057 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
2058 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
2059 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
2060 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
2061 // extract value of number of children from record and decrement it
2062 // by 1 before insert the value to new record.
2063 rc = pldm_msgbuf_extract(src, num_children);
2064 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302065 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002066 }
2067 if (num_children == 1) {
Archana Kakani94e2d752024-12-12 08:22:55 -06002068 // This is the last child which is getting removed so we need to delete the Entity Association PDR.
2069 pldm_pdr_remove_record(repo, record,
2070 pldm_pdr_get_prev_record(repo, record));
Andrew Jefferya1896962025-03-03 21:41:25 +10302071 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002072 } else if (num_children < 1) {
2073 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302074 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002075 }
2076 num_children -= 1;
2077 pldm_msgbuf_insert(dst, num_children);
2078 //Add all children of original PDR to new PDR
2079 for (int i = 0; i < num_children + 1; ++i) {
2080 struct pldm_entity e;
2081
2082 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
2083 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
2084 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302085 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002086 }
2087
2088 if (pldm_entity_cmp(entity, &e)) {
2089 continue;
2090 }
2091
2092 pldm_msgbuf_insert(dst, e.entity_type);
2093 pldm_msgbuf_insert(dst, e.entity_instance_num);
2094 pldm_msgbuf_insert(dst, e.entity_container_id);
2095 }
2096
Andrew Jefferya1896962025-03-03 21:41:25 +10302097 rc = pldm_msgbuf_complete(dst);
2098 if (rc) {
2099 goto cleanup_msgbuf_src;
2100 }
2101
2102 rc = pldm_msgbuf_complete(src);
2103 if (rc) {
2104 goto cleanup_new_record_data;
2105 }
2106
2107 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
2108 if (rc) {
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002109 goto cleanup_new_record_data;
2110 }
2111
2112 free(record->data);
2113 free(record);
2114 return rc;
2115
Andrew Jefferya1896962025-03-03 21:41:25 +10302116cleanup_msgbuf_dst:
2117 rc = pldm_msgbuf_discard(dst, rc);
2118cleanup_msgbuf_src:
2119 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002120cleanup_new_record_data:
2121 free(new_record->data);
2122cleanup_new_record:
2123 free(new_record);
2124 return rc;
2125}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002126
2127/* API to find the PDR record that is previous to a given PLDM PDR
2128 * record in a given PLDM PDR repository
2129 */
2130LIBPLDM_CC_NONNULL
2131static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
2132 pldm_pdr_record *record)
2133{
2134 pldm_pdr_record *prev = NULL;
2135 pldm_pdr_record *curr = repo->first;
2136
2137 while (curr != NULL) {
2138 if (curr->record_handle == record->record_handle) {
2139 break;
2140 }
2141 prev = curr;
2142 curr = curr->next;
2143 }
2144 return prev;
2145}
2146
2147/* API to check if a PLDM PDR record is present in a PLDM PDR repository
2148 */
2149LIBPLDM_CC_NONNULL
2150static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
2151{
2152 if (repo->first == record) {
2153 return true;
2154 }
2155
2156 return pldm_pdr_get_prev_record(repo, record) != NULL;
2157}
2158
2159/* API to check if FRU RSI of record matches the given record set identifier.
2160 * Returns 1 if the provided FRU record matches the provided record set identifier,
2161 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
2162 */
2163LIBPLDM_CC_NONNULL
2164static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
2165 uint16_t rsi)
2166{
2167 uint16_t record_fru_rsi = 0;
2168 uint8_t *skip_data = NULL;
2169 uint8_t skip_data_size = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10302170 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002171 int rc = 0;
2172
2173 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
2174 record->data, record->size);
2175 if (rc) {
2176 return rc;
2177 }
2178 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
2179 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
2180 pldm_msgbuf_extract(dst, record_fru_rsi);
2181
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302182 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002183 if (rc) {
2184 return rc;
2185 }
2186 return record_fru_rsi == rsi;
2187}
2188
2189/* API to remove PLDM PDR record from a PLDM PDR repository
2190 */
2191LIBPLDM_CC_NONNULL_ARGS(1, 2)
2192static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2193 pldm_pdr_record *prev)
2194{
2195 if (!is_prev_record_present(repo, record)) {
2196 return -EINVAL;
2197 }
2198
2199 assert(repo->size >= record->size);
2200 if (repo->size < record->size) {
2201 return -EOVERFLOW;
2202 }
2203
2204 if (repo->first == record) {
2205 repo->first = record->next;
2206 } else {
2207 if (prev != NULL) {
2208 prev->next = record->next;
2209 }
2210 }
2211
2212 if (repo->last == record) {
2213 repo->last = prev;
2214 if (prev != NULL) {
2215 prev->next = NULL;
2216 }
2217 }
2218 repo->record_count -= 1;
2219 repo->size -= record->size;
2220 free(record->data);
2221 free(record);
2222
2223 return 0;
2224}
2225
2226LIBPLDM_ABI_TESTING
2227int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2228 bool is_remote,
2229 uint32_t *record_handle)
2230{
2231 pldm_pdr_record *record;
2232 pldm_pdr_record *prev = NULL;
2233 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2234 uint8_t hdr_type = 0;
2235 int rc = 0;
2236 int match;
2237
2238 if (!repo || !record_handle) {
2239 return -EINVAL;
2240 }
2241 record = repo->first;
2242
2243 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302244 PLDM_MSGBUF_DEFINE_P(buf);
2245
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002246 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2247 record->data, record->size);
2248 if (rc) {
2249 return rc;
2250 }
2251 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302252 pldm_msgbuf_extract(buf, hdr_type);
2253 rc = pldm_msgbuf_complete(buf);
2254 if (rc) {
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002255 return rc;
2256 }
2257 if (record->is_remote != is_remote ||
2258 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302259 goto next;
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002260 }
2261 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2262 if (match < 0) {
2263 return match;
2264 }
2265 if (match) {
2266 *record_handle = record->record_handle;
2267 prev = pldm_pdr_get_prev_record(repo, record);
2268 return pldm_pdr_remove_record(repo, record, prev);
2269 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302270 next:
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002271 record = record->next;
2272 }
2273 return rc;
2274}