blob: 95526ffbedfa7573404617eb458e57c5985be38c [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery860a43d2024-08-23 01:21:58 +00002#include "compiler.h"
Varsha Kaverappa37552b92024-02-12 05:06:06 -06003#include "msgbuf.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10304#include <libpldm/pdr.h>
5#include <libpldm/platform.h>
6
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05308#include <endian.h>
Andrew Jeffery9e566592024-10-02 16:38:51 +09309#include <stdint.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010#include <stdlib.h>
11#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060012#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093013
Varsha Kaverappa37552b92024-02-12 05:06:06 -060014#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
15 (sizeof(struct pldm_pdr_hdr) + \
16 sizeof(struct pldm_pdr_entity_association))
17
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050018#define PDR_FRU_RECORD_SET_MIN_SIZE \
19 (sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
20
Andrew Jeffery9c766792022-08-10 23:12:49 +093021typedef struct pldm_pdr_record {
22 uint32_t record_handle;
23 uint32_t size;
24 uint8_t *data;
25 struct pldm_pdr_record *next;
26 bool is_remote;
27 uint16_t terminus_handle;
28} pldm_pdr_record;
29
30typedef struct pldm_pdr {
31 uint32_t record_count;
32 uint32_t size;
33 pldm_pdr_record *first;
34 pldm_pdr_record *last;
35} pldm_pdr;
36
Andrew Jeffery890d37a2024-09-22 20:50:53 +093037LIBPLDM_CC_NONNULL
Archana Kakani94e2d752024-12-12 08:22:55 -060038static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
39 pldm_pdr_record *record);
40
41LIBPLDM_CC_NONNULL_ARGS(1, 2)
42static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
43 pldm_pdr_record *prev);
44
45LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +093046static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
47 const pldm_pdr_record *record)
48{
Andrew Jeffery9c766792022-08-10 23:12:49 +093049 if (record == repo->last) {
50 return 0;
51 }
52 return record->next->record_handle;
53}
54
Andrew Jefferyca248ce2023-07-07 10:38:30 +093055LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000056int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
57 bool is_remote, uint16_t terminus_handle,
58 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093059{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050060 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093061
Andrew Jeffery3b93d092023-07-17 13:01:50 +093062 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093063 return -EINVAL;
64 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093065
Andrew Jeffery3b93d092023-07-17 13:01:50 +093066 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093067 curr = *record_handle;
68 } else if (repo->last) {
69 curr = repo->last->record_handle;
70 if (curr == UINT32_MAX) {
71 return -EOVERFLOW;
72 }
73 curr += 1;
74 } else {
75 curr = 1;
76 }
77
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093079 if (!record) {
80 return -ENOMEM;
81 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093082
Andrew Jeffery572a3952023-07-03 13:19:28 +093083 if (data) {
84 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093085 if (!record->data) {
86 free(record);
87 return -ENOMEM;
88 }
89 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093090 }
91
Andrew Jeffery9c766792022-08-10 23:12:49 +093092 record->size = size;
93 record->is_remote = is_remote;
94 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093095 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093096
Andrew Jeffery3b93d092023-07-17 13:01:50 +093097 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093098 /* If record handle is 0, that is an indication for this API to
99 * compute a new handle. For that reason, the computed handle
100 * needs to be populated in the PDR header. For a case where the
101 * caller supplied the record handle, it would exist in the
102 * header already.
103 */
104 struct pldm_pdr_hdr *hdr = (void *)record->data;
105 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930106 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930107
Andrew Jeffery9c766792022-08-10 23:12:49 +0930108 record->next = NULL;
109
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930110 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930111 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930112 repo->first = record;
113 repo->last = record;
114 } else {
115 repo->last->next = record;
116 repo->last = record;
117 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930119 repo->size += record->size;
120 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930122 if (record_handle) {
123 *record_handle = record->record_handle;
124 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930125
126 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930130pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930131{
132 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930133 if (!repo) {
134 return NULL;
135 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136 repo->record_count = 0;
137 repo->size = 0;
138 repo->first = NULL;
139 repo->last = NULL;
140
141 return repo;
142}
143
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930144LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145void pldm_pdr_destroy(pldm_pdr *repo)
146{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930147 if (!repo) {
148 return;
149 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150
151 pldm_pdr_record *record = repo->first;
152 while (record != NULL) {
153 pldm_pdr_record *next = record->next;
154 if (record->data) {
155 free(record->data);
156 record->data = NULL;
157 }
158 free(record);
159 record = next;
160 }
161 free(repo);
162}
163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
166 uint32_t record_handle,
167 uint8_t **data, uint32_t *size,
168 uint32_t *next_record_handle)
169{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930170 if (!repo || !data || !size || !next_record_handle) {
171 return NULL;
172 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173
174 if (!record_handle && (repo->first != NULL)) {
175 record_handle = repo->first->record_handle;
176 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930177
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178 pldm_pdr_record *record = repo->first;
179 while (record != NULL) {
180 if (record->record_handle == record_handle) {
181 *size = record->size;
182 *data = record->data;
183 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930184 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185 return record;
186 }
187 record = record->next;
188 }
189
190 *size = 0;
191 *next_record_handle = 0;
192 return NULL;
193}
194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196const pldm_pdr_record *
197pldm_pdr_get_next_record(const pldm_pdr *repo,
198 const pldm_pdr_record *curr_record, uint8_t **data,
199 uint32_t *size, uint32_t *next_record_handle)
200{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930201 if (!repo || !curr_record || !data || !size || !next_record_handle) {
202 return NULL;
203 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204
205 if (curr_record == repo->last) {
206 *data = NULL;
207 *size = 0;
208 *next_record_handle = get_next_record_handle(repo, curr_record);
209 return NULL;
210 }
211
212 *next_record_handle = get_next_record_handle(repo, curr_record->next);
213 *data = curr_record->next->data;
214 *size = curr_record->next->size;
215 return curr_record->next;
216}
217
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930218LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219const pldm_pdr_record *
220pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
221 const pldm_pdr_record *curr_record, uint8_t **data,
222 uint32_t *size)
223{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930224 if (!repo) {
225 return NULL;
226 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930227
228 pldm_pdr_record *record = repo->first;
229 if (curr_record != NULL) {
230 record = curr_record->next;
231 }
232 while (record != NULL) {
233 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
234 if (hdr->type == pdr_type) {
235 if (data && size) {
236 *size = record->size;
237 *data = record->data;
238 }
239 return record;
240 }
241 record = record->next;
242 }
243
244 if (size) {
245 *size = 0;
246 }
247 return NULL;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
252{
253 assert(repo != NULL);
254
255 return repo->record_count;
256}
257
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930258LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
260{
261 assert(repo != NULL);
262
263 return repo->size;
264}
265
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000267uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268 const pldm_pdr_record *record)
269{
270 assert(repo != NULL);
271 assert(record != NULL);
272
273 return record->record_handle;
274}
275
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530276LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000277uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530278 const pldm_pdr_record *record)
279{
280 assert(repo != NULL);
281 assert(record != NULL);
282
283 return record->terminus_handle;
284}
285
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930286LIBPLDM_ABI_STABLE
287bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288{
289 assert(record != NULL);
290
291 return record->is_remote;
292}
293
Andrew Jefferya2c69112023-07-07 10:41:38 +0930294LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930295int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
296 uint16_t fru_rsi, uint16_t entity_type,
297 uint16_t entity_instance_num,
298 uint16_t container_id,
299 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930300{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930301 if (!repo || !bmc_record_handle) {
302 return -EINVAL;
303 }
304
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930305 uint8_t data[sizeof(struct pldm_pdr_hdr) +
306 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307
308 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
309 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930310 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311 hdr->type = PLDM_PDR_FRU_RECORD_SET;
312 hdr->record_change_num = 0;
313 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
314 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
316 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 fru->terminus_handle = htole16(terminus_handle);
318 fru->fru_rsi = htole16(fru_rsi);
319 fru->entity_type = htole16(entity_type);
320 fru->entity_instance_num = htole16(entity_instance_num);
321 fru->container_id = htole16(container_id);
322
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930323 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000324 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325}
326
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930327LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930329 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
330 uint16_t *entity_type, uint16_t *entity_instance_num,
331 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930333 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
334 !container_id) {
335 return NULL;
336 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337
338 uint8_t *data = NULL;
339 uint32_t size = 0;
340 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 while (curr_record != NULL) {
343 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344 (struct pldm_pdr_fru_record_set
345 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346 if (fru->fru_rsi == htole16(fru_rsi)) {
347 *terminus_handle = le16toh(fru->terminus_handle);
348 *entity_type = le16toh(fru->entity_type);
349 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930350 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 *container_id = le16toh(fru->container_id);
352 return curr_record;
353 }
354 data = NULL;
355 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930356 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
357 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930358 }
359
360 *terminus_handle = 0;
361 *entity_type = 0;
362 *entity_instance_num = 0;
363 *container_id = 0;
364
365 return NULL;
366}
367
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930368LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369/* NOLINTNEXTLINE(readability-identifier-naming) */
370void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
371 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930373 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 uint32_t size = 0;
375 const pldm_pdr_record *record;
376 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378
379 do {
380 if (record != NULL) {
381 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930382 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930384 (struct pldm_terminus_locator_type_mctp_eid *)
385 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930386 if (pdr->terminus_handle == terminus_handle &&
387 pdr->tid == tid && value->eid == tl_eid) {
388 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389 break;
390 }
391 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930392 record = pldm_pdr_find_record_by_type(repo,
393 PLDM_TERMINUS_LOCATOR_PDR,
394 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930395 } while (record);
396}
397
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500398static bool pldm_record_handle_in_range(uint32_t record_handle,
399 uint32_t first_record_handle,
400 uint32_t last_record_handle)
401{
402 return record_handle >= first_record_handle &&
403 record_handle <= last_record_handle;
404}
405
406LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500407int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500408 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500409 uint8_t child_index, uint32_t range_exclude_start_handle,
410 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500411{
412 pldm_pdr_record *record;
413 if (!repo) {
414 return -EINVAL;
415 }
416
417 for (record = repo->first; record; record = record->next) {
418 bool is_container_entity_instance_number;
419 struct pldm_pdr_entity_association *pdr;
420 bool is_container_entity_type;
421 struct pldm_entity *child;
422 struct pldm_pdr_hdr *hdr;
423 bool in_range;
424
425 // pldm_pdr_add() takes only uint8_t* data as an argument.
426 // The expectation here is the pldm_pdr_hdr is the first field of the record data
427 hdr = (struct pldm_pdr_hdr *)record->data;
428 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
429 continue;
430 }
431 in_range = pldm_record_handle_in_range(
432 record->record_handle, range_exclude_start_handle,
433 range_exclude_end_handle);
434 if (in_range) {
435 continue;
436 }
437
438 // this cast is valid with respect to alignment because
439 // struct pldm_pdr_hdr is declared with __attribute__((packed))
440 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500441 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500442 continue;
443 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500444
445 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500446 is_container_entity_type = pdr->container.entity_type ==
447 entity_type;
448 is_container_entity_instance_number =
449 pdr->container.entity_instance_num == entity_instance;
450 if (is_container_entity_type &&
451 is_container_entity_instance_number) {
452 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500453 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500454 }
455 }
Matt Johnstonae05d5e2024-10-11 14:51:12 +0800456 return -ENOENT;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500457}
458
Andrew Jeffery9c766792022-08-10 23:12:49 +0930459typedef struct pldm_entity_association_tree {
460 pldm_entity_node *root;
461 uint16_t last_used_container_id;
462} pldm_entity_association_tree;
463
464typedef struct pldm_entity_node {
465 pldm_entity entity;
466 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600467 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930468 pldm_entity_node *first_child;
469 pldm_entity_node *next_sibling;
470 uint8_t association_type;
471} pldm_entity_node;
472
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930473LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930474pldm_entity pldm_entity_extract(pldm_entity_node *node)
475{
476 assert(node != NULL);
477
478 return node->entity;
479}
480
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500481LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930482uint16_t
483pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600484{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930485 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600486
Andrew Jeffery15b88182023-06-30 13:29:17 +0930487 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600488}
489
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930490LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930491pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930492{
493 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930494 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930495 if (!tree) {
496 return NULL;
497 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930498 tree->root = NULL;
499 tree->last_used_container_id = 0;
500
501 return tree;
502}
503
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930504LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930505static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
506 uint16_t entity_type)
507{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930508 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530509 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930510 */
511 while (start->next_sibling != NULL) {
512 uint16_t this_type = start->entity.entity_type;
513 pldm_entity_node *next = start->next_sibling;
514 if (this_type == entity_type &&
515 (this_type != next->entity.entity_type)) {
516 break;
517 }
518 start = start->next_sibling;
519 }
520
521 return start;
522}
523
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930524LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930525pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930526 pldm_entity_association_tree *tree, pldm_entity *entity,
527 uint16_t entity_instance_number, pldm_entity_node *parent,
528 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930529{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500530 return pldm_entity_association_tree_add_entity(tree, entity,
531 entity_instance_number,
532 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600533 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500534}
535
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500536LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500537pldm_entity_node *pldm_entity_association_tree_add_entity(
538 pldm_entity_association_tree *tree, pldm_entity *entity,
539 uint16_t entity_instance_number, pldm_entity_node *parent,
540 uint8_t association_type, bool is_remote, bool is_update_container_id,
541 uint16_t container_id)
542{
543 if ((!tree) || (!entity)) {
544 return NULL;
545 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930546
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600547 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930548 pldm_entity node;
549 node.entity_type = entity->entity_type;
550 node.entity_instance_num = entity_instance_number;
551 if (pldm_is_current_parent_child(parent, &node)) {
552 return NULL;
553 }
554 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500555 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
556 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
557 return NULL;
558 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930559 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500560 if (!node) {
561 return NULL;
562 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930563 node->first_child = NULL;
564 node->next_sibling = NULL;
565 node->parent.entity_type = 0;
566 node->parent.entity_instance_num = 0;
567 node->parent.entity_container_id = 0;
568 node->entity.entity_type = entity->entity_type;
569 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600570 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930571 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600572 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930573 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500574 if (parent != NULL) {
575 free(node);
576 return NULL;
577 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930578 tree->root = node;
579 /* container_id 0 here indicates this is the top-most entry */
580 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600581 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930582 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930583 /* Ensure next_container_id() will yield a valid ID */
584 if (tree->last_used_container_id == UINT16_MAX) {
585 free(node);
586 return NULL;
587 }
588
Andrew Jeffery9c766792022-08-10 23:12:49 +0930589 parent->first_child = node;
590 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500591
592 if (is_remote) {
593 node->remote_container_id = entity->entity_container_id;
594 }
595 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600596 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500597 node->entity.entity_container_id = container_id;
598 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930599 /* We will have returned above */
600 assert(tree->last_used_container_id !=
601 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500602 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930603 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500604 }
605 } else {
606 node->entity.entity_container_id =
607 entity->entity_container_id;
608 }
609
610 if (!is_remote) {
611 node->remote_container_id =
612 node->entity.entity_container_id;
613 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930614 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930615 pldm_entity_node *start = parent == NULL ? tree->root :
616 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930617 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930618 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500619 if (!prev) {
620 free(node);
621 return NULL;
622 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930623 pldm_entity_node *next = prev->next_sibling;
624 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500625 if (prev->entity.entity_instance_num == UINT16_MAX) {
626 free(node);
627 return NULL;
628 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930629 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600630 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930631 entity_instance_number :
632 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930633 }
634 prev->next_sibling = node;
635 node->parent = prev->parent;
636 node->next_sibling = next;
637 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930638 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600639 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930640 }
641 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500642 if (is_update_container_id) {
643 entity->entity_container_id = node->entity.entity_container_id;
644 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930645 return node;
646}
647
648static void get_num_nodes(pldm_entity_node *node, size_t *num)
649{
650 if (node == NULL) {
651 return;
652 }
653
654 ++(*num);
655 get_num_nodes(node->next_sibling, num);
656 get_num_nodes(node->first_child, num);
657}
658
659static void entity_association_tree_visit(pldm_entity_node *node,
660 pldm_entity *entities, size_t *index)
661{
662 if (node == NULL) {
663 return;
664 }
665
666 pldm_entity *entity = &entities[*index];
667 ++(*index);
668 entity->entity_type = node->entity.entity_type;
669 entity->entity_instance_num = node->entity.entity_instance_num;
670 entity->entity_container_id = node->entity.entity_container_id;
671
672 entity_association_tree_visit(node->next_sibling, entities, index);
673 entity_association_tree_visit(node->first_child, entities, index);
674}
675
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930676LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930677void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
678 pldm_entity **entities, size_t *size)
679{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930680 if (!tree || !entities || !size) {
681 return;
682 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930683
684 *size = 0;
685 if (tree->root == NULL) {
686 return;
687 }
688
689 get_num_nodes(tree->root, size);
690 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930691 if (!entities) {
692 return;
693 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694 size_t index = 0;
695 entity_association_tree_visit(tree->root, *entities, &index);
696}
697
698static void entity_association_tree_destroy(pldm_entity_node *node)
699{
700 if (node == NULL) {
701 return;
702 }
703
704 entity_association_tree_destroy(node->next_sibling);
705 entity_association_tree_destroy(node->first_child);
706 free(node);
707}
708
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930709LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930710void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
711{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930712 if (!tree) {
713 return;
714 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930715
716 entity_association_tree_destroy(tree->root);
717 free(tree);
718}
719
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930720LIBPLDM_ABI_STABLE
721bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930722{
723 assert(node != NULL);
724
725 return node->first_child != NULL;
726}
727
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930728LIBPLDM_ABI_STABLE
729pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930730{
731 assert(node != NULL);
732
733 return node->parent;
734}
735
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930736LIBPLDM_ABI_STABLE
737bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930738{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930739 if (!node) {
740 return false;
741 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930742
743 if (node->parent.entity_type == 0 &&
744 node->parent.entity_instance_num == 0 &&
745 node->parent.entity_container_id == 0) {
746 return false;
747 }
748
749 return true;
750}
751
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930752LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930753uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
754 uint8_t association_type)
755{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930756 if (!node) {
757 return 0;
758 }
759
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930760 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
761 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
762 return 0;
763 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930764
765 size_t count = 0;
766 pldm_entity_node *curr = node->first_child;
767 while (curr != NULL) {
768 if (curr->association_type == association_type) {
769 ++count;
770 }
771 curr = curr->next_sibling;
772 }
773
774 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930775 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930776}
777
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930778LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930779bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
780{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930781 if (!parent || !node) {
782 return false;
783 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930784
785 pldm_entity_node *curr = parent->first_child;
786 while (curr != NULL) {
787 if (node->entity_type == curr->entity.entity_type &&
788 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930789 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930790 return true;
791 }
792 curr = curr->next_sibling;
793 }
794
795 return false;
796}
797
Archana Kakanibc40dd52024-08-02 00:10:44 -0500798static int64_t entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500799 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
800 uint8_t contained_count, uint8_t association_type, bool is_remote,
801 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930803 uint8_t *start;
804 uint8_t *pdr;
Archana Kakanibc40dd52024-08-02 00:10:44 -0500805 int64_t rc;
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930806
807 pdr = calloc(1, size);
808 if (!pdr) {
809 return -ENOMEM;
810 }
811
812 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930813
814 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
815 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -0600816 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
818 hdr->record_change_num = 0;
819 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
820 start += sizeof(struct pldm_pdr_hdr);
821
822 uint16_t *container_id = (uint16_t *)start;
823 *container_id = htole16(curr->first_child->entity.entity_container_id);
824 start += sizeof(uint16_t);
825 *start = association_type;
826 start += sizeof(uint8_t);
827
828 pldm_entity *entity = (pldm_entity *)start;
829 entity->entity_type = htole16(curr->entity.entity_type);
830 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
831 entity->entity_container_id = htole16(curr->entity.entity_container_id);
832 start += sizeof(pldm_entity);
833
834 *start = contained_count;
835 start += sizeof(uint8_t);
836
837 pldm_entity_node *node = curr->first_child;
838 while (node != NULL) {
839 if (node->association_type == association_type) {
840 pldm_entity *entity = (pldm_entity *)start;
841 entity->entity_type = htole16(node->entity.entity_type);
842 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930843 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930844 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930845 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930846 start += sizeof(pldm_entity);
847 }
848 node = node->next_sibling;
849 }
850
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930851 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
852 &record_handle);
853 free(pdr);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500854 return (rc < 0) ? rc : record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930855}
856
Archana Kakanibc40dd52024-08-02 00:10:44 -0500857static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
858 pldm_pdr *repo, bool is_remote,
859 uint16_t terminus_handle,
860 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930861{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930862 uint8_t num_logical_children = pldm_entity_get_num_children(
863 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
864 uint8_t num_physical_children = pldm_entity_get_num_children(
865 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500866 int64_t rc;
867
868 if (!num_logical_children && !num_physical_children) {
869 if (record_handle == 0) {
870 return -EINVAL;
871 }
872 return record_handle - 1;
873 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930874
875 if (num_logical_children) {
876 uint16_t logical_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_logical_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, logical_pdr_size, num_logical_children,
883 PLDM_ENTITY_ASSOCIAION_LOGICAL, 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 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500888 if (num_physical_children) {
889 if (rc >= UINT32_MAX) {
890 return -EOVERFLOW;
891 }
892 record_handle = rc + 1;
893 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930894 }
895
896 if (num_physical_children) {
897 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930898 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
899 sizeof(uint8_t) + sizeof(pldm_entity) +
900 sizeof(uint8_t) +
901 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +0930902 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930903 curr, repo, physical_pdr_size, num_physical_children,
904 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500905 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +0930906 if (rc < 0) {
907 return rc;
908 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500909 record_handle = rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930911
Archana Kakanibc40dd52024-08-02 00:10:44 -0500912 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930913}
914
Andrew Jefferyd09b1af2023-07-17 12:39:16 +0930915static bool is_present(pldm_entity entity, pldm_entity **entities,
916 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930917{
918 if (entities == NULL || num_entities == 0) {
919 return true;
920 }
921 size_t i = 0;
922 while (i < num_entities) {
923 if ((*entities + i)->entity_type == entity.entity_type) {
924 return true;
925 }
926 i++;
927 }
928 return false;
929}
930
Archana Kakanibc40dd52024-08-02 00:10:44 -0500931static int64_t entity_association_pdr_add(pldm_entity_node *curr,
932 pldm_pdr *repo,
933 pldm_entity **entities,
934 size_t num_entities, bool is_remote,
935 uint16_t terminus_handle,
936 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930937{
Archana Kakanibc40dd52024-08-02 00:10:44 -0500938 int64_t rc;
Andrew Jeffery65945992023-07-17 15:04:21 +0930939
Andrew Jeffery9c766792022-08-10 23:12:49 +0930940 if (curr == NULL) {
Archana Kakanibc40dd52024-08-02 00:10:44 -0500941 // entity_association_pdr_add function gets called
942 // recursively for the siblings and children of the
943 // entity. This causes NULL current entity node, and the
944 // record handle is returned
945 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930946 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930947
948 if (is_present(curr->entity, entities, num_entities)) {
949 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500950 curr, repo, is_remote, terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500951 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930952 return rc;
953 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500954 if (rc >= UINT32_MAX) {
955 return -EOVERFLOW;
956 }
957 record_handle = rc + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930958 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930959
960 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
961 num_entities, is_remote,
962 terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -0500963 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930964 return rc;
965 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500966 // entity_association_pdr_add return record handle in success
967 // case. If the pdr gets added to the repo, new record handle
968 // will be returned. Below check confirms if the pdr is added
969 // to the repo and increments the record handle
970 if (record_handle != rc) {
971 if (rc >= UINT32_MAX) {
972 return -EOVERFLOW;
973 }
974 record_handle = rc + 1;
975 }
Andrew Jeffery65945992023-07-17 15:04:21 +0930976
Archana Kakanibc40dd52024-08-02 00:10:44 -0500977 rc = entity_association_pdr_add(curr->first_child, repo, entities,
978 num_entities, is_remote,
979 terminus_handle, record_handle);
980 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930981}
982
Andrew Jeffery096685b2023-07-17 17:36:14 +0930983LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +0930984int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
985 pldm_pdr *repo, bool is_remote,
986 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +0930987{
Andrew Jefferyc7883482023-06-30 15:52:04 +0930988 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +0930989 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +0930990 }
Archana Kakanibc40dd52024-08-02 00:10:44 -0500991 int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
992 is_remote, terminus_handle, 0);
993 assert(rc >= INT_MIN);
994 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930995}
996
Andrew Jeffery1354a6e2023-07-07 10:34:38 +0930997LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +0930998int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +0930999 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1000 size_t num_entities, bool is_remote, uint16_t terminus_handle)
1001{
1002 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001003 node, repo, entities, num_entities, is_remote, terminus_handle,
1004 0);
1005}
1006
Pavithra Barithaya3a267052023-11-13 05:01:36 -06001007LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001008int pldm_entity_association_pdr_add_from_node_with_record_handle(
1009 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1010 size_t num_entities, bool is_remote, uint16_t terminus_handle,
1011 uint32_t record_handle)
1012{
1013 if (!node || !repo || !entities) {
1014 return -EINVAL;
1015 }
1016
Archana Kakanibc40dd52024-08-02 00:10:44 -05001017 int64_t rc = entity_association_pdr_add(node, repo, entities,
1018 num_entities, is_remote,
1019 terminus_handle, record_handle);
1020
1021 assert(rc >= INT_MIN);
1022 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301023}
1024
Andrew Jeffery643c4432023-07-17 15:36:03 +09301025static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
1026 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301027{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001028 bool is_entity_container_id;
1029 bool is_entity_instance_num;
1030 bool is_type;
1031
Andrew Jeffery9c766792022-08-10 23:12:49 +09301032 if (tree_node == NULL) {
1033 return;
1034 }
1035
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001036 is_type = tree_node->entity.entity_type == entity.entity_type;
1037 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1038 entity.entity_instance_num;
1039 is_entity_container_id = tree_node->entity.entity_container_id ==
1040 entity.entity_container_id;
1041
1042 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043 *node = tree_node;
1044 return;
1045 }
1046
1047 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1048 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1049}
1050
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301051LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301052void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1053 pldm_entity entity, pldm_entity_node **node)
1054{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301055 if (!tree || !node) {
1056 return;
1057 }
1058
Andrew Jeffery9c766792022-08-10 23:12:49 +09301059 find_entity_ref_in_tree(tree->root, entity, node);
1060}
1061
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301062LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1064 uint16_t terminus_handle)
1065{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301066 if (!repo) {
1067 return;
1068 }
1069
Andrew Jeffery9c766792022-08-10 23:12:49 +09301070 bool removed = false;
1071
1072 pldm_pdr_record *record = repo->first;
1073 pldm_pdr_record *prev = NULL;
1074 while (record != NULL) {
1075 pldm_pdr_record *next = record->next;
1076 if (record->terminus_handle == terminus_handle) {
1077 if (repo->first == record) {
1078 repo->first = next;
1079 } else {
1080 prev->next = next;
1081 }
1082 if (repo->last == record) {
1083 repo->last = prev;
1084 }
1085 if (record->data) {
1086 free(record->data);
1087 }
1088 --repo->record_count;
1089 repo->size -= record->size;
1090 free(record);
1091 removed = true;
1092 } else {
1093 prev = record;
1094 }
1095 record = next;
1096 }
1097
1098 if (removed == true) {
1099 record = repo->first;
1100 uint32_t record_handle = 0;
1101 while (record != NULL) {
1102 record->record_handle = ++record_handle;
1103 if (record->data != NULL) {
1104 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301105 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301107 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301108 }
1109 record = record->next;
1110 }
1111 }
1112}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301113
1114LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301115void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1116{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301117 if (!repo) {
1118 return;
1119 }
1120
Andrew Jeffery9c766792022-08-10 23:12:49 +09301121 bool removed = false;
1122
1123 pldm_pdr_record *record = repo->first;
1124 pldm_pdr_record *prev = NULL;
1125 while (record != NULL) {
1126 pldm_pdr_record *next = record->next;
1127 if (record->is_remote == true) {
1128 if (repo->first == record) {
1129 repo->first = next;
1130 } else {
1131 prev->next = next;
1132 }
1133 if (repo->last == record) {
1134 repo->last = prev;
1135 }
1136 if (record->data) {
1137 free(record->data);
1138 }
1139 --repo->record_count;
1140 repo->size -= record->size;
1141 free(record);
1142 removed = true;
1143 } else {
1144 prev = record;
1145 }
1146 record = next;
1147 }
1148
1149 if (removed == true) {
1150 record = repo->first;
1151 uint32_t record_handle = 0;
1152 while (record != NULL) {
1153 record->record_handle = ++record_handle;
1154 if (record->data != NULL) {
1155 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301156 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301157 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301158 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301159 }
1160 record = record->next;
1161 }
1162 }
1163}
1164
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001165LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001166pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1167 uint32_t first, uint32_t last)
1168{
1169 pldm_pdr_record *record = NULL;
1170 pldm_pdr_record *curr;
1171
1172 if (!repo) {
1173 return NULL;
1174 }
1175 for (curr = repo->first; curr; curr = curr->next) {
1176 if (first > curr->record_handle || last < curr->record_handle) {
1177 continue;
1178 }
1179 if (!record || curr->record_handle > record->record_handle) {
1180 record = curr;
1181 }
1182 }
1183
1184 return record;
1185}
1186
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001187static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1188 pldm_entity *entity,
1189 pldm_entity_node **out,
1190 bool is_remote)
1191{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001192 if (node == NULL) {
1193 return;
1194 }
1195 bool is_entity_type;
1196 bool is_entity_instance_num;
1197
1198 is_entity_type = node->entity.entity_type == entity->entity_type;
1199 is_entity_instance_num = node->entity.entity_instance_num ==
1200 entity->entity_instance_num;
1201
1202 if (!is_remote ||
1203 node->remote_container_id == entity->entity_container_id) {
1204 if (is_entity_type && is_entity_instance_num) {
1205 entity->entity_container_id =
1206 node->entity.entity_container_id;
1207 *out = node;
1208 return;
1209 }
1210 }
1211 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1212 is_remote);
1213 entity_association_tree_find_if_remote(node->first_child, entity, out,
1214 is_remote);
1215}
1216
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001217LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001218pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1219 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001220{
1221 if (!tree || !entity) {
1222 return NULL;
1223 }
1224 pldm_entity_node *node = NULL;
1225 entity_association_tree_find_if_remote(tree->root, entity, &node,
1226 is_remote);
1227 return node;
1228}
1229
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301230static void entity_association_tree_find(pldm_entity_node *node,
1231 pldm_entity *entity,
1232 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301233{
1234 if (node == NULL) {
1235 return;
1236 }
1237
1238 if (node->entity.entity_type == entity->entity_type &&
1239 node->entity.entity_instance_num == entity->entity_instance_num) {
1240 entity->entity_container_id = node->entity.entity_container_id;
1241 *out = node;
1242 return;
1243 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301244 entity_association_tree_find(node->next_sibling, entity, out);
1245 entity_association_tree_find(node->first_child, entity, out);
1246}
1247
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301248LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301249pldm_entity_node *
1250pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1251 pldm_entity *entity)
1252{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301253 if (!tree || !entity) {
1254 return NULL;
1255 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301256
1257 pldm_entity_node *node = NULL;
1258 entity_association_tree_find(tree->root, entity, &node);
1259 return node;
1260}
1261
Andrew Jeffery60582152024-09-22 21:16:38 +09301262static int entity_association_tree_copy(pldm_entity_node *org_node,
1263 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301264{
Andrew Jeffery60582152024-09-22 21:16:38 +09301265 int rc;
1266
Andrew Jeffery9c766792022-08-10 23:12:49 +09301267 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301268 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301269 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301270
Andrew Jeffery9c766792022-08-10 23:12:49 +09301271 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301272 if (!*new_node) {
1273 return -ENOMEM;
1274 }
1275
Andrew Jeffery9c766792022-08-10 23:12:49 +09301276 (*new_node)->parent = org_node->parent;
1277 (*new_node)->entity = org_node->entity;
1278 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001279 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301280 (*new_node)->first_child = NULL;
1281 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301282
1283 rc = entity_association_tree_copy(org_node->first_child,
1284 &((*new_node)->first_child));
1285 if (rc) {
1286 goto cleanup;
1287 }
1288
1289 rc = entity_association_tree_copy(org_node->next_sibling,
1290 &((*new_node)->next_sibling));
1291 if (rc) {
1292 entity_association_tree_destroy((*new_node)->first_child);
1293 goto cleanup;
1294 }
1295
1296 return 0;
1297
1298cleanup:
1299 free(*new_node);
1300 *new_node = NULL;
1301 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301302}
1303
Andrew Jeffery36324f62024-09-25 13:41:41 +09301304LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301305void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301306 pldm_entity_association_tree *org_tree,
1307 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301308{
George Liuc6c391d2023-11-09 10:13:34 +08001309 assert(org_tree != NULL);
1310 assert(new_tree != NULL);
1311
Andrew Jeffery9c766792022-08-10 23:12:49 +09301312 new_tree->last_used_container_id = org_tree->last_used_container_id;
1313 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1314}
1315
Andrew Jeffery60582152024-09-22 21:16:38 +09301316LIBPLDM_ABI_TESTING
1317int pldm_entity_association_tree_copy_root_check(
1318 pldm_entity_association_tree *org_tree,
1319 pldm_entity_association_tree *new_tree)
1320{
1321 if (!org_tree || !new_tree) {
1322 return -EINVAL;
1323 }
1324
1325 new_tree->last_used_container_id = org_tree->last_used_container_id;
1326 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1327}
1328
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301329LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301330void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301331 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301332{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301333 if (!tree) {
1334 return;
1335 }
1336
Andrew Jeffery9c766792022-08-10 23:12:49 +09301337 entity_association_tree_destroy(tree->root);
1338 tree->last_used_container_id = 0;
1339 tree->root = NULL;
1340}
1341
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301342LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301343bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1344{
1345 return ((tree->root == NULL) ? true : false);
1346}
1347
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301348LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301349void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1350 size_t *num_entities,
1351 pldm_entity **entities)
1352{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301353 if (!pdr || !num_entities || !entities) {
1354 return;
1355 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001356 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301357 return;
1358 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301359
1360 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301361 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1362 return;
1363 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301364
1365 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301366
1367 if (UINTPTR_MAX - (uintptr_t)start <
1368 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1369 return;
1370 }
1371
1372 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1373 return;
1374 }
1375
1376 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301377 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301378 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301379
1380 if ((uintptr_t)end - (uintptr_t)start <
1381 sizeof(struct pldm_pdr_entity_association)) {
1382 return;
1383 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001384
Andrew Jeffery9c766792022-08-10 23:12:49 +09301385 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301386 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301387
Archana Kakanibc40dd52024-08-02 00:10:44 -05001388 size_t l_num_entities = entity_association_pdr->num_children;
1389
1390 if (l_num_entities == 0) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301391 return;
1392 }
Andrew Jeffery8f33a1d2024-10-11 18:01:19 +10301393
Archana Kakanibc40dd52024-08-02 00:10:44 -05001394 if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1395 l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301396 return;
1397 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301398
Archana Kakanibc40dd52024-08-02 00:10:44 -05001399 if (l_num_entities >= (size_t)UINT8_MAX) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301400 return;
1401 }
1402
Archana Kakanibc40dd52024-08-02 00:10:44 -05001403 l_num_entities++;
1404
Andrew Jeffery9e566592024-10-02 16:38:51 +09301405 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301406 if (!l_entities) {
1407 return;
1408 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301409 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301410 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301411 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301412 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301413 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301414 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301415 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301416 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1417 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1418 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301419 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301420 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301421 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301422 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301423
1424 *num_entities = l_num_entities;
1425 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301426}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001427
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301428/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001429 * the same position.
1430 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301431LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001432static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1433 pldm_pdr_record *prev,
1434 pldm_pdr_record *new_record)
1435{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001436 if (repo->size < record->size) {
1437 return -EOVERFLOW;
1438 }
1439
1440 if (repo->size + new_record->size < new_record->size) {
1441 return -EOVERFLOW;
1442 }
1443
1444 if (repo->first == record) {
1445 repo->first = new_record;
1446 } else {
1447 prev->next = new_record;
1448 }
1449 new_record->next = record->next;
1450
1451 if (repo->last == record) {
1452 repo->last = new_record;
1453 }
1454
1455 repo->size = (repo->size - record->size) + new_record->size;
1456 return 0;
1457}
1458
1459/* Insert a new record to pldm_pdr repo to a position that comes after
1460 * pldm_pdr_record record.
1461 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301462LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001463static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1464 pldm_pdr_record *new_record)
1465{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001466 if (repo->size + new_record->size < new_record->size) {
1467 return -EOVERFLOW;
1468 }
1469
1470 if (repo->record_count == UINT32_MAX) {
1471 return -EOVERFLOW;
1472 }
1473
1474 new_record->next = record->next;
1475 record->next = new_record;
1476
1477 if (repo->last == record) {
1478 repo->last = new_record;
1479 }
1480
1481 repo->size = repo->size + new_record->size;
1482 ++repo->record_count;
1483 return 0;
1484}
1485
1486/* Find the position of PDR when its record handle is known
1487 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301488LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001489static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1490 pldm_pdr_record **prev,
1491 uint32_t record_handle)
1492{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001493 while (*record != NULL) {
1494 if ((*record)->record_handle == record_handle) {
1495 return true;
1496 }
1497 *prev = *record;
1498 *record = (*record)->next;
1499 }
1500 return false;
1501}
1502
1503LIBPLDM_ABI_TESTING
1504int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1505 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1506{
1507 if (!repo || !entity) {
1508 return -EINVAL;
1509 }
1510
1511 pldm_pdr_record *record = repo->first;
1512 pldm_pdr_record *prev = repo->first;
1513 int rc = 0;
1514 uint16_t header_length = 0;
1515 uint8_t num_children = 0;
1516 struct pldm_msgbuf _src;
1517 struct pldm_msgbuf *src = &_src;
1518 struct pldm_msgbuf _dst;
1519 struct pldm_msgbuf *dst = &_dst;
1520
1521 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1522
1523 if (!record) {
1524 return -EINVAL;
1525 }
1526 // Initialize msg buffer for record and record->data
1527 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1528 record->data, record->size);
1529 if (rc) {
1530 return rc;
1531 }
1532
1533 // check if adding another entity to record causes overflow before
1534 // allocating memory for new_record.
1535 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1536 return -EOVERFLOW;
1537 }
1538 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1539 if (!new_record) {
1540 return -ENOMEM;
1541 }
1542
1543 new_record->data = malloc(record->size + sizeof(pldm_entity));
1544 if (!new_record->data) {
1545 rc = -ENOMEM;
1546 goto cleanup_new_record;
1547 }
1548
1549 new_record->record_handle = record->record_handle;
1550 new_record->size = record->size + sizeof(struct pldm_entity);
1551 new_record->is_remote = record->is_remote;
1552
1553 // Initialize new PDR record with data from original PDR record.
1554 // Start with adding the header of original PDR
1555 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1556 new_record->data, new_record->size);
1557 if (rc) {
1558 goto cleanup_new_record_data;
1559 }
1560
1561 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1562 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1563 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1564 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1565 // extract the header length from record and increment size with
1566 // size of pldm_entity before inserting the value into new_record.
1567 rc = pldm_msgbuf_extract(src, header_length);
1568 if (rc) {
1569 goto cleanup_new_record_data;
1570 }
1571 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1572 "Fix the following bounds check.");
1573 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1574 rc = -EOVERFLOW;
1575 goto cleanup_new_record_data;
1576 }
1577 header_length += sizeof(pldm_entity);
1578 pldm_msgbuf_insert(dst, header_length);
1579 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1580 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1581 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1582 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1583 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1584 // extract value of number of children from record and increment it
1585 // by 1 before insert the value to new record.
1586 rc = pldm_msgbuf_extract(src, num_children);
1587 if (rc) {
1588 goto cleanup_new_record_data;
1589 }
1590 if (num_children == UINT8_MAX) {
1591 rc = -EOVERFLOW;
1592 goto cleanup_new_record_data;
1593 }
1594 num_children += 1;
1595 pldm_msgbuf_insert(dst, num_children);
1596 //Add all children of original PDR to new PDR
1597 for (int i = 0; i < num_children - 1; i++) {
1598 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1599 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1600 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1601 }
1602
1603 // Add new contained entity as a child of new PDR
1604 rc = pldm_msgbuf_destroy(src);
1605 if (rc) {
1606 goto cleanup_new_record_data;
1607 }
1608 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1609 sizeof(struct pldm_entity));
1610 if (rc) {
1611 goto cleanup_new_record_data;
1612 }
1613 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1614 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1615 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1616
1617 rc = pldm_msgbuf_destroy(src);
1618 if (rc) {
1619 goto cleanup_new_record_data;
1620 }
1621 rc = pldm_msgbuf_destroy(dst);
1622 if (rc) {
1623 goto cleanup_new_record_data;
1624 }
1625
1626 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1627 if (rc) {
1628 goto cleanup_new_record_data;
1629 }
1630
1631 free(record->data);
1632 free(record);
1633 return rc;
1634cleanup_new_record_data:
1635 free(new_record->data);
1636cleanup_new_record:
1637 free(new_record);
1638 return rc;
1639}
1640
1641LIBPLDM_ABI_TESTING
1642int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1643 uint32_t pdr_record_handle,
1644 pldm_entity *parent,
1645 pldm_entity *entity,
1646 uint32_t *entity_record_handle)
1647{
1648 if (!repo || !parent || !entity || !entity_record_handle) {
1649 return -EINVAL;
1650 }
1651
1652 if (pdr_record_handle == UINT32_MAX) {
1653 return -EOVERFLOW;
1654 }
1655
1656 bool pdr_added = false;
1657 uint16_t new_pdr_size;
1658 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001659 void *container_id_addr;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001660 struct pldm_msgbuf _dst;
1661 struct pldm_msgbuf *dst = &_dst;
1662 struct pldm_msgbuf _src_p;
1663 struct pldm_msgbuf *src_p = &_src_p;
1664 struct pldm_msgbuf _src_c;
1665 struct pldm_msgbuf *src_c = &_src_c;
1666 int rc = 0;
1667
1668 pldm_pdr_record *prev = repo->first;
1669 pldm_pdr_record *record = repo->first;
1670 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1671 pdr_record_handle);
1672 if (!pdr_added) {
1673 return -ENOENT;
1674 }
1675
1676 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1677 "Truncation ahead");
1678 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1679 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1680 if (!new_record) {
1681 return -ENOMEM;
1682 }
1683
1684 new_record->data = malloc(new_pdr_size);
1685 if (!new_record->data) {
1686 rc = -ENOMEM;
1687 goto cleanup_new_record;
1688 }
1689
1690 // Initialise new PDR to be added with the header, size and handle.
1691 // Set the position of new PDR
1692 *entity_record_handle = pdr_record_handle + 1;
1693 new_record->record_handle = *entity_record_handle;
1694 new_record->size = new_pdr_size;
1695 new_record->is_remote = false;
1696
1697 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1698 new_record->data, new_record->size);
1699 if (rc) {
1700 goto cleanup_new_record_data;
1701 }
1702
1703 // header record handle
1704 pldm_msgbuf_insert(dst, *entity_record_handle);
1705 // header version
1706 pldm_msgbuf_insert_uint8(dst, 1);
1707 // header type
1708 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1709 // header change number
1710 pldm_msgbuf_insert_uint16(dst, 0);
1711 // header length
1712 pldm_msgbuf_insert_uint16(dst,
1713 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1714
1715 // Data for new PDR is obtained from parent PDR and new contained entity
1716 // is added as the child
1717 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1718 sizeof(*parent));
1719 if (rc) {
1720 goto cleanup_new_record_data;
1721 }
1722
1723 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1724 sizeof(*entity));
1725 if (rc) {
1726 goto cleanup_new_record_data;
1727 }
1728
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001729 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001730 // extract pointer for container ID and save the address
1731 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1732 (void **)&container_id_addr);
1733 if (rc) {
1734 goto cleanup_new_record_data;
1735 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001736 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001737 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1738 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1739 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1740 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1741 // number of children
1742 pldm_msgbuf_insert_uint8(dst, 1);
1743
1744 // Add new entity as child
1745 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1746 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1747 // Extract and insert child entity container ID and add same value to
1748 // container ID of entity
1749 pldm_msgbuf_extract(src_c, container_id);
1750 pldm_msgbuf_insert(dst, container_id);
1751 container_id = htole16(container_id);
1752 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1753
1754 rc = pldm_msgbuf_destroy(dst);
1755 if (rc) {
1756 goto cleanup_new_record_data;
1757 }
1758 rc = pldm_msgbuf_destroy(src_p);
1759 if (rc) {
1760 goto cleanup_new_record_data;
1761 }
1762 rc = pldm_msgbuf_destroy(src_c);
1763 if (rc) {
1764 goto cleanup_new_record_data;
1765 }
1766
1767 rc = pldm_pdr_insert_record(repo, record, new_record);
1768 if (rc) {
1769 goto cleanup_new_record_data;
1770 }
1771
1772 return rc;
1773cleanup_new_record_data:
1774 free(new_record->data);
1775cleanup_new_record:
1776 free(new_record);
1777 return rc;
1778}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001779
1780LIBPLDM_CC_NONNULL
1781static bool pldm_entity_cmp(const struct pldm_entity *l,
1782 const struct pldm_entity *r)
1783{
1784 return l->entity_type == r->entity_type &&
1785 l->entity_instance_num == r->entity_instance_num &&
1786 l->entity_container_id == r->entity_container_id;
1787}
1788
1789/* Find record handle of a PDR record from PDR repo and
1790 * entity
1791 */
1792LIBPLDM_CC_NONNULL
1793static int pldm_entity_association_find_record_handle_by_entity(
1794 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1795 uint32_t *record_handle)
1796{
1797 uint8_t num_children = 0;
1798 uint8_t hdr_type = 0;
1799 int rc = 0;
1800 size_t skip_data_size = 0;
1801 pldm_pdr_record *record = repo->first;
1802 struct pldm_msgbuf _dst;
1803 struct pldm_msgbuf *dst = &_dst;
1804
1805 while (record != NULL) {
1806 rc = pldm_msgbuf_init_errno(dst,
1807 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1808 record->data, record->size);
1809 if (rc) {
1810 return rc;
1811 }
1812 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
1813 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1814 pldm_msgbuf_extract(dst, hdr_type);
1815 if (record->is_remote != is_remote ||
1816 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
1817 goto cleanup;
1818 }
1819 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
1820 sizeof(uint16_t) + sizeof(uint8_t) +
1821 sizeof(struct pldm_entity);
1822 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
1823 pldm_msgbuf_extract(dst, num_children);
1824 for (int i = 0; i < num_children; ++i) {
1825 struct pldm_entity e;
1826
1827 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
1828 (rc = pldm_msgbuf_extract(dst,
1829 e.entity_instance_num)) ||
1830 (rc = pldm_msgbuf_extract(dst,
1831 e.entity_container_id))) {
1832 return rc;
1833 }
1834
1835 if (pldm_entity_cmp(entity, &e)) {
1836 *record_handle = record->record_handle;
1837 return 0;
1838 }
1839 }
1840 cleanup:
1841 rc = pldm_msgbuf_destroy(dst);
1842 if (rc) {
1843 return rc;
1844 }
1845 record = record->next;
1846 }
1847 return 0;
1848}
1849
1850LIBPLDM_ABI_TESTING
1851int pldm_entity_association_pdr_remove_contained_entity(
1852 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1853 uint32_t *pdr_record_handle)
1854{
1855 uint16_t header_length = 0;
1856 uint8_t num_children = 0;
1857 struct pldm_msgbuf _src;
1858 struct pldm_msgbuf *src = &_src;
1859 struct pldm_msgbuf _dst;
1860 struct pldm_msgbuf *dst = &_dst;
1861 int rc;
1862 pldm_pdr_record *record;
1863 pldm_pdr_record *prev;
1864
1865 if (!repo || !entity || !pdr_record_handle) {
1866 return -EINVAL;
1867 }
1868 record = repo->first;
1869 prev = repo->first;
1870
1871 rc = pldm_entity_association_find_record_handle_by_entity(
1872 repo, entity, is_remote, pdr_record_handle);
1873 if (rc) {
1874 return rc;
1875 }
1876 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
1877 if (!record) {
1878 return -EINVAL;
1879 }
1880 // Initialize msg buffer for record and record->data
1881 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1882 record->data, record->size);
1883 if (rc) {
1884 return rc;
1885 }
1886 // check if removing an entity from record causes overflow before
1887 // allocating memory for new_record.
1888 if (record->size < sizeof(pldm_entity)) {
1889 return -EOVERFLOW;
1890 }
1891 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1892 if (!new_record) {
1893 return -ENOMEM;
1894 }
1895 new_record->data = malloc(record->size - sizeof(pldm_entity));
1896 if (!new_record->data) {
1897 rc = -ENOMEM;
1898 goto cleanup_new_record;
1899 }
1900 new_record->record_handle = record->record_handle;
1901 new_record->size = record->size - sizeof(struct pldm_entity);
1902 new_record->is_remote = record->is_remote;
1903
1904 // Initialize new PDR record with data from original PDR record.
1905 // Start with adding the header of original PDR
Archana Kakani94e2d752024-12-12 08:22:55 -06001906 rc = pldm_msgbuf_init_errno(
1907 dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
1908 new_record->data, new_record->size);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001909 if (rc) {
1910 goto cleanup_new_record_data;
1911 }
1912 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1913 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1914 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1915 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1916 // extract the header length from record and decrement size with
1917 // size of pldm_entity before inserting the value into new_record.
1918 rc = pldm_msgbuf_extract(src, header_length);
1919 if (rc) {
1920 goto cleanup_new_record_data;
1921 }
1922 if (header_length < sizeof(pldm_entity)) {
1923 rc = -EOVERFLOW;
1924 goto cleanup_new_record_data;
1925 }
1926 header_length -= sizeof(pldm_entity);
1927 pldm_msgbuf_insert(dst, header_length);
1928 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1929 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1930 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1931 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1932 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1933 // extract value of number of children from record and decrement it
1934 // by 1 before insert the value to new record.
1935 rc = pldm_msgbuf_extract(src, num_children);
1936 if (rc) {
1937 goto cleanup_new_record_data;
1938 }
1939 if (num_children == 1) {
Archana Kakani94e2d752024-12-12 08:22:55 -06001940 // This is the last child which is getting removed so we need to delete the Entity Association PDR.
1941 pldm_pdr_remove_record(repo, record,
1942 pldm_pdr_get_prev_record(repo, record));
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001943 goto cleanup_new_record_data;
1944 } else if (num_children < 1) {
1945 rc = -EOVERFLOW;
1946 goto cleanup_new_record_data;
1947 }
1948 num_children -= 1;
1949 pldm_msgbuf_insert(dst, num_children);
1950 //Add all children of original PDR to new PDR
1951 for (int i = 0; i < num_children + 1; ++i) {
1952 struct pldm_entity e;
1953
1954 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
1955 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
1956 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
1957 goto cleanup_new_record_data;
1958 }
1959
1960 if (pldm_entity_cmp(entity, &e)) {
1961 continue;
1962 }
1963
1964 pldm_msgbuf_insert(dst, e.entity_type);
1965 pldm_msgbuf_insert(dst, e.entity_instance_num);
1966 pldm_msgbuf_insert(dst, e.entity_container_id);
1967 }
1968
1969 if ((rc = pldm_msgbuf_destroy(src)) ||
1970 (rc = pldm_msgbuf_destroy(dst)) ||
1971 (rc = pldm_pdr_replace_record(repo, record, prev, new_record))) {
1972 goto cleanup_new_record_data;
1973 }
1974
1975 free(record->data);
1976 free(record);
1977 return rc;
1978
1979cleanup_new_record_data:
1980 free(new_record->data);
1981cleanup_new_record:
1982 free(new_record);
1983 return rc;
1984}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05001985
1986/* API to find the PDR record that is previous to a given PLDM PDR
1987 * record in a given PLDM PDR repository
1988 */
1989LIBPLDM_CC_NONNULL
1990static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
1991 pldm_pdr_record *record)
1992{
1993 pldm_pdr_record *prev = NULL;
1994 pldm_pdr_record *curr = repo->first;
1995
1996 while (curr != NULL) {
1997 if (curr->record_handle == record->record_handle) {
1998 break;
1999 }
2000 prev = curr;
2001 curr = curr->next;
2002 }
2003 return prev;
2004}
2005
2006/* API to check if a PLDM PDR record is present in a PLDM PDR repository
2007 */
2008LIBPLDM_CC_NONNULL
2009static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
2010{
2011 if (repo->first == record) {
2012 return true;
2013 }
2014
2015 return pldm_pdr_get_prev_record(repo, record) != NULL;
2016}
2017
2018/* API to check if FRU RSI of record matches the given record set identifier.
2019 * Returns 1 if the provided FRU record matches the provided record set identifier,
2020 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
2021 */
2022LIBPLDM_CC_NONNULL
2023static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
2024 uint16_t rsi)
2025{
2026 uint16_t record_fru_rsi = 0;
2027 uint8_t *skip_data = NULL;
2028 uint8_t skip_data_size = 0;
2029 struct pldm_msgbuf _dst;
2030 struct pldm_msgbuf *dst = &_dst;
2031 int rc = 0;
2032
2033 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
2034 record->data, record->size);
2035 if (rc) {
2036 return rc;
2037 }
2038 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
2039 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
2040 pldm_msgbuf_extract(dst, record_fru_rsi);
2041
2042 rc = pldm_msgbuf_destroy(dst);
2043 if (rc) {
2044 return rc;
2045 }
2046 return record_fru_rsi == rsi;
2047}
2048
2049/* API to remove PLDM PDR record from a PLDM PDR repository
2050 */
2051LIBPLDM_CC_NONNULL_ARGS(1, 2)
2052static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2053 pldm_pdr_record *prev)
2054{
2055 if (!is_prev_record_present(repo, record)) {
2056 return -EINVAL;
2057 }
2058
2059 assert(repo->size >= record->size);
2060 if (repo->size < record->size) {
2061 return -EOVERFLOW;
2062 }
2063
2064 if (repo->first == record) {
2065 repo->first = record->next;
2066 } else {
2067 if (prev != NULL) {
2068 prev->next = record->next;
2069 }
2070 }
2071
2072 if (repo->last == record) {
2073 repo->last = prev;
2074 if (prev != NULL) {
2075 prev->next = NULL;
2076 }
2077 }
2078 repo->record_count -= 1;
2079 repo->size -= record->size;
2080 free(record->data);
2081 free(record);
2082
2083 return 0;
2084}
2085
2086LIBPLDM_ABI_TESTING
2087int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2088 bool is_remote,
2089 uint32_t *record_handle)
2090{
2091 pldm_pdr_record *record;
2092 pldm_pdr_record *prev = NULL;
2093 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2094 uint8_t hdr_type = 0;
2095 int rc = 0;
2096 int match;
2097
2098 if (!repo || !record_handle) {
2099 return -EINVAL;
2100 }
2101 record = repo->first;
2102
2103 while (record != NULL) {
2104 struct pldm_msgbuf _buf;
2105 struct pldm_msgbuf *buf = &_buf;
2106 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2107 record->data, record->size);
2108 if (rc) {
2109 return rc;
2110 }
2111 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
2112 if ((rc = pldm_msgbuf_extract(buf, hdr_type))) {
2113 return rc;
2114 }
2115 if (record->is_remote != is_remote ||
2116 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
2117 goto cleanup;
2118 }
2119 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2120 if (match < 0) {
2121 return match;
2122 }
2123 if (match) {
2124 *record_handle = record->record_handle;
2125 prev = pldm_pdr_get_prev_record(repo, record);
2126 return pldm_pdr_remove_record(repo, record, prev);
2127 }
2128 cleanup:
2129 rc = pldm_msgbuf_destroy(buf);
2130 if (rc) {
2131 return rc;
2132 }
2133 record = record->next;
2134 }
2135 return rc;
2136}