blob: 69229d50a3e8ef1362a66354b109d6ad4bad57bc [file] [log] [blame]
Patrick Williams691668f2023-11-01 08:19:10 -05001/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
Andrew Jeffery860a43d2024-08-23 01:21:58 +00002#include "compiler.h"
Varsha Kaverappa37552b92024-02-12 05:06:06 -06003#include "msgbuf.h"
Andrew Jefferyb0c1d202023-11-07 22:08:44 +10304#include <libpldm/pdr.h>
5#include <libpldm/platform.h>
6
Andrew Jeffery9c766792022-08-10 23:12:49 +09307#include <assert.h>
Manojkiran Eda9a8e4972022-11-28 16:38:21 +05308#include <endian.h>
Andrew Jeffery9e566592024-10-02 16:38:51 +09309#include <stdint.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093010#include <stdlib.h>
11#include <string.h>
ArchanaKakani39bd2ea2023-02-02 02:39:18 -060012#include <errno.h>
Andrew Jeffery9c766792022-08-10 23:12:49 +093013
Varsha Kaverappa37552b92024-02-12 05:06:06 -060014#define PDR_ENTITY_ASSOCIATION_MIN_SIZE \
15 (sizeof(struct pldm_pdr_hdr) + \
16 sizeof(struct pldm_pdr_entity_association))
17
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050018#define PDR_FRU_RECORD_SET_MIN_SIZE \
19 (sizeof(struct pldm_pdr_hdr) + sizeof(struct pldm_pdr_fru_record_set))
20
Andrew Jeffery9c766792022-08-10 23:12:49 +093021typedef struct pldm_pdr_record {
22 uint32_t record_handle;
23 uint32_t size;
24 uint8_t *data;
25 struct pldm_pdr_record *next;
26 bool is_remote;
27 uint16_t terminus_handle;
28} pldm_pdr_record;
29
30typedef struct pldm_pdr {
31 uint32_t record_count;
32 uint32_t size;
33 pldm_pdr_record *first;
34 pldm_pdr_record *last;
35} pldm_pdr;
36
Andrew Jeffery890d37a2024-09-22 20:50:53 +093037LIBPLDM_CC_NONNULL
Archana Kakani94e2d752024-12-12 08:22:55 -060038static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
39 pldm_pdr_record *record);
40
41LIBPLDM_CC_NONNULL_ARGS(1, 2)
42static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
43 pldm_pdr_record *prev);
44
45LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +093046static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
47 const pldm_pdr_record *record)
48{
Andrew Jeffery9c766792022-08-10 23:12:49 +093049 if (record == repo->last) {
50 return 0;
51 }
52 return record->next->record_handle;
53}
54
Andrew Jefferyca248ce2023-07-07 10:38:30 +093055LIBPLDM_ABI_STABLE
Andrew Jefferyfae36412024-06-20 06:35:51 +000056int pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
57 bool is_remote, uint16_t terminus_handle,
58 uint32_t *record_handle)
Andrew Jeffery572a3952023-07-03 13:19:28 +093059{
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -050060 uint32_t curr = 0;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093061
Andrew Jeffery3b93d092023-07-17 13:01:50 +093062 if (!repo || !data || !size) {
Andrew Jeffery572a3952023-07-03 13:19:28 +093063 return -EINVAL;
64 }
Andrew Jeffery9c766792022-08-10 23:12:49 +093065
Andrew Jeffery3b93d092023-07-17 13:01:50 +093066 if (record_handle && *record_handle) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093067 curr = *record_handle;
68 } else if (repo->last) {
69 curr = repo->last->record_handle;
70 if (curr == UINT32_MAX) {
71 return -EOVERFLOW;
72 }
73 curr += 1;
74 } else {
75 curr = 1;
76 }
77
Andrew Jeffery9c766792022-08-10 23:12:49 +093078 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
Andrew Jeffery572a3952023-07-03 13:19:28 +093079 if (!record) {
80 return -ENOMEM;
81 }
Andrew Jefferya51ccc22023-06-28 21:57:46 +093082
Andrew Jeffery572a3952023-07-03 13:19:28 +093083 if (data) {
84 record->data = malloc(size);
Andrew Jeffery572a3952023-07-03 13:19:28 +093085 if (!record->data) {
86 free(record);
87 return -ENOMEM;
88 }
89 memcpy(record->data, data, size);
Andrew Jeffery2ca7e642023-06-28 22:29:07 +093090 }
91
Andrew Jeffery9c766792022-08-10 23:12:49 +093092 record->size = size;
93 record->is_remote = is_remote;
94 record->terminus_handle = terminus_handle;
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093095 record->record_handle = curr;
Andrew Jeffery572a3952023-07-03 13:19:28 +093096
Andrew Jeffery3b93d092023-07-17 13:01:50 +093097 if (record_handle && !*record_handle && data) {
Andrew Jefferyc6cc0282023-07-17 12:11:37 +093098 /* If record handle is 0, that is an indication for this API to
99 * compute a new handle. For that reason, the computed handle
100 * needs to be populated in the PDR header. For a case where the
101 * caller supplied the record handle, it would exist in the
102 * header already.
103 */
104 struct pldm_pdr_hdr *hdr = (void *)record->data;
105 hdr->record_handle = htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930106 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930107
Andrew Jeffery9c766792022-08-10 23:12:49 +0930108 record->next = NULL;
109
Andrew Jeffery8d231da2023-07-04 11:28:46 +0930110 assert(!repo->first == !repo->last);
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930111 if (repo->first == NULL) {
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930112 repo->first = record;
113 repo->last = record;
114 } else {
115 repo->last->next = record;
116 repo->last = record;
117 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930118
Andrew Jefferya51ccc22023-06-28 21:57:46 +0930119 repo->size += record->size;
120 ++repo->record_count;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930121
Andrew Jeffery3b93d092023-07-17 13:01:50 +0930122 if (record_handle) {
123 *record_handle = record->record_handle;
124 }
Andrew Jeffery572a3952023-07-03 13:19:28 +0930125
126 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930127}
128
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930129LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930130pldm_pdr *pldm_pdr_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930131{
132 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
Andrew Jefferya8bb22e2023-06-30 12:01:12 +0930133 if (!repo) {
134 return NULL;
135 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930136 repo->record_count = 0;
137 repo->size = 0;
138 repo->first = NULL;
139 repo->last = NULL;
140
141 return repo;
142}
143
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930144LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930145void pldm_pdr_destroy(pldm_pdr *repo)
146{
Andrew Jefferyfca1b602023-06-30 12:29:25 +0930147 if (!repo) {
148 return;
149 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930150
151 pldm_pdr_record *record = repo->first;
152 while (record != NULL) {
153 pldm_pdr_record *next = record->next;
154 if (record->data) {
155 free(record->data);
156 record->data = NULL;
157 }
158 free(record);
159 record = next;
160 }
161 free(repo);
162}
163
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930164LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930165const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
166 uint32_t record_handle,
167 uint8_t **data, uint32_t *size,
168 uint32_t *next_record_handle)
169{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930170 if (!repo || !data || !size || !next_record_handle) {
171 return NULL;
172 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930173
174 if (!record_handle && (repo->first != NULL)) {
175 record_handle = repo->first->record_handle;
176 }
Andrew Jeffery68b51302023-06-28 21:29:42 +0930177
Andrew Jeffery9c766792022-08-10 23:12:49 +0930178 pldm_pdr_record *record = repo->first;
179 while (record != NULL) {
180 if (record->record_handle == record_handle) {
181 *size = record->size;
182 *data = record->data;
183 *next_record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930184 get_next_record_handle(repo, record);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930185 return record;
186 }
187 record = record->next;
188 }
189
190 *size = 0;
191 *next_record_handle = 0;
192 return NULL;
193}
194
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930195LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930196const pldm_pdr_record *
197pldm_pdr_get_next_record(const pldm_pdr *repo,
198 const pldm_pdr_record *curr_record, uint8_t **data,
199 uint32_t *size, uint32_t *next_record_handle)
200{
Andrew Jeffery68b51302023-06-28 21:29:42 +0930201 if (!repo || !curr_record || !data || !size || !next_record_handle) {
202 return NULL;
203 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930204
205 if (curr_record == repo->last) {
206 *data = NULL;
207 *size = 0;
208 *next_record_handle = get_next_record_handle(repo, curr_record);
209 return NULL;
210 }
211
212 *next_record_handle = get_next_record_handle(repo, curr_record->next);
213 *data = curr_record->next->data;
214 *size = curr_record->next->size;
215 return curr_record->next;
216}
217
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930218LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930219const pldm_pdr_record *
220pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
221 const pldm_pdr_record *curr_record, uint8_t **data,
222 uint32_t *size)
223{
Andrew Jefferyf85eeba2023-06-30 12:38:40 +0930224 if (!repo) {
225 return NULL;
226 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930227
228 pldm_pdr_record *record = repo->first;
229 if (curr_record != NULL) {
230 record = curr_record->next;
231 }
232 while (record != NULL) {
233 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
234 if (hdr->type == pdr_type) {
235 if (data && size) {
236 *size = record->size;
237 *data = record->data;
238 }
239 return record;
240 }
241 record = record->next;
242 }
243
244 if (size) {
245 *size = 0;
246 }
247 return NULL;
248}
249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930251uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
252{
253 assert(repo != NULL);
254
255 return repo->record_count;
256}
257
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930258LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930259uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
260{
261 assert(repo != NULL);
262
263 return repo->size;
264}
265
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930266LIBPLDM_ABI_STABLE
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000267uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Andrew Jeffery9c766792022-08-10 23:12:49 +0930268 const pldm_pdr_record *record)
269{
270 assert(repo != NULL);
271 assert(record != NULL);
272
273 return record->record_handle;
274}
275
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530276LIBPLDM_ABI_TESTING
Andrew Jeffery860a43d2024-08-23 01:21:58 +0000277uint16_t pldm_pdr_get_terminus_handle(const pldm_pdr *repo LIBPLDM_CC_UNUSED,
Pavithra Barithaya274732f2024-07-05 16:03:01 +0530278 const pldm_pdr_record *record)
279{
280 assert(repo != NULL);
281 assert(record != NULL);
282
283 return record->terminus_handle;
284}
285
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930286LIBPLDM_ABI_STABLE
287bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930288{
289 assert(record != NULL);
290
291 return record->is_remote;
292}
293
Andrew Jefferya2c69112023-07-07 10:41:38 +0930294LIBPLDM_ABI_STABLE
Andrew Jefferye7f55112024-06-20 16:16:01 +0930295int pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
296 uint16_t fru_rsi, uint16_t entity_type,
297 uint16_t entity_instance_num,
298 uint16_t container_id,
299 uint32_t *bmc_record_handle)
Andrew Jefferyc821a702023-07-03 13:32:11 +0930300{
Andrew Jeffery73d67792023-07-17 15:22:18 +0930301 if (!repo || !bmc_record_handle) {
302 return -EINVAL;
303 }
304
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930305 uint8_t data[sizeof(struct pldm_pdr_hdr) +
306 sizeof(struct pldm_pdr_fru_record_set)];
Andrew Jeffery9c766792022-08-10 23:12:49 +0930307
308 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
309 hdr->version = 1;
Andrew Jefferyc821a702023-07-03 13:32:11 +0930310 hdr->record_handle = *bmc_record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930311 hdr->type = PLDM_PDR_FRU_RECORD_SET;
312 hdr->record_change_num = 0;
313 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
314 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930315 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
316 sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930317 fru->terminus_handle = htole16(terminus_handle);
318 fru->fru_rsi = htole16(fru_rsi);
319 fru->entity_type = htole16(entity_type);
320 fru->entity_instance_num = htole16(entity_instance_num);
321 fru->container_id = htole16(container_id);
322
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930323 return pldm_pdr_add(repo, data, sizeof(data), false, terminus_handle,
Andrew Jefferyfae36412024-06-20 06:35:51 +0000324 bmc_record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930325}
326
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930327LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930328const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930329 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
330 uint16_t *entity_type, uint16_t *entity_instance_num,
331 uint16_t *container_id)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930332{
Andrew Jeffery01425e92023-06-30 13:47:40 +0930333 if (!repo || !terminus_handle || !entity_type || !entity_instance_num ||
334 !container_id) {
335 return NULL;
336 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930337
338 uint8_t *data = NULL;
339 uint32_t size = 0;
340 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930341 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930342 while (curr_record != NULL) {
343 struct pldm_pdr_fru_record_set *fru =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930344 (struct pldm_pdr_fru_record_set
345 *)(data + sizeof(struct pldm_pdr_hdr));
Andrew Jeffery9c766792022-08-10 23:12:49 +0930346 if (fru->fru_rsi == htole16(fru_rsi)) {
347 *terminus_handle = le16toh(fru->terminus_handle);
348 *entity_type = le16toh(fru->entity_type);
349 *entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930350 le16toh(fru->entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930351 *container_id = le16toh(fru->container_id);
352 return curr_record;
353 }
354 data = NULL;
355 curr_record = pldm_pdr_find_record_by_type(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930356 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data,
357 &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930358 }
359
360 *terminus_handle = 0;
361 *entity_type = 0;
362 *entity_instance_num = 0;
363 *container_id = 0;
364
365 return NULL;
366}
367
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930368LIBPLDM_ABI_STABLE
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930369/* NOLINTNEXTLINE(readability-identifier-naming) */
370void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
371 uint8_t tid, uint8_t tl_eid, bool valid_bit)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930372{
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930373 uint8_t *out_data = NULL;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930374 uint32_t size = 0;
375 const pldm_pdr_record *record;
376 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930377 NULL, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930378
379 do {
380 if (record != NULL) {
381 struct pldm_terminus_locator_pdr *pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930382 (struct pldm_terminus_locator_pdr *)out_data;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930383 struct pldm_terminus_locator_type_mctp_eid *value =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930384 (struct pldm_terminus_locator_type_mctp_eid *)
385 pdr->terminus_locator_value;
Andrew Jeffery6005f1c2023-04-05 20:02:52 +0930386 if (pdr->terminus_handle == terminus_handle &&
387 pdr->tid == tid && value->eid == tl_eid) {
388 pdr->validity = valid_bit;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930389 break;
390 }
391 }
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930392 record = pldm_pdr_find_record_by_type(repo,
393 PLDM_TERMINUS_LOCATOR_PDR,
394 record, &out_data, &size);
Andrew Jeffery9c766792022-08-10 23:12:49 +0930395 } while (record);
396}
397
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500398static bool pldm_record_handle_in_range(uint32_t record_handle,
399 uint32_t first_record_handle,
400 uint32_t last_record_handle)
401{
402 return record_handle >= first_record_handle &&
403 record_handle <= last_record_handle;
404}
405
Pavithra Barithayaf0eee362025-02-25 11:52:48 +0530406LIBPLDM_CC_NONNULL
407static int decode_pldm_state_sensor_pdr(uint8_t *data, uint32_t size,
408 struct pldm_state_sensor_pdr *pdr)
409{
410 PLDM_MSGBUF_DEFINE_P(buf);
411 int rc = 0;
412 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_sensor_pdr),
413 (uint8_t *)data, size);
414 if (rc) {
415 return rc;
416 }
417
418 pldm_msgbuf_extract(buf, pdr->hdr.record_handle);
419 pldm_msgbuf_extract(buf, pdr->hdr.version);
420 pldm_msgbuf_extract(buf, pdr->hdr.type);
421 pldm_msgbuf_extract(buf, pdr->hdr.record_change_num);
422 pldm_msgbuf_extract(buf, pdr->hdr.length);
423 pldm_msgbuf_extract(buf, pdr->terminus_handle);
424 pldm_msgbuf_extract(buf, pdr->sensor_id);
425 pldm_msgbuf_extract(buf, pdr->entity_type);
426 pldm_msgbuf_extract(buf, pdr->entity_instance);
427 pldm_msgbuf_extract(buf, pdr->container_id);
428 pldm_msgbuf_extract(buf, pdr->sensor_init);
429 pldm_msgbuf_extract(buf, pdr->sensor_auxiliary_names_pdr);
430 pldm_msgbuf_extract(buf, pdr->composite_sensor_count);
431
432 return pldm_msgbuf_complete(buf);
433}
434
435LIBPLDM_ABI_TESTING
436int pldm_pdr_delete_by_sensor_id(pldm_pdr *repo, uint16_t sensor_id,
437 bool is_remote, uint32_t *record_handle)
438{
439 pldm_pdr_record *record;
440 pldm_pdr_record *prev = NULL;
441 int rc = 0;
442 int found;
443 struct pldm_state_sensor_pdr pdr;
444
445 if (!repo) {
446 return -EINVAL;
447 }
448
449 record = repo->first;
450
451 while (record != NULL) {
452 if (!record->data) {
453 continue;
454 }
455
456 rc = decode_pldm_state_sensor_pdr(record->data, record->size,
457 &pdr);
458 if (rc) {
459 return rc;
460 }
461
462 if (record->is_remote != is_remote ||
463 pdr.hdr.type != PLDM_STATE_SENSOR_PDR) {
464 record = record->next;
465 continue;
466 }
467 found = pdr.sensor_id == sensor_id;
468 if (found) {
469 if (record_handle) {
470 *record_handle = record->record_handle;
471 }
472 prev = pldm_pdr_get_prev_record(repo, record);
473 return pldm_pdr_remove_record(repo, record, prev);
474 }
475 record = record->next;
476 }
477 return -ENOENT;
478}
479
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500480LIBPLDM_ABI_TESTING
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500481int pldm_pdr_find_child_container_id_index_range_exclude(
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500482 const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500483 uint8_t child_index, uint32_t range_exclude_start_handle,
484 uint32_t range_exclude_end_handle, uint16_t *container_id)
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500485{
486 pldm_pdr_record *record;
487 if (!repo) {
488 return -EINVAL;
489 }
490
491 for (record = repo->first; record; record = record->next) {
492 bool is_container_entity_instance_number;
493 struct pldm_pdr_entity_association *pdr;
494 bool is_container_entity_type;
495 struct pldm_entity *child;
496 struct pldm_pdr_hdr *hdr;
497 bool in_range;
498
499 // pldm_pdr_add() takes only uint8_t* data as an argument.
500 // The expectation here is the pldm_pdr_hdr is the first field of the record data
501 hdr = (struct pldm_pdr_hdr *)record->data;
502 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
503 continue;
504 }
505 in_range = pldm_record_handle_in_range(
506 record->record_handle, range_exclude_start_handle,
507 range_exclude_end_handle);
508 if (in_range) {
509 continue;
510 }
511
512 // this cast is valid with respect to alignment because
513 // struct pldm_pdr_hdr is declared with __attribute__((packed))
514 pdr = (void *)(record->data + sizeof(struct pldm_pdr_hdr));
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500515 if (child_index >= pdr->num_children) {
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500516 continue;
517 }
Pavithra Barithaya8cf70452023-06-22 04:36:19 -0500518
519 child = (&pdr->children[child_index]);
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500520 is_container_entity_type = pdr->container.entity_type ==
521 entity_type;
522 is_container_entity_instance_number =
523 pdr->container.entity_instance_num == entity_instance;
524 if (is_container_entity_type &&
525 is_container_entity_instance_number) {
526 *container_id = le16toh(child->entity_container_id);
Pavithra Barithayaffd53422023-06-23 23:20:48 -0500527 return 0;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500528 }
529 }
Matt Johnstonae05d5e2024-10-11 14:51:12 +0800530 return -ENOENT;
Pavithra Barithaya5dc02572023-05-19 09:24:36 -0500531}
532
Pavithra Barithaya8cfeb472025-02-25 10:43:34 +0530533LIBPLDM_CC_NONNULL
534static int decode_pldm_state_effecter_pdr(uint8_t *data, uint32_t size,
535 struct pldm_state_effecter_pdr *pdr)
536{
537 PLDM_MSGBUF_DEFINE_P(buf);
538 int rc = 0;
539 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_state_effecter_pdr),
540 (uint8_t *)data, size);
541 if (rc) {
542 return rc;
543 }
544
545 pldm_msgbuf_extract(buf, pdr->hdr.record_handle);
546 pldm_msgbuf_extract(buf, pdr->hdr.version);
547 pldm_msgbuf_extract(buf, pdr->hdr.type);
548 pldm_msgbuf_extract(buf, pdr->hdr.record_change_num);
549 pldm_msgbuf_extract(buf, pdr->hdr.length);
550 pldm_msgbuf_extract(buf, pdr->terminus_handle);
551 pldm_msgbuf_extract(buf, pdr->effecter_id);
552 pldm_msgbuf_extract(buf, pdr->entity_type);
553 pldm_msgbuf_extract(buf, pdr->entity_instance);
554 pldm_msgbuf_extract(buf, pdr->container_id);
555 pldm_msgbuf_extract(buf, pdr->effecter_semantic_id);
556 pldm_msgbuf_extract(buf, pdr->effecter_init);
557 pldm_msgbuf_extract(buf, pdr->has_description_pdr);
558 pldm_msgbuf_extract(buf, pdr->composite_effecter_count);
559
560 return pldm_msgbuf_complete(buf);
561}
562
563LIBPLDM_ABI_TESTING
564int pldm_pdr_delete_by_effecter_id(pldm_pdr *repo, uint16_t effecter_id,
565 bool is_remote, uint32_t *record_handle)
566{
567 pldm_pdr_record *record;
568 pldm_pdr_record *prev = NULL;
569 int rc = 0;
570 int found;
571 struct pldm_state_effecter_pdr pdr;
572
573 if (!repo) {
574 return -EINVAL;
575 }
576 record = repo->first;
577
578 while (record != NULL) {
579 if (!record->data) {
580 continue;
581 }
582
583 rc = decode_pldm_state_effecter_pdr(record->data, record->size,
584 &pdr);
585 if (rc) {
586 return rc;
587 }
588
589 if (record->is_remote != is_remote ||
590 pdr.hdr.type != PLDM_STATE_EFFECTER_PDR) {
591 record = record->next;
592 continue;
593 }
594 found = pdr.effecter_id == effecter_id;
595 if (found) {
596 if (record_handle) {
597 *record_handle = record->record_handle;
598 }
599 prev = pldm_pdr_get_prev_record(repo, record);
600 return pldm_pdr_remove_record(repo, record, prev);
601 }
602 record = record->next;
603 }
604 return rc;
605}
606
Pavithra Barithaya869c2872025-04-30 14:32:18 +0530607LIBPLDM_ABI_STABLE
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530608int pldm_pdr_delete_by_record_handle(pldm_pdr *repo, uint32_t record_handle,
609 bool is_remote)
610{
611 pldm_pdr_record *record;
612 pldm_pdr_record *prev = NULL;
613 int rc = 0;
614 uint16_t rec_handle = 0;
615
616 if (!repo) {
617 return -EINVAL;
618 }
619 record = repo->first;
620
621 while (record != NULL) {
622 struct pldm_msgbuf _buf;
623 struct pldm_msgbuf *buf = &_buf;
624 rc = pldm_msgbuf_init_errno(buf, sizeof(struct pldm_pdr_hdr),
625 record->data, record->size);
626
627 if (rc) {
628 return rc;
629 }
630 if ((rc = pldm_msgbuf_extract(buf, rec_handle))) {
631 return rc;
632 }
633 if (record->is_remote == is_remote &&
634 rec_handle == record_handle) {
635 prev = pldm_pdr_get_prev_record(repo, record);
636 return pldm_pdr_remove_record(repo, record, prev);
637 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +1030638 rc = pldm_msgbuf_complete(buf);
Pavithra Barithaya5192e2e2025-02-26 16:50:06 +0530639 if (rc) {
640 return rc;
641 }
642 record = record->next;
643 }
644 return -ENOENT;
645}
646
Andrew Jeffery9c766792022-08-10 23:12:49 +0930647typedef struct pldm_entity_association_tree {
648 pldm_entity_node *root;
649 uint16_t last_used_container_id;
650} pldm_entity_association_tree;
651
652typedef struct pldm_entity_node {
653 pldm_entity entity;
654 pldm_entity parent;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600655 uint16_t remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930656 pldm_entity_node *first_child;
657 pldm_entity_node *next_sibling;
658 uint8_t association_type;
659} pldm_entity_node;
660
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930661LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930662pldm_entity pldm_entity_extract(pldm_entity_node *node)
663{
664 assert(node != NULL);
665
666 return node->entity;
667}
668
Pavithra Barithayadef8e022023-08-16 00:31:06 -0500669LIBPLDM_ABI_STABLE
Andrew Jeffery15b88182023-06-30 13:29:17 +0930670uint16_t
671pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity)
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600672{
Andrew Jeffery15b88182023-06-30 13:29:17 +0930673 assert(entity != NULL);
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600674
Andrew Jeffery15b88182023-06-30 13:29:17 +0930675 return entity->remote_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600676}
677
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930678LIBPLDM_ABI_STABLE
Andrew Jeffery319304f2023-04-05 13:53:18 +0930679pldm_entity_association_tree *pldm_entity_association_tree_init(void)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930680{
681 pldm_entity_association_tree *tree =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930682 malloc(sizeof(pldm_entity_association_tree));
Andrew Jefferyc40037d2023-06-30 13:50:12 +0930683 if (!tree) {
684 return NULL;
685 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930686 tree->root = NULL;
687 tree->last_used_container_id = 0;
688
689 return tree;
690}
691
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930692LIBPLDM_CC_NONNULL
Andrew Jeffery9c766792022-08-10 23:12:49 +0930693static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
694 uint16_t entity_type)
695{
Andrew Jeffery9c766792022-08-10 23:12:49 +0930696 /* Insert after the the last node that matches the input entity type, or
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +0530697 * at the end if no such match occurs
Andrew Jeffery9c766792022-08-10 23:12:49 +0930698 */
699 while (start->next_sibling != NULL) {
700 uint16_t this_type = start->entity.entity_type;
701 pldm_entity_node *next = start->next_sibling;
702 if (this_type == entity_type &&
703 (this_type != next->entity.entity_type)) {
704 break;
705 }
706 start = start->next_sibling;
707 }
708
709 return start;
710}
711
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930712LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930713pldm_entity_node *pldm_entity_association_tree_add(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930714 pldm_entity_association_tree *tree, pldm_entity *entity,
715 uint16_t entity_instance_number, pldm_entity_node *parent,
716 uint8_t association_type)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930717{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500718 return pldm_entity_association_tree_add_entity(tree, entity,
719 entity_instance_number,
720 parent, association_type,
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600721 false, true, 0xffff);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500722}
723
Pavithra Barithaya1ade87f2023-07-28 04:03:01 -0500724LIBPLDM_ABI_STABLE
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500725pldm_entity_node *pldm_entity_association_tree_add_entity(
726 pldm_entity_association_tree *tree, pldm_entity *entity,
727 uint16_t entity_instance_number, pldm_entity_node *parent,
728 uint8_t association_type, bool is_remote, bool is_update_container_id,
729 uint16_t container_id)
730{
731 if ((!tree) || (!entity)) {
732 return NULL;
733 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930734
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600735 if (entity_instance_number != 0xffff && parent != NULL) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930736 pldm_entity node;
737 node.entity_type = entity->entity_type;
738 node.entity_instance_num = entity_instance_number;
739 if (pldm_is_current_parent_child(parent, &node)) {
740 return NULL;
741 }
742 }
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500743 if (association_type != PLDM_ENTITY_ASSOCIAION_PHYSICAL &&
744 association_type != PLDM_ENTITY_ASSOCIAION_LOGICAL) {
745 return NULL;
746 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930747 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500748 if (!node) {
749 return NULL;
750 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930751 node->first_child = NULL;
752 node->next_sibling = NULL;
753 node->parent.entity_type = 0;
754 node->parent.entity_instance_num = 0;
755 node->parent.entity_container_id = 0;
756 node->entity.entity_type = entity->entity_type;
757 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600758 entity_instance_number != 0xffff ? entity_instance_number : 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930759 node->association_type = association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600760 node->remote_container_id = 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930761 if (tree->root == NULL) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500762 if (parent != NULL) {
763 free(node);
764 return NULL;
765 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930766 tree->root = node;
767 /* container_id 0 here indicates this is the top-most entry */
768 node->entity.entity_container_id = 0;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600769 node->remote_container_id = node->entity.entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930770 } else if (parent != NULL && parent->first_child == NULL) {
Andrew Jeffery70623822023-08-10 16:05:27 +0930771 /* Ensure next_container_id() will yield a valid ID */
772 if (tree->last_used_container_id == UINT16_MAX) {
773 free(node);
774 return NULL;
775 }
776
Andrew Jeffery9c766792022-08-10 23:12:49 +0930777 parent->first_child = node;
778 node->parent = parent->entity;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500779
780 if (is_remote) {
781 node->remote_container_id = entity->entity_container_id;
782 }
783 if (is_update_container_id) {
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600784 if (container_id != 0xffff) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500785 node->entity.entity_container_id = container_id;
786 } else {
Andrew Jeffery05507772024-09-22 20:55:55 +0930787 /* We will have returned above */
788 assert(tree->last_used_container_id !=
789 UINT16_MAX);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500790 node->entity.entity_container_id =
Andrew Jeffery05507772024-09-22 20:55:55 +0930791 ++tree->last_used_container_id;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500792 }
793 } else {
794 node->entity.entity_container_id =
795 entity->entity_container_id;
796 }
797
798 if (!is_remote) {
799 node->remote_container_id =
800 node->entity.entity_container_id;
801 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930802 } else {
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930803 pldm_entity_node *start = parent == NULL ? tree->root :
804 parent->first_child;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930805 pldm_entity_node *prev =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930806 find_insertion_at(start, entity->entity_type);
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500807 if (!prev) {
808 free(node);
809 return NULL;
810 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930811 pldm_entity_node *next = prev->next_sibling;
812 if (prev->entity.entity_type == entity->entity_type) {
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500813 if (prev->entity.entity_instance_num == UINT16_MAX) {
814 free(node);
815 return NULL;
816 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930817 node->entity.entity_instance_num =
Pavithra Barithayadc7d3b52024-02-06 23:46:49 -0600818 entity_instance_number != 0xffff ?
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930819 entity_instance_number :
820 prev->entity.entity_instance_num + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930821 }
822 prev->next_sibling = node;
823 node->parent = prev->parent;
824 node->next_sibling = next;
825 node->entity.entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930826 prev->entity.entity_container_id;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -0600827 node->remote_container_id = entity->entity_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930828 }
829 entity->entity_instance_num = node->entity.entity_instance_num;
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -0500830 if (is_update_container_id) {
831 entity->entity_container_id = node->entity.entity_container_id;
832 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930833 return node;
834}
835
836static void get_num_nodes(pldm_entity_node *node, size_t *num)
837{
838 if (node == NULL) {
839 return;
840 }
841
842 ++(*num);
843 get_num_nodes(node->next_sibling, num);
844 get_num_nodes(node->first_child, num);
845}
846
847static void entity_association_tree_visit(pldm_entity_node *node,
848 pldm_entity *entities, size_t *index)
849{
850 if (node == NULL) {
851 return;
852 }
853
854 pldm_entity *entity = &entities[*index];
855 ++(*index);
856 entity->entity_type = node->entity.entity_type;
857 entity->entity_instance_num = node->entity.entity_instance_num;
858 entity->entity_container_id = node->entity.entity_container_id;
859
860 entity_association_tree_visit(node->next_sibling, entities, index);
861 entity_association_tree_visit(node->first_child, entities, index);
862}
863
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930864LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930865void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
866 pldm_entity **entities, size_t *size)
867{
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930868 if (!tree || !entities || !size) {
869 return;
870 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930871
872 *size = 0;
873 if (tree->root == NULL) {
874 return;
875 }
876
877 get_num_nodes(tree->root, size);
878 *entities = malloc(*size * sizeof(pldm_entity));
Andrew Jefferycd17e5c2023-06-30 14:06:18 +0930879 if (!entities) {
880 return;
881 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930882 size_t index = 0;
883 entity_association_tree_visit(tree->root, *entities, &index);
884}
885
886static void entity_association_tree_destroy(pldm_entity_node *node)
887{
888 if (node == NULL) {
889 return;
890 }
891
892 entity_association_tree_destroy(node->next_sibling);
893 entity_association_tree_destroy(node->first_child);
894 free(node);
895}
896
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930897LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930898void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
899{
Andrew Jefferya89e0152023-06-30 14:24:05 +0930900 if (!tree) {
901 return;
902 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930903
904 entity_association_tree_destroy(tree->root);
905 free(tree);
906}
907
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930908LIBPLDM_ABI_STABLE
909bool pldm_entity_is_node_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930910{
911 assert(node != NULL);
912
913 return node->first_child != NULL;
914}
915
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930916LIBPLDM_ABI_STABLE
917pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930918{
919 assert(node != NULL);
920
921 return node->parent;
922}
923
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930924LIBPLDM_ABI_STABLE
925bool pldm_entity_is_exist_parent(pldm_entity_node *node)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930926{
Andrew Jeffery890d37a2024-09-22 20:50:53 +0930927 if (!node) {
928 return false;
929 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930930
931 if (node->parent.entity_type == 0 &&
932 node->parent.entity_instance_num == 0 &&
933 node->parent.entity_container_id == 0) {
934 return false;
935 }
936
937 return true;
938}
939
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930940LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930941uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
942 uint8_t association_type)
943{
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930944 if (!node) {
945 return 0;
946 }
947
Andrew Jeffery6e8a2612023-06-30 15:36:48 +0930948 if (!(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
949 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL)) {
950 return 0;
951 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930952
953 size_t count = 0;
954 pldm_entity_node *curr = node->first_child;
955 while (curr != NULL) {
956 if (curr->association_type == association_type) {
957 ++count;
958 }
959 curr = curr->next_sibling;
960 }
961
962 assert(count < UINT8_MAX);
Andrew Jefferyc83ef862023-07-11 17:16:55 +0930963 return count < UINT8_MAX ? count : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +0930964}
965
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +0930966LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +0930967bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
968{
Andrew Jeffery375d9fc2023-06-30 15:45:54 +0930969 if (!parent || !node) {
970 return false;
971 }
Andrew Jeffery9c766792022-08-10 23:12:49 +0930972
973 pldm_entity_node *curr = parent->first_child;
974 while (curr != NULL) {
975 if (node->entity_type == curr->entity.entity_type &&
976 node->entity_instance_num ==
Andrew Jeffery37dd6a32023-05-12 16:04:06 +0930977 curr->entity.entity_instance_num) {
Andrew Jeffery9c766792022-08-10 23:12:49 +0930978 return true;
979 }
980 curr = curr->next_sibling;
981 }
982
983 return false;
984}
985
Archana Kakanibc40dd52024-08-02 00:10:44 -0500986static int64_t entity_association_pdr_add_children(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -0500987 pldm_entity_node *curr, pldm_pdr *repo, uint16_t size,
988 uint8_t contained_count, uint8_t association_type, bool is_remote,
989 uint16_t terminus_handle, uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +0930990{
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930991 uint8_t *start;
992 uint8_t *pdr;
Archana Kakanibc40dd52024-08-02 00:10:44 -0500993 int64_t rc;
Andrew Jeffery5c49f162024-09-22 15:45:35 +0930994
995 pdr = calloc(1, size);
996 if (!pdr) {
997 return -ENOMEM;
998 }
999
1000 start = pdr;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301001
1002 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
1003 hdr->version = 1;
Pavithra Barithaya39eb3222023-11-17 03:30:27 -06001004 hdr->record_handle = record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301005 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
1006 hdr->record_change_num = 0;
1007 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
1008 start += sizeof(struct pldm_pdr_hdr);
1009
1010 uint16_t *container_id = (uint16_t *)start;
1011 *container_id = htole16(curr->first_child->entity.entity_container_id);
1012 start += sizeof(uint16_t);
1013 *start = association_type;
1014 start += sizeof(uint8_t);
1015
1016 pldm_entity *entity = (pldm_entity *)start;
1017 entity->entity_type = htole16(curr->entity.entity_type);
1018 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
1019 entity->entity_container_id = htole16(curr->entity.entity_container_id);
1020 start += sizeof(pldm_entity);
1021
1022 *start = contained_count;
1023 start += sizeof(uint8_t);
1024
1025 pldm_entity_node *node = curr->first_child;
1026 while (node != NULL) {
1027 if (node->association_type == association_type) {
1028 pldm_entity *entity = (pldm_entity *)start;
1029 entity->entity_type = htole16(node->entity.entity_type);
1030 entity->entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301031 htole16(node->entity.entity_instance_num);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301032 entity->entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301033 htole16(node->entity.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301034 start += sizeof(pldm_entity);
1035 }
1036 node = node->next_sibling;
1037 }
1038
Andrew Jeffery5c49f162024-09-22 15:45:35 +09301039 rc = pldm_pdr_add(repo, pdr, size, is_remote, terminus_handle,
1040 &record_handle);
1041 free(pdr);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001042 return (rc < 0) ? rc : record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301043}
1044
Archana Kakanibc40dd52024-08-02 00:10:44 -05001045static int64_t entity_association_pdr_add_entry(pldm_entity_node *curr,
1046 pldm_pdr *repo, bool is_remote,
1047 uint16_t terminus_handle,
1048 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301049{
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301050 uint8_t num_logical_children = pldm_entity_get_num_children(
1051 curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
1052 uint8_t num_physical_children = pldm_entity_get_num_children(
1053 curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001054 int64_t rc;
1055
1056 if (!num_logical_children && !num_physical_children) {
1057 if (record_handle == 0) {
1058 return -EINVAL;
1059 }
1060 return record_handle - 1;
1061 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301062
1063 if (num_logical_children) {
1064 uint16_t logical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301065 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
1066 sizeof(uint8_t) + sizeof(pldm_entity) +
1067 sizeof(uint8_t) +
1068 (num_logical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +09301069 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301070 curr, repo, logical_pdr_size, num_logical_children,
1071 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001072 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +09301073 if (rc < 0) {
1074 return rc;
1075 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001076 if (num_physical_children) {
1077 if (rc >= UINT32_MAX) {
1078 return -EOVERFLOW;
1079 }
1080 record_handle = rc + 1;
1081 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301082 }
1083
1084 if (num_physical_children) {
1085 uint16_t physical_pdr_size =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301086 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
1087 sizeof(uint8_t) + sizeof(pldm_entity) +
1088 sizeof(uint8_t) +
1089 (num_physical_children * sizeof(pldm_entity));
Andrew Jeffery65945992023-07-17 15:04:21 +09301090 rc = entity_association_pdr_add_children(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301091 curr, repo, physical_pdr_size, num_physical_children,
1092 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote,
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001093 terminus_handle, record_handle);
Andrew Jeffery65945992023-07-17 15:04:21 +09301094 if (rc < 0) {
1095 return rc;
1096 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001097 record_handle = rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301098 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301099
Archana Kakanibc40dd52024-08-02 00:10:44 -05001100 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301101}
1102
Andrew Jefferyd09b1af2023-07-17 12:39:16 +09301103static bool is_present(pldm_entity entity, pldm_entity **entities,
1104 size_t num_entities)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301105{
1106 if (entities == NULL || num_entities == 0) {
1107 return true;
1108 }
1109 size_t i = 0;
1110 while (i < num_entities) {
1111 if ((*entities + i)->entity_type == entity.entity_type) {
1112 return true;
1113 }
1114 i++;
1115 }
1116 return false;
1117}
1118
Archana Kakanibc40dd52024-08-02 00:10:44 -05001119static int64_t entity_association_pdr_add(pldm_entity_node *curr,
1120 pldm_pdr *repo,
1121 pldm_entity **entities,
1122 size_t num_entities, bool is_remote,
1123 uint16_t terminus_handle,
1124 uint32_t record_handle)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301125{
Archana Kakanibc40dd52024-08-02 00:10:44 -05001126 int64_t rc;
Andrew Jeffery65945992023-07-17 15:04:21 +09301127
Andrew Jeffery9c766792022-08-10 23:12:49 +09301128 if (curr == NULL) {
Archana Kakanibc40dd52024-08-02 00:10:44 -05001129 // entity_association_pdr_add function gets called
1130 // recursively for the siblings and children of the
1131 // entity. This causes NULL current entity node, and the
1132 // record handle is returned
1133 return record_handle;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301134 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301135
1136 if (is_present(curr->entity, entities, num_entities)) {
1137 rc = entity_association_pdr_add_entry(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001138 curr, repo, is_remote, terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001139 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301140 return rc;
1141 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001142 if (rc >= UINT32_MAX) {
1143 return -EOVERFLOW;
1144 }
1145 record_handle = rc + 1;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301146 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301147
1148 rc = entity_association_pdr_add(curr->next_sibling, repo, entities,
1149 num_entities, is_remote,
1150 terminus_handle, record_handle);
Archana Kakanibc40dd52024-08-02 00:10:44 -05001151 if (rc < 0) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301152 return rc;
1153 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001154 // entity_association_pdr_add return record handle in success
1155 // case. If the pdr gets added to the repo, new record handle
1156 // will be returned. Below check confirms if the pdr is added
1157 // to the repo and increments the record handle
1158 if (record_handle != rc) {
1159 if (rc >= UINT32_MAX) {
1160 return -EOVERFLOW;
1161 }
1162 record_handle = rc + 1;
1163 }
Andrew Jeffery65945992023-07-17 15:04:21 +09301164
Archana Kakanibc40dd52024-08-02 00:10:44 -05001165 rc = entity_association_pdr_add(curr->first_child, repo, entities,
1166 num_entities, is_remote,
1167 terminus_handle, record_handle);
1168 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301169}
1170
Andrew Jeffery096685b2023-07-17 17:36:14 +09301171LIBPLDM_ABI_STABLE
Andrew Jefferyd72ea4b2024-06-24 21:33:33 +09301172int pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
1173 pldm_pdr *repo, bool is_remote,
1174 uint16_t terminus_handle)
Andrew Jeffery65945992023-07-17 15:04:21 +09301175{
Andrew Jefferyc7883482023-06-30 15:52:04 +09301176 if (!tree || !repo) {
Andrew Jeffery65945992023-07-17 15:04:21 +09301177 return 0;
Andrew Jefferyc7883482023-06-30 15:52:04 +09301178 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001179 int64_t rc = entity_association_pdr_add(tree->root, repo, NULL, 0,
1180 is_remote, terminus_handle, 0);
1181 assert(rc >= INT_MIN);
1182 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301183}
1184
Andrew Jeffery1354a6e2023-07-07 10:34:38 +09301185LIBPLDM_ABI_STABLE
Andrew Jefferyaa49b712024-06-24 21:43:52 +09301186int pldm_entity_association_pdr_add_from_node(
Andrew Jefferycc394522023-07-03 12:49:31 +09301187 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1188 size_t num_entities, bool is_remote, uint16_t terminus_handle)
1189{
1190 return pldm_entity_association_pdr_add_from_node_with_record_handle(
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001191 node, repo, entities, num_entities, is_remote, terminus_handle,
1192 0);
1193}
1194
Pavithra Barithaya3a267052023-11-13 05:01:36 -06001195LIBPLDM_ABI_STABLE
Pavithra Barithaya25ddbcc2023-05-19 08:28:59 -05001196int pldm_entity_association_pdr_add_from_node_with_record_handle(
1197 pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
1198 size_t num_entities, bool is_remote, uint16_t terminus_handle,
1199 uint32_t record_handle)
1200{
1201 if (!node || !repo || !entities) {
1202 return -EINVAL;
1203 }
1204
Archana Kakanibc40dd52024-08-02 00:10:44 -05001205 int64_t rc = entity_association_pdr_add(node, repo, entities,
1206 num_entities, is_remote,
1207 terminus_handle, record_handle);
1208
1209 assert(rc >= INT_MIN);
1210 return (rc < 0) ? (int)rc : 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301211}
1212
Andrew Jeffery643c4432023-07-17 15:36:03 +09301213static void find_entity_ref_in_tree(pldm_entity_node *tree_node,
1214 pldm_entity entity, pldm_entity_node **node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301215{
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001216 bool is_entity_container_id;
1217 bool is_entity_instance_num;
1218 bool is_type;
1219
Andrew Jeffery9c766792022-08-10 23:12:49 +09301220 if (tree_node == NULL) {
1221 return;
1222 }
1223
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001224 is_type = tree_node->entity.entity_type == entity.entity_type;
1225 is_entity_instance_num = tree_node->entity.entity_instance_num ==
1226 entity.entity_instance_num;
1227 is_entity_container_id = tree_node->entity.entity_container_id ==
1228 entity.entity_container_id;
1229
1230 if (is_type && is_entity_instance_num && is_entity_container_id) {
Andrew Jeffery9c766792022-08-10 23:12:49 +09301231 *node = tree_node;
1232 return;
1233 }
1234
1235 find_entity_ref_in_tree(tree_node->first_child, entity, node);
1236 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
1237}
1238
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301239LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301240void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
1241 pldm_entity entity, pldm_entity_node **node)
1242{
Andrew Jefferyba47e832023-07-03 11:41:03 +09301243 if (!tree || !node) {
1244 return;
1245 }
1246
Andrew Jeffery9c766792022-08-10 23:12:49 +09301247 find_entity_ref_in_tree(tree->root, entity, node);
1248}
1249
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301250LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301251void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
1252 uint16_t terminus_handle)
1253{
Andrew Jeffery438dd492023-07-03 11:51:43 +09301254 if (!repo) {
1255 return;
1256 }
1257
Andrew Jeffery9c766792022-08-10 23:12:49 +09301258 bool removed = false;
1259
1260 pldm_pdr_record *record = repo->first;
1261 pldm_pdr_record *prev = NULL;
1262 while (record != NULL) {
1263 pldm_pdr_record *next = record->next;
1264 if (record->terminus_handle == terminus_handle) {
1265 if (repo->first == record) {
1266 repo->first = next;
1267 } else {
1268 prev->next = next;
1269 }
1270 if (repo->last == record) {
1271 repo->last = prev;
1272 }
1273 if (record->data) {
1274 free(record->data);
1275 }
1276 --repo->record_count;
1277 repo->size -= record->size;
1278 free(record);
1279 removed = true;
1280 } else {
1281 prev = record;
1282 }
1283 record = next;
1284 }
1285
1286 if (removed == true) {
1287 record = repo->first;
1288 uint32_t record_handle = 0;
1289 while (record != NULL) {
1290 record->record_handle = ++record_handle;
1291 if (record->data != NULL) {
1292 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301293 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301294 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301295 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301296 }
1297 record = record->next;
1298 }
1299 }
1300}
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301301
1302LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301303void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
1304{
Andrew Jeffery3e1d6592023-07-03 11:57:16 +09301305 if (!repo) {
1306 return;
1307 }
1308
Andrew Jeffery9c766792022-08-10 23:12:49 +09301309 bool removed = false;
1310
1311 pldm_pdr_record *record = repo->first;
1312 pldm_pdr_record *prev = NULL;
1313 while (record != NULL) {
1314 pldm_pdr_record *next = record->next;
1315 if (record->is_remote == true) {
1316 if (repo->first == record) {
1317 repo->first = next;
1318 } else {
1319 prev->next = next;
1320 }
1321 if (repo->last == record) {
1322 repo->last = prev;
1323 }
1324 if (record->data) {
1325 free(record->data);
1326 }
1327 --repo->record_count;
1328 repo->size -= record->size;
1329 free(record);
1330 removed = true;
1331 } else {
1332 prev = record;
1333 }
1334 record = next;
1335 }
1336
1337 if (removed == true) {
1338 record = repo->first;
1339 uint32_t record_handle = 0;
1340 while (record != NULL) {
1341 record->record_handle = ++record_handle;
1342 if (record->data != NULL) {
1343 struct pldm_pdr_hdr *hdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301344 (struct pldm_pdr_hdr *)(record->data);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301345 hdr->record_handle =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301346 htole32(record->record_handle);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301347 }
1348 record = record->next;
1349 }
1350 }
1351}
1352
Pavithra Barithaya4a307bc2023-11-13 04:34:14 -06001353LIBPLDM_ABI_STABLE
Pavithra Barithaya4d694342023-05-19 08:04:41 -05001354pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
1355 uint32_t first, uint32_t last)
1356{
1357 pldm_pdr_record *record = NULL;
1358 pldm_pdr_record *curr;
1359
1360 if (!repo) {
1361 return NULL;
1362 }
1363 for (curr = repo->first; curr; curr = curr->next) {
1364 if (first > curr->record_handle || last < curr->record_handle) {
1365 continue;
1366 }
1367 if (!record || curr->record_handle > record->record_handle) {
1368 record = curr;
1369 }
1370 }
1371
1372 return record;
1373}
1374
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001375static void entity_association_tree_find_if_remote(pldm_entity_node *node,
1376 pldm_entity *entity,
1377 pldm_entity_node **out,
1378 bool is_remote)
1379{
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001380 if (node == NULL) {
1381 return;
1382 }
1383 bool is_entity_type;
1384 bool is_entity_instance_num;
1385
1386 is_entity_type = node->entity.entity_type == entity->entity_type;
1387 is_entity_instance_num = node->entity.entity_instance_num ==
1388 entity->entity_instance_num;
1389
1390 if (!is_remote ||
1391 node->remote_container_id == entity->entity_container_id) {
1392 if (is_entity_type && is_entity_instance_num) {
1393 entity->entity_container_id =
1394 node->entity.entity_container_id;
1395 *out = node;
1396 return;
1397 }
1398 }
1399 entity_association_tree_find_if_remote(node->next_sibling, entity, out,
1400 is_remote);
1401 entity_association_tree_find_if_remote(node->first_child, entity, out,
1402 is_remote);
1403}
1404
Pavithra Barithaya7570fae2023-07-28 02:15:16 -05001405LIBPLDM_ABI_STABLE
Sagar Srinivas302d9ff2023-08-01 02:11:30 -05001406pldm_entity_node *pldm_entity_association_tree_find_with_locality(
1407 pldm_entity_association_tree *tree, pldm_entity *entity, bool is_remote)
Pavithra Barithaya9947f9d2023-05-18 05:20:24 -05001408{
1409 if (!tree || !entity) {
1410 return NULL;
1411 }
1412 pldm_entity_node *node = NULL;
1413 entity_association_tree_find_if_remote(tree->root, entity, &node,
1414 is_remote);
1415 return node;
1416}
1417
Andrew Jeffery54d91e82023-07-17 15:37:12 +09301418static void entity_association_tree_find(pldm_entity_node *node,
1419 pldm_entity *entity,
1420 pldm_entity_node **out)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301421{
1422 if (node == NULL) {
1423 return;
1424 }
1425
1426 if (node->entity.entity_type == entity->entity_type &&
1427 node->entity.entity_instance_num == entity->entity_instance_num) {
1428 entity->entity_container_id = node->entity.entity_container_id;
1429 *out = node;
1430 return;
1431 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301432 entity_association_tree_find(node->next_sibling, entity, out);
1433 entity_association_tree_find(node->first_child, entity, out);
1434}
1435
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301436LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301437pldm_entity_node *
1438pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
1439 pldm_entity *entity)
1440{
Andrew Jeffery94e364d2023-07-03 12:26:59 +09301441 if (!tree || !entity) {
1442 return NULL;
1443 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301444
1445 pldm_entity_node *node = NULL;
1446 entity_association_tree_find(tree->root, entity, &node);
1447 return node;
1448}
1449
Andrew Jeffery60582152024-09-22 21:16:38 +09301450static int entity_association_tree_copy(pldm_entity_node *org_node,
1451 pldm_entity_node **new_node)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301452{
Andrew Jeffery60582152024-09-22 21:16:38 +09301453 int rc;
1454
Andrew Jeffery9c766792022-08-10 23:12:49 +09301455 if (org_node == NULL) {
Andrew Jeffery60582152024-09-22 21:16:38 +09301456 return 0;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301457 }
Andrew Jeffery60582152024-09-22 21:16:38 +09301458
Andrew Jeffery9c766792022-08-10 23:12:49 +09301459 *new_node = malloc(sizeof(pldm_entity_node));
Andrew Jeffery60582152024-09-22 21:16:38 +09301460 if (!*new_node) {
1461 return -ENOMEM;
1462 }
1463
Andrew Jeffery9c766792022-08-10 23:12:49 +09301464 (*new_node)->parent = org_node->parent;
1465 (*new_node)->entity = org_node->entity;
1466 (*new_node)->association_type = org_node->association_type;
ArchanaKakani39bd2ea2023-02-02 02:39:18 -06001467 (*new_node)->remote_container_id = org_node->remote_container_id;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301468 (*new_node)->first_child = NULL;
1469 (*new_node)->next_sibling = NULL;
Andrew Jeffery60582152024-09-22 21:16:38 +09301470
1471 rc = entity_association_tree_copy(org_node->first_child,
1472 &((*new_node)->first_child));
1473 if (rc) {
1474 goto cleanup;
1475 }
1476
1477 rc = entity_association_tree_copy(org_node->next_sibling,
1478 &((*new_node)->next_sibling));
1479 if (rc) {
1480 entity_association_tree_destroy((*new_node)->first_child);
1481 goto cleanup;
1482 }
1483
1484 return 0;
1485
1486cleanup:
1487 free(*new_node);
1488 *new_node = NULL;
1489 return rc;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301490}
1491
Andrew Jeffery36324f62024-09-25 13:41:41 +09301492LIBPLDM_ABI_DEPRECATED_UNSAFE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301493void pldm_entity_association_tree_copy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301494 pldm_entity_association_tree *org_tree,
1495 pldm_entity_association_tree *new_tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301496{
George Liuc6c391d2023-11-09 10:13:34 +08001497 assert(org_tree != NULL);
1498 assert(new_tree != NULL);
1499
Andrew Jeffery9c766792022-08-10 23:12:49 +09301500 new_tree->last_used_container_id = org_tree->last_used_container_id;
1501 entity_association_tree_copy(org_tree->root, &(new_tree->root));
1502}
1503
Andrew Jeffery60582152024-09-22 21:16:38 +09301504LIBPLDM_ABI_TESTING
1505int pldm_entity_association_tree_copy_root_check(
1506 pldm_entity_association_tree *org_tree,
1507 pldm_entity_association_tree *new_tree)
1508{
1509 if (!org_tree || !new_tree) {
1510 return -EINVAL;
1511 }
1512
1513 new_tree->last_used_container_id = org_tree->last_used_container_id;
1514 return entity_association_tree_copy(org_tree->root, &(new_tree->root));
1515}
1516
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301517LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301518void pldm_entity_association_tree_destroy_root(
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301519 pldm_entity_association_tree *tree)
Andrew Jeffery9c766792022-08-10 23:12:49 +09301520{
Andrew Jeffery85d7a052023-07-03 12:29:24 +09301521 if (!tree) {
1522 return;
1523 }
1524
Andrew Jeffery9c766792022-08-10 23:12:49 +09301525 entity_association_tree_destroy(tree->root);
1526 tree->last_used_container_id = 0;
1527 tree->root = NULL;
1528}
1529
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301530LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301531bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
1532{
1533 return ((tree->root == NULL) ? true : false);
1534}
1535
Andrew Jeffery9d2a1c62023-06-05 13:02:16 +09301536LIBPLDM_ABI_STABLE
Andrew Jeffery9c766792022-08-10 23:12:49 +09301537void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
1538 size_t *num_entities,
1539 pldm_entity **entities)
1540{
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301541 if (!pdr || !num_entities || !entities) {
1542 return;
1543 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001544 if (pdr_len < PDR_ENTITY_ASSOCIATION_MIN_SIZE) {
Andrew Jeffery3a5c46b2023-07-03 12:39:59 +09301545 return;
1546 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301547
1548 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
Andrew Jeffery918973f2023-07-11 17:11:03 +09301549 if (hdr->type != PLDM_PDR_ENTITY_ASSOCIATION) {
1550 return;
1551 }
Andrew Jeffery9c766792022-08-10 23:12:49 +09301552
1553 const uint8_t *start = (uint8_t *)pdr;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301554
1555 if (UINTPTR_MAX - (uintptr_t)start <
1556 (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1557 return;
1558 }
1559
1560 if (pdr_len < (sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length))) {
1561 return;
1562 }
1563
1564 const uint8_t *end =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301565 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301566 start += sizeof(struct pldm_pdr_hdr);
Andrew Jeffery9e566592024-10-02 16:38:51 +09301567
1568 if ((uintptr_t)end - (uintptr_t)start <
1569 sizeof(struct pldm_pdr_entity_association)) {
1570 return;
1571 }
Archana Kakanibc40dd52024-08-02 00:10:44 -05001572
Andrew Jeffery9c766792022-08-10 23:12:49 +09301573 struct pldm_pdr_entity_association *entity_association_pdr =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301574 (struct pldm_pdr_entity_association *)start;
Andrew Jeffery9e566592024-10-02 16:38:51 +09301575
Archana Kakanibc40dd52024-08-02 00:10:44 -05001576 size_t l_num_entities = entity_association_pdr->num_children;
1577
1578 if (l_num_entities == 0) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301579 return;
1580 }
Andrew Jeffery8f33a1d2024-10-11 18:01:19 +10301581
Archana Kakanibc40dd52024-08-02 00:10:44 -05001582 if ((pdr_len - sizeof(struct pldm_pdr_hdr)) / sizeof(pldm_entity) <
1583 l_num_entities) {
Andrew Jeffery918973f2023-07-11 17:11:03 +09301584 return;
1585 }
Andrew Jeffery9e566592024-10-02 16:38:51 +09301586
Archana Kakanibc40dd52024-08-02 00:10:44 -05001587 if (l_num_entities >= (size_t)UINT8_MAX) {
Andrew Jeffery9e566592024-10-02 16:38:51 +09301588 return;
1589 }
1590
Archana Kakanibc40dd52024-08-02 00:10:44 -05001591 l_num_entities++;
1592
Andrew Jeffery9e566592024-10-02 16:38:51 +09301593 pldm_entity *l_entities = calloc(l_num_entities, sizeof(pldm_entity));
Andrew Jeffery918973f2023-07-11 17:11:03 +09301594 if (!l_entities) {
1595 return;
1596 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301597 l_entities[0].entity_type =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301598 le16toh(entity_association_pdr->container.entity_type);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301599 l_entities[0].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301600 le16toh(entity_association_pdr->container.entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301601 l_entities[0].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301602 le16toh(entity_association_pdr->container.entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301603 pldm_entity *curr_entity = entity_association_pdr->children;
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301604 for (size_t i = 1; i < l_num_entities; i++, curr_entity++) {
1605 l_entities[i].entity_type = le16toh(curr_entity->entity_type);
1606 l_entities[i].entity_instance_num =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301607 le16toh(curr_entity->entity_instance_num);
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301608 l_entities[i].entity_container_id =
Andrew Jeffery37dd6a32023-05-12 16:04:06 +09301609 le16toh(curr_entity->entity_container_id);
Andrew Jeffery9c766792022-08-10 23:12:49 +09301610 }
Andrew Jeffery0dbaa702023-07-11 16:58:25 +09301611
1612 *num_entities = l_num_entities;
1613 *entities = l_entities;
Andrew Jeffery9c766792022-08-10 23:12:49 +09301614}
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001615
Manojkiran Eda9e3a5d42024-06-17 16:06:42 +05301616/* Find the position of record in pldm_pdr repo and place new_record in
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001617 * the same position.
1618 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301619LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001620static int pldm_pdr_replace_record(pldm_pdr *repo, pldm_pdr_record *record,
1621 pldm_pdr_record *prev,
1622 pldm_pdr_record *new_record)
1623{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001624 if (repo->size < record->size) {
1625 return -EOVERFLOW;
1626 }
1627
1628 if (repo->size + new_record->size < new_record->size) {
1629 return -EOVERFLOW;
1630 }
1631
1632 if (repo->first == record) {
1633 repo->first = new_record;
1634 } else {
1635 prev->next = new_record;
1636 }
1637 new_record->next = record->next;
1638
1639 if (repo->last == record) {
1640 repo->last = new_record;
1641 }
1642
1643 repo->size = (repo->size - record->size) + new_record->size;
1644 return 0;
1645}
1646
1647/* Insert a new record to pldm_pdr repo to a position that comes after
1648 * pldm_pdr_record record.
1649 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301650LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001651static int pldm_pdr_insert_record(pldm_pdr *repo, pldm_pdr_record *record,
1652 pldm_pdr_record *new_record)
1653{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001654 if (repo->size + new_record->size < new_record->size) {
1655 return -EOVERFLOW;
1656 }
1657
1658 if (repo->record_count == UINT32_MAX) {
1659 return -EOVERFLOW;
1660 }
1661
1662 new_record->next = record->next;
1663 record->next = new_record;
1664
1665 if (repo->last == record) {
1666 repo->last = new_record;
1667 }
1668
1669 repo->size = repo->size + new_record->size;
1670 ++repo->record_count;
1671 return 0;
1672}
1673
1674/* Find the position of PDR when its record handle is known
1675 */
Andrew Jeffery890d37a2024-09-22 20:50:53 +09301676LIBPLDM_CC_NONNULL
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001677static bool pldm_pdr_find_record_by_handle(pldm_pdr_record **record,
1678 pldm_pdr_record **prev,
1679 uint32_t record_handle)
1680{
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001681 while (*record != NULL) {
1682 if ((*record)->record_handle == record_handle) {
1683 return true;
1684 }
1685 *prev = *record;
1686 *record = (*record)->next;
1687 }
1688 return false;
1689}
1690
1691LIBPLDM_ABI_TESTING
1692int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
1693 pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle)
1694{
1695 if (!repo || !entity) {
1696 return -EINVAL;
1697 }
1698
1699 pldm_pdr_record *record = repo->first;
1700 pldm_pdr_record *prev = repo->first;
1701 int rc = 0;
1702 uint16_t header_length = 0;
1703 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10301704 PLDM_MSGBUF_DEFINE_P(src);
1705 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001706
1707 pldm_pdr_find_record_by_handle(&record, &prev, pdr_record_handle);
1708
1709 if (!record) {
1710 return -EINVAL;
1711 }
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001712
1713 // check if adding another entity to record causes overflow before
1714 // allocating memory for new_record.
1715 if (record->size + sizeof(pldm_entity) < sizeof(pldm_entity)) {
1716 return -EOVERFLOW;
1717 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301718
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001719 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1720 if (!new_record) {
1721 return -ENOMEM;
1722 }
1723
1724 new_record->data = malloc(record->size + sizeof(pldm_entity));
1725 if (!new_record->data) {
1726 rc = -ENOMEM;
1727 goto cleanup_new_record;
1728 }
1729
1730 new_record->record_handle = record->record_handle;
1731 new_record->size = record->size + sizeof(struct pldm_entity);
1732 new_record->is_remote = record->is_remote;
1733
Andrew Jefferya1896962025-03-03 21:41:25 +10301734 // Initialize msg buffer for record and record->data
1735 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1736 record->data, record->size);
1737 if (rc) {
1738 goto cleanup_new_record_data;
1739 }
1740
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001741 // Initialize new PDR record with data from original PDR record.
1742 // Start with adding the header of original PDR
1743 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1744 new_record->data, new_record->size);
1745 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301746 goto cleanup_src_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001747 }
1748
1749 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
1750 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
1751 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
1752 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
1753 // extract the header length from record and increment size with
1754 // size of pldm_entity before inserting the value into new_record.
1755 rc = pldm_msgbuf_extract(src, header_length);
1756 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301757 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001758 }
1759 static_assert(UINT16_MAX < (SIZE_MAX - sizeof(pldm_entity)),
1760 "Fix the following bounds check.");
1761 if (header_length + sizeof(pldm_entity) > UINT16_MAX) {
1762 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301763 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001764 }
1765 header_length += sizeof(pldm_entity);
1766 pldm_msgbuf_insert(dst, header_length);
1767 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
1768 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
1769 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
1770 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
1771 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
1772 // extract value of number of children from record and increment it
1773 // by 1 before insert the value to new record.
1774 rc = pldm_msgbuf_extract(src, num_children);
1775 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301776 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001777 }
1778 if (num_children == UINT8_MAX) {
1779 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10301780 goto cleanup_dst_msgbuf;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001781 }
1782 num_children += 1;
1783 pldm_msgbuf_insert(dst, num_children);
1784 //Add all children of original PDR to new PDR
1785 for (int i = 0; i < num_children - 1; i++) {
1786 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1787 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1788 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1789 }
1790
1791 // Add new contained entity as a child of new PDR
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301792 rc = pldm_msgbuf_complete(src);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001793 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301794 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001795 goto cleanup_new_record_data;
1796 }
1797 rc = pldm_msgbuf_init_errno(src, sizeof(struct pldm_entity), entity,
1798 sizeof(struct pldm_entity));
1799 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301800 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001801 goto cleanup_new_record_data;
1802 }
1803 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_type);
1804 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_instance_num);
1805 pldm_msgbuf_copy(dst, src, uint16_t, child_entity_container_id);
1806
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301807 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001808 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301809 goto cleanup_src_msgbuf;
1810 }
1811 rc = pldm_msgbuf_complete(src);
1812 if (rc) {
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001813 goto cleanup_new_record_data;
1814 }
1815
1816 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
1817 if (rc) {
1818 goto cleanup_new_record_data;
1819 }
1820
1821 free(record->data);
1822 free(record);
1823 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301824cleanup_dst_msgbuf:
1825 rc = pldm_msgbuf_discard(dst, rc);
1826cleanup_src_msgbuf:
1827 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001828cleanup_new_record_data:
1829 free(new_record->data);
1830cleanup_new_record:
1831 free(new_record);
1832 return rc;
1833}
1834
1835LIBPLDM_ABI_TESTING
1836int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
1837 uint32_t pdr_record_handle,
1838 pldm_entity *parent,
1839 pldm_entity *entity,
1840 uint32_t *entity_record_handle)
1841{
1842 if (!repo || !parent || !entity || !entity_record_handle) {
1843 return -EINVAL;
1844 }
1845
1846 if (pdr_record_handle == UINT32_MAX) {
1847 return -EOVERFLOW;
1848 }
1849
1850 bool pdr_added = false;
1851 uint16_t new_pdr_size;
1852 uint16_t container_id = 0;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001853 void *container_id_addr;
Andrew Jefferya1896962025-03-03 21:41:25 +10301854 PLDM_MSGBUF_DEFINE_P(dst);
1855 PLDM_MSGBUF_DEFINE_P(src_p);
1856 PLDM_MSGBUF_DEFINE_P(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001857 int rc = 0;
1858
1859 pldm_pdr_record *prev = repo->first;
1860 pldm_pdr_record *record = repo->first;
1861 pdr_added = pldm_pdr_find_record_by_handle(&record, &prev,
1862 pdr_record_handle);
1863 if (!pdr_added) {
1864 return -ENOENT;
1865 }
1866
1867 static_assert(PDR_ENTITY_ASSOCIATION_MIN_SIZE < UINT16_MAX,
1868 "Truncation ahead");
1869 new_pdr_size = PDR_ENTITY_ASSOCIATION_MIN_SIZE;
1870 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
1871 if (!new_record) {
1872 return -ENOMEM;
1873 }
1874
1875 new_record->data = malloc(new_pdr_size);
1876 if (!new_record->data) {
1877 rc = -ENOMEM;
1878 goto cleanup_new_record;
1879 }
1880
1881 // Initialise new PDR to be added with the header, size and handle.
1882 // Set the position of new PDR
1883 *entity_record_handle = pdr_record_handle + 1;
1884 new_record->record_handle = *entity_record_handle;
1885 new_record->size = new_pdr_size;
1886 new_record->is_remote = false;
1887
1888 rc = pldm_msgbuf_init_errno(dst, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
1889 new_record->data, new_record->size);
1890 if (rc) {
1891 goto cleanup_new_record_data;
1892 }
1893
1894 // header record handle
1895 pldm_msgbuf_insert(dst, *entity_record_handle);
1896 // header version
1897 pldm_msgbuf_insert_uint8(dst, 1);
1898 // header type
1899 pldm_msgbuf_insert_uint8(dst, PLDM_PDR_ENTITY_ASSOCIATION);
1900 // header change number
1901 pldm_msgbuf_insert_uint16(dst, 0);
1902 // header length
1903 pldm_msgbuf_insert_uint16(dst,
1904 (new_pdr_size - sizeof(struct pldm_pdr_hdr)));
1905
1906 // Data for new PDR is obtained from parent PDR and new contained entity
1907 // is added as the child
1908 rc = pldm_msgbuf_init_errno(src_p, sizeof(struct pldm_entity), parent,
1909 sizeof(*parent));
1910 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301911 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001912 }
1913
1914 rc = pldm_msgbuf_init_errno(src_c, sizeof(struct pldm_entity), entity,
1915 sizeof(*entity));
1916 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301917 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001918 }
1919
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001920 container_id_addr = NULL;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001921 // extract pointer for container ID and save the address
1922 rc = pldm_msgbuf_span_required(dst, sizeof(container_id),
1923 (void **)&container_id_addr);
1924 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301925 goto cleanup_msgbuf_src_c;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001926 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001927 assert(container_id_addr);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001928 pldm_msgbuf_insert_uint8(dst, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
1929 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_type);
1930 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_instance_num);
1931 pldm_msgbuf_copy(dst, src_p, uint16_t, entity_container_id);
1932 // number of children
1933 pldm_msgbuf_insert_uint8(dst, 1);
1934
1935 // Add new entity as child
1936 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_type);
1937 pldm_msgbuf_copy(dst, src_c, uint16_t, child_entity_instance_num);
1938 // Extract and insert child entity container ID and add same value to
1939 // container ID of entity
1940 pldm_msgbuf_extract(src_c, container_id);
1941 pldm_msgbuf_insert(dst, container_id);
1942 container_id = htole16(container_id);
1943 memcpy(container_id_addr, &container_id, sizeof(uint16_t));
1944
Andrew Jefferya1896962025-03-03 21:41:25 +10301945 rc = pldm_msgbuf_complete(src_c);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001946 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301947 goto cleanup_msgbuf_src_p;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001948 }
Andrew Jeffery70d21c92025-03-05 12:59:42 +10301949 rc = pldm_msgbuf_complete(src_p);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001950 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10301951 goto cleanup_msgbuf_dst;
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001952 }
Andrew Jefferya1896962025-03-03 21:41:25 +10301953 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001954 if (rc) {
1955 goto cleanup_new_record_data;
1956 }
1957
1958 rc = pldm_pdr_insert_record(repo, record, new_record);
1959 if (rc) {
1960 goto cleanup_new_record_data;
1961 }
1962
1963 return rc;
Andrew Jefferya1896962025-03-03 21:41:25 +10301964cleanup_msgbuf_src_c:
1965 rc = pldm_msgbuf_discard(src_c, rc);
1966cleanup_msgbuf_src_p:
1967 rc = pldm_msgbuf_discard(src_p, rc);
1968cleanup_msgbuf_dst:
1969 rc = pldm_msgbuf_discard(dst, rc);
Varsha Kaverappa37552b92024-02-12 05:06:06 -06001970cleanup_new_record_data:
1971 free(new_record->data);
1972cleanup_new_record:
1973 free(new_record);
1974 return rc;
1975}
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001976
1977LIBPLDM_CC_NONNULL
1978static bool pldm_entity_cmp(const struct pldm_entity *l,
1979 const struct pldm_entity *r)
1980{
1981 return l->entity_type == r->entity_type &&
1982 l->entity_instance_num == r->entity_instance_num &&
1983 l->entity_container_id == r->entity_container_id;
1984}
1985
1986/* Find record handle of a PDR record from PDR repo and
1987 * entity
1988 */
1989LIBPLDM_CC_NONNULL
1990static int pldm_entity_association_find_record_handle_by_entity(
1991 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
1992 uint32_t *record_handle)
1993{
1994 uint8_t num_children = 0;
1995 uint8_t hdr_type = 0;
1996 int rc = 0;
1997 size_t skip_data_size = 0;
1998 pldm_pdr_record *record = repo->first;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05001999
2000 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302001 PLDM_MSGBUF_DEFINE_P(dst);
2002
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002003 rc = pldm_msgbuf_init_errno(dst,
2004 PDR_ENTITY_ASSOCIATION_MIN_SIZE,
2005 record->data, record->size);
2006 if (rc) {
2007 return rc;
2008 }
2009 skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2010 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302011 rc = pldm_msgbuf_extract(dst, hdr_type);
2012 if (rc) {
2013 return pldm_msgbuf_discard(dst, rc);
2014 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002015 if (record->is_remote != is_remote ||
2016 hdr_type != PLDM_PDR_ENTITY_ASSOCIATION) {
2017 goto cleanup;
2018 }
2019 skip_data_size = sizeof(uint16_t) + sizeof(uint16_t) +
2020 sizeof(uint16_t) + sizeof(uint8_t) +
2021 sizeof(struct pldm_entity);
2022 pldm_msgbuf_span_required(dst, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302023 rc = pldm_msgbuf_extract(dst, num_children);
2024 if (rc) {
2025 return pldm_msgbuf_discard(dst, rc);
2026 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002027 for (int i = 0; i < num_children; ++i) {
2028 struct pldm_entity e;
2029
2030 if ((rc = pldm_msgbuf_extract(dst, e.entity_type)) ||
2031 (rc = pldm_msgbuf_extract(dst,
2032 e.entity_instance_num)) ||
2033 (rc = pldm_msgbuf_extract(dst,
2034 e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302035 return pldm_msgbuf_discard(dst, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002036 }
2037
2038 if (pldm_entity_cmp(entity, &e)) {
2039 *record_handle = record->record_handle;
Andrew Jefferya1896962025-03-03 21:41:25 +10302040 return pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002041 }
2042 }
2043 cleanup:
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302044 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002045 if (rc) {
2046 return rc;
2047 }
2048 record = record->next;
2049 }
2050 return 0;
2051}
2052
2053LIBPLDM_ABI_TESTING
2054int pldm_entity_association_pdr_remove_contained_entity(
2055 pldm_pdr *repo, pldm_entity *entity, bool is_remote,
2056 uint32_t *pdr_record_handle)
2057{
2058 uint16_t header_length = 0;
2059 uint8_t num_children = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10302060 PLDM_MSGBUF_DEFINE_P(src);
2061 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002062 int rc;
2063 pldm_pdr_record *record;
2064 pldm_pdr_record *prev;
2065
2066 if (!repo || !entity || !pdr_record_handle) {
2067 return -EINVAL;
2068 }
2069 record = repo->first;
2070 prev = repo->first;
2071
2072 rc = pldm_entity_association_find_record_handle_by_entity(
2073 repo, entity, is_remote, pdr_record_handle);
2074 if (rc) {
2075 return rc;
2076 }
2077 pldm_pdr_find_record_by_handle(&record, &prev, *pdr_record_handle);
2078 if (!record) {
2079 return -EINVAL;
2080 }
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002081 // check if removing an entity from record causes overflow before
2082 // allocating memory for new_record.
2083 if (record->size < sizeof(pldm_entity)) {
2084 return -EOVERFLOW;
2085 }
2086 pldm_pdr_record *new_record = malloc(sizeof(pldm_pdr_record));
2087 if (!new_record) {
2088 return -ENOMEM;
2089 }
2090 new_record->data = malloc(record->size - sizeof(pldm_entity));
2091 if (!new_record->data) {
2092 rc = -ENOMEM;
2093 goto cleanup_new_record;
2094 }
2095 new_record->record_handle = record->record_handle;
2096 new_record->size = record->size - sizeof(struct pldm_entity);
2097 new_record->is_remote = record->is_remote;
2098
Andrew Jefferya1896962025-03-03 21:41:25 +10302099 // Initialize msg buffer for record and record->data
2100 rc = pldm_msgbuf_init_errno(src, PDR_ENTITY_ASSOCIATION_MIN_SIZE,
2101 record->data, record->size);
2102 if (rc) {
2103 goto cleanup_new_record_data;
2104 }
2105
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002106 // Initialize new PDR record with data from original PDR record.
2107 // Start with adding the header of original PDR
Archana Kakani94e2d752024-12-12 08:22:55 -06002108 rc = pldm_msgbuf_init_errno(
2109 dst, (PDR_ENTITY_ASSOCIATION_MIN_SIZE - sizeof(pldm_entity)),
2110 new_record->data, new_record->size);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002111 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302112 goto cleanup_msgbuf_src;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002113 }
2114 pldm_msgbuf_copy(dst, src, uint32_t, hdr_record_handle);
2115 pldm_msgbuf_copy(dst, src, uint8_t, hdr_version);
2116 pldm_msgbuf_copy(dst, src, uint8_t, hdr_type);
2117 pldm_msgbuf_copy(dst, src, uint16_t, hdr_record_change_num);
2118 // extract the header length from record and decrement size with
2119 // size of pldm_entity before inserting the value into new_record.
2120 rc = pldm_msgbuf_extract(src, header_length);
2121 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302122 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002123 }
2124 if (header_length < sizeof(pldm_entity)) {
2125 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302126 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002127 }
2128 header_length -= sizeof(pldm_entity);
2129 pldm_msgbuf_insert(dst, header_length);
2130 pldm_msgbuf_copy(dst, src, uint16_t, container_id);
2131 pldm_msgbuf_copy(dst, src, uint8_t, association_type);
2132 pldm_msgbuf_copy(dst, src, uint16_t, entity_type);
2133 pldm_msgbuf_copy(dst, src, uint16_t, entity_instance_num);
2134 pldm_msgbuf_copy(dst, src, uint16_t, entity_container_id);
2135 // extract value of number of children from record and decrement it
2136 // by 1 before insert the value to new record.
2137 rc = pldm_msgbuf_extract(src, num_children);
2138 if (rc) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302139 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002140 }
2141 if (num_children == 1) {
Archana Kakani94e2d752024-12-12 08:22:55 -06002142 // This is the last child which is getting removed so we need to delete the Entity Association PDR.
2143 pldm_pdr_remove_record(repo, record,
2144 pldm_pdr_get_prev_record(repo, record));
Andrew Jefferya1896962025-03-03 21:41:25 +10302145 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002146 } else if (num_children < 1) {
2147 rc = -EOVERFLOW;
Andrew Jefferya1896962025-03-03 21:41:25 +10302148 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002149 }
2150 num_children -= 1;
2151 pldm_msgbuf_insert(dst, num_children);
2152 //Add all children of original PDR to new PDR
2153 for (int i = 0; i < num_children + 1; ++i) {
2154 struct pldm_entity e;
2155
2156 if ((rc = pldm_msgbuf_extract(src, e.entity_type)) ||
2157 (rc = pldm_msgbuf_extract(src, e.entity_instance_num)) ||
2158 (rc = pldm_msgbuf_extract(src, e.entity_container_id))) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302159 goto cleanup_msgbuf_dst;
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002160 }
2161
2162 if (pldm_entity_cmp(entity, &e)) {
2163 continue;
2164 }
2165
2166 pldm_msgbuf_insert(dst, e.entity_type);
2167 pldm_msgbuf_insert(dst, e.entity_instance_num);
2168 pldm_msgbuf_insert(dst, e.entity_container_id);
2169 }
2170
Andrew Jefferya1896962025-03-03 21:41:25 +10302171 rc = pldm_msgbuf_complete(dst);
2172 if (rc) {
2173 goto cleanup_msgbuf_src;
2174 }
2175
2176 rc = pldm_msgbuf_complete(src);
2177 if (rc) {
2178 goto cleanup_new_record_data;
2179 }
2180
2181 rc = pldm_pdr_replace_record(repo, record, prev, new_record);
2182 if (rc) {
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002183 goto cleanup_new_record_data;
2184 }
2185
2186 free(record->data);
2187 free(record);
2188 return rc;
2189
Andrew Jefferya1896962025-03-03 21:41:25 +10302190cleanup_msgbuf_dst:
2191 rc = pldm_msgbuf_discard(dst, rc);
2192cleanup_msgbuf_src:
2193 rc = pldm_msgbuf_discard(src, rc);
Varsha Kaverappab31e4c62024-06-25 06:45:46 -05002194cleanup_new_record_data:
2195 free(new_record->data);
2196cleanup_new_record:
2197 free(new_record);
2198 return rc;
2199}
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002200
2201/* API to find the PDR record that is previous to a given PLDM PDR
2202 * record in a given PLDM PDR repository
2203 */
2204LIBPLDM_CC_NONNULL
2205static pldm_pdr_record *pldm_pdr_get_prev_record(pldm_pdr *repo,
2206 pldm_pdr_record *record)
2207{
2208 pldm_pdr_record *prev = NULL;
2209 pldm_pdr_record *curr = repo->first;
2210
2211 while (curr != NULL) {
2212 if (curr->record_handle == record->record_handle) {
2213 break;
2214 }
2215 prev = curr;
2216 curr = curr->next;
2217 }
2218 return prev;
2219}
2220
2221/* API to check if a PLDM PDR record is present in a PLDM PDR repository
2222 */
2223LIBPLDM_CC_NONNULL
2224static bool is_prev_record_present(pldm_pdr *repo, pldm_pdr_record *record)
2225{
2226 if (repo->first == record) {
2227 return true;
2228 }
2229
2230 return pldm_pdr_get_prev_record(repo, record) != NULL;
2231}
2232
2233/* API to check if FRU RSI of record matches the given record set identifier.
2234 * Returns 1 if the provided FRU record matches the provided record set identifier,
2235 * 0 if it does not, otherwise -EINVAL if the arguments are invalid.
2236 */
2237LIBPLDM_CC_NONNULL
2238static int pldm_pdr_record_matches_fru_rsi(const pldm_pdr_record *record,
2239 uint16_t rsi)
2240{
2241 uint16_t record_fru_rsi = 0;
2242 uint8_t *skip_data = NULL;
2243 uint8_t skip_data_size = 0;
Andrew Jefferya1896962025-03-03 21:41:25 +10302244 PLDM_MSGBUF_DEFINE_P(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002245 int rc = 0;
2246
2247 rc = pldm_msgbuf_init_errno(dst, PDR_FRU_RECORD_SET_MIN_SIZE,
2248 record->data, record->size);
2249 if (rc) {
2250 return rc;
2251 }
2252 skip_data_size = sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t);
2253 pldm_msgbuf_span_required(dst, skip_data_size, (void **)&skip_data);
2254 pldm_msgbuf_extract(dst, record_fru_rsi);
2255
Andrew Jeffery70d21c92025-03-05 12:59:42 +10302256 rc = pldm_msgbuf_complete(dst);
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002257 if (rc) {
2258 return rc;
2259 }
2260 return record_fru_rsi == rsi;
2261}
2262
2263/* API to remove PLDM PDR record from a PLDM PDR repository
2264 */
2265LIBPLDM_CC_NONNULL_ARGS(1, 2)
2266static int pldm_pdr_remove_record(pldm_pdr *repo, pldm_pdr_record *record,
2267 pldm_pdr_record *prev)
2268{
2269 if (!is_prev_record_present(repo, record)) {
2270 return -EINVAL;
2271 }
2272
2273 assert(repo->size >= record->size);
2274 if (repo->size < record->size) {
2275 return -EOVERFLOW;
2276 }
2277
2278 if (repo->first == record) {
2279 repo->first = record->next;
2280 } else {
2281 if (prev != NULL) {
2282 prev->next = record->next;
2283 }
2284 }
2285
2286 if (repo->last == record) {
2287 repo->last = prev;
2288 if (prev != NULL) {
2289 prev->next = NULL;
2290 }
2291 }
2292 repo->record_count -= 1;
2293 repo->size -= record->size;
2294 free(record->data);
2295 free(record);
2296
2297 return 0;
2298}
2299
2300LIBPLDM_ABI_TESTING
2301int pldm_pdr_remove_fru_record_set_by_rsi(pldm_pdr *repo, uint16_t fru_rsi,
2302 bool is_remote,
2303 uint32_t *record_handle)
2304{
2305 pldm_pdr_record *record;
2306 pldm_pdr_record *prev = NULL;
2307 size_t skip_data_size = sizeof(uint32_t) + sizeof(uint8_t);
2308 uint8_t hdr_type = 0;
2309 int rc = 0;
2310 int match;
2311
2312 if (!repo || !record_handle) {
2313 return -EINVAL;
2314 }
2315 record = repo->first;
2316
2317 while (record != NULL) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302318 PLDM_MSGBUF_DEFINE_P(buf);
2319
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002320 rc = pldm_msgbuf_init_errno(buf, PDR_FRU_RECORD_SET_MIN_SIZE,
2321 record->data, record->size);
2322 if (rc) {
2323 return rc;
2324 }
2325 pldm_msgbuf_span_required(buf, skip_data_size, NULL);
Andrew Jefferya1896962025-03-03 21:41:25 +10302326 pldm_msgbuf_extract(buf, hdr_type);
2327 rc = pldm_msgbuf_complete(buf);
2328 if (rc) {
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002329 return rc;
2330 }
2331 if (record->is_remote != is_remote ||
2332 hdr_type != PLDM_PDR_FRU_RECORD_SET) {
Andrew Jefferya1896962025-03-03 21:41:25 +10302333 goto next;
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002334 }
2335 match = pldm_pdr_record_matches_fru_rsi(record, fru_rsi);
2336 if (match < 0) {
2337 return match;
2338 }
2339 if (match) {
2340 *record_handle = record->record_handle;
2341 prev = pldm_pdr_get_prev_record(repo, record);
2342 return pldm_pdr_remove_record(repo, record, prev);
2343 }
Andrew Jefferya1896962025-03-03 21:41:25 +10302344 next:
Varsha Kaverappa8b53ad92024-06-15 06:36:06 -05002345 record = record->next;
2346 }
2347 return rc;
2348}