blob: 670e1ed8c19cbc118ecf4aea99e0e9309bcb45e0 [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery860a43d2024-08-23 01:21:58 +00002#include "compiler.h"
Varsha Kaverappa37552b92024-02-12 05:06:06 -06003#include "msgbuf.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10304#include <libpldm/pdr.h>
5#include <libpldm/platform.h>
6
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05308#include <endian.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +09309#include <stdlib.h>
10#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060011#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093012
Varsha Kaverappa37552b92024-02-12 05:06:06 -060013#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
14 (sizeof(struct pldm_pdr_hdr) + \
15 sizeof(struct pldm_pdr_entity_association))
16
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050017#define PDR_FRU_RECORD_SET_MIN_SIZE \
18 (sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
19
Andrew Jeffery9c766792022-08-10 23:12:49 +093020typedef struct pldm_pdr_record {
21 uint32_t record_handle;
22 uint32_t size;
23 uint8_t *data;
24 struct pldm_pdr_record *next;
25 bool is_remote;
26 uint16_t terminus_handle;
27} pldm_pdr_record;
28
29typedef struct pldm_pdr {
30 uint32_t record_count;
31 uint32_t size;
32 pldm_pdr_record *first;
33 pldm_pdr_record *last;
34} pldm_pdr;
35
Andrew Jeffery890d37a2024-09-22 20:50:53 +093036LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +093037static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
38 const pldm_pdr_record *record)
39{
Andrew Jeffery9c766792022-08-10 23:12:49 +093040 if (record == repo->last) {
41 return 0;
42 }
43 return record->next->record_handle;
44}
45
Andrew Jefferyca248ce2023-07-07 10:38:30 +093046LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000047int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
48 bool is_remote, uint16_t terminus_handle,
49 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093050{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050051 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093052
Andrew Jeffery3b93d092023-07-17 13:01:50 +093053 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093054 return -EINVAL;
55 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093056
Andrew Jeffery3b93d092023-07-17 13:01:50 +093057 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093058 curr = *record_handle;
59 } else if (repo->last) {
60 curr = repo->last->record_handle;
61 if (curr == UINT32_MAX) {
62 return -EOVERFLOW;
63 }
64 curr += 1;
65 } else {
66 curr = 1;
67 }
68
Andrew Jeffery9c766792022-08-10 23:12:49 +093069 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093070 if (!record) {
71 return -ENOMEM;
72 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093073
Andrew Jeffery572a3952023-07-03 13:19:28 +093074 if (data) {
75 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093076 if (!record->data) {
77 free(record);
78 return -ENOMEM;
79 }
80 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093081 }
82
Andrew Jeffery9c766792022-08-10 23:12:49 +093083 record->size = size;
84 record->is_remote = is_remote;
85 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093086 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093087
Andrew Jeffery3b93d092023-07-17 13:01:50 +093088 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093089 /* If record handle is 0, that is an indication for this API to
90 * compute a new handle. For that reason, the computed handle
91 * needs to be populated in the PDR header. For a case where the
92 * caller supplied the record handle, it would exist in the
93 * header already.
94 */
95 struct pldm_pdr_hdr *hdr = (void *)record->data;
96 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +093097 }
Andrew Jeffery572a3952023-07-03 13:19:28 +093098
Andrew Jeffery9c766792022-08-10 23:12:49 +093099 record->next = NULL;
100
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930101 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930102 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930103 repo->first = record;
104 repo->last = record;
105 } else {
106 repo->last->next = record;
107 repo->last = record;
108 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930110 repo->size += record->size;
111 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930112
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930113 if (record_handle) {
114 *record_handle = record->record_handle;
115 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930116
117 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118}
119
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930120LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930121pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930122{
123 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930124 if (!repo) {
125 return NULL;
126 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127 repo->record_count = 0;
128 repo->size = 0;
129 repo->first = NULL;
130 repo->last = NULL;
131
132 return repo;
133}
134
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930135LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136void pldm_pdr_destroy(pldm_pdr *repo)
137{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930138 if (!repo) {
139 return;
140 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930141
142 pldm_pdr_record *record = repo->first;
143 while (record != NULL) {
144 pldm_pdr_record *next = record->next;
145 if (record->data) {
146 free(record->data);
147 record->data = NULL;
148 }
149 free(record);
150 record = next;
151 }
152 free(repo);
153}
154
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930155LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930156const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
157 uint32_t record_handle,
158 uint8_t **data, uint32_t *size,
159 uint32_t *next_record_handle)
160{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930161 if (!repo || !data || !size || !next_record_handle) {
162 return NULL;
163 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930164
165 if (!record_handle && (repo->first != NULL)) {
166 record_handle = repo->first->record_handle;
167 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930168
Andrew Jeffery9c766792022-08-10 23:12:49 +0930169 pldm_pdr_record *record = repo->first;
170 while (record != NULL) {
171 if (record->record_handle == record_handle) {
172 *size = record->size;
173 *data = record->data;
174 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930175 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930176 return record;
177 }
178 record = record->next;
179 }
180
181 *size = 0;
182 *next_record_handle = 0;
183 return NULL;
184}
185
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930186LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930187const pldm_pdr_record *
188pldm_pdr_get_next_record(const pldm_pdr *repo,
189 const pldm_pdr_record *curr_record, uint8_t **data,
190 uint32_t *size, uint32_t *next_record_handle)
191{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930192 if (!repo || !curr_record || !data || !size || !next_record_handle) {
193 return NULL;
194 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930195
196 if (curr_record == repo->last) {
197 *data = NULL;
198 *size = 0;
199 *next_record_handle = get_next_record_handle(repo, curr_record);
200 return NULL;
201 }
202
203 *next_record_handle = get_next_record_handle(repo, curr_record->next);
204 *data = curr_record->next->data;
205 *size = curr_record->next->size;
206 return curr_record->next;
207}
208
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930209LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930210const pldm_pdr_record *
211pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
212 const pldm_pdr_record *curr_record, uint8_t **data,
213 uint32_t *size)
214{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930215 if (!repo) {
216 return NULL;
217 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930218
219 pldm_pdr_record *record = repo->first;
220 if (curr_record != NULL) {
221 record = curr_record->next;
222 }
223 while (record != NULL) {
224 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
225 if (hdr->type == pdr_type) {
226 if (data && size) {
227 *size = record->size;
228 *data = record->data;
229 }
230 return record;
231 }
232 record = record->next;
233 }
234
235 if (size) {
236 *size = 0;
237 }
238 return NULL;
239}
240
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930241LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930242uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
243{
244 assert(repo != NULL);
245
246 return repo->record_count;
247}
248
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930249LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930250uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
251{
252 assert(repo != NULL);
253
254 return repo->size;
255}
256
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930257LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000258uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259 const pldm_pdr_record *record)
260{
261 assert(repo != NULL);
262 assert(record != NULL);
263
264 return record->record_handle;
265}
266
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530267LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000268uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530269 const pldm_pdr_record *record)
270{
271 assert(repo != NULL);
272 assert(record != NULL);
273
274 return record->terminus_handle;
275}
276
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930277LIBPLDM_ABI_STABLE
278bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930279{
280 assert(record != NULL);
281
282 return record->is_remote;
283}
284
Andrew Jefferya2c69112023-07-07 10:41:38 +0930285LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930286int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
287 uint16_t fru_rsi, uint16_t entity_type,
288 uint16_t entity_instance_num,
289 uint16_t container_id,
290 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930291{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930292 if (!repo || !bmc_record_handle) {
293 return -EINVAL;
294 }
295
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930296 uint8_t data[sizeof(struct pldm_pdr_hdr) +
297 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930298
299 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
300 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930301 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930302 hdr->type = PLDM_PDR_FRU_RECORD_SET;
303 hdr->record_change_num = 0;
304 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
305 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930306 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
307 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308 fru->terminus_handle = htole16(terminus_handle);
309 fru->fru_rsi = htole16(fru_rsi);
310 fru->entity_type = htole16(entity_type);
311 fru->entity_instance_num = htole16(entity_instance_num);
312 fru->container_id = htole16(container_id);
313
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930314 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000315 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930316}
317
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930318LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930319const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930320 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
321 uint16_t *entity_type, uint16_t *entity_instance_num,
322 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930323{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930324 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
325 !container_id) {
326 return NULL;
327 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328
329 uint8_t *data = NULL;
330 uint32_t size = 0;
331 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930332 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333 while (curr_record != NULL) {
334 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930335 (struct pldm_pdr_fru_record_set
336 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337 if (fru->fru_rsi == htole16(fru_rsi)) {
338 *terminus_handle = le16toh(fru->terminus_handle);
339 *entity_type = le16toh(fru->entity_type);
340 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 *container_id = le16toh(fru->container_id);
343 return curr_record;
344 }
345 data = NULL;
346 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930347 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
348 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930349 }
350
351 *terminus_handle = 0;
352 *entity_type = 0;
353 *entity_instance_num = 0;
354 *container_id = 0;
355
356 return NULL;
357}
358
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930359LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930360/* NOLINTNEXTLINE(readability-identifier-naming) */
361void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
362 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930363{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930364 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930365 uint32_t size = 0;
366 const pldm_pdr_record *record;
367 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930368 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930369
370 do {
371 if (record != NULL) {
372 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930373 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930375 (struct pldm_terminus_locator_type_mctp_eid *)
376 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 if (pdr->terminus_handle == terminus_handle &&
378 pdr->tid == tid && value->eid == tl_eid) {
379 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930380 break;
381 }
382 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930383 record = pldm_pdr_find_record_by_type(repo,
384 PLDM_TERMINUS_LOCATOR_PDR,
385 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930386 } while (record);
387}
388
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500389static bool pldm_record_handle_in_range(uint32_t record_handle,
390 uint32_t first_record_handle,
391 uint32_t last_record_handle)
392{
393 return record_handle >= first_record_handle &&
394 record_handle <= last_record_handle;
395}
396
397LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500398int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500399 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500400 uint8_t child_index, uint32_t range_exclude_start_handle,
401 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500402{
403 pldm_pdr_record *record;
404 if (!repo) {
405 return -EINVAL;
406 }
407
408 for (record = repo->first; record; record = record->next) {
409 bool is_container_entity_instance_number;
410 struct pldm_pdr_entity_association *pdr;
411 bool is_container_entity_type;
412 struct pldm_entity *child;
413 struct pldm_pdr_hdr *hdr;
414 bool in_range;
415
416 // pldm_pdr_add() takes only uint8_t* data as an argument.
417 // The expectation here is the pldm_pdr_hdr is the first field of the record data
418 hdr = (struct pldm_pdr_hdr *)record->data;
419 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
420 continue;
421 }
422 in_range = pldm_record_handle_in_range(
423 record->record_handle, range_exclude_start_handle,
424 range_exclude_end_handle);
425 if (in_range) {
426 continue;
427 }
428
429 // this cast is valid with respect to alignment because
430 // struct pldm_pdr_hdr is declared with __attribute__((packed))
431 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500432 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500433 continue;
434 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500435
436 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500437 is_container_entity_type = pdr->container.entity_type ==
438 entity_type;
439 is_container_entity_instance_number =
440 pdr->container.entity_instance_num == entity_instance;
441 if (is_container_entity_type &&
442 is_container_entity_instance_number) {
443 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500444 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500445 }
446 }
447 return -ENOKEY;
448}
449
Andrew Jeffery9c766792022-08-10 23:12:49 +0930450typedef struct pldm_entity_association_tree {
451 pldm_entity_node *root;
452 uint16_t last_used_container_id;
453} pldm_entity_association_tree;
454
455typedef struct pldm_entity_node {
456 pldm_entity entity;
457 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600458 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459 pldm_entity_node *first_child;
460 pldm_entity_node *next_sibling;
461 uint8_t association_type;
462} pldm_entity_node;
463
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930464LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930465pldm_entity pldm_entity_extract(pldm_entity_node *node)
466{
467 assert(node != NULL);
468
469 return node->entity;
470}
471
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500472LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930473uint16_t
474pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600475{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930476 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600477
Andrew Jeffery15b88182023-06-30 13:29:17 +0930478 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600479}
480
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930481LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930482pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930483{
484 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930485 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930486 if (!tree) {
487 return NULL;
488 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930489 tree->root = NULL;
490 tree->last_used_container_id = 0;
491
492 return tree;
493}
494
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930495LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930496static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
497 uint16_t entity_type)
498{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930499 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530500 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930501 */
502 while (start->next_sibling != NULL) {
503 uint16_t this_type = start->entity.entity_type;
504 pldm_entity_node *next = start->next_sibling;
505 if (this_type == entity_type &&
506 (this_type != next->entity.entity_type)) {
507 break;
508 }
509 start = start->next_sibling;
510 }
511
512 return start;
513}
514
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930515LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930516pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930517 pldm_entity_association_tree *tree, pldm_entity *entity,
518 uint16_t entity_instance_number, pldm_entity_node *parent,
519 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930520{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500521 return pldm_entity_association_tree_add_entity(tree, entity,
522 entity_instance_number,
523 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600524 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500525}
526
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500527LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500528pldm_entity_node *pldm_entity_association_tree_add_entity(
529 pldm_entity_association_tree *tree, pldm_entity *entity,
530 uint16_t entity_instance_number, pldm_entity_node *parent,
531 uint8_t association_type, bool is_remote, bool is_update_container_id,
532 uint16_t container_id)
533{
534 if ((!tree) || (!entity)) {
535 return NULL;
536 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930537
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600538 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930539 pldm_entity node;
540 node.entity_type = entity->entity_type;
541 node.entity_instance_num = entity_instance_number;
542 if (pldm_is_current_parent_child(parent, &node)) {
543 return NULL;
544 }
545 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500546 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
547 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
548 return NULL;
549 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930550 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500551 if (!node) {
552 return NULL;
553 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930554 node->first_child = NULL;
555 node->next_sibling = NULL;
556 node->parent.entity_type = 0;
557 node->parent.entity_instance_num = 0;
558 node->parent.entity_container_id = 0;
559 node->entity.entity_type = entity->entity_type;
560 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600561 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930562 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600563 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930564 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500565 if (parent != NULL) {
566 free(node);
567 return NULL;
568 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930569 tree->root = node;
570 /* container_id 0 here indicates this is the top-most entry */
571 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600572 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930574 /* Ensure next_container_id() will yield a valid ID */
575 if (tree->last_used_container_id == UINT16_MAX) {
576 free(node);
577 return NULL;
578 }
579
Andrew Jeffery9c766792022-08-10 23:12:49 +0930580 parent->first_child = node;
581 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500582
583 if (is_remote) {
584 node->remote_container_id = entity->entity_container_id;
585 }
586 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600587 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500588 node->entity.entity_container_id = container_id;
589 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930590 /* We will have returned above */
591 assert(tree->last_used_container_id !=
592 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500593 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930594 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500595 }
596 } else {
597 node->entity.entity_container_id =
598 entity->entity_container_id;
599 }
600
601 if (!is_remote) {
602 node->remote_container_id =
603 node->entity.entity_container_id;
604 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930605 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930606 pldm_entity_node *start = parent == NULL ? tree->root :
607 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930608 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930609 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500610 if (!prev) {
611 free(node);
612 return NULL;
613 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614 pldm_entity_node *next = prev->next_sibling;
615 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500616 if (prev->entity.entity_instance_num == UINT16_MAX) {
617 free(node);
618 return NULL;
619 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930620 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600621 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930622 entity_instance_number :
623 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930624 }
625 prev->next_sibling = node;
626 node->parent = prev->parent;
627 node->next_sibling = next;
628 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930629 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600630 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930631 }
632 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500633 if (is_update_container_id) {
634 entity->entity_container_id = node->entity.entity_container_id;
635 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930636 return node;
637}
638
639static void get_num_nodes(pldm_entity_node *node, size_t *num)
640{
641 if (node == NULL) {
642 return;
643 }
644
645 ++(*num);
646 get_num_nodes(node->next_sibling, num);
647 get_num_nodes(node->first_child, num);
648}
649
650static void entity_association_tree_visit(pldm_entity_node *node,
651 pldm_entity *entities, size_t *index)
652{
653 if (node == NULL) {
654 return;
655 }
656
657 pldm_entity *entity = &entities[*index];
658 ++(*index);
659 entity->entity_type = node->entity.entity_type;
660 entity->entity_instance_num = node->entity.entity_instance_num;
661 entity->entity_container_id = node->entity.entity_container_id;
662
663 entity_association_tree_visit(node->next_sibling, entities, index);
664 entity_association_tree_visit(node->first_child, entities, index);
665}
666
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930667LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930668void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
669 pldm_entity **entities, size_t *size)
670{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930671 if (!tree || !entities || !size) {
672 return;
673 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930674
675 *size = 0;
676 if (tree->root == NULL) {
677 return;
678 }
679
680 get_num_nodes(tree->root, size);
681 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930682 if (!entities) {
683 return;
684 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930685 size_t index = 0;
686 entity_association_tree_visit(tree->root, *entities, &index);
687}
688
689static void entity_association_tree_destroy(pldm_entity_node *node)
690{
691 if (node == NULL) {
692 return;
693 }
694
695 entity_association_tree_destroy(node->next_sibling);
696 entity_association_tree_destroy(node->first_child);
697 free(node);
698}
699
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930700LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930701void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
702{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930703 if (!tree) {
704 return;
705 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930706
707 entity_association_tree_destroy(tree->root);
708 free(tree);
709}
710
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930711LIBPLDM_ABI_STABLE
712bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713{
714 assert(node != NULL);
715
716 return node->first_child != NULL;
717}
718
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930719LIBPLDM_ABI_STABLE
720pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930721{
722 assert(node != NULL);
723
724 return node->parent;
725}
726
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930727LIBPLDM_ABI_STABLE
728bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930729{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930730 if (!node) {
731 return false;
732 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930733
734 if (node->parent.entity_type == 0 &&
735 node->parent.entity_instance_num == 0 &&
736 node->parent.entity_container_id == 0) {
737 return false;
738 }
739
740 return true;
741}
742
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930743LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930744uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
745 uint8_t association_type)
746{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930747 if (!node) {
748 return 0;
749 }
750
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930751 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
752 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
753 return 0;
754 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930755
756 size_t count = 0;
757 pldm_entity_node *curr = node->first_child;
758 while (curr != NULL) {
759 if (curr->association_type == association_type) {
760 ++count;
761 }
762 curr = curr->next_sibling;
763 }
764
765 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930766 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930767}
768
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930769LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
771{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930772 if (!parent || !node) {
773 return false;
774 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930775
776 pldm_entity_node *curr = parent->first_child;
777 while (curr != NULL) {
778 if (node->entity_type == curr->entity.entity_type &&
779 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930780 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930781 return true;
782 }
783 curr = curr->next_sibling;
784 }
785
786 return false;
787}
788
Andrew Jeffery65945992023-07-17 15:04:21 +0930789static int entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500790 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
791 uint8_t contained_count, uint8_t association_type, bool is_remote,
792 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930793{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930794 uint8_t *start;
795 uint8_t *pdr;
796 int rc;
797
798 pdr = calloc(1, size);
799 if (!pdr) {
800 return -ENOMEM;
801 }
802
803 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930804
805 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
806 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600807 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930808 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
809 hdr->record_change_num = 0;
810 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
811 start += sizeof(struct pldm_pdr_hdr);
812
813 uint16_t *container_id = (uint16_t *)start;
814 *container_id = htole16(curr->first_child->entity.entity_container_id);
815 start += sizeof(uint16_t);
816 *start = association_type;
817 start += sizeof(uint8_t);
818
819 pldm_entity *entity = (pldm_entity *)start;
820 entity->entity_type = htole16(curr->entity.entity_type);
821 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
822 entity->entity_container_id = htole16(curr->entity.entity_container_id);
823 start += sizeof(pldm_entity);
824
825 *start = contained_count;
826 start += sizeof(uint8_t);
827
828 pldm_entity_node *node = curr->first_child;
829 while (node != NULL) {
830 if (node->association_type == association_type) {
831 pldm_entity *entity = (pldm_entity *)start;
832 entity->entity_type = htole16(node->entity.entity_type);
833 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930834 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930835 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930836 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930837 start += sizeof(pldm_entity);
838 }
839 node = node->next_sibling;
840 }
841
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930842 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
843 &record_handle);
844 free(pdr);
845 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846}
847
Andrew Jeffery65945992023-07-17 15:04:21 +0930848static int entity_association_pdr_add_entry(pldm_entity_node *curr,
849 pldm_pdr *repo, bool is_remote,
850 uint16_t terminus_handle,
851 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930852{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930853 uint8_t num_logical_children = pldm_entity_get_num_children(
854 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
855 uint8_t num_physical_children = pldm_entity_get_num_children(
856 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Andrew Jeffery65945992023-07-17 15:04:21 +0930857 int rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930858
859 if (num_logical_children) {
860 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930861 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
862 sizeof(uint8_t) + sizeof(pldm_entity) +
863 sizeof(uint8_t) +
864 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930865 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930866 curr, repo, logical_pdr_size, num_logical_children,
867 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500868 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930869 if (rc < 0) {
870 return rc;
871 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872 }
873
874 if (num_physical_children) {
875 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930876 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
877 sizeof(uint8_t) + sizeof(pldm_entity) +
878 sizeof(uint8_t) +
879 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930880 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930881 curr, repo, physical_pdr_size, num_physical_children,
882 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500883 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930884 if (rc < 0) {
885 return rc;
886 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930887 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930888
889 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930890}
891
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930892static bool is_present(pldm_entity entity, pldm_entity **entities,
893 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894{
895 if (entities == NULL || num_entities == 0) {
896 return true;
897 }
898 size_t i = 0;
899 while (i < num_entities) {
900 if ((*entities + i)->entity_type == entity.entity_type) {
901 return true;
902 }
903 i++;
904 }
905 return false;
906}
907
Andrew Jeffery65945992023-07-17 15:04:21 +0930908static int entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
909 pldm_entity **entities,
910 size_t num_entities, bool is_remote,
911 uint16_t terminus_handle,
912 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913{
Andrew Jeffery65945992023-07-17 15:04:21 +0930914 int rc;
915
Andrew Jeffery9c766792022-08-10 23:12:49 +0930916 if (curr == NULL) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930917 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930919
920 if (is_present(curr->entity, entities, num_entities)) {
921 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500922 curr, repo, is_remote, terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930923 if (rc) {
924 return rc;
925 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930927
928 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
929 num_entities, is_remote,
930 terminus_handle, record_handle);
931 if (rc) {
932 return rc;
933 }
934
935 return entity_association_pdr_add(curr->first_child, repo, entities,
936 num_entities, is_remote,
937 terminus_handle, record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930938}
939
Andrew Jeffery096685b2023-07-17 17:36:14 +0930940LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +0930941int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
942 pldm_pdr *repo, bool is_remote,
943 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +0930944{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930945 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930946 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930947 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930948
Andrew Jeffery65945992023-07-17 15:04:21 +0930949 return entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote,
950 terminus_handle, 0);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930951}
952
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930953LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +0930954int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +0930955 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
956 size_t num_entities, bool is_remote, uint16_t terminus_handle)
957{
958 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500959 node, repo, entities, num_entities, is_remote, terminus_handle,
960 0);
961}
962
Pavithra Barithaya3a267052023-11-13 05:01:36 -0600963LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500964int pldm_entity_association_pdr_add_from_node_with_record_handle(
965 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
966 size_t num_entities, bool is_remote, uint16_t terminus_handle,
967 uint32_t record_handle)
968{
969 if (!node || !repo || !entities) {
970 return -EINVAL;
971 }
972
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973 entity_association_pdr_add(node, repo, entities, num_entities,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500974 is_remote, terminus_handle, record_handle);
975
976 return 0;
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 Jeffery860a43d2024-08-23 01:21:58 +00001320 const uint8_t *end LIBPLDM_CC_UNUSED =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301321 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301322 start += sizeof(struct pldm_pdr_hdr);
1323 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301324 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301325 size_t l_num_entities = entity_association_pdr->num_children + 1;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301326 if (l_num_entities < 2) {
1327 return;
1328 }
Andrew Jeffery918973f2023-07-11 17:11:03 +09301329 if (start + sizeof(struct pldm_pdr_entity_association) +
1330 sizeof(pldm_entity) * (l_num_entities - 2) !=
1331 end) {
1332 return;
1333 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301334 pldm_entity *l_entities = malloc(sizeof(pldm_entity) * l_num_entities);
Andrew Jeffery918973f2023-07-11 17:11:03 +09301335 if (!l_entities) {
1336 return;
1337 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301338 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301339 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301340 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301341 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301342 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301343 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301344 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301345 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1346 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1347 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301348 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301349 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301350 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301351 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301352
1353 *num_entities = l_num_entities;
1354 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301355}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001356
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301357/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001358 * the same position.
1359 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301360LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001361static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1362 pldm_pdr_record *prev,
1363 pldm_pdr_record *new_record)
1364{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001365 if (repo->size < record->size) {
1366 return -EOVERFLOW;
1367 }
1368
1369 if (repo->size + new_record->size < new_record->size) {
1370 return -EOVERFLOW;
1371 }
1372
1373 if (repo->first == record) {
1374 repo->first = new_record;
1375 } else {
1376 prev->next = new_record;
1377 }
1378 new_record->next = record->next;
1379
1380 if (repo->last == record) {
1381 repo->last = new_record;
1382 }
1383
1384 repo->size = (repo->size - record->size) + new_record->size;
1385 return 0;
1386}
1387
1388/* Insert a new record to pldm_pdr repo to a position that comes after
1389 * pldm_pdr_record record.
1390 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301391LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001392static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1393 pldm_pdr_record *new_record)
1394{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001395 if (repo->size + new_record->size < new_record->size) {
1396 return -EOVERFLOW;
1397 }
1398
1399 if (repo->record_count == UINT32_MAX) {
1400 return -EOVERFLOW;
1401 }
1402
1403 new_record->next = record->next;
1404 record->next = new_record;
1405
1406 if (repo->last == record) {
1407 repo->last = new_record;
1408 }
1409
1410 repo->size = repo->size + new_record->size;
1411 ++repo->record_count;
1412 return 0;
1413}
1414
1415/* Find the position of PDR when its record handle is known
1416 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301417LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001418static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1419 pldm_pdr_record **prev,
1420 uint32_t record_handle)
1421{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001422 while (*record != NULL) {
1423 if ((*record)->record_handle == record_handle) {
1424 return true;
1425 }
1426 *prev = *record;
1427 *record = (*record)->next;
1428 }
1429 return false;
1430}
1431
1432LIBPLDM_ABI_TESTING
1433int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1434 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1435{
1436 if (!repo || !entity) {
1437 return -EINVAL;
1438 }
1439
1440 pldm_pdr_record *record = repo->first;
1441 pldm_pdr_record *prev = repo->first;
1442 int rc = 0;
1443 uint16_t header_length = 0;
1444 uint8_t num_children = 0;
1445 struct pldm_msgbuf _src;
1446 struct pldm_msgbuf *src = &_src;
1447 struct pldm_msgbuf _dst;
1448 struct pldm_msgbuf *dst = &_dst;
1449
1450 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1451
1452 if (!record) {
1453 return -EINVAL;
1454 }
1455 // Initialize msg buffer for record and record->data
1456 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1457 record->data, record->size);
1458 if (rc) {
1459 return rc;
1460 }
1461
1462 // check if adding another entity to record causes overflow before
1463 // allocating memory for new_record.
1464 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1465 return -EOVERFLOW;
1466 }
1467 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1468 if (!new_record) {
1469 return -ENOMEM;
1470 }
1471
1472 new_record->data = malloc(record->size + sizeof(pldm_entity));
1473 if (!new_record->data) {
1474 rc = -ENOMEM;
1475 goto cleanup_new_record;
1476 }
1477
1478 new_record->record_handle = record->record_handle;
1479 new_record->size = record->size + sizeof(struct pldm_entity);
1480 new_record->is_remote = record->is_remote;
1481
1482 // Initialize new PDR record with data from original PDR record.
1483 // Start with adding the header of original PDR
1484 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1485 new_record->data, new_record->size);
1486 if (rc) {
1487 goto cleanup_new_record_data;
1488 }
1489
1490 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1491 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1492 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1493 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1494 // extract the header length from record and increment size with
1495 // size of pldm_entity before inserting the value into new_record.
1496 rc = pldm_msgbuf_extract(src, header_length);
1497 if (rc) {
1498 goto cleanup_new_record_data;
1499 }
1500 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1501 "Fix the following bounds check.");
1502 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1503 rc = -EOVERFLOW;
1504 goto cleanup_new_record_data;
1505 }
1506 header_length += sizeof(pldm_entity);
1507 pldm_msgbuf_insert(dst, header_length);
1508 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1509 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1510 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1511 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1512 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1513 // extract value of number of children from record and increment it
1514 // by 1 before insert the value to new record.
1515 rc = pldm_msgbuf_extract(src, num_children);
1516 if (rc) {
1517 goto cleanup_new_record_data;
1518 }
1519 if (num_children == UINT8_MAX) {
1520 rc = -EOVERFLOW;
1521 goto cleanup_new_record_data;
1522 }
1523 num_children += 1;
1524 pldm_msgbuf_insert(dst, num_children);
1525 //Add all children of original PDR to new PDR
1526 for (int i = 0; i < num_children - 1; i++) {
1527 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1528 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1529 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1530 }
1531
1532 // Add new contained entity as a child of new PDR
1533 rc = pldm_msgbuf_destroy(src);
1534 if (rc) {
1535 goto cleanup_new_record_data;
1536 }
1537 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1538 sizeof(struct pldm_entity));
1539 if (rc) {
1540 goto cleanup_new_record_data;
1541 }
1542 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1543 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1544 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1545
1546 rc = pldm_msgbuf_destroy(src);
1547 if (rc) {
1548 goto cleanup_new_record_data;
1549 }
1550 rc = pldm_msgbuf_destroy(dst);
1551 if (rc) {
1552 goto cleanup_new_record_data;
1553 }
1554
1555 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1556 if (rc) {
1557 goto cleanup_new_record_data;
1558 }
1559
1560 free(record->data);
1561 free(record);
1562 return rc;
1563cleanup_new_record_data:
1564 free(new_record->data);
1565cleanup_new_record:
1566 free(new_record);
1567 return rc;
1568}
1569
1570LIBPLDM_ABI_TESTING
1571int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1572 uint32_t pdr_record_handle,
1573 pldm_entity *parent,
1574 pldm_entity *entity,
1575 uint32_t *entity_record_handle)
1576{
1577 if (!repo || !parent || !entity || !entity_record_handle) {
1578 return -EINVAL;
1579 }
1580
1581 if (pdr_record_handle == UINT32_MAX) {
1582 return -EOVERFLOW;
1583 }
1584
1585 bool pdr_added = false;
1586 uint16_t new_pdr_size;
1587 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001588 void *container_id_addr;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001589 struct pldm_msgbuf _dst;
1590 struct pldm_msgbuf *dst = &_dst;
1591 struct pldm_msgbuf _src_p;
1592 struct pldm_msgbuf *src_p = &_src_p;
1593 struct pldm_msgbuf _src_c;
1594 struct pldm_msgbuf *src_c = &_src_c;
1595 int rc = 0;
1596
1597 pldm_pdr_record *prev = repo->first;
1598 pldm_pdr_record *record = repo->first;
1599 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1600 pdr_record_handle);
1601 if (!pdr_added) {
1602 return -ENOENT;
1603 }
1604
1605 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1606 "Truncation ahead");
1607 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1608 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1609 if (!new_record) {
1610 return -ENOMEM;
1611 }
1612
1613 new_record->data = malloc(new_pdr_size);
1614 if (!new_record->data) {
1615 rc = -ENOMEM;
1616 goto cleanup_new_record;
1617 }
1618
1619 // Initialise new PDR to be added with the header, size and handle.
1620 // Set the position of new PDR
1621 *entity_record_handle = pdr_record_handle + 1;
1622 new_record->record_handle = *entity_record_handle;
1623 new_record->size = new_pdr_size;
1624 new_record->is_remote = false;
1625
1626 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1627 new_record->data, new_record->size);
1628 if (rc) {
1629 goto cleanup_new_record_data;
1630 }
1631
1632 // header record handle
1633 pldm_msgbuf_insert(dst, *entity_record_handle);
1634 // header version
1635 pldm_msgbuf_insert_uint8(dst, 1);
1636 // header type
1637 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1638 // header change number
1639 pldm_msgbuf_insert_uint16(dst, 0);
1640 // header length
1641 pldm_msgbuf_insert_uint16(dst,
1642 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1643
1644 // Data for new PDR is obtained from parent PDR and new contained entity
1645 // is added as the child
1646 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1647 sizeof(*parent));
1648 if (rc) {
1649 goto cleanup_new_record_data;
1650 }
1651
1652 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1653 sizeof(*entity));
1654 if (rc) {
1655 goto cleanup_new_record_data;
1656 }
1657
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001658 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001659 // extract pointer for container ID and save the address
1660 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1661 (void **)&container_id_addr);
1662 if (rc) {
1663 goto cleanup_new_record_data;
1664 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001665 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001666 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1667 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1668 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1669 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1670 // number of children
1671 pldm_msgbuf_insert_uint8(dst, 1);
1672
1673 // Add new entity as child
1674 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1675 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1676 // Extract and insert child entity container ID and add same value to
1677 // container ID of entity
1678 pldm_msgbuf_extract(src_c, container_id);
1679 pldm_msgbuf_insert(dst, container_id);
1680 container_id = htole16(container_id);
1681 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1682
1683 rc = pldm_msgbuf_destroy(dst);
1684 if (rc) {
1685 goto cleanup_new_record_data;
1686 }
1687 rc = pldm_msgbuf_destroy(src_p);
1688 if (rc) {
1689 goto cleanup_new_record_data;
1690 }
1691 rc = pldm_msgbuf_destroy(src_c);
1692 if (rc) {
1693 goto cleanup_new_record_data;
1694 }
1695
1696 rc = pldm_pdr_insert_record(repo, record, new_record);
1697 if (rc) {
1698 goto cleanup_new_record_data;
1699 }
1700
1701 return rc;
1702cleanup_new_record_data:
1703 free(new_record->data);
1704cleanup_new_record:
1705 free(new_record);
1706 return rc;
1707}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001708
1709LIBPLDM_CC_NONNULL
1710static bool pldm_entity_cmp(const struct pldm_entity *l,
1711 const struct pldm_entity *r)
1712{
1713 return l->entity_type == r->entity_type &&
1714 l->entity_instance_num == r->entity_instance_num &&
1715 l->entity_container_id == r->entity_container_id;
1716}
1717
1718/* Find record handle of a PDR record from PDR repo and
1719 * entity
1720 */
1721LIBPLDM_CC_NONNULL
1722static int pldm_entity_association_find_record_handle_by_entity(
1723 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1724 uint32_t *record_handle)
1725{
1726 uint8_t num_children = 0;
1727 uint8_t hdr_type = 0;
1728 int rc = 0;
1729 size_t skip_data_size = 0;
1730 pldm_pdr_record *record = repo->first;
1731 struct pldm_msgbuf _dst;
1732 struct pldm_msgbuf *dst = &_dst;
1733
1734 while (record != NULL) {
1735 rc = pldm_msgbuf_init_errno(dst,
1736 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1737 record->data, record->size);
1738 if (rc) {
1739 return rc;
1740 }
1741 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1742 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1743 pldm_msgbuf_extract(dst, hdr_type);
1744 if (record->is_remote != is_remote ||
1745 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1746 goto cleanup;
1747 }
1748 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1749 sizeof(uint16_t) + sizeof(uint8_t) +
1750 sizeof(struct pldm_entity);
1751 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1752 pldm_msgbuf_extract(dst, num_children);
1753 for (int i = 0; i < num_children; ++i) {
1754 struct pldm_entity e;
1755
1756 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1757 (rc = pldm_msgbuf_extract(dst,
1758 e.entity_instance_num)) ||
1759 (rc = pldm_msgbuf_extract(dst,
1760 e.entity_container_id))) {
1761 return rc;
1762 }
1763
1764 if (pldm_entity_cmp(entity, &e)) {
1765 *record_handle = record->record_handle;
1766 return 0;
1767 }
1768 }
1769 cleanup:
1770 rc = pldm_msgbuf_destroy(dst);
1771 if (rc) {
1772 return rc;
1773 }
1774 record = record->next;
1775 }
1776 return 0;
1777}
1778
1779LIBPLDM_ABI_TESTING
1780int pldm_entity_association_pdr_remove_contained_entity(
1781 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1782 uint32_t *pdr_record_handle)
1783{
1784 uint16_t header_length = 0;
1785 uint8_t num_children = 0;
1786 struct pldm_msgbuf _src;
1787 struct pldm_msgbuf *src = &_src;
1788 struct pldm_msgbuf _dst;
1789 struct pldm_msgbuf *dst = &_dst;
1790 int rc;
1791 pldm_pdr_record *record;
1792 pldm_pdr_record *prev;
1793
1794 if (!repo || !entity || !pdr_record_handle) {
1795 return -EINVAL;
1796 }
1797 record = repo->first;
1798 prev = repo->first;
1799
1800 rc = pldm_entity_association_find_record_handle_by_entity(
1801 repo, entity, is_remote, pdr_record_handle);
1802 if (rc) {
1803 return rc;
1804 }
1805 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
1806 if (!record) {
1807 return -EINVAL;
1808 }
1809 // Initialize msg buffer for record and record->data
1810 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1811 record->data, record->size);
1812 if (rc) {
1813 return rc;
1814 }
1815 // check if removing an entity from record causes overflow before
1816 // allocating memory for new_record.
1817 if (record->size < sizeof(pldm_entity)) {
1818 return -EOVERFLOW;
1819 }
1820 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1821 if (!new_record) {
1822 return -ENOMEM;
1823 }
1824 new_record->data = malloc(record->size - sizeof(pldm_entity));
1825 if (!new_record->data) {
1826 rc = -ENOMEM;
1827 goto cleanup_new_record;
1828 }
1829 new_record->record_handle = record->record_handle;
1830 new_record->size = record->size - sizeof(struct pldm_entity);
1831 new_record->is_remote = record->is_remote;
1832
1833 // Initialize new PDR record with data from original PDR record.
1834 // Start with adding the header of original PDR
1835 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1836 new_record->data, new_record->size);
1837 if (rc) {
1838 goto cleanup_new_record_data;
1839 }
1840 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1841 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1842 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1843 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1844 // extract the header length from record and decrement size with
1845 // size of pldm_entity before inserting the value into new_record.
1846 rc = pldm_msgbuf_extract(src, header_length);
1847 if (rc) {
1848 goto cleanup_new_record_data;
1849 }
1850 if (header_length < sizeof(pldm_entity)) {
1851 rc = -EOVERFLOW;
1852 goto cleanup_new_record_data;
1853 }
1854 header_length -= sizeof(pldm_entity);
1855 pldm_msgbuf_insert(dst, header_length);
1856 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1857 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1858 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1859 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1860 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1861 // extract value of number of children from record and decrement it
1862 // by 1 before insert the value to new record.
1863 rc = pldm_msgbuf_extract(src, num_children);
1864 if (rc) {
1865 goto cleanup_new_record_data;
1866 }
1867 if (num_children == 1) {
1868 prev->next = record->next;
1869 free(record->data);
1870 free(record);
1871 goto cleanup_new_record_data;
1872 } else if (num_children < 1) {
1873 rc = -EOVERFLOW;
1874 goto cleanup_new_record_data;
1875 }
1876 num_children -= 1;
1877 pldm_msgbuf_insert(dst, num_children);
1878 //Add all children of original PDR to new PDR
1879 for (int i = 0; i < num_children + 1; ++i) {
1880 struct pldm_entity e;
1881
1882 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
1883 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
1884 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
1885 goto cleanup_new_record_data;
1886 }
1887
1888 if (pldm_entity_cmp(entity, &e)) {
1889 continue;
1890 }
1891
1892 pldm_msgbuf_insert(dst, e.entity_type);
1893 pldm_msgbuf_insert(dst, e.entity_instance_num);
1894 pldm_msgbuf_insert(dst, e.entity_container_id);
1895 }
1896
1897 if ((rc = pldm_msgbuf_destroy(src)) ||
1898 (rc = pldm_msgbuf_destroy(dst)) ||
1899 (rc = pldm_pdr_replace_record(repo, record, prev, new_record))) {
1900 goto cleanup_new_record_data;
1901 }
1902
1903 free(record->data);
1904 free(record);
1905 return rc;
1906
1907cleanup_new_record_data:
1908 free(new_record->data);
1909cleanup_new_record:
1910 free(new_record);
1911 return rc;
1912}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05001913
1914/* API to find the PDR record that is previous to a given PLDM PDR
1915 * record in a given PLDM PDR repository
1916 */
1917LIBPLDM_CC_NONNULL
1918static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
1919 pldm_pdr_record *record)
1920{
1921 pldm_pdr_record *prev = NULL;
1922 pldm_pdr_record *curr = repo->first;
1923
1924 while (curr != NULL) {
1925 if (curr->record_handle == record->record_handle) {
1926 break;
1927 }
1928 prev = curr;
1929 curr = curr->next;
1930 }
1931 return prev;
1932}
1933
1934/* API to check if a PLDM PDR record is present in a PLDM PDR repository
1935 */
1936LIBPLDM_CC_NONNULL
1937static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
1938{
1939 if (repo->first == record) {
1940 return true;
1941 }
1942
1943 return pldm_pdr_get_prev_record(repo, record) != NULL;
1944}
1945
1946/* API to check if FRU RSI of record matches the given record set identifier.
1947 * Returns 1 if the provided FRU record matches the provided record set identifier,
1948 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
1949 */
1950LIBPLDM_CC_NONNULL
1951static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
1952 uint16_t rsi)
1953{
1954 uint16_t record_fru_rsi = 0;
1955 uint8_t *skip_data = NULL;
1956 uint8_t skip_data_size = 0;
1957 struct pldm_msgbuf _dst;
1958 struct pldm_msgbuf *dst = &_dst;
1959 int rc = 0;
1960
1961 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
1962 record->data, record->size);
1963 if (rc) {
1964 return rc;
1965 }
1966 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
1967 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
1968 pldm_msgbuf_extract(dst, record_fru_rsi);
1969
1970 rc = pldm_msgbuf_destroy(dst);
1971 if (rc) {
1972 return rc;
1973 }
1974 return record_fru_rsi == rsi;
1975}
1976
1977/* API to remove PLDM PDR record from a PLDM PDR repository
1978 */
1979LIBPLDM_CC_NONNULL_ARGS(1, 2)
1980static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
1981 pldm_pdr_record *prev)
1982{
1983 if (!is_prev_record_present(repo, record)) {
1984 return -EINVAL;
1985 }
1986
1987 assert(repo->size >= record->size);
1988 if (repo->size < record->size) {
1989 return -EOVERFLOW;
1990 }
1991
1992 if (repo->first == record) {
1993 repo->first = record->next;
1994 } else {
1995 if (prev != NULL) {
1996 prev->next = record->next;
1997 }
1998 }
1999
2000 if (repo->last == record) {
2001 repo->last = prev;
2002 if (prev != NULL) {
2003 prev->next = NULL;
2004 }
2005 }
2006 repo->record_count -= 1;
2007 repo->size -= record->size;
2008 free(record->data);
2009 free(record);
2010
2011 return 0;
2012}
2013
2014LIBPLDM_ABI_TESTING
2015int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2016 bool is_remote,
2017 uint32_t *record_handle)
2018{
2019 pldm_pdr_record *record;
2020 pldm_pdr_record *prev = NULL;
2021 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2022 uint8_t hdr_type = 0;
2023 int rc = 0;
2024 int match;
2025
2026 if (!repo || !record_handle) {
2027 return -EINVAL;
2028 }
2029 record = repo->first;
2030
2031 while (record != NULL) {
2032 struct pldm_msgbuf _buf;
2033 struct pldm_msgbuf *buf = &_buf;
2034 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2035 record->data, record->size);
2036 if (rc) {
2037 return rc;
2038 }
2039 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
2040 if ((rc = pldm_msgbuf_extract(buf, hdr_type))) {
2041 return rc;
2042 }
2043 if (record->is_remote != is_remote ||
2044 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
2045 goto cleanup;
2046 }
2047 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2048 if (match < 0) {
2049 return match;
2050 }
2051 if (match) {
2052 *record_handle = record->record_handle;
2053 prev = pldm_pdr_get_prev_record(repo, record);
2054 return pldm_pdr_remove_record(repo, record, prev);
2055 }
2056 cleanup:
2057 rc = pldm_msgbuf_destroy(buf);
2058 if (rc) {
2059 return rc;
2060 }
2061 record = record->next;
2062 }
2063 return rc;
2064}