blob: eeb98054267661d9df8fb94bd28c63205a960277 [file] [log] [blame]
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -06001#include "pdr.h"
2#include "platform.h"
3#include <assert.h>
4#include <stdlib.h>
5#include <string.h>
6
7typedef struct pldm_pdr_record {
8 uint32_t record_handle;
9 uint32_t size;
10 uint8_t *data;
11 struct pldm_pdr_record *next;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050012 bool is_remote;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060013} pldm_pdr_record;
14
15typedef struct pldm_pdr {
16 uint32_t record_count;
17 uint32_t size;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060018 pldm_pdr_record *first;
19 pldm_pdr_record *last;
20} pldm_pdr;
21
22static inline uint32_t get_next_record_handle(const pldm_pdr *repo,
23 const pldm_pdr_record *record)
24{
25 assert(repo != NULL);
26 assert(record != NULL);
27
28 if (record == repo->last) {
29 return 0;
30 }
31 return record->next->record_handle;
32}
33
34static void add_record(pldm_pdr *repo, pldm_pdr_record *record)
35{
36 assert(repo != NULL);
37 assert(record != NULL);
38
39 if (repo->first == NULL) {
40 assert(repo->last == NULL);
41 repo->first = record;
42 repo->last = record;
43 } else {
44 repo->last->next = record;
45 repo->last = record;
46 }
47 repo->size += record->size;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060048 ++repo->record_count;
49}
50
51static inline uint32_t get_new_record_handle(const pldm_pdr *repo)
52{
53 assert(repo != NULL);
Deepak Kodihallib9848732020-04-21 23:34:01 -050054 uint32_t last_used_hdl =
55 repo->last != NULL ? repo->last->record_handle : 0;
56 assert(last_used_hdl != UINT32_MAX);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060057
Deepak Kodihallib9848732020-04-21 23:34:01 -050058 return last_used_hdl + 1;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060059}
60
61static pldm_pdr_record *make_new_record(const pldm_pdr *repo,
62 const uint8_t *data, uint32_t size,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050063 uint32_t record_handle, bool is_remote)
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060064{
65 assert(repo != NULL);
66 assert(size != 0);
67
68 pldm_pdr_record *record = malloc(sizeof(pldm_pdr_record));
69 assert(record != NULL);
70 record->record_handle =
71 record_handle == 0 ? get_new_record_handle(repo) : record_handle;
72 record->size = size;
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050073 record->is_remote = is_remote;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060074 if (data != NULL) {
75 record->data = malloc(size);
76 assert(record->data != NULL);
77 memcpy(record->data, data, size);
78 /* If record handle is 0, that is an indication for this API to
79 * compute a new handle. For that reason, the computed handle
80 * needs to be populated in the PDR header. For a case where the
81 * caller supplied the record handle, it would exist in the
82 * header already.
83 */
84 if (!record_handle) {
85 struct pldm_pdr_hdr *hdr =
86 (struct pldm_pdr_hdr *)(record->data);
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -050087 hdr->record_handle = htole32(record->record_handle);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060088 }
89 }
90 record->next = NULL;
91
92 return record;
93}
94
95uint32_t pldm_pdr_add(pldm_pdr *repo, const uint8_t *data, uint32_t size,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -050096 uint32_t record_handle, bool is_remote)
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -060097{
98 assert(size != 0);
99 assert(data != NULL);
100
101 pldm_pdr_record *record =
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500102 make_new_record(repo, data, size, record_handle, is_remote);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600103 add_record(repo, record);
104
105 return record->record_handle;
106}
107
108pldm_pdr *pldm_pdr_init()
109{
110 pldm_pdr *repo = malloc(sizeof(pldm_pdr));
111 assert(repo != NULL);
112 repo->record_count = 0;
113 repo->size = 0;
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600114 repo->first = NULL;
115 repo->last = NULL;
116
117 return repo;
118}
119
120void pldm_pdr_destroy(pldm_pdr *repo)
121{
122 assert(repo != NULL);
123
124 pldm_pdr_record *record = repo->first;
125 while (record != NULL) {
126 pldm_pdr_record *next = record->next;
127 if (record->data) {
128 free(record->data);
129 record->data = NULL;
130 }
131 free(record);
132 record = next;
133 }
134 free(repo);
135}
136
137const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
138 uint32_t record_handle,
139 uint8_t **data, uint32_t *size,
140 uint32_t *next_record_handle)
141{
142 assert(repo != NULL);
143 assert(data != NULL);
144 assert(size != NULL);
145 assert(next_record_handle != NULL);
146
147 if (!record_handle && (repo->first != NULL)) {
148 record_handle = repo->first->record_handle;
149 }
150 pldm_pdr_record *record = repo->first;
151 while (record != NULL) {
152 if (record->record_handle == record_handle) {
153 *size = record->size;
154 *data = record->data;
155 *next_record_handle =
156 get_next_record_handle(repo, record);
157 return record;
158 }
159 record = record->next;
160 }
161
162 *size = 0;
163 *next_record_handle = 0;
164 return NULL;
165}
166
167const pldm_pdr_record *
168pldm_pdr_get_next_record(const pldm_pdr *repo,
169 const pldm_pdr_record *curr_record, uint8_t **data,
170 uint32_t *size, uint32_t *next_record_handle)
171{
172 assert(repo != NULL);
173 assert(curr_record != NULL);
174 assert(data != NULL);
175 assert(size != NULL);
176 assert(next_record_handle != NULL);
177
178 if (curr_record == repo->last) {
179 *data = NULL;
180 *size = 0;
181 *next_record_handle = get_next_record_handle(repo, curr_record);
182 return NULL;
183 }
184
185 *next_record_handle = get_next_record_handle(repo, curr_record->next);
186 *data = curr_record->next->data;
187 *size = curr_record->next->size;
188 return curr_record->next;
189}
190
191const pldm_pdr_record *
192pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
193 const pldm_pdr_record *curr_record, uint8_t **data,
194 uint32_t *size)
195{
196 assert(repo != NULL);
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600197
198 pldm_pdr_record *record = repo->first;
199 if (curr_record != NULL) {
200 record = curr_record->next;
201 }
202 while (record != NULL) {
203 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)record->data;
204 if (hdr->type == pdr_type) {
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500205 if (data && size) {
206 *size = record->size;
207 *data = record->data;
208 }
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600209 return record;
210 }
211 record = record->next;
212 }
213
Pavithra Barithayae8beb892020-04-14 23:24:25 -0500214 if (size) {
215 *size = 0;
216 }
Deepak Kodihalli3b02ed82020-02-06 01:18:25 -0600217 return NULL;
218}
219
220uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo)
221{
222 assert(repo != NULL);
223
224 return repo->record_count;
225}
226
227uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo)
228{
229 assert(repo != NULL);
230
231 return repo->size;
232}
233
234uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
235 const pldm_pdr_record *record)
236{
237 assert(repo != NULL);
238 assert(record != NULL);
239
240 return record->record_handle;
241}
Deepak Kodihallidb914672020-02-07 02:47:45 -0600242
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500243inline bool pldm_pdr_record_is_remote(const pldm_pdr_record *record)
244{
245 assert(record != NULL);
246
247 return record->is_remote;
248}
249
Deepak Kodihallidb914672020-02-07 02:47:45 -0600250uint32_t pldm_pdr_add_fru_record_set(pldm_pdr *repo, uint16_t terminus_handle,
251 uint16_t fru_rsi, uint16_t entity_type,
252 uint16_t entity_instance_num,
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600253 uint16_t container_id,
254 uint32_t bmc_record_handle)
Deepak Kodihallidb914672020-02-07 02:47:45 -0600255{
256 uint32_t size = sizeof(struct pldm_pdr_hdr) +
257 sizeof(struct pldm_pdr_fru_record_set);
258 uint8_t data[size];
259
260 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)&data;
261 hdr->version = 1;
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600262 hdr->record_handle = bmc_record_handle;
Deepak Kodihallidb914672020-02-07 02:47:45 -0600263 hdr->type = PLDM_PDR_FRU_RECORD_SET;
264 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500265 hdr->length = htole16(sizeof(struct pldm_pdr_fru_record_set));
Deepak Kodihallidb914672020-02-07 02:47:45 -0600266 struct pldm_pdr_fru_record_set *fru =
267 (struct pldm_pdr_fru_record_set *)((uint8_t *)hdr +
268 sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500269 fru->terminus_handle = htole16(terminus_handle);
270 fru->fru_rsi = htole16(fru_rsi);
271 fru->entity_type = htole16(entity_type);
272 fru->entity_instance_num = htole16(entity_instance_num);
273 fru->container_id = htole16(container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600274
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600275 return pldm_pdr_add(repo, data, size, bmc_record_handle, false);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600276}
277
278const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
279 const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
280 uint16_t *entity_type, uint16_t *entity_instance_num,
281 uint16_t *container_id)
282{
283 assert(terminus_handle != NULL);
284 assert(entity_type != NULL);
285 assert(entity_instance_num != NULL);
286 assert(container_id != NULL);
287
288 uint8_t *data = NULL;
289 uint32_t size = 0;
290 const pldm_pdr_record *curr_record = pldm_pdr_find_record_by_type(
291 repo, PLDM_PDR_FRU_RECORD_SET, NULL, &data, &size);
292 while (curr_record != NULL) {
293 struct pldm_pdr_fru_record_set *fru =
294 (struct pldm_pdr_fru_record_set
295 *)(data + sizeof(struct pldm_pdr_hdr));
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500296 if (fru->fru_rsi == htole16(fru_rsi)) {
297 *terminus_handle = le16toh(fru->terminus_handle);
298 *entity_type = le16toh(fru->entity_type);
299 *entity_instance_num =
300 le16toh(fru->entity_instance_num);
301 *container_id = le16toh(fru->container_id);
Deepak Kodihallidb914672020-02-07 02:47:45 -0600302 return curr_record;
303 }
304 data = NULL;
305 curr_record = pldm_pdr_find_record_by_type(
306 repo, PLDM_PDR_FRU_RECORD_SET, curr_record, &data, &size);
307 }
308
309 *terminus_handle = 0;
310 *entity_type = 0;
311 *entity_instance_num = 0;
312 *container_id = 0;
313
314 return NULL;
315}
Deepak Kodihalli05787052020-03-10 01:54:08 -0500316
Pavithra Barithaya4f2538a2021-03-05 07:32:15 -0600317void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminusHandle,
318 uint8_t tid, uint8_t tlEid, bool validBit)
319{
320 uint8_t *outData = NULL;
321 uint32_t size = 0;
322 const pldm_pdr_record *record;
323 record = pldm_pdr_find_record_by_type(repo, PLDM_TERMINUS_LOCATOR_PDR,
324 NULL, &outData, &size);
325
326 do {
327 if (record != NULL) {
328 struct pldm_terminus_locator_pdr *pdr =
329 (struct pldm_terminus_locator_pdr *)outData;
330 struct pldm_terminus_locator_type_mctp_eid *value =
331 (struct pldm_terminus_locator_type_mctp_eid *)
332 pdr->terminus_locator_value;
333 if (pdr->terminus_handle == terminusHandle &&
334 pdr->tid == tid && value->eid == tlEid) {
335 pdr->validity = validBit;
336 break;
337 }
338 }
339 record = pldm_pdr_find_record_by_type(
340 repo, PLDM_TERMINUS_LOCATOR_PDR, record, &outData, &size);
341 } while (record);
342}
343
Deepak Kodihalli05787052020-03-10 01:54:08 -0500344typedef struct pldm_entity_association_tree {
345 pldm_entity_node *root;
346 uint16_t last_used_container_id;
347} pldm_entity_association_tree;
348
349typedef struct pldm_entity_node {
350 pldm_entity entity;
George Liub6b3cf32021-06-07 16:30:59 +0800351 pldm_entity parent;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500352 pldm_entity_node *first_child;
353 pldm_entity_node *next_sibling;
354 uint8_t association_type;
355} pldm_entity_node;
356
357static inline uint16_t next_container_id(pldm_entity_association_tree *tree)
358{
359 assert(tree != NULL);
360 assert(tree->last_used_container_id != UINT16_MAX);
361
362 return ++tree->last_used_container_id;
363}
364
George Liud9855ab2021-05-13 09:41:31 +0800365pldm_entity pldm_entity_extract(pldm_entity_node *node)
366{
367 assert(node != NULL);
368
369 return node->entity;
370}
371
Deepak Kodihalli05787052020-03-10 01:54:08 -0500372pldm_entity_association_tree *pldm_entity_association_tree_init()
373{
374 pldm_entity_association_tree *tree =
375 malloc(sizeof(pldm_entity_association_tree));
376 assert(tree != NULL);
377 tree->root = NULL;
378 tree->last_used_container_id = 0;
379
380 return tree;
381}
382
383static pldm_entity_node *find_insertion_at(pldm_entity_node *start,
384 uint16_t entity_type)
385{
386 assert(start != NULL);
387
388 /* Insert after the the last node that matches the input entity type, or
389 * at the end if no such match occurrs
390 */
391 while (start->next_sibling != NULL) {
392 uint16_t this_type = start->entity.entity_type;
393 pldm_entity_node *next = start->next_sibling;
394 if (this_type == entity_type &&
395 (this_type != next->entity.entity_type)) {
396 break;
397 }
398 start = start->next_sibling;
399 }
400
401 return start;
402}
403
George Liu64a8f0f2021-06-12 10:56:11 +0800404pldm_entity_node *pldm_entity_association_tree_add(
405 pldm_entity_association_tree *tree, pldm_entity *entity,
406 uint16_t entity_instance_number, pldm_entity_node *parent,
407 uint8_t association_type)
Deepak Kodihalli05787052020-03-10 01:54:08 -0500408{
409 assert(tree != NULL);
George Liu64a8f0f2021-06-12 10:56:11 +0800410 assert(entity != NULL);
411
412 if (entity_instance_number != 0xFFFF && parent != NULL) {
413 pldm_entity node;
414 node.entity_type = entity->entity_type;
415 node.entity_instance_num = entity_instance_number;
416 if (pldm_is_current_parent_child(parent, &node)) {
417 return NULL;
418 }
419 }
420
Deepak Kodihalli05787052020-03-10 01:54:08 -0500421 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
422 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
423 pldm_entity_node *node = malloc(sizeof(pldm_entity_node));
424 assert(node != NULL);
425 node->first_child = NULL;
426 node->next_sibling = NULL;
George Liub6b3cf32021-06-07 16:30:59 +0800427 node->parent.entity_type = 0;
428 node->parent.entity_instance_num = 0;
429 node->parent.entity_container_id = 0;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500430 node->entity.entity_type = entity->entity_type;
George Liu64a8f0f2021-06-12 10:56:11 +0800431 node->entity.entity_instance_num =
432 entity_instance_number != 0xFFFF ? entity_instance_number : 1;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500433 node->association_type = association_type;
434
435 if (tree->root == NULL) {
436 assert(parent == NULL);
437 tree->root = node;
438 /* container_id 0 here indicates this is the top-most entry */
439 node->entity.entity_container_id = 0;
440 } else if (parent != NULL && parent->first_child == NULL) {
441 parent->first_child = node;
George Liub6b3cf32021-06-07 16:30:59 +0800442 node->parent = parent->entity;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500443 node->entity.entity_container_id = next_container_id(tree);
444 } else {
445 pldm_entity_node *start =
446 parent == NULL ? tree->root : parent->first_child;
447 pldm_entity_node *prev =
448 find_insertion_at(start, entity->entity_type);
449 assert(prev != NULL);
450 pldm_entity_node *next = prev->next_sibling;
451 if (prev->entity.entity_type == entity->entity_type) {
452 assert(prev->entity.entity_instance_num != UINT16_MAX);
453 node->entity.entity_instance_num =
George Liu64a8f0f2021-06-12 10:56:11 +0800454 entity_instance_number != 0xFFFF
455 ? entity_instance_number
456 : prev->entity.entity_instance_num + 1;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500457 }
458 prev->next_sibling = node;
George Liufe77eea2021-04-28 15:08:07 +0800459 node->parent = prev->parent;
Deepak Kodihalli05787052020-03-10 01:54:08 -0500460 node->next_sibling = next;
461 node->entity.entity_container_id =
462 prev->entity.entity_container_id;
463 }
464 entity->entity_instance_num = node->entity.entity_instance_num;
465 entity->entity_container_id = node->entity.entity_container_id;
466
467 return node;
468}
469
470static void get_num_nodes(pldm_entity_node *node, size_t *num)
471{
472 if (node == NULL) {
473 return;
474 }
475
476 ++(*num);
477 get_num_nodes(node->next_sibling, num);
478 get_num_nodes(node->first_child, num);
479}
480
481static void entity_association_tree_visit(pldm_entity_node *node,
482 pldm_entity *entities, size_t *index)
483{
484 if (node == NULL) {
485 return;
486 }
487
488 pldm_entity *entity = &entities[*index];
489 ++(*index);
490 entity->entity_type = node->entity.entity_type;
491 entity->entity_instance_num = node->entity.entity_instance_num;
492 entity->entity_container_id = node->entity.entity_container_id;
493
494 entity_association_tree_visit(node->next_sibling, entities, index);
495 entity_association_tree_visit(node->first_child, entities, index);
496}
497
498void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
499 pldm_entity **entities, size_t *size)
500{
501 assert(tree != NULL);
502
503 *size = 0;
504 if (tree->root == NULL) {
505 return;
506 }
507
508 get_num_nodes(tree->root, size);
509 *entities = malloc(*size * sizeof(pldm_entity));
510 size_t index = 0;
511 entity_association_tree_visit(tree->root, *entities, &index);
512}
513
514static void entity_association_tree_destroy(pldm_entity_node *node)
515{
516 if (node == NULL) {
517 return;
518 }
519
520 entity_association_tree_destroy(node->next_sibling);
521 entity_association_tree_destroy(node->first_child);
522 free(node);
523}
524
525void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree)
526{
527 assert(tree != NULL);
528
529 entity_association_tree_destroy(tree->root);
530 free(tree);
531}
532
533inline bool pldm_entity_is_node_parent(pldm_entity_node *node)
534{
535 assert(node != NULL);
536
537 return node->first_child != NULL;
538}
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500539
George Liub6b3cf32021-06-07 16:30:59 +0800540inline pldm_entity pldm_entity_get_parent(pldm_entity_node *node)
George Liufe77eea2021-04-28 15:08:07 +0800541{
542 assert(node != NULL);
543
544 return node->parent;
545}
546
George Liub6b3cf32021-06-07 16:30:59 +0800547inline bool pldm_entity_is_exist_parent(pldm_entity_node *node)
548{
549 assert(node != NULL);
550
551 if (node->parent.entity_type == 0 &&
552 node->parent.entity_instance_num == 0 &&
553 node->parent.entity_container_id == 0) {
554 return false;
555 }
556
557 return true;
558}
559
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500560uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
561 uint8_t association_type)
562{
563 assert(node != NULL);
564 assert(association_type == PLDM_ENTITY_ASSOCIAION_PHYSICAL ||
565 association_type == PLDM_ENTITY_ASSOCIAION_LOGICAL);
566
567 size_t count = 0;
568 pldm_entity_node *curr = node->first_child;
569 while (curr != NULL) {
570 if (curr->association_type == association_type) {
571 ++count;
572 }
573 curr = curr->next_sibling;
574 }
575
576 assert(count < UINT8_MAX);
577 return count;
578}
579
George Liu6a6c3ab2021-06-22 16:12:42 +0800580bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node)
581{
582 assert(parent != NULL);
583 assert(node != NULL);
584
585 pldm_entity_node *curr = parent->first_child;
586 while (curr != NULL) {
587 if (node->entity_type == curr->entity.entity_type &&
588 node->entity_instance_num ==
589 curr->entity.entity_instance_num) {
590
591 return true;
592 }
593 curr = curr->next_sibling;
594 }
595
596 return false;
597}
598
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500599static void _entity_association_pdr_add_entry(pldm_entity_node *curr,
600 pldm_pdr *repo, uint16_t size,
601 uint8_t contained_count,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500602 uint8_t association_type,
603 bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500604{
605 uint8_t pdr[size];
606 uint8_t *start = pdr;
607
608 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)start;
609 hdr->version = 1;
610 hdr->record_handle = 0;
611 hdr->type = PLDM_PDR_ENTITY_ASSOCIATION;
612 hdr->record_change_num = 0;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500613 hdr->length = htole16(size - sizeof(struct pldm_pdr_hdr));
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500614 start += sizeof(struct pldm_pdr_hdr);
615
616 uint16_t *container_id = (uint16_t *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500617 *container_id = htole16(curr->first_child->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500618 start += sizeof(uint16_t);
619 *start = association_type;
620 start += sizeof(uint8_t);
621
622 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500623 entity->entity_type = htole16(curr->entity.entity_type);
624 entity->entity_instance_num = htole16(curr->entity.entity_instance_num);
625 entity->entity_container_id = htole16(curr->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500626 start += sizeof(pldm_entity);
627
628 *start = contained_count;
629 start += sizeof(uint8_t);
630
631 pldm_entity_node *node = curr->first_child;
632 while (node != NULL) {
633 if (node->association_type == association_type) {
634 pldm_entity *entity = (pldm_entity *)start;
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500635 entity->entity_type = htole16(node->entity.entity_type);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500636 entity->entity_instance_num =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500637 htole16(node->entity.entity_instance_num);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500638 entity->entity_container_id =
Deepak Kodihallifb4dd7b2020-03-17 03:27:22 -0500639 htole16(node->entity.entity_container_id);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500640 start += sizeof(pldm_entity);
641 }
642 node = node->next_sibling;
643 }
644
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500645 pldm_pdr_add(repo, pdr, size, 0, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500646}
647
648static void entity_association_pdr_add_entry(pldm_entity_node *curr,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500649 pldm_pdr *repo, bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500650{
651 uint8_t num_logical_children =
652 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_LOGICAL);
653 uint8_t num_physical_children =
654 pldm_entity_get_num_children(curr, PLDM_ENTITY_ASSOCIAION_PHYSICAL);
655
656 if (num_logical_children) {
657 uint16_t logical_pdr_size =
658 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
659 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
660 (num_logical_children * sizeof(pldm_entity));
661 _entity_association_pdr_add_entry(
662 curr, repo, logical_pdr_size, num_logical_children,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500663 PLDM_ENTITY_ASSOCIAION_LOGICAL, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500664 }
665
666 if (num_physical_children) {
667 uint16_t physical_pdr_size =
668 sizeof(struct pldm_pdr_hdr) + sizeof(uint16_t) +
669 sizeof(uint8_t) + sizeof(pldm_entity) + sizeof(uint8_t) +
670 (num_physical_children * sizeof(pldm_entity));
671 _entity_association_pdr_add_entry(
672 curr, repo, physical_pdr_size, num_physical_children,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500673 PLDM_ENTITY_ASSOCIAION_PHYSICAL, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500674 }
675}
676
Sampa Misra719ed392021-06-04 05:15:13 -0500677bool is_present(pldm_entity entity, pldm_entity **entities, size_t num_entities)
678{
679 if (entities == NULL || num_entities == 0) {
680 return true;
681 }
682 size_t i = 0;
683 while (i < num_entities) {
684 if ((*entities + i)->entity_type == entity.entity_type) {
685 return true;
686 }
687 i++;
688 }
689 return false;
690}
691
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500692static void entity_association_pdr_add(pldm_entity_node *curr, pldm_pdr *repo,
Sampa Misra719ed392021-06-04 05:15:13 -0500693 pldm_entity **entities,
694 size_t num_entities, bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500695{
696 if (curr == NULL) {
697 return;
698 }
Sampa Misra719ed392021-06-04 05:15:13 -0500699 bool to_add = true;
700 to_add = is_present(curr->entity, entities, num_entities);
701 if (to_add) {
702 entity_association_pdr_add_entry(curr, repo, is_remote);
703 }
704 entity_association_pdr_add(curr->next_sibling, repo, entities,
705 num_entities, is_remote);
706 entity_association_pdr_add(curr->first_child, repo, entities,
707 num_entities, is_remote);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500708}
709
710void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
Deepak Kodihalli87514cc2020-04-16 09:08:38 -0500711 pldm_pdr *repo, bool is_remote)
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500712{
713 assert(tree != NULL);
714 assert(repo != NULL);
715
Sampa Misra719ed392021-06-04 05:15:13 -0500716 entity_association_pdr_add(tree->root, repo, NULL, 0, is_remote);
717}
718
719void pldm_entity_association_pdr_add_from_node(pldm_entity_node *node,
720 pldm_pdr *repo,
721 pldm_entity **entities,
722 size_t num_entities,
723 bool is_remote)
724{
725 assert(repo != NULL);
726
727 entity_association_pdr_add(node, repo, entities, num_entities,
728 is_remote);
729}
730
731void find_entity_ref_in_tree(pldm_entity_node *tree_node, pldm_entity entity,
732 pldm_entity_node **node)
733{
734 if (tree_node == NULL) {
735 return;
736 }
737
738 if (tree_node->entity.entity_type == entity.entity_type &&
739 tree_node->entity.entity_instance_num ==
740 entity.entity_instance_num) {
741 *node = tree_node;
742 return;
743 }
744
745 find_entity_ref_in_tree(tree_node->first_child, entity, node);
746 find_entity_ref_in_tree(tree_node->next_sibling, entity, node);
747}
748
749void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
750 pldm_entity entity, pldm_entity_node **node)
751{
752 assert(tree != NULL);
753 find_entity_ref_in_tree(tree->root, entity, node);
Deepak Kodihalli0a738f02020-03-10 01:56:21 -0500754}
Deepak Kodihalli3b28ba82020-03-30 07:39:47 -0500755
Deepak Kodihalli4a680932020-04-22 03:31:17 -0500756void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo)
757{
758 assert(repo != NULL);
759 bool removed = false;
760
761 pldm_pdr_record *record = repo->first;
762 pldm_pdr_record *prev = NULL;
763 while (record != NULL) {
764 pldm_pdr_record *next = record->next;
765 if (record->is_remote == true) {
766 if (repo->first == record) {
767 repo->first = next;
768 } else {
769 prev->next = next;
770 }
771 if (repo->last == record) {
772 repo->last = prev;
773 }
774 if (record->data) {
775 free(record->data);
776 }
777 --repo->record_count;
778 repo->size -= record->size;
779 free(record);
780 removed = true;
781 } else {
782 prev = record;
783 }
784 record = next;
785 }
786
787 if (removed == true) {
788 record = repo->first;
789 uint32_t record_handle = 0;
790 while (record != NULL) {
791 record->record_handle = ++record_handle;
792 if (record->data != NULL) {
793 struct pldm_pdr_hdr *hdr =
794 (struct pldm_pdr_hdr *)(record->data);
795 hdr->record_handle =
796 htole32(record->record_handle);
797 }
798 record = record->next;
799 }
800 }
801}
802
Deepak Kodihalli3b28ba82020-03-30 07:39:47 -0500803void entity_association_tree_find(pldm_entity_node *node, pldm_entity *entity,
804 pldm_entity_node **out)
805{
806 if (node == NULL) {
807 return;
808 }
809
810 if (node->entity.entity_type == entity->entity_type &&
811 node->entity.entity_instance_num == entity->entity_instance_num) {
812 entity->entity_container_id = node->entity.entity_container_id;
813 *out = node;
814 return;
815 }
816
817 entity_association_tree_find(node->next_sibling, entity, out);
818 entity_association_tree_find(node->first_child, entity, out);
819}
820
821pldm_entity_node *
822pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
823 pldm_entity *entity)
824{
825 assert(tree != NULL);
826
827 pldm_entity_node *node = NULL;
828 entity_association_tree_find(tree->root, entity, &node);
829 return node;
830}
831
Sampa Misrac073a202021-05-08 10:56:05 -0500832static void entity_association_tree_copy(pldm_entity_node *org_node,
833 pldm_entity_node **new_node)
834{
835 if (org_node == NULL) {
836 return;
837 }
838 *new_node = malloc(sizeof(pldm_entity_node));
George Liub6b3cf32021-06-07 16:30:59 +0800839 (*new_node)->parent = org_node->parent;
Sampa Misrac073a202021-05-08 10:56:05 -0500840 (*new_node)->entity = org_node->entity;
841 (*new_node)->association_type = org_node->association_type;
842 (*new_node)->first_child = NULL;
843 (*new_node)->next_sibling = NULL;
844 entity_association_tree_copy(org_node->first_child,
845 &((*new_node)->first_child));
846 entity_association_tree_copy(org_node->next_sibling,
847 &((*new_node)->next_sibling));
848}
849
850void pldm_entity_association_tree_copy_root(
851 pldm_entity_association_tree *org_tree,
852 pldm_entity_association_tree *new_tree)
853{
854 new_tree->last_used_container_id = org_tree->last_used_container_id;
855 entity_association_tree_copy(org_tree->root, &(new_tree->root));
856}
857
858void pldm_entity_association_tree_destroy_root(
859 pldm_entity_association_tree *tree)
860{
861 assert(tree != NULL);
862 entity_association_tree_destroy(tree->root);
863 tree->last_used_container_id = 0;
864 tree->root = NULL;
865}
866
867bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree)
868{
869 return ((tree->root == NULL) ? true : false);
870}
871
Deepak Kodihalli3b28ba82020-03-30 07:39:47 -0500872void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
873 size_t *num_entities,
874 pldm_entity **entities)
875{
876 assert(pdr != NULL);
877 assert(pdr_len >= sizeof(struct pldm_pdr_hdr) +
878 sizeof(struct pldm_pdr_entity_association));
879
880 struct pldm_pdr_hdr *hdr = (struct pldm_pdr_hdr *)pdr;
881 assert(hdr->type == PLDM_PDR_ENTITY_ASSOCIATION);
882
883 const uint8_t *start = (uint8_t *)pdr;
884 const uint8_t *end =
885 start + sizeof(struct pldm_pdr_hdr) + le16toh(hdr->length);
886 start += sizeof(struct pldm_pdr_hdr);
887 struct pldm_pdr_entity_association *entity_association_pdr =
888 (struct pldm_pdr_entity_association *)start;
889 *num_entities = entity_association_pdr->num_children + 1;
890 assert(*num_entities >= 2);
891 *entities = malloc(sizeof(pldm_entity) * *num_entities);
892 assert(*entities != NULL);
893 assert(start + sizeof(struct pldm_pdr_entity_association) +
894 sizeof(pldm_entity) * (*num_entities - 2) ==
895 end);
896 (*entities)->entity_type =
897 le16toh(entity_association_pdr->container.entity_type);
898 (*entities)->entity_instance_num =
899 le16toh(entity_association_pdr->container.entity_instance_num);
900 (*entities)->entity_container_id =
901 le16toh(entity_association_pdr->container.entity_container_id);
902 pldm_entity *curr_entity = entity_association_pdr->children;
903 size_t i = 1;
904 while (i < *num_entities) {
905 (*entities + i)->entity_type =
906 le16toh(curr_entity->entity_type);
907 (*entities + i)->entity_instance_num =
908 le16toh(curr_entity->entity_instance_num);
909 (*entities + i)->entity_container_id =
910 le16toh(curr_entity->entity_container_id);
911 ++curr_entity;
912 ++i;
913 }
914}