blob: 326233c33df805671116e8e3d192f997164545e0 [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
Andrew Jeffery9c766792022-08-10 23:12:49 +093038static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
39 const pldm_pdr_record *record)
40{
Andrew Jeffery9c766792022-08-10 23:12:49 +093041 if (record == repo->last) {
42 return 0;
43 }
44 return record->next->record_handle;
45}
46
Andrew Jefferyca248ce2023-07-07 10:38:30 +093047LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000048int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
49 bool is_remote, uint16_t terminus_handle,
50 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093051{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050052 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093053
Andrew Jeffery3b93d092023-07-17 13:01:50 +093054 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093055 return -EINVAL;
56 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093057
Andrew Jeffery3b93d092023-07-17 13:01:50 +093058 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093059 curr = *record_handle;
60 } else if (repo->last) {
61 curr = repo->last->record_handle;
62 if (curr == UINT32_MAX) {
63 return -EOVERFLOW;
64 }
65 curr += 1;
66 } else {
67 curr = 1;
68 }
69
Andrew Jeffery9c766792022-08-10 23:12:49 +093070 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093071 if (!record) {
72 return -ENOMEM;
73 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093074
Andrew Jeffery572a3952023-07-03 13:19:28 +093075 if (data) {
76 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093077 if (!record->data) {
78 free(record);
79 return -ENOMEM;
80 }
81 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093082 }
83
Andrew Jeffery9c766792022-08-10 23:12:49 +093084 record->size = size;
85 record->is_remote = is_remote;
86 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093087 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093088
Andrew Jeffery3b93d092023-07-17 13:01:50 +093089 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093090 /* If record handle is 0, that is an indication for this API to
91 * compute a new handle. For that reason, the computed handle
92 * needs to be populated in the PDR header. For a case where the
93 * caller supplied the record handle, it would exist in the
94 * header already.
95 */
96 struct pldm_pdr_hdr *hdr = (void *)record->data;
97 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093098 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093099
Andrew Jeffery9c766792022-08-10 23:12:49 +0930100 record->next = NULL;
101
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930102 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930103 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930104 repo->first = record;
105 repo->last = record;
106 } else {
107 repo->last->next = record;
108 repo->last = record;
109 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930110
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930111 repo->size += record->size;
112 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930113
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930114 if (record_handle) {
115 *record_handle = record->record_handle;
116 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930117
118 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119}
120
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930121LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930122pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930123{
124 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930125 if (!repo) {
126 return NULL;
127 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128 repo->record_count = 0;
129 repo->size = 0;
130 repo->first = NULL;
131 repo->last = NULL;
132
133 return repo;
134}
135
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930136LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137void pldm_pdr_destroy(pldm_pdr *repo)
138{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930139 if (!repo) {
140 return;
141 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930142
143 pldm_pdr_record *record = repo->first;
144 while (record != NULL) {
145 pldm_pdr_record *next = record->next;
146 if (record->data) {
147 free(record->data);
148 record->data = NULL;
149 }
150 free(record);
151 record = next;
152 }
153 free(repo);
154}
155
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930156LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930157const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
158 uint32_t record_handle,
159 uint8_t **data, uint32_t *size,
160 uint32_t *next_record_handle)
161{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930162 if (!repo || !data || !size || !next_record_handle) {
163 return NULL;
164 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165
166 if (!record_handle && (repo->first != NULL)) {
167 record_handle = repo->first->record_handle;
168 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930169
Andrew Jeffery9c766792022-08-10 23:12:49 +0930170 pldm_pdr_record *record = repo->first;
171 while (record != NULL) {
172 if (record->record_handle == record_handle) {
173 *size = record->size;
174 *data = record->data;
175 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930176 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930177 return record;
178 }
179 record = record->next;
180 }
181
182 *size = 0;
183 *next_record_handle = 0;
184 return NULL;
185}
186
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930187LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930188const pldm_pdr_record *
189pldm_pdr_get_next_record(const pldm_pdr *repo,
190 const pldm_pdr_record *curr_record, uint8_t **data,
191 uint32_t *size, uint32_t *next_record_handle)
192{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930193 if (!repo || !curr_record || !data || !size || !next_record_handle) {
194 return NULL;
195 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196
197 if (curr_record == repo->last) {
198 *data = NULL;
199 *size = 0;
200 *next_record_handle = get_next_record_handle(repo, curr_record);
201 return NULL;
202 }
203
204 *next_record_handle = get_next_record_handle(repo, curr_record->next);
205 *data = curr_record->next->data;
206 *size = curr_record->next->size;
207 return curr_record->next;
208}
209
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930210LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930211const pldm_pdr_record *
212pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
213 const pldm_pdr_record *curr_record, uint8_t **data,
214 uint32_t *size)
215{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930216 if (!repo) {
217 return NULL;
218 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219
220 pldm_pdr_record *record = repo->first;
221 if (curr_record != NULL) {
222 record = curr_record->next;
223 }
224 while (record != NULL) {
225 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
226 if (hdr->type == pdr_type) {
227 if (data && size) {
228 *size = record->size;
229 *data = record->data;
230 }
231 return record;
232 }
233 record = record->next;
234 }
235
236 if (size) {
237 *size = 0;
238 }
239 return NULL;
240}
241
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930242LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930243uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
244{
245 assert(repo != NULL);
246
247 return repo->record_count;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
252{
253 assert(repo != NULL);
254
255 return repo->size;
256}
257
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930258LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000259uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930260 const pldm_pdr_record *record)
261{
262 assert(repo != NULL);
263 assert(record != NULL);
264
265 return record->record_handle;
266}
267
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530268LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000269uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530270 const pldm_pdr_record *record)
271{
272 assert(repo != NULL);
273 assert(record != NULL);
274
275 return record->terminus_handle;
276}
277
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930278LIBPLDM_ABI_STABLE
279bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930280{
281 assert(record != NULL);
282
283 return record->is_remote;
284}
285
Andrew Jefferya2c69112023-07-07 10:41:38 +0930286LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930287int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
288 uint16_t fru_rsi, uint16_t entity_type,
289 uint16_t entity_instance_num,
290 uint16_t container_id,
291 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930292{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930293 if (!repo || !bmc_record_handle) {
294 return -EINVAL;
295 }
296
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930297 uint8_t data[sizeof(struct pldm_pdr_hdr) +
298 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930299
300 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
301 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930302 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930303 hdr->type = PLDM_PDR_FRU_RECORD_SET;
304 hdr->record_change_num = 0;
305 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
306 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930307 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
308 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930309 fru->terminus_handle = htole16(terminus_handle);
310 fru->fru_rsi = htole16(fru_rsi);
311 fru->entity_type = htole16(entity_type);
312 fru->entity_instance_num = htole16(entity_instance_num);
313 fru->container_id = htole16(container_id);
314
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930315 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000316 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317}
318
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930319LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930320const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930321 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
322 uint16_t *entity_type, uint16_t *entity_instance_num,
323 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930324{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930325 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
326 !container_id) {
327 return NULL;
328 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329
330 uint8_t *data = NULL;
331 uint32_t size = 0;
332 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930333 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930334 while (curr_record != NULL) {
335 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930336 (struct pldm_pdr_fru_record_set
337 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338 if (fru->fru_rsi == htole16(fru_rsi)) {
339 *terminus_handle = le16toh(fru->terminus_handle);
340 *entity_type = le16toh(fru->entity_type);
341 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930342 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343 *container_id = le16toh(fru->container_id);
344 return curr_record;
345 }
346 data = NULL;
347 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930348 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
349 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930350 }
351
352 *terminus_handle = 0;
353 *entity_type = 0;
354 *entity_instance_num = 0;
355 *container_id = 0;
356
357 return NULL;
358}
359
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930360LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930361/* NOLINTNEXTLINE(readability-identifier-naming) */
362void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
363 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930364{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930365 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930366 uint32_t size = 0;
367 const pldm_pdr_record *record;
368 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930370
371 do {
372 if (record != NULL) {
373 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930374 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930375 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930376 (struct pldm_terminus_locator_type_mctp_eid *)
377 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930378 if (pdr->terminus_handle == terminus_handle &&
379 pdr->tid == tid && value->eid == tl_eid) {
380 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930381 break;
382 }
383 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930384 record = pldm_pdr_find_record_by_type(repo,
385 PLDM_TERMINUS_LOCATOR_PDR,
386 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930387 } while (record);
388}
389
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500390static bool pldm_record_handle_in_range(uint32_t record_handle,
391 uint32_t first_record_handle,
392 uint32_t last_record_handle)
393{
394 return record_handle >= first_record_handle &&
395 record_handle <= last_record_handle;
396}
397
398LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500399int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500400 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500401 uint8_t child_index, uint32_t range_exclude_start_handle,
402 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500403{
404 pldm_pdr_record *record;
405 if (!repo) {
406 return -EINVAL;
407 }
408
409 for (record = repo->first; record; record = record->next) {
410 bool is_container_entity_instance_number;
411 struct pldm_pdr_entity_association *pdr;
412 bool is_container_entity_type;
413 struct pldm_entity *child;
414 struct pldm_pdr_hdr *hdr;
415 bool in_range;
416
417 // pldm_pdr_add() takes only uint8_t* data as an argument.
418 // The expectation here is the pldm_pdr_hdr is the first field of the record data
419 hdr = (struct pldm_pdr_hdr *)record->data;
420 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
421 continue;
422 }
423 in_range = pldm_record_handle_in_range(
424 record->record_handle, range_exclude_start_handle,
425 range_exclude_end_handle);
426 if (in_range) {
427 continue;
428 }
429
430 // this cast is valid with respect to alignment because
431 // struct pldm_pdr_hdr is declared with __attribute__((packed))
432 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500433 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500434 continue;
435 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500436
437 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500438 is_container_entity_type = pdr->container.entity_type ==
439 entity_type;
440 is_container_entity_instance_number =
441 pdr->container.entity_instance_num == entity_instance;
442 if (is_container_entity_type &&
443 is_container_entity_instance_number) {
444 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500445 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500446 }
447 }
448 return -ENOKEY;
449}
450
Andrew Jeffery9c766792022-08-10 23:12:49 +0930451typedef struct pldm_entity_association_tree {
452 pldm_entity_node *root;
453 uint16_t last_used_container_id;
454} pldm_entity_association_tree;
455
456typedef struct pldm_entity_node {
457 pldm_entity entity;
458 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600459 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930460 pldm_entity_node *first_child;
461 pldm_entity_node *next_sibling;
462 uint8_t association_type;
463} pldm_entity_node;
464
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930465LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930466pldm_entity pldm_entity_extract(pldm_entity_node *node)
467{
468 assert(node != NULL);
469
470 return node->entity;
471}
472
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500473LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930474uint16_t
475pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600476{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930477 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600478
Andrew Jeffery15b88182023-06-30 13:29:17 +0930479 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600480}
481
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930482LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930483pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930484{
485 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930486 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930487 if (!tree) {
488 return NULL;
489 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930490 tree->root = NULL;
491 tree->last_used_container_id = 0;
492
493 return tree;
494}
495
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930496LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930497static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
498 uint16_t entity_type)
499{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930500 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530501 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930502 */
503 while (start->next_sibling != NULL) {
504 uint16_t this_type = start->entity.entity_type;
505 pldm_entity_node *next = start->next_sibling;
506 if (this_type == entity_type &&
507 (this_type != next->entity.entity_type)) {
508 break;
509 }
510 start = start->next_sibling;
511 }
512
513 return start;
514}
515
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930516LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930517pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930518 pldm_entity_association_tree *tree, pldm_entity *entity,
519 uint16_t entity_instance_number, pldm_entity_node *parent,
520 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930521{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500522 return pldm_entity_association_tree_add_entity(tree, entity,
523 entity_instance_number,
524 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600525 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500526}
527
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500528LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500529pldm_entity_node *pldm_entity_association_tree_add_entity(
530 pldm_entity_association_tree *tree, pldm_entity *entity,
531 uint16_t entity_instance_number, pldm_entity_node *parent,
532 uint8_t association_type, bool is_remote, bool is_update_container_id,
533 uint16_t container_id)
534{
535 if ((!tree) || (!entity)) {
536 return NULL;
537 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930538
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600539 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930540 pldm_entity node;
541 node.entity_type = entity->entity_type;
542 node.entity_instance_num = entity_instance_number;
543 if (pldm_is_current_parent_child(parent, &node)) {
544 return NULL;
545 }
546 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500547 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
548 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
549 return NULL;
550 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930551 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500552 if (!node) {
553 return NULL;
554 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930555 node->first_child = NULL;
556 node->next_sibling = NULL;
557 node->parent.entity_type = 0;
558 node->parent.entity_instance_num = 0;
559 node->parent.entity_container_id = 0;
560 node->entity.entity_type = entity->entity_type;
561 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600562 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600564 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930565 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500566 if (parent != NULL) {
567 free(node);
568 return NULL;
569 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930570 tree->root = node;
571 /* container_id 0 here indicates this is the top-most entry */
572 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600573 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930574 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930575 /* Ensure next_container_id() will yield a valid ID */
576 if (tree->last_used_container_id == UINT16_MAX) {
577 free(node);
578 return NULL;
579 }
580
Andrew Jeffery9c766792022-08-10 23:12:49 +0930581 parent->first_child = node;
582 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500583
584 if (is_remote) {
585 node->remote_container_id = entity->entity_container_id;
586 }
587 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600588 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500589 node->entity.entity_container_id = container_id;
590 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930591 /* We will have returned above */
592 assert(tree->last_used_container_id !=
593 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500594 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930595 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500596 }
597 } else {
598 node->entity.entity_container_id =
599 entity->entity_container_id;
600 }
601
602 if (!is_remote) {
603 node->remote_container_id =
604 node->entity.entity_container_id;
605 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930606 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930607 pldm_entity_node *start = parent == NULL ? tree->root :
608 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930609 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930610 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500611 if (!prev) {
612 free(node);
613 return NULL;
614 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930615 pldm_entity_node *next = prev->next_sibling;
616 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500617 if (prev->entity.entity_instance_num == UINT16_MAX) {
618 free(node);
619 return NULL;
620 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930621 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600622 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930623 entity_instance_number :
624 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930625 }
626 prev->next_sibling = node;
627 node->parent = prev->parent;
628 node->next_sibling = next;
629 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930630 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600631 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930632 }
633 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500634 if (is_update_container_id) {
635 entity->entity_container_id = node->entity.entity_container_id;
636 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930637 return node;
638}
639
640static void get_num_nodes(pldm_entity_node *node, size_t *num)
641{
642 if (node == NULL) {
643 return;
644 }
645
646 ++(*num);
647 get_num_nodes(node->next_sibling, num);
648 get_num_nodes(node->first_child, num);
649}
650
651static void entity_association_tree_visit(pldm_entity_node *node,
652 pldm_entity *entities, size_t *index)
653{
654 if (node == NULL) {
655 return;
656 }
657
658 pldm_entity *entity = &entities[*index];
659 ++(*index);
660 entity->entity_type = node->entity.entity_type;
661 entity->entity_instance_num = node->entity.entity_instance_num;
662 entity->entity_container_id = node->entity.entity_container_id;
663
664 entity_association_tree_visit(node->next_sibling, entities, index);
665 entity_association_tree_visit(node->first_child, entities, index);
666}
667
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930668LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930669void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
670 pldm_entity **entities, size_t *size)
671{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930672 if (!tree || !entities || !size) {
673 return;
674 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930675
676 *size = 0;
677 if (tree->root == NULL) {
678 return;
679 }
680
681 get_num_nodes(tree->root, size);
682 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930683 if (!entities) {
684 return;
685 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686 size_t index = 0;
687 entity_association_tree_visit(tree->root, *entities, &index);
688}
689
690static void entity_association_tree_destroy(pldm_entity_node *node)
691{
692 if (node == NULL) {
693 return;
694 }
695
696 entity_association_tree_destroy(node->next_sibling);
697 entity_association_tree_destroy(node->first_child);
698 free(node);
699}
700
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930701LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930702void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
703{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930704 if (!tree) {
705 return;
706 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930707
708 entity_association_tree_destroy(tree->root);
709 free(tree);
710}
711
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930712LIBPLDM_ABI_STABLE
713bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714{
715 assert(node != NULL);
716
717 return node->first_child != NULL;
718}
719
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930720LIBPLDM_ABI_STABLE
721pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722{
723 assert(node != NULL);
724
725 return node->parent;
726}
727
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930728LIBPLDM_ABI_STABLE
729bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930731 if (!node) {
732 return false;
733 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734
735 if (node->parent.entity_type == 0 &&
736 node->parent.entity_instance_num == 0 &&
737 node->parent.entity_container_id == 0) {
738 return false;
739 }
740
741 return true;
742}
743
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930744LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930745uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
746 uint8_t association_type)
747{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930748 if (!node) {
749 return 0;
750 }
751
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930752 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
753 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
754 return 0;
755 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930756
757 size_t count = 0;
758 pldm_entity_node *curr = node->first_child;
759 while (curr != NULL) {
760 if (curr->association_type == association_type) {
761 ++count;
762 }
763 curr = curr->next_sibling;
764 }
765
766 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930767 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930768}
769
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930770LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
772{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930773 if (!parent || !node) {
774 return false;
775 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930776
777 pldm_entity_node *curr = parent->first_child;
778 while (curr != NULL) {
779 if (node->entity_type == curr->entity.entity_type &&
780 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930781 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930782 return true;
783 }
784 curr = curr->next_sibling;
785 }
786
787 return false;
788}
789
Andrew Jeffery65945992023-07-17 15:04:21 +0930790static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500791 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
792 uint8_t contained_count, uint8_t association_type, bool is_remote,
793 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930794{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930795 uint8_t *start;
796 uint8_t *pdr;
797 int rc;
798
799 pdr = calloc(1, size);
800 if (!pdr) {
801 return -ENOMEM;
802 }
803
804 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805
806 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
807 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600808 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930809 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
810 hdr->record_change_num = 0;
811 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
812 start += sizeof(struct pldm_pdr_hdr);
813
814 uint16_t *container_id = (uint16_t *)start;
815 *container_id = htole16(curr->first_child->entity.entity_container_id);
816 start += sizeof(uint16_t);
817 *start = association_type;
818 start += sizeof(uint8_t);
819
820 pldm_entity *entity = (pldm_entity *)start;
821 entity->entity_type = htole16(curr->entity.entity_type);
822 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
823 entity->entity_container_id = htole16(curr->entity.entity_container_id);
824 start += sizeof(pldm_entity);
825
826 *start = contained_count;
827 start += sizeof(uint8_t);
828
829 pldm_entity_node *node = curr->first_child;
830 while (node != NULL) {
831 if (node->association_type == association_type) {
832 pldm_entity *entity = (pldm_entity *)start;
833 entity->entity_type = htole16(node->entity.entity_type);
834 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930835 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930836 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930837 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930838 start += sizeof(pldm_entity);
839 }
840 node = node->next_sibling;
841 }
842
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930843 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
844 &record_handle);
845 free(pdr);
846 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930847}
848
Andrew Jeffery65945992023-07-17 15:04:21 +0930849static int entity_association_pdr_add_entry(pldm_entity_node *curr,
850 pldm_pdr *repo, bool is_remote,
851 uint16_t terminus_handle,
852 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930853{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930854 uint8_t num_logical_children = pldm_entity_get_num_children(
855 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
856 uint8_t num_physical_children = pldm_entity_get_num_children(
857 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930858 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930859
860 if (num_logical_children) {
861 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930862 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
863 sizeof(uint8_t) + sizeof(pldm_entity) +
864 sizeof(uint8_t) +
865 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930866 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930867 curr, repo, logical_pdr_size, num_logical_children,
868 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500869 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930870 if (rc < 0) {
871 return rc;
872 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930873 }
874
875 if (num_physical_children) {
876 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930877 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
878 sizeof(uint8_t) + sizeof(pldm_entity) +
879 sizeof(uint8_t) +
880 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930881 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930882 curr, repo, physical_pdr_size, num_physical_children,
883 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500884 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930885 if (rc < 0) {
886 return rc;
887 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930888 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930889
890 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930891}
892
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930893static bool is_present(pldm_entity entity, pldm_entity **entities,
894 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930895{
896 if (entities == NULL || num_entities == 0) {
897 return true;
898 }
899 size_t i = 0;
900 while (i < num_entities) {
901 if ((*entities + i)->entity_type == entity.entity_type) {
902 return true;
903 }
904 i++;
905 }
906 return false;
907}
908
Andrew Jeffery65945992023-07-17 15:04:21 +0930909static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
910 pldm_entity **entities,
911 size_t num_entities, bool is_remote,
912 uint16_t terminus_handle,
913 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930914{
Andrew Jeffery65945992023-07-17 15:04:21 +0930915 int rc;
916
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930918 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930920
921 if (is_present(curr->entity, entities, num_entities)) {
922 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500923 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930924 if (rc) {
925 return rc;
926 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930928
929 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
930 num_entities, is_remote,
931 terminus_handle, record_handle);
932 if (rc) {
933 return rc;
934 }
935
936 return entity_association_pdr_add(curr->first_child, repo, entities,
937 num_entities, is_remote,
938 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930939}
940
Andrew Jeffery096685b2023-07-17 17:36:14 +0930941LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +0930942int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
943 pldm_pdr *repo, bool is_remote,
944 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +0930945{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930946 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930947 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930948 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930949
Andrew Jeffery65945992023-07-17 15:04:21 +0930950 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
951 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952}
953
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930954LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +0930955int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +0930956 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
957 size_t num_entities, bool is_remote, uint16_t terminus_handle)
958{
959 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500960 node, repo, entities, num_entities, is_remote, terminus_handle,
961 0);
962}
963
Pavithra Barithaya3a267052023-11-13 05:01:36 -0600964LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500965int pldm_entity_association_pdr_add_from_node_with_record_handle(
966 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
967 size_t num_entities, bool is_remote, uint16_t terminus_handle,
968 uint32_t record_handle)
969{
970 if (!node || !repo || !entities) {
971 return -EINVAL;
972 }
973
Archana Kakani74c9a542024-09-13 00:33:57 -0500974 return entity_association_pdr_add(node, repo, entities, num_entities,
975 is_remote, terminus_handle,
976 record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930977}
978
Andrew Jeffery643c4432023-07-17 15:36:03 +0930979static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
980 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600982 bool is_entity_container_id;
983 bool is_entity_instance_num;
984 bool is_type;
985
Andrew Jeffery9c766792022-08-10 23:12:49 +0930986 if (tree_node == NULL) {
987 return;
988 }
989
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600990 is_type = tree_node->entity.entity_type == entity.entity_type;
991 is_entity_instance_num = tree_node->entity.entity_instance_num ==
992 entity.entity_instance_num;
993 is_entity_container_id = tree_node->entity.entity_container_id ==
994 entity.entity_container_id;
995
996 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930997 *node = tree_node;
998 return;
999 }
1000
1001 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1002 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1003}
1004
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301005LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1007 pldm_entity entity, pldm_entity_node **node)
1008{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301009 if (!tree || !node) {
1010 return;
1011 }
1012
Andrew Jeffery9c766792022-08-10 23:12:49 +09301013 find_entity_ref_in_tree(tree->root, entity, node);
1014}
1015
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301016LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301017void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1018 uint16_t terminus_handle)
1019{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301020 if (!repo) {
1021 return;
1022 }
1023
Andrew Jeffery9c766792022-08-10 23:12:49 +09301024 bool removed = false;
1025
1026 pldm_pdr_record *record = repo->first;
1027 pldm_pdr_record *prev = NULL;
1028 while (record != NULL) {
1029 pldm_pdr_record *next = record->next;
1030 if (record->terminus_handle == terminus_handle) {
1031 if (repo->first == record) {
1032 repo->first = next;
1033 } else {
1034 prev->next = next;
1035 }
1036 if (repo->last == record) {
1037 repo->last = prev;
1038 }
1039 if (record->data) {
1040 free(record->data);
1041 }
1042 --repo->record_count;
1043 repo->size -= record->size;
1044 free(record);
1045 removed = true;
1046 } else {
1047 prev = record;
1048 }
1049 record = next;
1050 }
1051
1052 if (removed == true) {
1053 record = repo->first;
1054 uint32_t record_handle = 0;
1055 while (record != NULL) {
1056 record->record_handle = ++record_handle;
1057 if (record->data != NULL) {
1058 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301059 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301060 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301061 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301062 }
1063 record = record->next;
1064 }
1065 }
1066}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301067
1068LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301069void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1070{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301071 if (!repo) {
1072 return;
1073 }
1074
Andrew Jeffery9c766792022-08-10 23:12:49 +09301075 bool removed = false;
1076
1077 pldm_pdr_record *record = repo->first;
1078 pldm_pdr_record *prev = NULL;
1079 while (record != NULL) {
1080 pldm_pdr_record *next = record->next;
1081 if (record->is_remote == true) {
1082 if (repo->first == record) {
1083 repo->first = next;
1084 } else {
1085 prev->next = next;
1086 }
1087 if (repo->last == record) {
1088 repo->last = prev;
1089 }
1090 if (record->data) {
1091 free(record->data);
1092 }
1093 --repo->record_count;
1094 repo->size -= record->size;
1095 free(record);
1096 removed = true;
1097 } else {
1098 prev = record;
1099 }
1100 record = next;
1101 }
1102
1103 if (removed == true) {
1104 record = repo->first;
1105 uint32_t record_handle = 0;
1106 while (record != NULL) {
1107 record->record_handle = ++record_handle;
1108 if (record->data != NULL) {
1109 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301110 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301111 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301112 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301113 }
1114 record = record->next;
1115 }
1116 }
1117}
1118
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001119LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001120pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1121 uint32_t first, uint32_t last)
1122{
1123 pldm_pdr_record *record = NULL;
1124 pldm_pdr_record *curr;
1125
1126 if (!repo) {
1127 return NULL;
1128 }
1129 for (curr = repo->first; curr; curr = curr->next) {
1130 if (first > curr->record_handle || last < curr->record_handle) {
1131 continue;
1132 }
1133 if (!record || curr->record_handle > record->record_handle) {
1134 record = curr;
1135 }
1136 }
1137
1138 return record;
1139}
1140
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001141static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1142 pldm_entity *entity,
1143 pldm_entity_node **out,
1144 bool is_remote)
1145{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001146 if (node == NULL) {
1147 return;
1148 }
1149 bool is_entity_type;
1150 bool is_entity_instance_num;
1151
1152 is_entity_type = node->entity.entity_type == entity->entity_type;
1153 is_entity_instance_num = node->entity.entity_instance_num ==
1154 entity->entity_instance_num;
1155
1156 if (!is_remote ||
1157 node->remote_container_id == entity->entity_container_id) {
1158 if (is_entity_type && is_entity_instance_num) {
1159 entity->entity_container_id =
1160 node->entity.entity_container_id;
1161 *out = node;
1162 return;
1163 }
1164 }
1165 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1166 is_remote);
1167 entity_association_tree_find_if_remote(node->first_child, entity, out,
1168 is_remote);
1169}
1170
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001171LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001172pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1173 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001174{
1175 if (!tree || !entity) {
1176 return NULL;
1177 }
1178 pldm_entity_node *node = NULL;
1179 entity_association_tree_find_if_remote(tree->root, entity, &node,
1180 is_remote);
1181 return node;
1182}
1183
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301184static void entity_association_tree_find(pldm_entity_node *node,
1185 pldm_entity *entity,
1186 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301187{
1188 if (node == NULL) {
1189 return;
1190 }
1191
1192 if (node->entity.entity_type == entity->entity_type &&
1193 node->entity.entity_instance_num == entity->entity_instance_num) {
1194 entity->entity_container_id = node->entity.entity_container_id;
1195 *out = node;
1196 return;
1197 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301198 entity_association_tree_find(node->next_sibling, entity, out);
1199 entity_association_tree_find(node->first_child, entity, out);
1200}
1201
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301202LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301203pldm_entity_node *
1204pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1205 pldm_entity *entity)
1206{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301207 if (!tree || !entity) {
1208 return NULL;
1209 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301210
1211 pldm_entity_node *node = NULL;
1212 entity_association_tree_find(tree->root, entity, &node);
1213 return node;
1214}
1215
Andrew Jeffery60582152024-09-22 21:16:38 +09301216static int entity_association_tree_copy(pldm_entity_node *org_node,
1217 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301218{
Andrew Jeffery60582152024-09-22 21:16:38 +09301219 int rc;
1220
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301222 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301223 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301224
Andrew Jeffery9c766792022-08-10 23:12:49 +09301225 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301226 if (!*new_node) {
1227 return -ENOMEM;
1228 }
1229
Andrew Jeffery9c766792022-08-10 23:12:49 +09301230 (*new_node)->parent = org_node->parent;
1231 (*new_node)->entity = org_node->entity;
1232 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001233 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301234 (*new_node)->first_child = NULL;
1235 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301236
1237 rc = entity_association_tree_copy(org_node->first_child,
1238 &((*new_node)->first_child));
1239 if (rc) {
1240 goto cleanup;
1241 }
1242
1243 rc = entity_association_tree_copy(org_node->next_sibling,
1244 &((*new_node)->next_sibling));
1245 if (rc) {
1246 entity_association_tree_destroy((*new_node)->first_child);
1247 goto cleanup;
1248 }
1249
1250 return 0;
1251
1252cleanup:
1253 free(*new_node);
1254 *new_node = NULL;
1255 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301256}
1257
Andrew Jeffery60582152024-09-22 21:16:38 +09301258LIBPLDM_ABI_DEPRECATED
Andrew Jeffery9c766792022-08-10 23:12:49 +09301259void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301260 pldm_entity_association_tree *org_tree,
1261 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301262{
George Liuc6c391d2023-11-09 10:13:34 +08001263 assert(org_tree != NULL);
1264 assert(new_tree != NULL);
1265
Andrew Jeffery9c766792022-08-10 23:12:49 +09301266 new_tree->last_used_container_id = org_tree->last_used_container_id;
1267 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1268}
1269
Andrew Jeffery60582152024-09-22 21:16:38 +09301270LIBPLDM_ABI_TESTING
1271int pldm_entity_association_tree_copy_root_check(
1272 pldm_entity_association_tree *org_tree,
1273 pldm_entity_association_tree *new_tree)
1274{
1275 if (!org_tree || !new_tree) {
1276 return -EINVAL;
1277 }
1278
1279 new_tree->last_used_container_id = org_tree->last_used_container_id;
1280 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1281}
1282
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301283LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301284void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301285 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301286{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301287 if (!tree) {
1288 return;
1289 }
1290
Andrew Jeffery9c766792022-08-10 23:12:49 +09301291 entity_association_tree_destroy(tree->root);
1292 tree->last_used_container_id = 0;
1293 tree->root = NULL;
1294}
1295
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301296LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1298{
1299 return ((tree->root == NULL) ? true : false);
1300}
1301
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301302LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301303void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1304 size_t *num_entities,
1305 pldm_entity **entities)
1306{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301307 if (!pdr || !num_entities || !entities) {
1308 return;
1309 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001310 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301311 return;
1312 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301313
1314 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301315 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1316 return;
1317 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301318
1319 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301320
1321 if (UINTPTR_MAX - (uintptr_t)start <
1322 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1323 return;
1324 }
1325
1326 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1327 return;
1328 }
1329
1330 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301331 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301332 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301333
1334 if ((uintptr_t)end - (uintptr_t)start <
1335 sizeof(struct pldm_pdr_entity_association)) {
1336 return;
1337 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301338 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301339 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301340
1341 if (entity_association_pdr->num_children == UINT8_MAX) {
1342 return;
1343 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301344 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301345 if (l_num_entities < 2) {
1346 return;
1347 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301348
1349 if (SIZE_MAX / sizeof(pldm_entity) < l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301350 return;
1351 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301352
1353 if (pdr_len - sizeof(*entity_association_pdr) + 1 <
1354 sizeof(pldm_entity) * l_num_entities) {
1355 return;
1356 }
1357
1358 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301359 if (!l_entities) {
1360 return;
1361 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301362 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301363 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301364 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301365 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301366 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301367 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301368 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301369 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1370 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1371 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301372 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301373 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301374 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301375 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301376
1377 *num_entities = l_num_entities;
1378 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301379}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001380
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301381/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001382 * the same position.
1383 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301384LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001385static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1386 pldm_pdr_record *prev,
1387 pldm_pdr_record *new_record)
1388{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001389 if (repo->size < record->size) {
1390 return -EOVERFLOW;
1391 }
1392
1393 if (repo->size + new_record->size < new_record->size) {
1394 return -EOVERFLOW;
1395 }
1396
1397 if (repo->first == record) {
1398 repo->first = new_record;
1399 } else {
1400 prev->next = new_record;
1401 }
1402 new_record->next = record->next;
1403
1404 if (repo->last == record) {
1405 repo->last = new_record;
1406 }
1407
1408 repo->size = (repo->size - record->size) + new_record->size;
1409 return 0;
1410}
1411
1412/* Insert a new record to pldm_pdr repo to a position that comes after
1413 * pldm_pdr_record record.
1414 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301415LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001416static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1417 pldm_pdr_record *new_record)
1418{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001419 if (repo->size + new_record->size < new_record->size) {
1420 return -EOVERFLOW;
1421 }
1422
1423 if (repo->record_count == UINT32_MAX) {
1424 return -EOVERFLOW;
1425 }
1426
1427 new_record->next = record->next;
1428 record->next = new_record;
1429
1430 if (repo->last == record) {
1431 repo->last = new_record;
1432 }
1433
1434 repo->size = repo->size + new_record->size;
1435 ++repo->record_count;
1436 return 0;
1437}
1438
1439/* Find the position of PDR when its record handle is known
1440 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301441LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001442static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1443 pldm_pdr_record **prev,
1444 uint32_t record_handle)
1445{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001446 while (*record != NULL) {
1447 if ((*record)->record_handle == record_handle) {
1448 return true;
1449 }
1450 *prev = *record;
1451 *record = (*record)->next;
1452 }
1453 return false;
1454}
1455
1456LIBPLDM_ABI_TESTING
1457int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1458 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1459{
1460 if (!repo || !entity) {
1461 return -EINVAL;
1462 }
1463
1464 pldm_pdr_record *record = repo->first;
1465 pldm_pdr_record *prev = repo->first;
1466 int rc = 0;
1467 uint16_t header_length = 0;
1468 uint8_t num_children = 0;
1469 struct pldm_msgbuf _src;
1470 struct pldm_msgbuf *src = &_src;
1471 struct pldm_msgbuf _dst;
1472 struct pldm_msgbuf *dst = &_dst;
1473
1474 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1475
1476 if (!record) {
1477 return -EINVAL;
1478 }
1479 // Initialize msg buffer for record and record->data
1480 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1481 record->data, record->size);
1482 if (rc) {
1483 return rc;
1484 }
1485
1486 // check if adding another entity to record causes overflow before
1487 // allocating memory for new_record.
1488 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1489 return -EOVERFLOW;
1490 }
1491 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1492 if (!new_record) {
1493 return -ENOMEM;
1494 }
1495
1496 new_record->data = malloc(record->size + sizeof(pldm_entity));
1497 if (!new_record->data) {
1498 rc = -ENOMEM;
1499 goto cleanup_new_record;
1500 }
1501
1502 new_record->record_handle = record->record_handle;
1503 new_record->size = record->size + sizeof(struct pldm_entity);
1504 new_record->is_remote = record->is_remote;
1505
1506 // Initialize new PDR record with data from original PDR record.
1507 // Start with adding the header of original PDR
1508 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1509 new_record->data, new_record->size);
1510 if (rc) {
1511 goto cleanup_new_record_data;
1512 }
1513
1514 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1515 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1516 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1517 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1518 // extract the header length from record and increment size with
1519 // size of pldm_entity before inserting the value into new_record.
1520 rc = pldm_msgbuf_extract(src, header_length);
1521 if (rc) {
1522 goto cleanup_new_record_data;
1523 }
1524 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1525 "Fix the following bounds check.");
1526 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1527 rc = -EOVERFLOW;
1528 goto cleanup_new_record_data;
1529 }
1530 header_length += sizeof(pldm_entity);
1531 pldm_msgbuf_insert(dst, header_length);
1532 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1533 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1534 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1535 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1536 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1537 // extract value of number of children from record and increment it
1538 // by 1 before insert the value to new record.
1539 rc = pldm_msgbuf_extract(src, num_children);
1540 if (rc) {
1541 goto cleanup_new_record_data;
1542 }
1543 if (num_children == UINT8_MAX) {
1544 rc = -EOVERFLOW;
1545 goto cleanup_new_record_data;
1546 }
1547 num_children += 1;
1548 pldm_msgbuf_insert(dst, num_children);
1549 //Add all children of original PDR to new PDR
1550 for (int i = 0; i < num_children - 1; i++) {
1551 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1552 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1553 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1554 }
1555
1556 // Add new contained entity as a child of new PDR
1557 rc = pldm_msgbuf_destroy(src);
1558 if (rc) {
1559 goto cleanup_new_record_data;
1560 }
1561 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1562 sizeof(struct pldm_entity));
1563 if (rc) {
1564 goto cleanup_new_record_data;
1565 }
1566 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1567 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1568 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1569
1570 rc = pldm_msgbuf_destroy(src);
1571 if (rc) {
1572 goto cleanup_new_record_data;
1573 }
1574 rc = pldm_msgbuf_destroy(dst);
1575 if (rc) {
1576 goto cleanup_new_record_data;
1577 }
1578
1579 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1580 if (rc) {
1581 goto cleanup_new_record_data;
1582 }
1583
1584 free(record->data);
1585 free(record);
1586 return rc;
1587cleanup_new_record_data:
1588 free(new_record->data);
1589cleanup_new_record:
1590 free(new_record);
1591 return rc;
1592}
1593
1594LIBPLDM_ABI_TESTING
1595int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1596 uint32_t pdr_record_handle,
1597 pldm_entity *parent,
1598 pldm_entity *entity,
1599 uint32_t *entity_record_handle)
1600{
1601 if (!repo || !parent || !entity || !entity_record_handle) {
1602 return -EINVAL;
1603 }
1604
1605 if (pdr_record_handle == UINT32_MAX) {
1606 return -EOVERFLOW;
1607 }
1608
1609 bool pdr_added = false;
1610 uint16_t new_pdr_size;
1611 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001612 void *container_id_addr;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001613 struct pldm_msgbuf _dst;
1614 struct pldm_msgbuf *dst = &_dst;
1615 struct pldm_msgbuf _src_p;
1616 struct pldm_msgbuf *src_p = &_src_p;
1617 struct pldm_msgbuf _src_c;
1618 struct pldm_msgbuf *src_c = &_src_c;
1619 int rc = 0;
1620
1621 pldm_pdr_record *prev = repo->first;
1622 pldm_pdr_record *record = repo->first;
1623 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1624 pdr_record_handle);
1625 if (!pdr_added) {
1626 return -ENOENT;
1627 }
1628
1629 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1630 "Truncation ahead");
1631 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1632 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1633 if (!new_record) {
1634 return -ENOMEM;
1635 }
1636
1637 new_record->data = malloc(new_pdr_size);
1638 if (!new_record->data) {
1639 rc = -ENOMEM;
1640 goto cleanup_new_record;
1641 }
1642
1643 // Initialise new PDR to be added with the header, size and handle.
1644 // Set the position of new PDR
1645 *entity_record_handle = pdr_record_handle + 1;
1646 new_record->record_handle = *entity_record_handle;
1647 new_record->size = new_pdr_size;
1648 new_record->is_remote = false;
1649
1650 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1651 new_record->data, new_record->size);
1652 if (rc) {
1653 goto cleanup_new_record_data;
1654 }
1655
1656 // header record handle
1657 pldm_msgbuf_insert(dst, *entity_record_handle);
1658 // header version
1659 pldm_msgbuf_insert_uint8(dst, 1);
1660 // header type
1661 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1662 // header change number
1663 pldm_msgbuf_insert_uint16(dst, 0);
1664 // header length
1665 pldm_msgbuf_insert_uint16(dst,
1666 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1667
1668 // Data for new PDR is obtained from parent PDR and new contained entity
1669 // is added as the child
1670 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1671 sizeof(*parent));
1672 if (rc) {
1673 goto cleanup_new_record_data;
1674 }
1675
1676 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1677 sizeof(*entity));
1678 if (rc) {
1679 goto cleanup_new_record_data;
1680 }
1681
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001682 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001683 // extract pointer for container ID and save the address
1684 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1685 (void **)&container_id_addr);
1686 if (rc) {
1687 goto cleanup_new_record_data;
1688 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001689 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001690 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1691 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1692 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1693 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1694 // number of children
1695 pldm_msgbuf_insert_uint8(dst, 1);
1696
1697 // Add new entity as child
1698 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1699 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1700 // Extract and insert child entity container ID and add same value to
1701 // container ID of entity
1702 pldm_msgbuf_extract(src_c, container_id);
1703 pldm_msgbuf_insert(dst, container_id);
1704 container_id = htole16(container_id);
1705 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1706
1707 rc = pldm_msgbuf_destroy(dst);
1708 if (rc) {
1709 goto cleanup_new_record_data;
1710 }
1711 rc = pldm_msgbuf_destroy(src_p);
1712 if (rc) {
1713 goto cleanup_new_record_data;
1714 }
1715 rc = pldm_msgbuf_destroy(src_c);
1716 if (rc) {
1717 goto cleanup_new_record_data;
1718 }
1719
1720 rc = pldm_pdr_insert_record(repo, record, new_record);
1721 if (rc) {
1722 goto cleanup_new_record_data;
1723 }
1724
1725 return rc;
1726cleanup_new_record_data:
1727 free(new_record->data);
1728cleanup_new_record:
1729 free(new_record);
1730 return rc;
1731}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001732
1733LIBPLDM_CC_NONNULL
1734static bool pldm_entity_cmp(const struct pldm_entity *l,
1735 const struct pldm_entity *r)
1736{
1737 return l->entity_type == r->entity_type &&
1738 l->entity_instance_num == r->entity_instance_num &&
1739 l->entity_container_id == r->entity_container_id;
1740}
1741
1742/* Find record handle of a PDR record from PDR repo and
1743 * entity
1744 */
1745LIBPLDM_CC_NONNULL
1746static int pldm_entity_association_find_record_handle_by_entity(
1747 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1748 uint32_t *record_handle)
1749{
1750 uint8_t num_children = 0;
1751 uint8_t hdr_type = 0;
1752 int rc = 0;
1753 size_t skip_data_size = 0;
1754 pldm_pdr_record *record = repo->first;
1755 struct pldm_msgbuf _dst;
1756 struct pldm_msgbuf *dst = &_dst;
1757
1758 while (record != NULL) {
1759 rc = pldm_msgbuf_init_errno(dst,
1760 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1761 record->data, record->size);
1762 if (rc) {
1763 return rc;
1764 }
1765 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1766 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1767 pldm_msgbuf_extract(dst, hdr_type);
1768 if (record->is_remote != is_remote ||
1769 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1770 goto cleanup;
1771 }
1772 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1773 sizeof(uint16_t) + sizeof(uint8_t) +
1774 sizeof(struct pldm_entity);
1775 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1776 pldm_msgbuf_extract(dst, num_children);
1777 for (int i = 0; i < num_children; ++i) {
1778 struct pldm_entity e;
1779
1780 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1781 (rc = pldm_msgbuf_extract(dst,
1782 e.entity_instance_num)) ||
1783 (rc = pldm_msgbuf_extract(dst,
1784 e.entity_container_id))) {
1785 return rc;
1786 }
1787
1788 if (pldm_entity_cmp(entity, &e)) {
1789 *record_handle = record->record_handle;
1790 return 0;
1791 }
1792 }
1793 cleanup:
1794 rc = pldm_msgbuf_destroy(dst);
1795 if (rc) {
1796 return rc;
1797 }
1798 record = record->next;
1799 }
1800 return 0;
1801}
1802
1803LIBPLDM_ABI_TESTING
1804int pldm_entity_association_pdr_remove_contained_entity(
1805 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1806 uint32_t *pdr_record_handle)
1807{
1808 uint16_t header_length = 0;
1809 uint8_t num_children = 0;
1810 struct pldm_msgbuf _src;
1811 struct pldm_msgbuf *src = &_src;
1812 struct pldm_msgbuf _dst;
1813 struct pldm_msgbuf *dst = &_dst;
1814 int rc;
1815 pldm_pdr_record *record;
1816 pldm_pdr_record *prev;
1817
1818 if (!repo || !entity || !pdr_record_handle) {
1819 return -EINVAL;
1820 }
1821 record = repo->first;
1822 prev = repo->first;
1823
1824 rc = pldm_entity_association_find_record_handle_by_entity(
1825 repo, entity, is_remote, pdr_record_handle);
1826 if (rc) {
1827 return rc;
1828 }
1829 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
1830 if (!record) {
1831 return -EINVAL;
1832 }
1833 // Initialize msg buffer for record and record->data
1834 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1835 record->data, record->size);
1836 if (rc) {
1837 return rc;
1838 }
1839 // check if removing an entity from record causes overflow before
1840 // allocating memory for new_record.
1841 if (record->size < sizeof(pldm_entity)) {
1842 return -EOVERFLOW;
1843 }
1844 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1845 if (!new_record) {
1846 return -ENOMEM;
1847 }
1848 new_record->data = malloc(record->size - sizeof(pldm_entity));
1849 if (!new_record->data) {
1850 rc = -ENOMEM;
1851 goto cleanup_new_record;
1852 }
1853 new_record->record_handle = record->record_handle;
1854 new_record->size = record->size - sizeof(struct pldm_entity);
1855 new_record->is_remote = record->is_remote;
1856
1857 // Initialize new PDR record with data from original PDR record.
1858 // Start with adding the header of original PDR
1859 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1860 new_record->data, new_record->size);
1861 if (rc) {
1862 goto cleanup_new_record_data;
1863 }
1864 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1865 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1866 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1867 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1868 // extract the header length from record and decrement size with
1869 // size of pldm_entity before inserting the value into new_record.
1870 rc = pldm_msgbuf_extract(src, header_length);
1871 if (rc) {
1872 goto cleanup_new_record_data;
1873 }
1874 if (header_length < sizeof(pldm_entity)) {
1875 rc = -EOVERFLOW;
1876 goto cleanup_new_record_data;
1877 }
1878 header_length -= sizeof(pldm_entity);
1879 pldm_msgbuf_insert(dst, header_length);
1880 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1881 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1882 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1883 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1884 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1885 // extract value of number of children from record and decrement it
1886 // by 1 before insert the value to new record.
1887 rc = pldm_msgbuf_extract(src, num_children);
1888 if (rc) {
1889 goto cleanup_new_record_data;
1890 }
1891 if (num_children == 1) {
1892 prev->next = record->next;
1893 free(record->data);
1894 free(record);
1895 goto cleanup_new_record_data;
1896 } else if (num_children < 1) {
1897 rc = -EOVERFLOW;
1898 goto cleanup_new_record_data;
1899 }
1900 num_children -= 1;
1901 pldm_msgbuf_insert(dst, num_children);
1902 //Add all children of original PDR to new PDR
1903 for (int i = 0; i < num_children + 1; ++i) {
1904 struct pldm_entity e;
1905
1906 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
1907 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
1908 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
1909 goto cleanup_new_record_data;
1910 }
1911
1912 if (pldm_entity_cmp(entity, &e)) {
1913 continue;
1914 }
1915
1916 pldm_msgbuf_insert(dst, e.entity_type);
1917 pldm_msgbuf_insert(dst, e.entity_instance_num);
1918 pldm_msgbuf_insert(dst, e.entity_container_id);
1919 }
1920
1921 if ((rc = pldm_msgbuf_destroy(src)) ||
1922 (rc = pldm_msgbuf_destroy(dst)) ||
1923 (rc = pldm_pdr_replace_record(repo, record, prev, new_record))) {
1924 goto cleanup_new_record_data;
1925 }
1926
1927 free(record->data);
1928 free(record);
1929 return rc;
1930
1931cleanup_new_record_data:
1932 free(new_record->data);
1933cleanup_new_record:
1934 free(new_record);
1935 return rc;
1936}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05001937
1938/* API to find the PDR record that is previous to a given PLDM PDR
1939 * record in a given PLDM PDR repository
1940 */
1941LIBPLDM_CC_NONNULL
1942static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
1943 pldm_pdr_record *record)
1944{
1945 pldm_pdr_record *prev = NULL;
1946 pldm_pdr_record *curr = repo->first;
1947
1948 while (curr != NULL) {
1949 if (curr->record_handle == record->record_handle) {
1950 break;
1951 }
1952 prev = curr;
1953 curr = curr->next;
1954 }
1955 return prev;
1956}
1957
1958/* API to check if a PLDM PDR record is present in a PLDM PDR repository
1959 */
1960LIBPLDM_CC_NONNULL
1961static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
1962{
1963 if (repo->first == record) {
1964 return true;
1965 }
1966
1967 return pldm_pdr_get_prev_record(repo, record) != NULL;
1968}
1969
1970/* API to check if FRU RSI of record matches the given record set identifier.
1971 * Returns 1 if the provided FRU record matches the provided record set identifier,
1972 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
1973 */
1974LIBPLDM_CC_NONNULL
1975static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
1976 uint16_t rsi)
1977{
1978 uint16_t record_fru_rsi = 0;
1979 uint8_t *skip_data = NULL;
1980 uint8_t skip_data_size = 0;
1981 struct pldm_msgbuf _dst;
1982 struct pldm_msgbuf *dst = &_dst;
1983 int rc = 0;
1984
1985 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
1986 record->data, record->size);
1987 if (rc) {
1988 return rc;
1989 }
1990 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
1991 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
1992 pldm_msgbuf_extract(dst, record_fru_rsi);
1993
1994 rc = pldm_msgbuf_destroy(dst);
1995 if (rc) {
1996 return rc;
1997 }
1998 return record_fru_rsi == rsi;
1999}
2000
2001/* API to remove PLDM PDR record from a PLDM PDR repository
2002 */
2003LIBPLDM_CC_NONNULL_ARGS(1, 2)
2004static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2005 pldm_pdr_record *prev)
2006{
2007 if (!is_prev_record_present(repo, record)) {
2008 return -EINVAL;
2009 }
2010
2011 assert(repo->size >= record->size);
2012 if (repo->size < record->size) {
2013 return -EOVERFLOW;
2014 }
2015
2016 if (repo->first == record) {
2017 repo->first = record->next;
2018 } else {
2019 if (prev != NULL) {
2020 prev->next = record->next;
2021 }
2022 }
2023
2024 if (repo->last == record) {
2025 repo->last = prev;
2026 if (prev != NULL) {
2027 prev->next = NULL;
2028 }
2029 }
2030 repo->record_count -= 1;
2031 repo->size -= record->size;
2032 free(record->data);
2033 free(record);
2034
2035 return 0;
2036}
2037
2038LIBPLDM_ABI_TESTING
2039int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2040 bool is_remote,
2041 uint32_t *record_handle)
2042{
2043 pldm_pdr_record *record;
2044 pldm_pdr_record *prev = NULL;
2045 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2046 uint8_t hdr_type = 0;
2047 int rc = 0;
2048 int match;
2049
2050 if (!repo || !record_handle) {
2051 return -EINVAL;
2052 }
2053 record = repo->first;
2054
2055 while (record != NULL) {
2056 struct pldm_msgbuf _buf;
2057 struct pldm_msgbuf *buf = &_buf;
2058 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2059 record->data, record->size);
2060 if (rc) {
2061 return rc;
2062 }
2063 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
2064 if ((rc = pldm_msgbuf_extract(buf, hdr_type))) {
2065 return rc;
2066 }
2067 if (record->is_remote != is_remote ||
2068 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
2069 goto cleanup;
2070 }
2071 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2072 if (match < 0) {
2073 return match;
2074 }
2075 if (match) {
2076 *record_handle = record->record_handle;
2077 prev = pldm_pdr_get_prev_record(repo, record);
2078 return pldm_pdr_remove_record(repo, record, prev);
2079 }
2080 cleanup:
2081 rc = pldm_msgbuf_destroy(buf);
2082 if (rc) {
2083 return rc;
2084 }
2085 record = record->next;
2086 }
2087 return rc;
2088}