blob: fd36b560761dc3c8623967342affe19e5cd09ef7 [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>
John Chung7a8d9322025-08-27 20:56:19 -05009#include <errno.h>
10#include <limits.h>
Andrew Jeffery9e566592024-10-02 16:38:51 +093011#include <stdint.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093012#include <stdlib.h>
13#include <string.h>
14
Varsha Kaverappa37552b92024-02-12 05:06:06 -060015#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
16 (sizeof(struct pldm_pdr_hdr) + \
17 sizeof(struct pldm_pdr_entity_association))
18
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050019#define PDR_FRU_RECORD_SET_MIN_SIZE \
20 (sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
21
Andrew Jeffery9c766792022-08-10 23:12:49 +093022typedef struct pldm_pdr_record {
23 uint32_t record_handle;
24 uint32_t size;
25 uint8_t *data;
26 struct pldm_pdr_record *next;
27 bool is_remote;
28 uint16_t terminus_handle;
29} pldm_pdr_record;
30
31typedef struct pldm_pdr {
32 uint32_t record_count;
33 uint32_t size;
34 pldm_pdr_record *first;
35 pldm_pdr_record *last;
36} pldm_pdr;
37
Andrew Jeffery890d37a2024-09-22 20:50:53 +093038LIBPLDM_CC_NONNULL
Archana Kakani94e2d752024-12-12 08:22:55 -060039static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
40 pldm_pdr_record *record);
41
42LIBPLDM_CC_NONNULL_ARGS(1, 2)
43static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
44 pldm_pdr_record *prev);
45
46LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +093047static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
48 const pldm_pdr_record *record)
49{
Andrew Jeffery9c766792022-08-10 23:12:49 +093050 if (record == repo->last) {
51 return 0;
52 }
53 return record->next->record_handle;
54}
55
Andrew Jefferyca248ce2023-07-07 10:38:30 +093056LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000057int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
58 bool is_remote, uint16_t terminus_handle,
59 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093060{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050061 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093062
Andrew Jeffery3b93d092023-07-17 13:01:50 +093063 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093064 return -EINVAL;
65 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093066
Andrew Jeffery3b93d092023-07-17 13:01:50 +093067 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093068 curr = *record_handle;
69 } else if (repo->last) {
70 curr = repo->last->record_handle;
71 if (curr == UINT32_MAX) {
72 return -EOVERFLOW;
73 }
74 curr += 1;
75 } else {
76 curr = 1;
77 }
78
Andrew Jeffery9c766792022-08-10 23:12:49 +093079 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093080 if (!record) {
81 return -ENOMEM;
82 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093083
Andrew Jeffery572a3952023-07-03 13:19:28 +093084 if (data) {
85 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093086 if (!record->data) {
87 free(record);
88 return -ENOMEM;
89 }
90 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093091 }
92
Andrew Jeffery9c766792022-08-10 23:12:49 +093093 record->size = size;
94 record->is_remote = is_remote;
95 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093096 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093097
Andrew Jeffery3b93d092023-07-17 13:01:50 +093098 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093099 /* If record handle is 0, that is an indication for this API to
100 * compute a new handle. For that reason, the computed handle
101 * needs to be populated in the PDR header. For a case where the
102 * caller supplied the record handle, it would exist in the
103 * header already.
104 */
105 struct pldm_pdr_hdr *hdr = (void *)record->data;
106 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930107 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930108
Andrew Jeffery9c766792022-08-10 23:12:49 +0930109 record->next = NULL;
110
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930111 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930112 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930113 repo->first = record;
114 repo->last = record;
115 } else {
116 repo->last->next = record;
117 repo->last = record;
118 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930119
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930120 repo->size += record->size;
121 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930122
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930123 if (record_handle) {
124 *record_handle = record->record_handle;
125 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930126
127 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930128}
129
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930130LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930131pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930132{
133 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930134 if (!repo) {
135 return NULL;
136 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930137 repo->record_count = 0;
138 repo->size = 0;
139 repo->first = NULL;
140 repo->last = NULL;
141
142 return repo;
143}
144
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930145LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930146void pldm_pdr_destroy(pldm_pdr *repo)
147{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930148 if (!repo) {
149 return;
150 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930151
152 pldm_pdr_record *record = repo->first;
153 while (record != NULL) {
154 pldm_pdr_record *next = record->next;
155 if (record->data) {
156 free(record->data);
157 record->data = NULL;
158 }
159 free(record);
160 record = next;
161 }
162 free(repo);
163}
164
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930165LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930166const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
167 uint32_t record_handle,
168 uint8_t **data, uint32_t *size,
169 uint32_t *next_record_handle)
170{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930171 if (!repo || !data || !size || !next_record_handle) {
172 return NULL;
173 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930174
175 if (!record_handle && (repo->first != NULL)) {
176 record_handle = repo->first->record_handle;
177 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930178
Andrew Jeffery9c766792022-08-10 23:12:49 +0930179 pldm_pdr_record *record = repo->first;
180 while (record != NULL) {
181 if (record->record_handle == record_handle) {
182 *size = record->size;
183 *data = record->data;
184 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930185 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930186 return record;
187 }
188 record = record->next;
189 }
190
191 *size = 0;
192 *next_record_handle = 0;
193 return NULL;
194}
195
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930196LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930197const pldm_pdr_record *
198pldm_pdr_get_next_record(const pldm_pdr *repo,
199 const pldm_pdr_record *curr_record, uint8_t **data,
200 uint32_t *size, uint32_t *next_record_handle)
201{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930202 if (!repo || !curr_record || !data || !size || !next_record_handle) {
203 return NULL;
204 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930205
206 if (curr_record == repo->last) {
207 *data = NULL;
208 *size = 0;
209 *next_record_handle = get_next_record_handle(repo, curr_record);
210 return NULL;
211 }
212
213 *next_record_handle = get_next_record_handle(repo, curr_record->next);
214 *data = curr_record->next->data;
215 *size = curr_record->next->size;
216 return curr_record->next;
217}
218
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930219LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930220const pldm_pdr_record *
221pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
222 const pldm_pdr_record *curr_record, uint8_t **data,
223 uint32_t *size)
224{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930225 if (!repo) {
226 return NULL;
227 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930228
229 pldm_pdr_record *record = repo->first;
230 if (curr_record != NULL) {
231 record = curr_record->next;
232 }
233 while (record != NULL) {
234 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
235 if (hdr->type == pdr_type) {
236 if (data && size) {
237 *size = record->size;
238 *data = record->data;
239 }
240 return record;
241 }
242 record = record->next;
243 }
244
245 if (size) {
246 *size = 0;
247 }
248 return NULL;
249}
250
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930251LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930252uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
253{
254 assert(repo != NULL);
255
256 return repo->record_count;
257}
258
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930259LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930260uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
261{
262 assert(repo != NULL);
263
264 return repo->size;
265}
266
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930267LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000268uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930269 const pldm_pdr_record *record)
270{
271 assert(repo != NULL);
272 assert(record != NULL);
273
274 return record->record_handle;
275}
276
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530277LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000278uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530279 const pldm_pdr_record *record)
280{
281 assert(repo != NULL);
282 assert(record != NULL);
283
284 return record->terminus_handle;
285}
286
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930287LIBPLDM_ABI_STABLE
288bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930289{
290 assert(record != NULL);
291
292 return record->is_remote;
293}
294
Andrew Jefferya2c69112023-07-07 10:41:38 +0930295LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930296int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
297 uint16_t fru_rsi, uint16_t entity_type,
298 uint16_t entity_instance_num,
299 uint16_t container_id,
300 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930301{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930302 if (!repo || !bmc_record_handle) {
303 return -EINVAL;
304 }
305
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930306 uint8_t data[sizeof(struct pldm_pdr_hdr) +
307 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930308
309 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
310 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930311 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930312 hdr->type = PLDM_PDR_FRU_RECORD_SET;
313 hdr->record_change_num = 0;
314 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
315 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930316 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
317 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930318 fru->terminus_handle = htole16(terminus_handle);
319 fru->fru_rsi = htole16(fru_rsi);
320 fru->entity_type = htole16(entity_type);
321 fru->entity_instance_num = htole16(entity_instance_num);
322 fru->container_id = htole16(container_id);
323
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930324 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000325 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930326}
327
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930328LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930329const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930330 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
331 uint16_t *entity_type, uint16_t *entity_instance_num,
332 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930333{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930334 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
335 !container_id) {
336 return NULL;
337 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930338
339 uint8_t *data = NULL;
340 uint32_t size = 0;
341 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930342 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930343 while (curr_record != NULL) {
344 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930345 (struct pldm_pdr_fru_record_set
346 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930347 if (fru->fru_rsi == htole16(fru_rsi)) {
348 *terminus_handle = le16toh(fru->terminus_handle);
349 *entity_type = le16toh(fru->entity_type);
350 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930351 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930352 *container_id = le16toh(fru->container_id);
353 return curr_record;
354 }
355 data = NULL;
356 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930357 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
358 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930359 }
360
361 *terminus_handle = 0;
362 *entity_type = 0;
363 *entity_instance_num = 0;
364 *container_id = 0;
365
366 return NULL;
367}
368
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930369LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930370/* NOLINTNEXTLINE(readability-identifier-naming) */
371void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
372 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930373{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930374 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930375 uint32_t size = 0;
376 const pldm_pdr_record *record;
377 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930378 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930379
380 do {
381 if (record != NULL) {
382 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930383 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930384 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930385 (struct pldm_terminus_locator_type_mctp_eid *)
386 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930387 if (pdr->terminus_handle == terminus_handle &&
388 pdr->tid == tid && value->eid == tl_eid) {
389 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930390 break;
391 }
392 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930393 record = pldm_pdr_find_record_by_type(repo,
394 PLDM_TERMINUS_LOCATOR_PDR,
395 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930396 } while (record);
397}
398
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500399static bool pldm_record_handle_in_range(uint32_t record_handle,
400 uint32_t first_record_handle,
401 uint32_t last_record_handle)
402{
403 return record_handle >= first_record_handle &&
404 record_handle <= last_record_handle;
405}
406
Pavithra Barithayaf0eee362025-02-25 11:52:48 +0530407LIBPLDM_CC_NONNULL
408static int decode_pldm_state_sensor_pdr(uint8_t *data, uint32_t size,
409 struct pldm_state_sensor_pdr *pdr)
410{
John Chung7a8d9322025-08-27 20:56:19 -0500411 PLDM_MSGBUF_RO_DEFINE_P(buf);
Pavithra Barithayaf0eee362025-02-25 11:52:48 +0530412 int rc = 0;
413 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_sensor_pdr),
414 (uint8_t *)data, size);
415 if (rc) {
416 return rc;
417 }
418
419 pldm_msgbuf_extract(buf, pdr->hdr.record_handle);
420 pldm_msgbuf_extract(buf, pdr->hdr.version);
421 pldm_msgbuf_extract(buf, pdr->hdr.type);
422 pldm_msgbuf_extract(buf, pdr->hdr.record_change_num);
423 pldm_msgbuf_extract(buf, pdr->hdr.length);
424 pldm_msgbuf_extract(buf, pdr->terminus_handle);
425 pldm_msgbuf_extract(buf, pdr->sensor_id);
426 pldm_msgbuf_extract(buf, pdr->entity_type);
427 pldm_msgbuf_extract(buf, pdr->entity_instance);
428 pldm_msgbuf_extract(buf, pdr->container_id);
429 pldm_msgbuf_extract(buf, pdr->sensor_init);
430 pldm_msgbuf_extract(buf, pdr->sensor_auxiliary_names_pdr);
431 pldm_msgbuf_extract(buf, pdr->composite_sensor_count);
432
433 return pldm_msgbuf_complete(buf);
434}
435
436LIBPLDM_ABI_TESTING
437int pldm_pdr_delete_by_sensor_id(pldm_pdr *repo, uint16_t sensor_id,
438 bool is_remote, uint32_t *record_handle)
439{
440 pldm_pdr_record *record;
441 pldm_pdr_record *prev = NULL;
442 int rc = 0;
443 int found;
444 struct pldm_state_sensor_pdr pdr;
445
446 if (!repo) {
447 return -EINVAL;
448 }
449
450 record = repo->first;
451
452 while (record != NULL) {
453 if (!record->data) {
454 continue;
455 }
456
457 rc = decode_pldm_state_sensor_pdr(record->data, record->size,
458 &pdr);
459 if (rc) {
460 return rc;
461 }
462
463 if (record->is_remote != is_remote ||
464 pdr.hdr.type != PLDM_STATE_SENSOR_PDR) {
465 record = record->next;
466 continue;
467 }
468 found = pdr.sensor_id == sensor_id;
469 if (found) {
470 if (record_handle) {
471 *record_handle = record->record_handle;
472 }
473 prev = pldm_pdr_get_prev_record(repo, record);
474 return pldm_pdr_remove_record(repo, record, prev);
475 }
476 record = record->next;
477 }
478 return -ENOENT;
479}
480
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500481LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500482int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500483 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500484 uint8_t child_index, uint32_t range_exclude_start_handle,
485 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500486{
487 pldm_pdr_record *record;
488 if (!repo) {
489 return -EINVAL;
490 }
491
492 for (record = repo->first; record; record = record->next) {
493 bool is_container_entity_instance_number;
494 struct pldm_pdr_entity_association *pdr;
495 bool is_container_entity_type;
496 struct pldm_entity *child;
497 struct pldm_pdr_hdr *hdr;
498 bool in_range;
499
500 // pldm_pdr_add() takes only uint8_t* data as an argument.
501 // The expectation here is the pldm_pdr_hdr is the first field of the record data
502 hdr = (struct pldm_pdr_hdr *)record->data;
503 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
504 continue;
505 }
506 in_range = pldm_record_handle_in_range(
507 record->record_handle, range_exclude_start_handle,
508 range_exclude_end_handle);
509 if (in_range) {
510 continue;
511 }
512
513 // this cast is valid with respect to alignment because
514 // struct pldm_pdr_hdr is declared with __attribute__((packed))
515 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500516 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500517 continue;
518 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500519
520 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500521 is_container_entity_type = pdr->container.entity_type ==
522 entity_type;
523 is_container_entity_instance_number =
524 pdr->container.entity_instance_num == entity_instance;
525 if (is_container_entity_type &&
526 is_container_entity_instance_number) {
527 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500528 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500529 }
530 }
Matt Johnstonae05d5e2024-10-11 14:51:12 +0800531 return -ENOENT;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500532}
533
Pavithra Barithaya8cfeb472025-02-25 10:43:34 +0530534LIBPLDM_CC_NONNULL
535static int decode_pldm_state_effecter_pdr(uint8_t *data, uint32_t size,
536 struct pldm_state_effecter_pdr *pdr)
537{
John Chung7a8d9322025-08-27 20:56:19 -0500538 PLDM_MSGBUF_RO_DEFINE_P(buf);
Pavithra Barithaya8cfeb472025-02-25 10:43:34 +0530539 int rc = 0;
540 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_effecter_pdr),
541 (uint8_t *)data, size);
542 if (rc) {
543 return rc;
544 }
545
546 pldm_msgbuf_extract(buf, pdr->hdr.record_handle);
547 pldm_msgbuf_extract(buf, pdr->hdr.version);
548 pldm_msgbuf_extract(buf, pdr->hdr.type);
549 pldm_msgbuf_extract(buf, pdr->hdr.record_change_num);
550 pldm_msgbuf_extract(buf, pdr->hdr.length);
551 pldm_msgbuf_extract(buf, pdr->terminus_handle);
552 pldm_msgbuf_extract(buf, pdr->effecter_id);
553 pldm_msgbuf_extract(buf, pdr->entity_type);
554 pldm_msgbuf_extract(buf, pdr->entity_instance);
555 pldm_msgbuf_extract(buf, pdr->container_id);
556 pldm_msgbuf_extract(buf, pdr->effecter_semantic_id);
557 pldm_msgbuf_extract(buf, pdr->effecter_init);
558 pldm_msgbuf_extract(buf, pdr->has_description_pdr);
559 pldm_msgbuf_extract(buf, pdr->composite_effecter_count);
560
561 return pldm_msgbuf_complete(buf);
562}
563
564LIBPLDM_ABI_TESTING
565int pldm_pdr_delete_by_effecter_id(pldm_pdr *repo, uint16_t effecter_id,
566 bool is_remote, uint32_t *record_handle)
567{
568 pldm_pdr_record *record;
569 pldm_pdr_record *prev = NULL;
570 int rc = 0;
571 int found;
572 struct pldm_state_effecter_pdr pdr;
573
574 if (!repo) {
575 return -EINVAL;
576 }
577 record = repo->first;
578
579 while (record != NULL) {
580 if (!record->data) {
581 continue;
582 }
583
584 rc = decode_pldm_state_effecter_pdr(record->data, record->size,
585 &pdr);
586 if (rc) {
587 return rc;
588 }
589
590 if (record->is_remote != is_remote ||
591 pdr.hdr.type != PLDM_STATE_EFFECTER_PDR) {
592 record = record->next;
593 continue;
594 }
595 found = pdr.effecter_id == effecter_id;
596 if (found) {
597 if (record_handle) {
598 *record_handle = record->record_handle;
599 }
600 prev = pldm_pdr_get_prev_record(repo, record);
601 return pldm_pdr_remove_record(repo, record, prev);
602 }
603 record = record->next;
604 }
605 return rc;
606}
607
Pavithra Barithaya869c2872025-04-30 14:32:18 +0530608LIBPLDM_ABI_STABLE
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530609int pldm_pdr_delete_by_record_handle(pldm_pdr *repo, uint32_t record_handle,
610 bool is_remote)
611{
612 pldm_pdr_record *record;
613 pldm_pdr_record *prev = NULL;
614 int rc = 0;
615 uint16_t rec_handle = 0;
616
617 if (!repo) {
618 return -EINVAL;
619 }
620 record = repo->first;
621
622 while (record != NULL) {
John Chung7a8d9322025-08-27 20:56:19 -0500623 struct pldm_msgbuf_ro _buf;
624 struct pldm_msgbuf_ro *buf = &_buf;
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530625 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
626 record->data, record->size);
627
628 if (rc) {
629 return rc;
630 }
631 if ((rc = pldm_msgbuf_extract(buf, rec_handle))) {
632 return rc;
633 }
634 if (record->is_remote == is_remote &&
635 rec_handle == record_handle) {
636 prev = pldm_pdr_get_prev_record(repo, record);
637 return pldm_pdr_remove_record(repo, record, prev);
638 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030639 rc = pldm_msgbuf_complete(buf);
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530640 if (rc) {
641 return rc;
642 }
643 record = record->next;
644 }
645 return -ENOENT;
646}
647
Andrew Jeffery9c766792022-08-10 23:12:49 +0930648typedef struct pldm_entity_association_tree {
649 pldm_entity_node *root;
650 uint16_t last_used_container_id;
651} pldm_entity_association_tree;
652
653typedef struct pldm_entity_node {
654 pldm_entity entity;
655 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600656 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930657 pldm_entity_node *first_child;
658 pldm_entity_node *next_sibling;
659 uint8_t association_type;
660} pldm_entity_node;
661
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930662LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930663pldm_entity pldm_entity_extract(pldm_entity_node *node)
664{
665 assert(node != NULL);
666
667 return node->entity;
668}
669
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500670LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930671uint16_t
672pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600673{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930674 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600675
Andrew Jeffery15b88182023-06-30 13:29:17 +0930676 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600677}
678
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930679LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930680pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930681{
682 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930683 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930684 if (!tree) {
685 return NULL;
686 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930687 tree->root = NULL;
688 tree->last_used_container_id = 0;
689
690 return tree;
691}
692
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930693LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930694static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
695 uint16_t entity_type)
696{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930697 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530698 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930699 */
700 while (start->next_sibling != NULL) {
701 uint16_t this_type = start->entity.entity_type;
702 pldm_entity_node *next = start->next_sibling;
703 if (this_type == entity_type &&
704 (this_type != next->entity.entity_type)) {
705 break;
706 }
707 start = start->next_sibling;
708 }
709
710 return start;
711}
712
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930713LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930714pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930715 pldm_entity_association_tree *tree, pldm_entity *entity,
716 uint16_t entity_instance_number, pldm_entity_node *parent,
717 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930718{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500719 return pldm_entity_association_tree_add_entity(tree, entity,
720 entity_instance_number,
721 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600722 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500723}
724
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500725LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500726pldm_entity_node *pldm_entity_association_tree_add_entity(
727 pldm_entity_association_tree *tree, pldm_entity *entity,
728 uint16_t entity_instance_number, pldm_entity_node *parent,
729 uint8_t association_type, bool is_remote, bool is_update_container_id,
730 uint16_t container_id)
731{
732 if ((!tree) || (!entity)) {
733 return NULL;
734 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930735
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600736 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930737 pldm_entity node;
738 node.entity_type = entity->entity_type;
739 node.entity_instance_num = entity_instance_number;
740 if (pldm_is_current_parent_child(parent, &node)) {
741 return NULL;
742 }
743 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500744 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
745 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
746 return NULL;
747 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930748 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500749 if (!node) {
750 return NULL;
751 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930752 node->first_child = NULL;
753 node->next_sibling = NULL;
754 node->parent.entity_type = 0;
755 node->parent.entity_instance_num = 0;
756 node->parent.entity_container_id = 0;
757 node->entity.entity_type = entity->entity_type;
758 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600759 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930760 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600761 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930762 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500763 if (parent != NULL) {
764 free(node);
765 return NULL;
766 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930767 tree->root = node;
768 /* container_id 0 here indicates this is the top-most entry */
769 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600770 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930771 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930772 /* Ensure next_container_id() will yield a valid ID */
773 if (tree->last_used_container_id == UINT16_MAX) {
774 free(node);
775 return NULL;
776 }
777
Andrew Jeffery9c766792022-08-10 23:12:49 +0930778 parent->first_child = node;
779 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500780
781 if (is_remote) {
782 node->remote_container_id = entity->entity_container_id;
783 }
784 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600785 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500786 node->entity.entity_container_id = container_id;
787 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930788 /* We will have returned above */
789 assert(tree->last_used_container_id !=
790 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500791 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930792 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500793 }
794 } else {
795 node->entity.entity_container_id =
796 entity->entity_container_id;
797 }
798
799 if (!is_remote) {
800 node->remote_container_id =
801 node->entity.entity_container_id;
802 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930803 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930804 pldm_entity_node *start = parent == NULL ? tree->root :
805 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930806 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930807 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500808 if (!prev) {
809 free(node);
810 return NULL;
811 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930812 pldm_entity_node *next = prev->next_sibling;
813 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500814 if (prev->entity.entity_instance_num == UINT16_MAX) {
815 free(node);
816 return NULL;
817 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930818 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600819 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930820 entity_instance_number :
821 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930822 }
823 prev->next_sibling = node;
824 node->parent = prev->parent;
825 node->next_sibling = next;
826 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930827 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600828 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930829 }
830 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500831 if (is_update_container_id) {
832 entity->entity_container_id = node->entity.entity_container_id;
833 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930834 return node;
835}
836
837static void get_num_nodes(pldm_entity_node *node, size_t *num)
838{
839 if (node == NULL) {
840 return;
841 }
842
843 ++(*num);
844 get_num_nodes(node->next_sibling, num);
845 get_num_nodes(node->first_child, num);
846}
847
848static void entity_association_tree_visit(pldm_entity_node *node,
849 pldm_entity *entities, size_t *index)
850{
851 if (node == NULL) {
852 return;
853 }
854
855 pldm_entity *entity = &entities[*index];
856 ++(*index);
857 entity->entity_type = node->entity.entity_type;
858 entity->entity_instance_num = node->entity.entity_instance_num;
859 entity->entity_container_id = node->entity.entity_container_id;
860
861 entity_association_tree_visit(node->next_sibling, entities, index);
862 entity_association_tree_visit(node->first_child, entities, index);
863}
864
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930865LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930866void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
867 pldm_entity **entities, size_t *size)
868{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930869 if (!tree || !entities || !size) {
870 return;
871 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930872
873 *size = 0;
874 if (tree->root == NULL) {
875 return;
876 }
877
878 get_num_nodes(tree->root, size);
879 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930880 if (!entities) {
881 return;
882 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930883 size_t index = 0;
884 entity_association_tree_visit(tree->root, *entities, &index);
885}
886
887static void entity_association_tree_destroy(pldm_entity_node *node)
888{
889 if (node == NULL) {
890 return;
891 }
892
893 entity_association_tree_destroy(node->next_sibling);
894 entity_association_tree_destroy(node->first_child);
895 free(node);
896}
897
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930898LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930899void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
900{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930901 if (!tree) {
902 return;
903 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930904
905 entity_association_tree_destroy(tree->root);
906 free(tree);
907}
908
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930909LIBPLDM_ABI_STABLE
910bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930911{
912 assert(node != NULL);
913
914 return node->first_child != NULL;
915}
916
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930917LIBPLDM_ABI_STABLE
918pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930919{
920 assert(node != NULL);
921
922 return node->parent;
923}
924
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930925LIBPLDM_ABI_STABLE
926bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930927{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930928 if (!node) {
929 return false;
930 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930931
932 if (node->parent.entity_type == 0 &&
933 node->parent.entity_instance_num == 0 &&
934 node->parent.entity_container_id == 0) {
935 return false;
936 }
937
938 return true;
939}
940
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930941LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930942uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
943 uint8_t association_type)
944{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930945 if (!node) {
946 return 0;
947 }
948
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930949 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
950 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
951 return 0;
952 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930953
954 size_t count = 0;
955 pldm_entity_node *curr = node->first_child;
956 while (curr != NULL) {
957 if (curr->association_type == association_type) {
958 ++count;
959 }
960 curr = curr->next_sibling;
961 }
962
963 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930964 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930965}
966
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930967LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930968bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
969{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930970 if (!parent || !node) {
971 return false;
972 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930973
974 pldm_entity_node *curr = parent->first_child;
975 while (curr != NULL) {
976 if (node->entity_type == curr->entity.entity_type &&
977 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930978 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930979 return true;
980 }
981 curr = curr->next_sibling;
982 }
983
984 return false;
985}
986
Archana Kakanibc40dd52024-08-02 00:10:44 -0500987static int64_t entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500988 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
989 uint8_t contained_count, uint8_t association_type, bool is_remote,
990 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930991{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930992 uint8_t *start;
993 uint8_t *pdr;
Archana Kakanibc40dd52024-08-02 00:10:44 -0500994 int64_t rc;
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930995
996 pdr = calloc(1, size);
997 if (!pdr) {
998 return -ENOMEM;
999 }
1000
1001 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301002
1003 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
1004 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -06001005 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301006 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
1007 hdr->record_change_num = 0;
1008 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
1009 start += sizeof(struct pldm_pdr_hdr);
1010
1011 uint16_t *container_id = (uint16_t *)start;
1012 *container_id = htole16(curr->first_child->entity.entity_container_id);
1013 start += sizeof(uint16_t);
1014 *start = association_type;
1015 start += sizeof(uint8_t);
1016
1017 pldm_entity *entity = (pldm_entity *)start;
1018 entity->entity_type = htole16(curr->entity.entity_type);
1019 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
1020 entity->entity_container_id = htole16(curr->entity.entity_container_id);
1021 start += sizeof(pldm_entity);
1022
1023 *start = contained_count;
1024 start += sizeof(uint8_t);
1025
1026 pldm_entity_node *node = curr->first_child;
1027 while (node != NULL) {
1028 if (node->association_type == association_type) {
1029 pldm_entity *entity = (pldm_entity *)start;
1030 entity->entity_type = htole16(node->entity.entity_type);
1031 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301032 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301033 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301034 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301035 start += sizeof(pldm_entity);
1036 }
1037 node = node->next_sibling;
1038 }
1039
Andrew Jeffery5c49f162024-09-22 15:45:35 +09301040 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
1041 &record_handle);
1042 free(pdr);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001043 return (rc < 0) ? rc : record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301044}
1045
Archana Kakanibc40dd52024-08-02 00:10:44 -05001046static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
1047 pldm_pdr *repo, bool is_remote,
1048 uint16_t terminus_handle,
1049 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301050{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301051 uint8_t num_logical_children = pldm_entity_get_num_children(
1052 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
1053 uint8_t num_physical_children = pldm_entity_get_num_children(
1054 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001055 int64_t rc;
1056
1057 if (!num_logical_children && !num_physical_children) {
1058 if (record_handle == 0) {
1059 return -EINVAL;
1060 }
1061 return record_handle - 1;
1062 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301063
1064 if (num_logical_children) {
1065 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301066 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
1067 sizeof(uint8_t) + sizeof(pldm_entity) +
1068 sizeof(uint8_t) +
1069 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +09301070 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301071 curr, repo, logical_pdr_size, num_logical_children,
1072 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001073 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +09301074 if (rc < 0) {
1075 return rc;
1076 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001077 if (num_physical_children) {
1078 if (rc >= UINT32_MAX) {
1079 return -EOVERFLOW;
1080 }
1081 record_handle = rc + 1;
1082 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301083 }
1084
1085 if (num_physical_children) {
1086 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301087 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
1088 sizeof(uint8_t) + sizeof(pldm_entity) +
1089 sizeof(uint8_t) +
1090 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +09301091 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301092 curr, repo, physical_pdr_size, num_physical_children,
1093 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001094 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +09301095 if (rc < 0) {
1096 return rc;
1097 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001098 record_handle = rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301099 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301100
Archana Kakanibc40dd52024-08-02 00:10:44 -05001101 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301102}
1103
Andrew Jefferyd09b1af2023-07-17 12:39:16 +09301104static bool is_present(pldm_entity entity, pldm_entity **entities,
1105 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301106{
1107 if (entities == NULL || num_entities == 0) {
1108 return true;
1109 }
1110 size_t i = 0;
1111 while (i < num_entities) {
1112 if ((*entities + i)->entity_type == entity.entity_type) {
1113 return true;
1114 }
1115 i++;
1116 }
1117 return false;
1118}
1119
Archana Kakanibc40dd52024-08-02 00:10:44 -05001120static int64_t entity_association_pdr_add(pldm_entity_node *curr,
1121 pldm_pdr *repo,
1122 pldm_entity **entities,
1123 size_t num_entities, bool is_remote,
1124 uint16_t terminus_handle,
1125 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301126{
Archana Kakanibc40dd52024-08-02 00:10:44 -05001127 int64_t rc;
Andrew Jeffery65945992023-07-17 15:04:21 +09301128
Andrew Jeffery9c766792022-08-10 23:12:49 +09301129 if (curr == NULL) {
Archana Kakanibc40dd52024-08-02 00:10:44 -05001130 // entity_association_pdr_add function gets called
1131 // recursively for the siblings and children of the
1132 // entity. This causes NULL current entity node, and the
1133 // record handle is returned
1134 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301135 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301136
1137 if (is_present(curr->entity, entities, num_entities)) {
1138 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001139 curr, repo, is_remote, terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001140 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301141 return rc;
1142 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001143 if (rc >= UINT32_MAX) {
1144 return -EOVERFLOW;
1145 }
1146 record_handle = rc + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301147 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301148
1149 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
1150 num_entities, is_remote,
1151 terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001152 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301153 return rc;
1154 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001155 // entity_association_pdr_add return record handle in success
1156 // case. If the pdr gets added to the repo, new record handle
1157 // will be returned. Below check confirms if the pdr is added
1158 // to the repo and increments the record handle
1159 if (record_handle != rc) {
1160 if (rc >= UINT32_MAX) {
1161 return -EOVERFLOW;
1162 }
1163 record_handle = rc + 1;
1164 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301165
Archana Kakanibc40dd52024-08-02 00:10:44 -05001166 rc = entity_association_pdr_add(curr->first_child, repo, entities,
1167 num_entities, is_remote,
1168 terminus_handle, record_handle);
1169 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301170}
1171
Andrew Jeffery096685b2023-07-17 17:36:14 +09301172LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +09301173int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
1174 pldm_pdr *repo, bool is_remote,
1175 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +09301176{
Andrew Jefferyc7883482023-06-30 15:52:04 +09301177 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301178 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +09301179 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001180 int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
1181 is_remote, terminus_handle, 0);
1182 assert(rc >= INT_MIN);
1183 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301184}
1185
Andrew Jeffery1354a6e2023-07-07 10:34:38 +09301186LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +09301187int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +09301188 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1189 size_t num_entities, bool is_remote, uint16_t terminus_handle)
1190{
1191 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001192 node, repo, entities, num_entities, is_remote, terminus_handle,
1193 0);
1194}
1195
Pavithra Barithaya3a267052023-11-13 05:01:36 -06001196LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001197int pldm_entity_association_pdr_add_from_node_with_record_handle(
1198 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1199 size_t num_entities, bool is_remote, uint16_t terminus_handle,
1200 uint32_t record_handle)
1201{
1202 if (!node || !repo || !entities) {
1203 return -EINVAL;
1204 }
1205
Archana Kakanibc40dd52024-08-02 00:10:44 -05001206 int64_t rc = entity_association_pdr_add(node, repo, entities,
1207 num_entities, is_remote,
1208 terminus_handle, record_handle);
1209
1210 assert(rc >= INT_MIN);
1211 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301212}
1213
Andrew Jeffery643c4432023-07-17 15:36:03 +09301214static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
1215 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301216{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001217 bool is_entity_container_id;
1218 bool is_entity_instance_num;
1219 bool is_type;
1220
Andrew Jeffery9c766792022-08-10 23:12:49 +09301221 if (tree_node == NULL) {
1222 return;
1223 }
1224
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001225 is_type = tree_node->entity.entity_type == entity.entity_type;
1226 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1227 entity.entity_instance_num;
1228 is_entity_container_id = tree_node->entity.entity_container_id ==
1229 entity.entity_container_id;
1230
1231 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301232 *node = tree_node;
1233 return;
1234 }
1235
1236 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1237 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1238}
1239
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301240LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301241void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1242 pldm_entity entity, pldm_entity_node **node)
1243{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301244 if (!tree || !node) {
1245 return;
1246 }
1247
Andrew Jeffery9c766792022-08-10 23:12:49 +09301248 find_entity_ref_in_tree(tree->root, entity, node);
1249}
1250
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301251LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301252void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1253 uint16_t terminus_handle)
1254{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301255 if (!repo) {
1256 return;
1257 }
1258
Andrew Jeffery9c766792022-08-10 23:12:49 +09301259 bool removed = false;
1260
1261 pldm_pdr_record *record = repo->first;
1262 pldm_pdr_record *prev = NULL;
1263 while (record != NULL) {
1264 pldm_pdr_record *next = record->next;
1265 if (record->terminus_handle == terminus_handle) {
1266 if (repo->first == record) {
1267 repo->first = next;
1268 } else {
1269 prev->next = next;
1270 }
1271 if (repo->last == record) {
1272 repo->last = prev;
1273 }
1274 if (record->data) {
1275 free(record->data);
1276 }
1277 --repo->record_count;
1278 repo->size -= record->size;
1279 free(record);
1280 removed = true;
1281 } else {
1282 prev = record;
1283 }
1284 record = next;
1285 }
1286
1287 if (removed == true) {
1288 record = repo->first;
1289 uint32_t record_handle = 0;
1290 while (record != NULL) {
1291 record->record_handle = ++record_handle;
1292 if (record->data != NULL) {
1293 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301294 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301295 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301296 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301297 }
1298 record = record->next;
1299 }
1300 }
1301}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301302
1303LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301304void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1305{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301306 if (!repo) {
1307 return;
1308 }
1309
Andrew Jeffery9c766792022-08-10 23:12:49 +09301310 bool removed = false;
1311
1312 pldm_pdr_record *record = repo->first;
1313 pldm_pdr_record *prev = NULL;
1314 while (record != NULL) {
1315 pldm_pdr_record *next = record->next;
1316 if (record->is_remote == true) {
1317 if (repo->first == record) {
1318 repo->first = next;
1319 } else {
1320 prev->next = next;
1321 }
1322 if (repo->last == record) {
1323 repo->last = prev;
1324 }
1325 if (record->data) {
1326 free(record->data);
1327 }
1328 --repo->record_count;
1329 repo->size -= record->size;
1330 free(record);
1331 removed = true;
1332 } else {
1333 prev = record;
1334 }
1335 record = next;
1336 }
1337
1338 if (removed == true) {
1339 record = repo->first;
1340 uint32_t record_handle = 0;
1341 while (record != NULL) {
1342 record->record_handle = ++record_handle;
1343 if (record->data != NULL) {
1344 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301345 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301346 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301347 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301348 }
1349 record = record->next;
1350 }
1351 }
1352}
1353
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001354LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001355pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1356 uint32_t first, uint32_t last)
1357{
1358 pldm_pdr_record *record = NULL;
1359 pldm_pdr_record *curr;
1360
1361 if (!repo) {
1362 return NULL;
1363 }
1364 for (curr = repo->first; curr; curr = curr->next) {
1365 if (first > curr->record_handle || last < curr->record_handle) {
1366 continue;
1367 }
1368 if (!record || curr->record_handle > record->record_handle) {
1369 record = curr;
1370 }
1371 }
1372
1373 return record;
1374}
1375
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001376static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1377 pldm_entity *entity,
1378 pldm_entity_node **out,
1379 bool is_remote)
1380{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001381 if (node == NULL) {
1382 return;
1383 }
1384 bool is_entity_type;
1385 bool is_entity_instance_num;
1386
1387 is_entity_type = node->entity.entity_type == entity->entity_type;
1388 is_entity_instance_num = node->entity.entity_instance_num ==
1389 entity->entity_instance_num;
1390
1391 if (!is_remote ||
1392 node->remote_container_id == entity->entity_container_id) {
1393 if (is_entity_type && is_entity_instance_num) {
1394 entity->entity_container_id =
1395 node->entity.entity_container_id;
1396 *out = node;
1397 return;
1398 }
1399 }
1400 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1401 is_remote);
1402 entity_association_tree_find_if_remote(node->first_child, entity, out,
1403 is_remote);
1404}
1405
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001406LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001407pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1408 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001409{
1410 if (!tree || !entity) {
1411 return NULL;
1412 }
1413 pldm_entity_node *node = NULL;
1414 entity_association_tree_find_if_remote(tree->root, entity, &node,
1415 is_remote);
1416 return node;
1417}
1418
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301419static void entity_association_tree_find(pldm_entity_node *node,
1420 pldm_entity *entity,
1421 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301422{
1423 if (node == NULL) {
1424 return;
1425 }
1426
1427 if (node->entity.entity_type == entity->entity_type &&
1428 node->entity.entity_instance_num == entity->entity_instance_num) {
1429 entity->entity_container_id = node->entity.entity_container_id;
1430 *out = node;
1431 return;
1432 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301433 entity_association_tree_find(node->next_sibling, entity, out);
1434 entity_association_tree_find(node->first_child, entity, out);
1435}
1436
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301437LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301438pldm_entity_node *
1439pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1440 pldm_entity *entity)
1441{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301442 if (!tree || !entity) {
1443 return NULL;
1444 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301445
1446 pldm_entity_node *node = NULL;
1447 entity_association_tree_find(tree->root, entity, &node);
1448 return node;
1449}
1450
Andrew Jeffery60582152024-09-22 21:16:38 +09301451static int entity_association_tree_copy(pldm_entity_node *org_node,
1452 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301453{
Andrew Jeffery60582152024-09-22 21:16:38 +09301454 int rc;
1455
Andrew Jeffery9c766792022-08-10 23:12:49 +09301456 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301457 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301458 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301459
Andrew Jeffery9c766792022-08-10 23:12:49 +09301460 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301461 if (!*new_node) {
1462 return -ENOMEM;
1463 }
1464
Andrew Jeffery9c766792022-08-10 23:12:49 +09301465 (*new_node)->parent = org_node->parent;
1466 (*new_node)->entity = org_node->entity;
1467 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001468 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301469 (*new_node)->first_child = NULL;
1470 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301471
1472 rc = entity_association_tree_copy(org_node->first_child,
1473 &((*new_node)->first_child));
1474 if (rc) {
1475 goto cleanup;
1476 }
1477
1478 rc = entity_association_tree_copy(org_node->next_sibling,
1479 &((*new_node)->next_sibling));
1480 if (rc) {
1481 entity_association_tree_destroy((*new_node)->first_child);
1482 goto cleanup;
1483 }
1484
1485 return 0;
1486
1487cleanup:
1488 free(*new_node);
1489 *new_node = NULL;
1490 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301491}
1492
Andrew Jeffery36324f62024-09-25 13:41:41 +09301493LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301494void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301495 pldm_entity_association_tree *org_tree,
1496 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301497{
George Liuc6c391d2023-11-09 10:13:34 +08001498 assert(org_tree != NULL);
1499 assert(new_tree != NULL);
1500
Andrew Jeffery9c766792022-08-10 23:12:49 +09301501 new_tree->last_used_container_id = org_tree->last_used_container_id;
1502 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1503}
1504
Andrew Jeffery60582152024-09-22 21:16:38 +09301505LIBPLDM_ABI_TESTING
1506int pldm_entity_association_tree_copy_root_check(
1507 pldm_entity_association_tree *org_tree,
1508 pldm_entity_association_tree *new_tree)
1509{
1510 if (!org_tree || !new_tree) {
1511 return -EINVAL;
1512 }
1513
1514 new_tree->last_used_container_id = org_tree->last_used_container_id;
1515 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1516}
1517
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301518LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301519void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301520 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301521{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301522 if (!tree) {
1523 return;
1524 }
1525
Andrew Jeffery9c766792022-08-10 23:12:49 +09301526 entity_association_tree_destroy(tree->root);
1527 tree->last_used_container_id = 0;
1528 tree->root = NULL;
1529}
1530
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301531LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301532bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1533{
1534 return ((tree->root == NULL) ? true : false);
1535}
1536
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301537LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301538void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1539 size_t *num_entities,
1540 pldm_entity **entities)
1541{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301542 if (!pdr || !num_entities || !entities) {
1543 return;
1544 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001545 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301546 return;
1547 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301548
1549 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301550 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1551 return;
1552 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301553
1554 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301555
1556 if (UINTPTR_MAX - (uintptr_t)start <
1557 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1558 return;
1559 }
1560
1561 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1562 return;
1563 }
1564
1565 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301566 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301567 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301568
1569 if ((uintptr_t)end - (uintptr_t)start <
1570 sizeof(struct pldm_pdr_entity_association)) {
1571 return;
1572 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001573
Andrew Jeffery9c766792022-08-10 23:12:49 +09301574 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301575 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301576
Archana Kakanibc40dd52024-08-02 00:10:44 -05001577 size_t l_num_entities = entity_association_pdr->num_children;
1578
1579 if (l_num_entities == 0) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301580 return;
1581 }
Andrew Jeffery8f33a1d2024-10-11 18:01:19 +10301582
Archana Kakanibc40dd52024-08-02 00:10:44 -05001583 if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1584 l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301585 return;
1586 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301587
Archana Kakanibc40dd52024-08-02 00:10:44 -05001588 if (l_num_entities >= (size_t)UINT8_MAX) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301589 return;
1590 }
1591
Archana Kakanibc40dd52024-08-02 00:10:44 -05001592 l_num_entities++;
1593
Andrew Jeffery9e566592024-10-02 16:38:51 +09301594 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301595 if (!l_entities) {
1596 return;
1597 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301598 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301599 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301600 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301601 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301602 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301603 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301604 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301605 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1606 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1607 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301608 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301609 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301610 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301611 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301612
1613 *num_entities = l_num_entities;
1614 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301615}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001616
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301617/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001618 * the same position.
1619 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301620LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001621static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1622 pldm_pdr_record *prev,
1623 pldm_pdr_record *new_record)
1624{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001625 if (repo->size < record->size) {
1626 return -EOVERFLOW;
1627 }
1628
1629 if (repo->size + new_record->size < new_record->size) {
1630 return -EOVERFLOW;
1631 }
1632
1633 if (repo->first == record) {
1634 repo->first = new_record;
1635 } else {
1636 prev->next = new_record;
1637 }
1638 new_record->next = record->next;
1639
1640 if (repo->last == record) {
1641 repo->last = new_record;
1642 }
1643
1644 repo->size = (repo->size - record->size) + new_record->size;
1645 return 0;
1646}
1647
1648/* Insert a new record to pldm_pdr repo to a position that comes after
1649 * pldm_pdr_record record.
1650 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301651LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001652static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1653 pldm_pdr_record *new_record)
1654{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001655 if (repo->size + new_record->size < new_record->size) {
1656 return -EOVERFLOW;
1657 }
1658
1659 if (repo->record_count == UINT32_MAX) {
1660 return -EOVERFLOW;
1661 }
1662
1663 new_record->next = record->next;
1664 record->next = new_record;
1665
1666 if (repo->last == record) {
1667 repo->last = new_record;
1668 }
1669
1670 repo->size = repo->size + new_record->size;
1671 ++repo->record_count;
1672 return 0;
1673}
1674
1675/* Find the position of PDR when its record handle is known
1676 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301677LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001678static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1679 pldm_pdr_record **prev,
1680 uint32_t record_handle)
1681{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001682 while (*record != NULL) {
1683 if ((*record)->record_handle == record_handle) {
1684 return true;
1685 }
1686 *prev = *record;
1687 *record = (*record)->next;
1688 }
1689 return false;
1690}
1691
1692LIBPLDM_ABI_TESTING
1693int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1694 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1695{
1696 if (!repo || !entity) {
1697 return -EINVAL;
1698 }
1699
1700 pldm_pdr_record *record = repo->first;
1701 pldm_pdr_record *prev = repo->first;
1702 int rc = 0;
1703 uint16_t header_length = 0;
1704 uint8_t num_children = 0;
John Chung7a8d9322025-08-27 20:56:19 -05001705 PLDM_MSGBUF_RO_DEFINE_P(src);
1706 PLDM_MSGBUF_RW_DEFINE_P(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001707
1708 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1709
1710 if (!record) {
1711 return -EINVAL;
1712 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001713
1714 // check if adding another entity to record causes overflow before
1715 // allocating memory for new_record.
1716 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1717 return -EOVERFLOW;
1718 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301719
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001720 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1721 if (!new_record) {
1722 return -ENOMEM;
1723 }
1724
1725 new_record->data = malloc(record->size + sizeof(pldm_entity));
1726 if (!new_record->data) {
1727 rc = -ENOMEM;
1728 goto cleanup_new_record;
1729 }
1730
1731 new_record->record_handle = record->record_handle;
1732 new_record->size = record->size + sizeof(struct pldm_entity);
1733 new_record->is_remote = record->is_remote;
1734
Andrew Jefferya1896962025-03-03 21:41:25 +10301735 // Initialize msg buffer for record and record->data
1736 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1737 record->data, record->size);
1738 if (rc) {
1739 goto cleanup_new_record_data;
1740 }
1741
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001742 // Initialize new PDR record with data from original PDR record.
1743 // Start with adding the header of original PDR
1744 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1745 new_record->data, new_record->size);
1746 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301747 goto cleanup_src_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001748 }
1749
1750 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1751 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1752 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1753 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1754 // extract the header length from record and increment size with
1755 // size of pldm_entity before inserting the value into new_record.
1756 rc = pldm_msgbuf_extract(src, header_length);
1757 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301758 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001759 }
1760 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1761 "Fix the following bounds check.");
1762 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1763 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301764 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001765 }
1766 header_length += sizeof(pldm_entity);
1767 pldm_msgbuf_insert(dst, header_length);
1768 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1769 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1770 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1771 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1772 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1773 // extract value of number of children from record and increment it
1774 // by 1 before insert the value to new record.
1775 rc = pldm_msgbuf_extract(src, num_children);
1776 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301777 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001778 }
1779 if (num_children == UINT8_MAX) {
1780 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301781 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001782 }
1783 num_children += 1;
1784 pldm_msgbuf_insert(dst, num_children);
1785 //Add all children of original PDR to new PDR
1786 for (int i = 0; i < num_children - 1; i++) {
1787 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1788 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1789 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1790 }
1791
1792 // Add new contained entity as a child of new PDR
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301793 rc = pldm_msgbuf_complete(src);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001794 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301795 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001796 goto cleanup_new_record_data;
1797 }
1798 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1799 sizeof(struct pldm_entity));
1800 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301801 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001802 goto cleanup_new_record_data;
1803 }
1804 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1805 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1806 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1807
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301808 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001809 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301810 goto cleanup_src_msgbuf;
1811 }
1812 rc = pldm_msgbuf_complete(src);
1813 if (rc) {
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001814 goto cleanup_new_record_data;
1815 }
1816
1817 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1818 if (rc) {
1819 goto cleanup_new_record_data;
1820 }
1821
1822 free(record->data);
1823 free(record);
1824 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301825cleanup_dst_msgbuf:
1826 rc = pldm_msgbuf_discard(dst, rc);
1827cleanup_src_msgbuf:
1828 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001829cleanup_new_record_data:
1830 free(new_record->data);
1831cleanup_new_record:
1832 free(new_record);
1833 return rc;
1834}
1835
1836LIBPLDM_ABI_TESTING
1837int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1838 uint32_t pdr_record_handle,
1839 pldm_entity *parent,
1840 pldm_entity *entity,
1841 uint32_t *entity_record_handle)
1842{
1843 if (!repo || !parent || !entity || !entity_record_handle) {
1844 return -EINVAL;
1845 }
1846
1847 if (pdr_record_handle == UINT32_MAX) {
1848 return -EOVERFLOW;
1849 }
1850
1851 bool pdr_added = false;
1852 uint16_t new_pdr_size;
1853 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001854 void *container_id_addr;
John Chung7a8d9322025-08-27 20:56:19 -05001855 PLDM_MSGBUF_RW_DEFINE_P(dst);
1856 PLDM_MSGBUF_RO_DEFINE_P(src_p);
1857 PLDM_MSGBUF_RO_DEFINE_P(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001858 int rc = 0;
1859
1860 pldm_pdr_record *prev = repo->first;
1861 pldm_pdr_record *record = repo->first;
1862 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1863 pdr_record_handle);
1864 if (!pdr_added) {
1865 return -ENOENT;
1866 }
1867
1868 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1869 "Truncation ahead");
1870 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1871 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1872 if (!new_record) {
1873 return -ENOMEM;
1874 }
1875
1876 new_record->data = malloc(new_pdr_size);
1877 if (!new_record->data) {
1878 rc = -ENOMEM;
1879 goto cleanup_new_record;
1880 }
1881
1882 // Initialise new PDR to be added with the header, size and handle.
1883 // Set the position of new PDR
1884 *entity_record_handle = pdr_record_handle + 1;
1885 new_record->record_handle = *entity_record_handle;
1886 new_record->size = new_pdr_size;
1887 new_record->is_remote = false;
1888
1889 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1890 new_record->data, new_record->size);
1891 if (rc) {
1892 goto cleanup_new_record_data;
1893 }
1894
1895 // header record handle
1896 pldm_msgbuf_insert(dst, *entity_record_handle);
1897 // header version
1898 pldm_msgbuf_insert_uint8(dst, 1);
1899 // header type
1900 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1901 // header change number
1902 pldm_msgbuf_insert_uint16(dst, 0);
1903 // header length
1904 pldm_msgbuf_insert_uint16(dst,
1905 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1906
1907 // Data for new PDR is obtained from parent PDR and new contained entity
1908 // is added as the child
1909 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1910 sizeof(*parent));
1911 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301912 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001913 }
1914
1915 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1916 sizeof(*entity));
1917 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301918 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001919 }
1920
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001921 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001922 // extract pointer for container ID and save the address
1923 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1924 (void **)&container_id_addr);
1925 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301926 goto cleanup_msgbuf_src_c;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001927 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001928 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001929 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1930 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1931 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1932 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1933 // number of children
1934 pldm_msgbuf_insert_uint8(dst, 1);
1935
1936 // Add new entity as child
1937 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1938 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1939 // Extract and insert child entity container ID and add same value to
1940 // container ID of entity
1941 pldm_msgbuf_extract(src_c, container_id);
1942 pldm_msgbuf_insert(dst, container_id);
1943 container_id = htole16(container_id);
1944 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1945
Andrew Jefferya1896962025-03-03 21:41:25 +10301946 rc = pldm_msgbuf_complete(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001947 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301948 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001949 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301950 rc = pldm_msgbuf_complete(src_p);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001951 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301952 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001953 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301954 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001955 if (rc) {
1956 goto cleanup_new_record_data;
1957 }
1958
1959 rc = pldm_pdr_insert_record(repo, record, new_record);
1960 if (rc) {
1961 goto cleanup_new_record_data;
1962 }
1963
1964 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301965cleanup_msgbuf_src_c:
1966 rc = pldm_msgbuf_discard(src_c, rc);
1967cleanup_msgbuf_src_p:
1968 rc = pldm_msgbuf_discard(src_p, rc);
1969cleanup_msgbuf_dst:
1970 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001971cleanup_new_record_data:
1972 free(new_record->data);
1973cleanup_new_record:
1974 free(new_record);
1975 return rc;
1976}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001977
1978LIBPLDM_CC_NONNULL
1979static bool pldm_entity_cmp(const struct pldm_entity *l,
1980 const struct pldm_entity *r)
1981{
1982 return l->entity_type == r->entity_type &&
1983 l->entity_instance_num == r->entity_instance_num &&
1984 l->entity_container_id == r->entity_container_id;
1985}
1986
1987/* Find record handle of a PDR record from PDR repo and
1988 * entity
1989 */
1990LIBPLDM_CC_NONNULL
1991static int pldm_entity_association_find_record_handle_by_entity(
1992 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1993 uint32_t *record_handle)
1994{
1995 uint8_t num_children = 0;
1996 uint8_t hdr_type = 0;
1997 int rc = 0;
1998 size_t skip_data_size = 0;
1999 pldm_pdr_record *record = repo->first;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002000
2001 while (record != NULL) {
John Chung7a8d9322025-08-27 20:56:19 -05002002 PLDM_MSGBUF_RO_DEFINE_P(dst);
Andrew Jefferya1896962025-03-03 21:41:25 +10302003
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002004 rc = pldm_msgbuf_init_errno(dst,
2005 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
2006 record->data, record->size);
2007 if (rc) {
2008 return rc;
2009 }
2010 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2011 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302012 rc = pldm_msgbuf_extract(dst, hdr_type);
2013 if (rc) {
2014 return pldm_msgbuf_discard(dst, rc);
2015 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002016 if (record->is_remote != is_remote ||
2017 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
2018 goto cleanup;
2019 }
2020 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
2021 sizeof(uint16_t) + sizeof(uint8_t) +
2022 sizeof(struct pldm_entity);
2023 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302024 rc = pldm_msgbuf_extract(dst, num_children);
2025 if (rc) {
2026 return pldm_msgbuf_discard(dst, rc);
2027 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002028 for (int i = 0; i < num_children; ++i) {
2029 struct pldm_entity e;
2030
2031 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
2032 (rc = pldm_msgbuf_extract(dst,
2033 e.entity_instance_num)) ||
2034 (rc = pldm_msgbuf_extract(dst,
2035 e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302036 return pldm_msgbuf_discard(dst, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002037 }
2038
2039 if (pldm_entity_cmp(entity, &e)) {
2040 *record_handle = record->record_handle;
Andrew Jefferya1896962025-03-03 21:41:25 +10302041 return pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002042 }
2043 }
2044 cleanup:
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302045 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002046 if (rc) {
2047 return rc;
2048 }
2049 record = record->next;
2050 }
2051 return 0;
2052}
2053
2054LIBPLDM_ABI_TESTING
2055int pldm_entity_association_pdr_remove_contained_entity(
2056 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
2057 uint32_t *pdr_record_handle)
2058{
2059 uint16_t header_length = 0;
2060 uint8_t num_children = 0;
John Chung7a8d9322025-08-27 20:56:19 -05002061 PLDM_MSGBUF_RO_DEFINE_P(src);
2062 PLDM_MSGBUF_RW_DEFINE_P(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002063 int rc;
2064 pldm_pdr_record *record;
2065 pldm_pdr_record *prev;
2066
2067 if (!repo || !entity || !pdr_record_handle) {
2068 return -EINVAL;
2069 }
2070 record = repo->first;
2071 prev = repo->first;
2072
2073 rc = pldm_entity_association_find_record_handle_by_entity(
2074 repo, entity, is_remote, pdr_record_handle);
2075 if (rc) {
2076 return rc;
2077 }
2078 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
2079 if (!record) {
2080 return -EINVAL;
2081 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002082 // check if removing an entity from record causes overflow before
2083 // allocating memory for new_record.
2084 if (record->size < sizeof(pldm_entity)) {
2085 return -EOVERFLOW;
2086 }
2087 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
2088 if (!new_record) {
2089 return -ENOMEM;
2090 }
2091 new_record->data = malloc(record->size - sizeof(pldm_entity));
2092 if (!new_record->data) {
2093 rc = -ENOMEM;
2094 goto cleanup_new_record;
2095 }
2096 new_record->record_handle = record->record_handle;
2097 new_record->size = record->size - sizeof(struct pldm_entity);
2098 new_record->is_remote = record->is_remote;
2099
Andrew Jefferya1896962025-03-03 21:41:25 +10302100 // Initialize msg buffer for record and record->data
2101 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
2102 record->data, record->size);
2103 if (rc) {
2104 goto cleanup_new_record_data;
2105 }
2106
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002107 // Initialize new PDR record with data from original PDR record.
2108 // Start with adding the header of original PDR
Archana Kakani94e2d752024-12-12 08:22:55 -06002109 rc = pldm_msgbuf_init_errno(
2110 dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
2111 new_record->data, new_record->size);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002112 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302113 goto cleanup_msgbuf_src;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002114 }
2115 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
2116 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
2117 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
2118 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
2119 // extract the header length from record and decrement size with
2120 // size of pldm_entity before inserting the value into new_record.
2121 rc = pldm_msgbuf_extract(src, header_length);
2122 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302123 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002124 }
2125 if (header_length < sizeof(pldm_entity)) {
2126 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302127 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002128 }
2129 header_length -= sizeof(pldm_entity);
2130 pldm_msgbuf_insert(dst, header_length);
2131 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
2132 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
2133 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
2134 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
2135 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
2136 // extract value of number of children from record and decrement it
2137 // by 1 before insert the value to new record.
2138 rc = pldm_msgbuf_extract(src, num_children);
2139 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302140 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002141 }
2142 if (num_children == 1) {
Archana Kakani94e2d752024-12-12 08:22:55 -06002143 // This is the last child which is getting removed so we need to delete the Entity Association PDR.
2144 pldm_pdr_remove_record(repo, record,
2145 pldm_pdr_get_prev_record(repo, record));
Andrew Jefferya1896962025-03-03 21:41:25 +10302146 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002147 } else if (num_children < 1) {
2148 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302149 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002150 }
2151 num_children -= 1;
2152 pldm_msgbuf_insert(dst, num_children);
2153 //Add all children of original PDR to new PDR
2154 for (int i = 0; i < num_children + 1; ++i) {
2155 struct pldm_entity e;
2156
2157 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
2158 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
2159 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302160 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002161 }
2162
2163 if (pldm_entity_cmp(entity, &e)) {
2164 continue;
2165 }
2166
2167 pldm_msgbuf_insert(dst, e.entity_type);
2168 pldm_msgbuf_insert(dst, e.entity_instance_num);
2169 pldm_msgbuf_insert(dst, e.entity_container_id);
2170 }
2171
Andrew Jefferya1896962025-03-03 21:41:25 +10302172 rc = pldm_msgbuf_complete(dst);
2173 if (rc) {
2174 goto cleanup_msgbuf_src;
2175 }
2176
2177 rc = pldm_msgbuf_complete(src);
2178 if (rc) {
2179 goto cleanup_new_record_data;
2180 }
2181
2182 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
2183 if (rc) {
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002184 goto cleanup_new_record_data;
2185 }
2186
2187 free(record->data);
2188 free(record);
2189 return rc;
2190
Andrew Jefferya1896962025-03-03 21:41:25 +10302191cleanup_msgbuf_dst:
2192 rc = pldm_msgbuf_discard(dst, rc);
2193cleanup_msgbuf_src:
2194 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002195cleanup_new_record_data:
2196 free(new_record->data);
2197cleanup_new_record:
2198 free(new_record);
2199 return rc;
2200}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002201
2202/* API to find the PDR record that is previous to a given PLDM PDR
2203 * record in a given PLDM PDR repository
2204 */
2205LIBPLDM_CC_NONNULL
2206static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
2207 pldm_pdr_record *record)
2208{
2209 pldm_pdr_record *prev = NULL;
2210 pldm_pdr_record *curr = repo->first;
2211
2212 while (curr != NULL) {
2213 if (curr->record_handle == record->record_handle) {
2214 break;
2215 }
2216 prev = curr;
2217 curr = curr->next;
2218 }
2219 return prev;
2220}
2221
2222/* API to check if a PLDM PDR record is present in a PLDM PDR repository
2223 */
2224LIBPLDM_CC_NONNULL
2225static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
2226{
2227 if (repo->first == record) {
2228 return true;
2229 }
2230
2231 return pldm_pdr_get_prev_record(repo, record) != NULL;
2232}
2233
2234/* API to check if FRU RSI of record matches the given record set identifier.
2235 * Returns 1 if the provided FRU record matches the provided record set identifier,
2236 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
2237 */
2238LIBPLDM_CC_NONNULL
2239static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
2240 uint16_t rsi)
2241{
2242 uint16_t record_fru_rsi = 0;
2243 uint8_t *skip_data = NULL;
2244 uint8_t skip_data_size = 0;
John Chung7a8d9322025-08-27 20:56:19 -05002245 PLDM_MSGBUF_RO_DEFINE_P(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002246 int rc = 0;
2247
2248 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
2249 record->data, record->size);
2250 if (rc) {
2251 return rc;
2252 }
2253 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
John Chung7a8d9322025-08-27 20:56:19 -05002254 pldm_msgbuf_span_required(dst, skip_data_size,
2255 (const void **)&skip_data);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002256 pldm_msgbuf_extract(dst, record_fru_rsi);
2257
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302258 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002259 if (rc) {
2260 return rc;
2261 }
2262 return record_fru_rsi == rsi;
2263}
2264
2265/* API to remove PLDM PDR record from a PLDM PDR repository
2266 */
2267LIBPLDM_CC_NONNULL_ARGS(1, 2)
2268static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2269 pldm_pdr_record *prev)
2270{
2271 if (!is_prev_record_present(repo, record)) {
2272 return -EINVAL;
2273 }
2274
2275 assert(repo->size >= record->size);
2276 if (repo->size < record->size) {
2277 return -EOVERFLOW;
2278 }
2279
2280 if (repo->first == record) {
2281 repo->first = record->next;
2282 } else {
2283 if (prev != NULL) {
2284 prev->next = record->next;
2285 }
2286 }
2287
2288 if (repo->last == record) {
2289 repo->last = prev;
2290 if (prev != NULL) {
2291 prev->next = NULL;
2292 }
2293 }
2294 repo->record_count -= 1;
2295 repo->size -= record->size;
2296 free(record->data);
2297 free(record);
2298
2299 return 0;
2300}
2301
2302LIBPLDM_ABI_TESTING
2303int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2304 bool is_remote,
2305 uint32_t *record_handle)
2306{
2307 pldm_pdr_record *record;
2308 pldm_pdr_record *prev = NULL;
2309 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2310 uint8_t hdr_type = 0;
2311 int rc = 0;
2312 int match;
2313
2314 if (!repo || !record_handle) {
2315 return -EINVAL;
2316 }
2317 record = repo->first;
2318
2319 while (record != NULL) {
John Chung7a8d9322025-08-27 20:56:19 -05002320 PLDM_MSGBUF_RO_DEFINE_P(buf);
Andrew Jefferya1896962025-03-03 21:41:25 +10302321
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002322 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2323 record->data, record->size);
2324 if (rc) {
2325 return rc;
2326 }
2327 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302328 pldm_msgbuf_extract(buf, hdr_type);
2329 rc = pldm_msgbuf_complete(buf);
2330 if (rc) {
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002331 return rc;
2332 }
2333 if (record->is_remote != is_remote ||
2334 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302335 goto next;
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002336 }
2337 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2338 if (match < 0) {
2339 return match;
2340 }
2341 if (match) {
2342 *record_handle = record->record_handle;
2343 prev = pldm_pdr_get_prev_record(repo, record);
2344 return pldm_pdr_remove_record(repo, record, prev);
2345 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302346 next:
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002347 record = record->next;
2348 }
2349 return rc;
2350}
Pavithra Barithaya59edcb12025-02-26 15:39:17 +05302351
2352LIBPLDM_ABI_TESTING
2353int pldm_entity_association_tree_delete_node(pldm_entity_association_tree *tree,
2354 const pldm_entity *entity)
2355{
2356 if (!tree || !entity) {
2357 return -EINVAL;
2358 }
2359 pldm_entity_node *node = NULL;
2360 pldm_find_entity_ref_in_tree(tree, *entity, &node);
2361 if (!node) {
2362 return -ENOENT;
2363 }
2364
2365 pldm_entity_node *parent = NULL;
2366 pldm_find_entity_ref_in_tree(tree, node->parent, &parent);
2367 if (!parent) {
2368 return -ENOENT;
2369 }
2370
2371 pldm_entity_node *curr = parent->first_child;
2372 pldm_entity_node *prev = NULL;
2373 while (curr != NULL) {
2374 if (pldm_entity_cmp(entity, &curr->entity)) {
2375 if (curr == parent->first_child) {
2376 parent->first_child = curr->next_sibling;
2377 } else {
2378 if (prev) {
2379 prev->next_sibling = curr->next_sibling;
2380 }
2381 }
2382 curr->next_sibling = NULL;
2383
2384 entity_association_tree_destroy(node);
2385 break;
2386 }
2387 prev = curr;
2388 curr = curr->next_sibling;
2389 }
2390 return 0;
2391}