blob: 2d9082152c5c4946c703f0b1bb52c42731ae7d06 [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 Barithaya5192e2e2025-02-26 16:50:06 +0530459LIBPLDM_ABI_TESTING
460int pldm_pdr_delete_by_record_handle(pldm_pdr *repo, uint32_t record_handle,
461 bool is_remote)
462{
463 pldm_pdr_record *record;
464 pldm_pdr_record *prev = NULL;
465 int rc = 0;
466 uint16_t rec_handle = 0;
467
468 if (!repo) {
469 return -EINVAL;
470 }
471 record = repo->first;
472
473 while (record != NULL) {
474 struct pldm_msgbuf _buf;
475 struct pldm_msgbuf *buf = &_buf;
476 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
477 record->data, record->size);
478
479 if (rc) {
480 return rc;
481 }
482 if ((rc = pldm_msgbuf_extract(buf, rec_handle))) {
483 return rc;
484 }
485 if (record->is_remote == is_remote &&
486 rec_handle == record_handle) {
487 prev = pldm_pdr_get_prev_record(repo, record);
488 return pldm_pdr_remove_record(repo, record, prev);
489 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030490 rc = pldm_msgbuf_complete(buf);
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530491 if (rc) {
492 return rc;
493 }
494 record = record->next;
495 }
496 return -ENOENT;
497}
498
Andrew Jeffery9c766792022-08-10 23:12:49 +0930499typedef struct pldm_entity_association_tree {
500 pldm_entity_node *root;
501 uint16_t last_used_container_id;
502} pldm_entity_association_tree;
503
504typedef struct pldm_entity_node {
505 pldm_entity entity;
506 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600507 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508 pldm_entity_node *first_child;
509 pldm_entity_node *next_sibling;
510 uint8_t association_type;
511} pldm_entity_node;
512
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930513LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930514pldm_entity pldm_entity_extract(pldm_entity_node *node)
515{
516 assert(node != NULL);
517
518 return node->entity;
519}
520
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500521LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930522uint16_t
523pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600524{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930525 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600526
Andrew Jeffery15b88182023-06-30 13:29:17 +0930527 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600528}
529
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930530LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930531pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930532{
533 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930534 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930535 if (!tree) {
536 return NULL;
537 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538 tree->root = NULL;
539 tree->last_used_container_id = 0;
540
541 return tree;
542}
543
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930544LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930545static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
546 uint16_t entity_type)
547{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530549 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 */
551 while (start->next_sibling != NULL) {
552 uint16_t this_type = start->entity.entity_type;
553 pldm_entity_node *next = start->next_sibling;
554 if (this_type == entity_type &&
555 (this_type != next->entity.entity_type)) {
556 break;
557 }
558 start = start->next_sibling;
559 }
560
561 return start;
562}
563
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930564LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930566 pldm_entity_association_tree *tree, pldm_entity *entity,
567 uint16_t entity_instance_number, pldm_entity_node *parent,
568 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500570 return pldm_entity_association_tree_add_entity(tree, entity,
571 entity_instance_number,
572 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600573 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500574}
575
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500576LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500577pldm_entity_node *pldm_entity_association_tree_add_entity(
578 pldm_entity_association_tree *tree, pldm_entity *entity,
579 uint16_t entity_instance_number, pldm_entity_node *parent,
580 uint8_t association_type, bool is_remote, bool is_update_container_id,
581 uint16_t container_id)
582{
583 if ((!tree) || (!entity)) {
584 return NULL;
585 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930586
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600587 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930588 pldm_entity node;
589 node.entity_type = entity->entity_type;
590 node.entity_instance_num = entity_instance_number;
591 if (pldm_is_current_parent_child(parent, &node)) {
592 return NULL;
593 }
594 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500595 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
596 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
597 return NULL;
598 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930599 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500600 if (!node) {
601 return NULL;
602 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930603 node->first_child = NULL;
604 node->next_sibling = NULL;
605 node->parent.entity_type = 0;
606 node->parent.entity_instance_num = 0;
607 node->parent.entity_container_id = 0;
608 node->entity.entity_type = entity->entity_type;
609 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600610 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930611 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600612 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930613 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500614 if (parent != NULL) {
615 free(node);
616 return NULL;
617 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930618 tree->root = node;
619 /* container_id 0 here indicates this is the top-most entry */
620 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600621 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930622 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930623 /* Ensure next_container_id() will yield a valid ID */
624 if (tree->last_used_container_id == UINT16_MAX) {
625 free(node);
626 return NULL;
627 }
628
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 parent->first_child = node;
630 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500631
632 if (is_remote) {
633 node->remote_container_id = entity->entity_container_id;
634 }
635 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600636 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500637 node->entity.entity_container_id = container_id;
638 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930639 /* We will have returned above */
640 assert(tree->last_used_container_id !=
641 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500642 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930643 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500644 }
645 } else {
646 node->entity.entity_container_id =
647 entity->entity_container_id;
648 }
649
650 if (!is_remote) {
651 node->remote_container_id =
652 node->entity.entity_container_id;
653 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930654 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930655 pldm_entity_node *start = parent == NULL ? tree->root :
656 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930658 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500659 if (!prev) {
660 free(node);
661 return NULL;
662 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930663 pldm_entity_node *next = prev->next_sibling;
664 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500665 if (prev->entity.entity_instance_num == UINT16_MAX) {
666 free(node);
667 return NULL;
668 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930669 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600670 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930671 entity_instance_number :
672 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930673 }
674 prev->next_sibling = node;
675 node->parent = prev->parent;
676 node->next_sibling = next;
677 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930678 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600679 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680 }
681 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500682 if (is_update_container_id) {
683 entity->entity_container_id = node->entity.entity_container_id;
684 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685 return node;
686}
687
688static void get_num_nodes(pldm_entity_node *node, size_t *num)
689{
690 if (node == NULL) {
691 return;
692 }
693
694 ++(*num);
695 get_num_nodes(node->next_sibling, num);
696 get_num_nodes(node->first_child, num);
697}
698
699static void entity_association_tree_visit(pldm_entity_node *node,
700 pldm_entity *entities, size_t *index)
701{
702 if (node == NULL) {
703 return;
704 }
705
706 pldm_entity *entity = &entities[*index];
707 ++(*index);
708 entity->entity_type = node->entity.entity_type;
709 entity->entity_instance_num = node->entity.entity_instance_num;
710 entity->entity_container_id = node->entity.entity_container_id;
711
712 entity_association_tree_visit(node->next_sibling, entities, index);
713 entity_association_tree_visit(node->first_child, entities, index);
714}
715
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930716LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930717void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
718 pldm_entity **entities, size_t *size)
719{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930720 if (!tree || !entities || !size) {
721 return;
722 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930723
724 *size = 0;
725 if (tree->root == NULL) {
726 return;
727 }
728
729 get_num_nodes(tree->root, size);
730 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930731 if (!entities) {
732 return;
733 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734 size_t index = 0;
735 entity_association_tree_visit(tree->root, *entities, &index);
736}
737
738static void entity_association_tree_destroy(pldm_entity_node *node)
739{
740 if (node == NULL) {
741 return;
742 }
743
744 entity_association_tree_destroy(node->next_sibling);
745 entity_association_tree_destroy(node->first_child);
746 free(node);
747}
748
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930749LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930750void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
751{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930752 if (!tree) {
753 return;
754 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755
756 entity_association_tree_destroy(tree->root);
757 free(tree);
758}
759
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930760LIBPLDM_ABI_STABLE
761bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930762{
763 assert(node != NULL);
764
765 return node->first_child != NULL;
766}
767
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930768LIBPLDM_ABI_STABLE
769pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770{
771 assert(node != NULL);
772
773 return node->parent;
774}
775
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930776LIBPLDM_ABI_STABLE
777bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930778{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930779 if (!node) {
780 return false;
781 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930782
783 if (node->parent.entity_type == 0 &&
784 node->parent.entity_instance_num == 0 &&
785 node->parent.entity_container_id == 0) {
786 return false;
787 }
788
789 return true;
790}
791
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930792LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
794 uint8_t association_type)
795{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930796 if (!node) {
797 return 0;
798 }
799
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930800 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
801 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
802 return 0;
803 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804
805 size_t count = 0;
806 pldm_entity_node *curr = node->first_child;
807 while (curr != NULL) {
808 if (curr->association_type == association_type) {
809 ++count;
810 }
811 curr = curr->next_sibling;
812 }
813
814 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930815 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930816}
817
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930818LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930819bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
820{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930821 if (!parent || !node) {
822 return false;
823 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930824
825 pldm_entity_node *curr = parent->first_child;
826 while (curr != NULL) {
827 if (node->entity_type == curr->entity.entity_type &&
828 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930829 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930830 return true;
831 }
832 curr = curr->next_sibling;
833 }
834
835 return false;
836}
837
Archana Kakanibc40dd52024-08-02 00:10:44 -0500838static int64_t entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500839 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
840 uint8_t contained_count, uint8_t association_type, bool is_remote,
841 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930842{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930843 uint8_t *start;
844 uint8_t *pdr;
Archana Kakanibc40dd52024-08-02 00:10:44 -0500845 int64_t rc;
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930846
847 pdr = calloc(1, size);
848 if (!pdr) {
849 return -ENOMEM;
850 }
851
852 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853
854 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
855 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600856 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930857 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
858 hdr->record_change_num = 0;
859 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
860 start += sizeof(struct pldm_pdr_hdr);
861
862 uint16_t *container_id = (uint16_t *)start;
863 *container_id = htole16(curr->first_child->entity.entity_container_id);
864 start += sizeof(uint16_t);
865 *start = association_type;
866 start += sizeof(uint8_t);
867
868 pldm_entity *entity = (pldm_entity *)start;
869 entity->entity_type = htole16(curr->entity.entity_type);
870 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
871 entity->entity_container_id = htole16(curr->entity.entity_container_id);
872 start += sizeof(pldm_entity);
873
874 *start = contained_count;
875 start += sizeof(uint8_t);
876
877 pldm_entity_node *node = curr->first_child;
878 while (node != NULL) {
879 if (node->association_type == association_type) {
880 pldm_entity *entity = (pldm_entity *)start;
881 entity->entity_type = htole16(node->entity.entity_type);
882 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930883 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930884 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930885 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930886 start += sizeof(pldm_entity);
887 }
888 node = node->next_sibling;
889 }
890
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930891 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
892 &record_handle);
893 free(pdr);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500894 return (rc < 0) ? rc : record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895}
896
Archana Kakanibc40dd52024-08-02 00:10:44 -0500897static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
898 pldm_pdr *repo, bool is_remote,
899 uint16_t terminus_handle,
900 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930901{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930902 uint8_t num_logical_children = pldm_entity_get_num_children(
903 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
904 uint8_t num_physical_children = pldm_entity_get_num_children(
905 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500906 int64_t rc;
907
908 if (!num_logical_children && !num_physical_children) {
909 if (record_handle == 0) {
910 return -EINVAL;
911 }
912 return record_handle - 1;
913 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914
915 if (num_logical_children) {
916 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930917 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
918 sizeof(uint8_t) + sizeof(pldm_entity) +
919 sizeof(uint8_t) +
920 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930921 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930922 curr, repo, logical_pdr_size, num_logical_children,
923 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500924 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930925 if (rc < 0) {
926 return rc;
927 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500928 if (num_physical_children) {
929 if (rc >= UINT32_MAX) {
930 return -EOVERFLOW;
931 }
932 record_handle = rc + 1;
933 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930934 }
935
936 if (num_physical_children) {
937 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930938 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
939 sizeof(uint8_t) + sizeof(pldm_entity) +
940 sizeof(uint8_t) +
941 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930942 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930943 curr, repo, physical_pdr_size, num_physical_children,
944 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500945 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930946 if (rc < 0) {
947 return rc;
948 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500949 record_handle = rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930950 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930951
Archana Kakanibc40dd52024-08-02 00:10:44 -0500952 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953}
954
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930955static bool is_present(pldm_entity entity, pldm_entity **entities,
956 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930957{
958 if (entities == NULL || num_entities == 0) {
959 return true;
960 }
961 size_t i = 0;
962 while (i < num_entities) {
963 if ((*entities + i)->entity_type == entity.entity_type) {
964 return true;
965 }
966 i++;
967 }
968 return false;
969}
970
Archana Kakanibc40dd52024-08-02 00:10:44 -0500971static int64_t entity_association_pdr_add(pldm_entity_node *curr,
972 pldm_pdr *repo,
973 pldm_entity **entities,
974 size_t num_entities, bool is_remote,
975 uint16_t terminus_handle,
976 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930977{
Archana Kakanibc40dd52024-08-02 00:10:44 -0500978 int64_t rc;
Andrew Jeffery65945992023-07-17 15:04:21 +0930979
Andrew Jeffery9c766792022-08-10 23:12:49 +0930980 if (curr == NULL) {
Archana Kakanibc40dd52024-08-02 00:10:44 -0500981 // entity_association_pdr_add function gets called
982 // recursively for the siblings and children of the
983 // entity. This causes NULL current entity node, and the
984 // record handle is returned
985 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930986 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930987
988 if (is_present(curr->entity, entities, num_entities)) {
989 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500990 curr, repo, is_remote, terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500991 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930992 return rc;
993 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500994 if (rc >= UINT32_MAX) {
995 return -EOVERFLOW;
996 }
997 record_handle = rc + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930998 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930999
1000 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
1001 num_entities, is_remote,
1002 terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001003 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301004 return rc;
1005 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001006 // entity_association_pdr_add return record handle in success
1007 // case. If the pdr gets added to the repo, new record handle
1008 // will be returned. Below check confirms if the pdr is added
1009 // to the repo and increments the record handle
1010 if (record_handle != rc) {
1011 if (rc >= UINT32_MAX) {
1012 return -EOVERFLOW;
1013 }
1014 record_handle = rc + 1;
1015 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301016
Archana Kakanibc40dd52024-08-02 00:10:44 -05001017 rc = entity_association_pdr_add(curr->first_child, repo, entities,
1018 num_entities, is_remote,
1019 terminus_handle, record_handle);
1020 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301021}
1022
Andrew Jeffery096685b2023-07-17 17:36:14 +09301023LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +09301024int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
1025 pldm_pdr *repo, bool is_remote,
1026 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +09301027{
Andrew Jefferyc7883482023-06-30 15:52:04 +09301028 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301029 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +09301030 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001031 int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
1032 is_remote, terminus_handle, 0);
1033 assert(rc >= INT_MIN);
1034 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301035}
1036
Andrew Jeffery1354a6e2023-07-07 10:34:38 +09301037LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +09301038int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +09301039 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1040 size_t num_entities, bool is_remote, uint16_t terminus_handle)
1041{
1042 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001043 node, repo, entities, num_entities, is_remote, terminus_handle,
1044 0);
1045}
1046
Pavithra Barithaya3a267052023-11-13 05:01:36 -06001047LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001048int pldm_entity_association_pdr_add_from_node_with_record_handle(
1049 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1050 size_t num_entities, bool is_remote, uint16_t terminus_handle,
1051 uint32_t record_handle)
1052{
1053 if (!node || !repo || !entities) {
1054 return -EINVAL;
1055 }
1056
Archana Kakanibc40dd52024-08-02 00:10:44 -05001057 int64_t rc = entity_association_pdr_add(node, repo, entities,
1058 num_entities, is_remote,
1059 terminus_handle, record_handle);
1060
1061 assert(rc >= INT_MIN);
1062 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063}
1064
Andrew Jeffery643c4432023-07-17 15:36:03 +09301065static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
1066 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301067{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001068 bool is_entity_container_id;
1069 bool is_entity_instance_num;
1070 bool is_type;
1071
Andrew Jeffery9c766792022-08-10 23:12:49 +09301072 if (tree_node == NULL) {
1073 return;
1074 }
1075
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001076 is_type = tree_node->entity.entity_type == entity.entity_type;
1077 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1078 entity.entity_instance_num;
1079 is_entity_container_id = tree_node->entity.entity_container_id ==
1080 entity.entity_container_id;
1081
1082 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301083 *node = tree_node;
1084 return;
1085 }
1086
1087 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1088 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1089}
1090
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301091LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301092void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1093 pldm_entity entity, pldm_entity_node **node)
1094{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301095 if (!tree || !node) {
1096 return;
1097 }
1098
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099 find_entity_ref_in_tree(tree->root, entity, node);
1100}
1101
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301102LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301103void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1104 uint16_t terminus_handle)
1105{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301106 if (!repo) {
1107 return;
1108 }
1109
Andrew Jeffery9c766792022-08-10 23:12:49 +09301110 bool removed = false;
1111
1112 pldm_pdr_record *record = repo->first;
1113 pldm_pdr_record *prev = NULL;
1114 while (record != NULL) {
1115 pldm_pdr_record *next = record->next;
1116 if (record->terminus_handle == terminus_handle) {
1117 if (repo->first == record) {
1118 repo->first = next;
1119 } else {
1120 prev->next = next;
1121 }
1122 if (repo->last == record) {
1123 repo->last = prev;
1124 }
1125 if (record->data) {
1126 free(record->data);
1127 }
1128 --repo->record_count;
1129 repo->size -= record->size;
1130 free(record);
1131 removed = true;
1132 } else {
1133 prev = record;
1134 }
1135 record = next;
1136 }
1137
1138 if (removed == true) {
1139 record = repo->first;
1140 uint32_t record_handle = 0;
1141 while (record != NULL) {
1142 record->record_handle = ++record_handle;
1143 if (record->data != NULL) {
1144 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301145 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301147 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301148 }
1149 record = record->next;
1150 }
1151 }
1152}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301153
1154LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301155void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1156{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301157 if (!repo) {
1158 return;
1159 }
1160
Andrew Jeffery9c766792022-08-10 23:12:49 +09301161 bool removed = false;
1162
1163 pldm_pdr_record *record = repo->first;
1164 pldm_pdr_record *prev = NULL;
1165 while (record != NULL) {
1166 pldm_pdr_record *next = record->next;
1167 if (record->is_remote == true) {
1168 if (repo->first == record) {
1169 repo->first = next;
1170 } else {
1171 prev->next = next;
1172 }
1173 if (repo->last == record) {
1174 repo->last = prev;
1175 }
1176 if (record->data) {
1177 free(record->data);
1178 }
1179 --repo->record_count;
1180 repo->size -= record->size;
1181 free(record);
1182 removed = true;
1183 } else {
1184 prev = record;
1185 }
1186 record = next;
1187 }
1188
1189 if (removed == true) {
1190 record = repo->first;
1191 uint32_t record_handle = 0;
1192 while (record != NULL) {
1193 record->record_handle = ++record_handle;
1194 if (record->data != NULL) {
1195 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301196 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301197 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301198 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301199 }
1200 record = record->next;
1201 }
1202 }
1203}
1204
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001205LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001206pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1207 uint32_t first, uint32_t last)
1208{
1209 pldm_pdr_record *record = NULL;
1210 pldm_pdr_record *curr;
1211
1212 if (!repo) {
1213 return NULL;
1214 }
1215 for (curr = repo->first; curr; curr = curr->next) {
1216 if (first > curr->record_handle || last < curr->record_handle) {
1217 continue;
1218 }
1219 if (!record || curr->record_handle > record->record_handle) {
1220 record = curr;
1221 }
1222 }
1223
1224 return record;
1225}
1226
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001227static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1228 pldm_entity *entity,
1229 pldm_entity_node **out,
1230 bool is_remote)
1231{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001232 if (node == NULL) {
1233 return;
1234 }
1235 bool is_entity_type;
1236 bool is_entity_instance_num;
1237
1238 is_entity_type = node->entity.entity_type == entity->entity_type;
1239 is_entity_instance_num = node->entity.entity_instance_num ==
1240 entity->entity_instance_num;
1241
1242 if (!is_remote ||
1243 node->remote_container_id == entity->entity_container_id) {
1244 if (is_entity_type && is_entity_instance_num) {
1245 entity->entity_container_id =
1246 node->entity.entity_container_id;
1247 *out = node;
1248 return;
1249 }
1250 }
1251 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1252 is_remote);
1253 entity_association_tree_find_if_remote(node->first_child, entity, out,
1254 is_remote);
1255}
1256
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001257LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001258pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1259 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001260{
1261 if (!tree || !entity) {
1262 return NULL;
1263 }
1264 pldm_entity_node *node = NULL;
1265 entity_association_tree_find_if_remote(tree->root, entity, &node,
1266 is_remote);
1267 return node;
1268}
1269
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301270static void entity_association_tree_find(pldm_entity_node *node,
1271 pldm_entity *entity,
1272 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301273{
1274 if (node == NULL) {
1275 return;
1276 }
1277
1278 if (node->entity.entity_type == entity->entity_type &&
1279 node->entity.entity_instance_num == entity->entity_instance_num) {
1280 entity->entity_container_id = node->entity.entity_container_id;
1281 *out = node;
1282 return;
1283 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284 entity_association_tree_find(node->next_sibling, entity, out);
1285 entity_association_tree_find(node->first_child, entity, out);
1286}
1287
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301288LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301289pldm_entity_node *
1290pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1291 pldm_entity *entity)
1292{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301293 if (!tree || !entity) {
1294 return NULL;
1295 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301296
1297 pldm_entity_node *node = NULL;
1298 entity_association_tree_find(tree->root, entity, &node);
1299 return node;
1300}
1301
Andrew Jeffery60582152024-09-22 21:16:38 +09301302static int entity_association_tree_copy(pldm_entity_node *org_node,
1303 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301304{
Andrew Jeffery60582152024-09-22 21:16:38 +09301305 int rc;
1306
Andrew Jeffery9c766792022-08-10 23:12:49 +09301307 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301308 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301309 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301310
Andrew Jeffery9c766792022-08-10 23:12:49 +09301311 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301312 if (!*new_node) {
1313 return -ENOMEM;
1314 }
1315
Andrew Jeffery9c766792022-08-10 23:12:49 +09301316 (*new_node)->parent = org_node->parent;
1317 (*new_node)->entity = org_node->entity;
1318 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001319 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301320 (*new_node)->first_child = NULL;
1321 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301322
1323 rc = entity_association_tree_copy(org_node->first_child,
1324 &((*new_node)->first_child));
1325 if (rc) {
1326 goto cleanup;
1327 }
1328
1329 rc = entity_association_tree_copy(org_node->next_sibling,
1330 &((*new_node)->next_sibling));
1331 if (rc) {
1332 entity_association_tree_destroy((*new_node)->first_child);
1333 goto cleanup;
1334 }
1335
1336 return 0;
1337
1338cleanup:
1339 free(*new_node);
1340 *new_node = NULL;
1341 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301342}
1343
Andrew Jeffery36324f62024-09-25 13:41:41 +09301344LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301345void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301346 pldm_entity_association_tree *org_tree,
1347 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301348{
George Liuc6c391d2023-11-09 10:13:34 +08001349 assert(org_tree != NULL);
1350 assert(new_tree != NULL);
1351
Andrew Jeffery9c766792022-08-10 23:12:49 +09301352 new_tree->last_used_container_id = org_tree->last_used_container_id;
1353 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1354}
1355
Andrew Jeffery60582152024-09-22 21:16:38 +09301356LIBPLDM_ABI_TESTING
1357int pldm_entity_association_tree_copy_root_check(
1358 pldm_entity_association_tree *org_tree,
1359 pldm_entity_association_tree *new_tree)
1360{
1361 if (!org_tree || !new_tree) {
1362 return -EINVAL;
1363 }
1364
1365 new_tree->last_used_container_id = org_tree->last_used_container_id;
1366 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1367}
1368
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301369LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301370void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301371 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301372{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301373 if (!tree) {
1374 return;
1375 }
1376
Andrew Jeffery9c766792022-08-10 23:12:49 +09301377 entity_association_tree_destroy(tree->root);
1378 tree->last_used_container_id = 0;
1379 tree->root = NULL;
1380}
1381
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301382LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301383bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1384{
1385 return ((tree->root == NULL) ? true : false);
1386}
1387
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301388LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301389void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1390 size_t *num_entities,
1391 pldm_entity **entities)
1392{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301393 if (!pdr || !num_entities || !entities) {
1394 return;
1395 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001396 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301397 return;
1398 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301399
1400 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301401 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1402 return;
1403 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301404
1405 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301406
1407 if (UINTPTR_MAX - (uintptr_t)start <
1408 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1409 return;
1410 }
1411
1412 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1413 return;
1414 }
1415
1416 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301417 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301418 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301419
1420 if ((uintptr_t)end - (uintptr_t)start <
1421 sizeof(struct pldm_pdr_entity_association)) {
1422 return;
1423 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001424
Andrew Jeffery9c766792022-08-10 23:12:49 +09301425 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301426 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301427
Archana Kakanibc40dd52024-08-02 00:10:44 -05001428 size_t l_num_entities = entity_association_pdr->num_children;
1429
1430 if (l_num_entities == 0) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301431 return;
1432 }
Andrew Jeffery8f33a1d2024-10-11 18:01:19 +10301433
Archana Kakanibc40dd52024-08-02 00:10:44 -05001434 if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1435 l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301436 return;
1437 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301438
Archana Kakanibc40dd52024-08-02 00:10:44 -05001439 if (l_num_entities >= (size_t)UINT8_MAX) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301440 return;
1441 }
1442
Archana Kakanibc40dd52024-08-02 00:10:44 -05001443 l_num_entities++;
1444
Andrew Jeffery9e566592024-10-02 16:38:51 +09301445 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301446 if (!l_entities) {
1447 return;
1448 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301449 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301450 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301451 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301452 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301453 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301454 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301455 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301456 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1457 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1458 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301459 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301460 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301461 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301462 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301463
1464 *num_entities = l_num_entities;
1465 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301466}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001467
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301468/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001469 * the same position.
1470 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301471LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001472static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1473 pldm_pdr_record *prev,
1474 pldm_pdr_record *new_record)
1475{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001476 if (repo->size < record->size) {
1477 return -EOVERFLOW;
1478 }
1479
1480 if (repo->size + new_record->size < new_record->size) {
1481 return -EOVERFLOW;
1482 }
1483
1484 if (repo->first == record) {
1485 repo->first = new_record;
1486 } else {
1487 prev->next = new_record;
1488 }
1489 new_record->next = record->next;
1490
1491 if (repo->last == record) {
1492 repo->last = new_record;
1493 }
1494
1495 repo->size = (repo->size - record->size) + new_record->size;
1496 return 0;
1497}
1498
1499/* Insert a new record to pldm_pdr repo to a position that comes after
1500 * pldm_pdr_record record.
1501 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301502LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001503static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1504 pldm_pdr_record *new_record)
1505{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001506 if (repo->size + new_record->size < new_record->size) {
1507 return -EOVERFLOW;
1508 }
1509
1510 if (repo->record_count == UINT32_MAX) {
1511 return -EOVERFLOW;
1512 }
1513
1514 new_record->next = record->next;
1515 record->next = new_record;
1516
1517 if (repo->last == record) {
1518 repo->last = new_record;
1519 }
1520
1521 repo->size = repo->size + new_record->size;
1522 ++repo->record_count;
1523 return 0;
1524}
1525
1526/* Find the position of PDR when its record handle is known
1527 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301528LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001529static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1530 pldm_pdr_record **prev,
1531 uint32_t record_handle)
1532{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001533 while (*record != NULL) {
1534 if ((*record)->record_handle == record_handle) {
1535 return true;
1536 }
1537 *prev = *record;
1538 *record = (*record)->next;
1539 }
1540 return false;
1541}
1542
1543LIBPLDM_ABI_TESTING
1544int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1545 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1546{
1547 if (!repo || !entity) {
1548 return -EINVAL;
1549 }
1550
1551 pldm_pdr_record *record = repo->first;
1552 pldm_pdr_record *prev = repo->first;
1553 int rc = 0;
1554 uint16_t header_length = 0;
1555 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10301556 PLDM_MSGBUF_DEFINE_P(src);
1557 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001558
1559 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1560
1561 if (!record) {
1562 return -EINVAL;
1563 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001564
1565 // check if adding another entity to record causes overflow before
1566 // allocating memory for new_record.
1567 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1568 return -EOVERFLOW;
1569 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301570
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001571 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1572 if (!new_record) {
1573 return -ENOMEM;
1574 }
1575
1576 new_record->data = malloc(record->size + sizeof(pldm_entity));
1577 if (!new_record->data) {
1578 rc = -ENOMEM;
1579 goto cleanup_new_record;
1580 }
1581
1582 new_record->record_handle = record->record_handle;
1583 new_record->size = record->size + sizeof(struct pldm_entity);
1584 new_record->is_remote = record->is_remote;
1585
Andrew Jefferya1896962025-03-03 21:41:25 +10301586 // Initialize msg buffer for record and record->data
1587 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1588 record->data, record->size);
1589 if (rc) {
1590 goto cleanup_new_record_data;
1591 }
1592
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001593 // Initialize new PDR record with data from original PDR record.
1594 // Start with adding the header of original PDR
1595 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1596 new_record->data, new_record->size);
1597 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301598 goto cleanup_src_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001599 }
1600
1601 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1602 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1603 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1604 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1605 // extract the header length from record and increment size with
1606 // size of pldm_entity before inserting the value into new_record.
1607 rc = pldm_msgbuf_extract(src, header_length);
1608 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301609 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001610 }
1611 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1612 "Fix the following bounds check.");
1613 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1614 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301615 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001616 }
1617 header_length += sizeof(pldm_entity);
1618 pldm_msgbuf_insert(dst, header_length);
1619 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1620 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1621 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1622 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1623 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1624 // extract value of number of children from record and increment it
1625 // by 1 before insert the value to new record.
1626 rc = pldm_msgbuf_extract(src, num_children);
1627 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301628 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001629 }
1630 if (num_children == UINT8_MAX) {
1631 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301632 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001633 }
1634 num_children += 1;
1635 pldm_msgbuf_insert(dst, num_children);
1636 //Add all children of original PDR to new PDR
1637 for (int i = 0; i < num_children - 1; i++) {
1638 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1639 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1640 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1641 }
1642
1643 // Add new contained entity as a child of new PDR
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301644 rc = pldm_msgbuf_complete(src);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001645 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301646 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001647 goto cleanup_new_record_data;
1648 }
1649 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1650 sizeof(struct pldm_entity));
1651 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301652 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001653 goto cleanup_new_record_data;
1654 }
1655 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1656 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1657 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1658
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301659 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001660 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301661 goto cleanup_src_msgbuf;
1662 }
1663 rc = pldm_msgbuf_complete(src);
1664 if (rc) {
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001665 goto cleanup_new_record_data;
1666 }
1667
1668 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1669 if (rc) {
1670 goto cleanup_new_record_data;
1671 }
1672
1673 free(record->data);
1674 free(record);
1675 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301676cleanup_dst_msgbuf:
1677 rc = pldm_msgbuf_discard(dst, rc);
1678cleanup_src_msgbuf:
1679 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001680cleanup_new_record_data:
1681 free(new_record->data);
1682cleanup_new_record:
1683 free(new_record);
1684 return rc;
1685}
1686
1687LIBPLDM_ABI_TESTING
1688int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1689 uint32_t pdr_record_handle,
1690 pldm_entity *parent,
1691 pldm_entity *entity,
1692 uint32_t *entity_record_handle)
1693{
1694 if (!repo || !parent || !entity || !entity_record_handle) {
1695 return -EINVAL;
1696 }
1697
1698 if (pdr_record_handle == UINT32_MAX) {
1699 return -EOVERFLOW;
1700 }
1701
1702 bool pdr_added = false;
1703 uint16_t new_pdr_size;
1704 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001705 void *container_id_addr;
Andrew Jefferya1896962025-03-03 21:41:25 +10301706 PLDM_MSGBUF_DEFINE_P(dst);
1707 PLDM_MSGBUF_DEFINE_P(src_p);
1708 PLDM_MSGBUF_DEFINE_P(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001709 int rc = 0;
1710
1711 pldm_pdr_record *prev = repo->first;
1712 pldm_pdr_record *record = repo->first;
1713 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1714 pdr_record_handle);
1715 if (!pdr_added) {
1716 return -ENOENT;
1717 }
1718
1719 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1720 "Truncation ahead");
1721 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1722 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1723 if (!new_record) {
1724 return -ENOMEM;
1725 }
1726
1727 new_record->data = malloc(new_pdr_size);
1728 if (!new_record->data) {
1729 rc = -ENOMEM;
1730 goto cleanup_new_record;
1731 }
1732
1733 // Initialise new PDR to be added with the header, size and handle.
1734 // Set the position of new PDR
1735 *entity_record_handle = pdr_record_handle + 1;
1736 new_record->record_handle = *entity_record_handle;
1737 new_record->size = new_pdr_size;
1738 new_record->is_remote = false;
1739
1740 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1741 new_record->data, new_record->size);
1742 if (rc) {
1743 goto cleanup_new_record_data;
1744 }
1745
1746 // header record handle
1747 pldm_msgbuf_insert(dst, *entity_record_handle);
1748 // header version
1749 pldm_msgbuf_insert_uint8(dst, 1);
1750 // header type
1751 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1752 // header change number
1753 pldm_msgbuf_insert_uint16(dst, 0);
1754 // header length
1755 pldm_msgbuf_insert_uint16(dst,
1756 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1757
1758 // Data for new PDR is obtained from parent PDR and new contained entity
1759 // is added as the child
1760 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1761 sizeof(*parent));
1762 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301763 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001764 }
1765
1766 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1767 sizeof(*entity));
1768 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301769 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001770 }
1771
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001772 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001773 // extract pointer for container ID and save the address
1774 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1775 (void **)&container_id_addr);
1776 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301777 goto cleanup_msgbuf_src_c;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001778 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001779 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001780 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1781 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1782 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1783 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1784 // number of children
1785 pldm_msgbuf_insert_uint8(dst, 1);
1786
1787 // Add new entity as child
1788 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1789 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1790 // Extract and insert child entity container ID and add same value to
1791 // container ID of entity
1792 pldm_msgbuf_extract(src_c, container_id);
1793 pldm_msgbuf_insert(dst, container_id);
1794 container_id = htole16(container_id);
1795 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1796
Andrew Jefferya1896962025-03-03 21:41:25 +10301797 rc = pldm_msgbuf_complete(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001798 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301799 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001800 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301801 rc = pldm_msgbuf_complete(src_p);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001802 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301803 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001804 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301805 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001806 if (rc) {
1807 goto cleanup_new_record_data;
1808 }
1809
1810 rc = pldm_pdr_insert_record(repo, record, new_record);
1811 if (rc) {
1812 goto cleanup_new_record_data;
1813 }
1814
1815 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301816cleanup_msgbuf_src_c:
1817 rc = pldm_msgbuf_discard(src_c, rc);
1818cleanup_msgbuf_src_p:
1819 rc = pldm_msgbuf_discard(src_p, rc);
1820cleanup_msgbuf_dst:
1821 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001822cleanup_new_record_data:
1823 free(new_record->data);
1824cleanup_new_record:
1825 free(new_record);
1826 return rc;
1827}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001828
1829LIBPLDM_CC_NONNULL
1830static bool pldm_entity_cmp(const struct pldm_entity *l,
1831 const struct pldm_entity *r)
1832{
1833 return l->entity_type == r->entity_type &&
1834 l->entity_instance_num == r->entity_instance_num &&
1835 l->entity_container_id == r->entity_container_id;
1836}
1837
1838/* Find record handle of a PDR record from PDR repo and
1839 * entity
1840 */
1841LIBPLDM_CC_NONNULL
1842static int pldm_entity_association_find_record_handle_by_entity(
1843 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1844 uint32_t *record_handle)
1845{
1846 uint8_t num_children = 0;
1847 uint8_t hdr_type = 0;
1848 int rc = 0;
1849 size_t skip_data_size = 0;
1850 pldm_pdr_record *record = repo->first;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001851
1852 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301853 PLDM_MSGBUF_DEFINE_P(dst);
1854
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001855 rc = pldm_msgbuf_init_errno(dst,
1856 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1857 record->data, record->size);
1858 if (rc) {
1859 return rc;
1860 }
1861 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1862 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10301863 rc = pldm_msgbuf_extract(dst, hdr_type);
1864 if (rc) {
1865 return pldm_msgbuf_discard(dst, rc);
1866 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001867 if (record->is_remote != is_remote ||
1868 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1869 goto cleanup;
1870 }
1871 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1872 sizeof(uint16_t) + sizeof(uint8_t) +
1873 sizeof(struct pldm_entity);
1874 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10301875 rc = pldm_msgbuf_extract(dst, num_children);
1876 if (rc) {
1877 return pldm_msgbuf_discard(dst, rc);
1878 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001879 for (int i = 0; i < num_children; ++i) {
1880 struct pldm_entity e;
1881
1882 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1883 (rc = pldm_msgbuf_extract(dst,
1884 e.entity_instance_num)) ||
1885 (rc = pldm_msgbuf_extract(dst,
1886 e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301887 return pldm_msgbuf_discard(dst, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001888 }
1889
1890 if (pldm_entity_cmp(entity, &e)) {
1891 *record_handle = record->record_handle;
Andrew Jefferya1896962025-03-03 21:41:25 +10301892 return pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001893 }
1894 }
1895 cleanup:
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301896 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001897 if (rc) {
1898 return rc;
1899 }
1900 record = record->next;
1901 }
1902 return 0;
1903}
1904
1905LIBPLDM_ABI_TESTING
1906int pldm_entity_association_pdr_remove_contained_entity(
1907 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1908 uint32_t *pdr_record_handle)
1909{
1910 uint16_t header_length = 0;
1911 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10301912 PLDM_MSGBUF_DEFINE_P(src);
1913 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001914 int rc;
1915 pldm_pdr_record *record;
1916 pldm_pdr_record *prev;
1917
1918 if (!repo || !entity || !pdr_record_handle) {
1919 return -EINVAL;
1920 }
1921 record = repo->first;
1922 prev = repo->first;
1923
1924 rc = pldm_entity_association_find_record_handle_by_entity(
1925 repo, entity, is_remote, pdr_record_handle);
1926 if (rc) {
1927 return rc;
1928 }
1929 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
1930 if (!record) {
1931 return -EINVAL;
1932 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001933 // check if removing an entity from record causes overflow before
1934 // allocating memory for new_record.
1935 if (record->size < sizeof(pldm_entity)) {
1936 return -EOVERFLOW;
1937 }
1938 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1939 if (!new_record) {
1940 return -ENOMEM;
1941 }
1942 new_record->data = malloc(record->size - sizeof(pldm_entity));
1943 if (!new_record->data) {
1944 rc = -ENOMEM;
1945 goto cleanup_new_record;
1946 }
1947 new_record->record_handle = record->record_handle;
1948 new_record->size = record->size - sizeof(struct pldm_entity);
1949 new_record->is_remote = record->is_remote;
1950
Andrew Jefferya1896962025-03-03 21:41:25 +10301951 // Initialize msg buffer for record and record->data
1952 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1953 record->data, record->size);
1954 if (rc) {
1955 goto cleanup_new_record_data;
1956 }
1957
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001958 // Initialize new PDR record with data from original PDR record.
1959 // Start with adding the header of original PDR
Archana Kakani94e2d752024-12-12 08:22:55 -06001960 rc = pldm_msgbuf_init_errno(
1961 dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
1962 new_record->data, new_record->size);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001963 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301964 goto cleanup_msgbuf_src;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001965 }
1966 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1967 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1968 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1969 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1970 // extract the header length from record and decrement size with
1971 // size of pldm_entity before inserting the value into new_record.
1972 rc = pldm_msgbuf_extract(src, header_length);
1973 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301974 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001975 }
1976 if (header_length < sizeof(pldm_entity)) {
1977 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301978 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001979 }
1980 header_length -= sizeof(pldm_entity);
1981 pldm_msgbuf_insert(dst, header_length);
1982 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1983 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1984 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1985 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1986 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1987 // extract value of number of children from record and decrement it
1988 // by 1 before insert the value to new record.
1989 rc = pldm_msgbuf_extract(src, num_children);
1990 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301991 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001992 }
1993 if (num_children == 1) {
Archana Kakani94e2d752024-12-12 08:22:55 -06001994 // This is the last child which is getting removed so we need to delete the Entity Association PDR.
1995 pldm_pdr_remove_record(repo, record,
1996 pldm_pdr_get_prev_record(repo, record));
Andrew Jefferya1896962025-03-03 21:41:25 +10301997 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001998 } else if (num_children < 1) {
1999 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302000 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002001 }
2002 num_children -= 1;
2003 pldm_msgbuf_insert(dst, num_children);
2004 //Add all children of original PDR to new PDR
2005 for (int i = 0; i < num_children + 1; ++i) {
2006 struct pldm_entity e;
2007
2008 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
2009 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
2010 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302011 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002012 }
2013
2014 if (pldm_entity_cmp(entity, &e)) {
2015 continue;
2016 }
2017
2018 pldm_msgbuf_insert(dst, e.entity_type);
2019 pldm_msgbuf_insert(dst, e.entity_instance_num);
2020 pldm_msgbuf_insert(dst, e.entity_container_id);
2021 }
2022
Andrew Jefferya1896962025-03-03 21:41:25 +10302023 rc = pldm_msgbuf_complete(dst);
2024 if (rc) {
2025 goto cleanup_msgbuf_src;
2026 }
2027
2028 rc = pldm_msgbuf_complete(src);
2029 if (rc) {
2030 goto cleanup_new_record_data;
2031 }
2032
2033 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
2034 if (rc) {
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002035 goto cleanup_new_record_data;
2036 }
2037
2038 free(record->data);
2039 free(record);
2040 return rc;
2041
Andrew Jefferya1896962025-03-03 21:41:25 +10302042cleanup_msgbuf_dst:
2043 rc = pldm_msgbuf_discard(dst, rc);
2044cleanup_msgbuf_src:
2045 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002046cleanup_new_record_data:
2047 free(new_record->data);
2048cleanup_new_record:
2049 free(new_record);
2050 return rc;
2051}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002052
2053/* API to find the PDR record that is previous to a given PLDM PDR
2054 * record in a given PLDM PDR repository
2055 */
2056LIBPLDM_CC_NONNULL
2057static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
2058 pldm_pdr_record *record)
2059{
2060 pldm_pdr_record *prev = NULL;
2061 pldm_pdr_record *curr = repo->first;
2062
2063 while (curr != NULL) {
2064 if (curr->record_handle == record->record_handle) {
2065 break;
2066 }
2067 prev = curr;
2068 curr = curr->next;
2069 }
2070 return prev;
2071}
2072
2073/* API to check if a PLDM PDR record is present in a PLDM PDR repository
2074 */
2075LIBPLDM_CC_NONNULL
2076static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
2077{
2078 if (repo->first == record) {
2079 return true;
2080 }
2081
2082 return pldm_pdr_get_prev_record(repo, record) != NULL;
2083}
2084
2085/* API to check if FRU RSI of record matches the given record set identifier.
2086 * Returns 1 if the provided FRU record matches the provided record set identifier,
2087 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
2088 */
2089LIBPLDM_CC_NONNULL
2090static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
2091 uint16_t rsi)
2092{
2093 uint16_t record_fru_rsi = 0;
2094 uint8_t *skip_data = NULL;
2095 uint8_t skip_data_size = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10302096 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002097 int rc = 0;
2098
2099 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
2100 record->data, record->size);
2101 if (rc) {
2102 return rc;
2103 }
2104 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
2105 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
2106 pldm_msgbuf_extract(dst, record_fru_rsi);
2107
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302108 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002109 if (rc) {
2110 return rc;
2111 }
2112 return record_fru_rsi == rsi;
2113}
2114
2115/* API to remove PLDM PDR record from a PLDM PDR repository
2116 */
2117LIBPLDM_CC_NONNULL_ARGS(1, 2)
2118static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2119 pldm_pdr_record *prev)
2120{
2121 if (!is_prev_record_present(repo, record)) {
2122 return -EINVAL;
2123 }
2124
2125 assert(repo->size >= record->size);
2126 if (repo->size < record->size) {
2127 return -EOVERFLOW;
2128 }
2129
2130 if (repo->first == record) {
2131 repo->first = record->next;
2132 } else {
2133 if (prev != NULL) {
2134 prev->next = record->next;
2135 }
2136 }
2137
2138 if (repo->last == record) {
2139 repo->last = prev;
2140 if (prev != NULL) {
2141 prev->next = NULL;
2142 }
2143 }
2144 repo->record_count -= 1;
2145 repo->size -= record->size;
2146 free(record->data);
2147 free(record);
2148
2149 return 0;
2150}
2151
2152LIBPLDM_ABI_TESTING
2153int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2154 bool is_remote,
2155 uint32_t *record_handle)
2156{
2157 pldm_pdr_record *record;
2158 pldm_pdr_record *prev = NULL;
2159 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2160 uint8_t hdr_type = 0;
2161 int rc = 0;
2162 int match;
2163
2164 if (!repo || !record_handle) {
2165 return -EINVAL;
2166 }
2167 record = repo->first;
2168
2169 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302170 PLDM_MSGBUF_DEFINE_P(buf);
2171
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002172 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2173 record->data, record->size);
2174 if (rc) {
2175 return rc;
2176 }
2177 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302178 pldm_msgbuf_extract(buf, hdr_type);
2179 rc = pldm_msgbuf_complete(buf);
2180 if (rc) {
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002181 return rc;
2182 }
2183 if (record->is_remote != is_remote ||
2184 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302185 goto next;
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002186 }
2187 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2188 if (match < 0) {
2189 return match;
2190 }
2191 if (match) {
2192 *record_handle = record->record_handle;
2193 prev = pldm_pdr_get_prev_record(repo, record);
2194 return pldm_pdr_remove_record(repo, record, prev);
2195 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302196 next:
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002197 record = record->next;
2198 }
2199 return rc;
2200}