xref: /openbmc/libpldm/include/libpldm/pdr.h (revision 9e3a5d45)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 #ifndef PDR_H
3 #define PDR_H
4 
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8 
9 #include <stdbool.h>
10 #include <stddef.h>
11 #include <stdint.h>
12 
13 /** @struct pldm_pdr
14  *  opaque structure that acts as a handle to a PDR repository
15  */
16 typedef struct pldm_pdr pldm_pdr;
17 
18 /** @struct pldm_pdr_record
19  *  opaque structure that acts as a handle to a PDR record
20  */
21 typedef struct pldm_pdr_record pldm_pdr_record;
22 
23 /* ====================== */
24 /* Common PDR access APIs */
25 /* ====================== */
26 
27 /** @brief Make a new PDR repository
28  *
29  *  @return opaque pointer that acts as a handle to the repository; NULL if no
30  *  repository could be created
31  *
32  *  @note  Caller may make multiple repositories (for its own PDRs, as well as
33  *  for PDRs received by other entities) and can associate the returned handle
34  *  to a PLDM terminus id.
35  */
36 pldm_pdr *pldm_pdr_init(void);
37 
38 /** @brief Destroy a PDR repository (and free up associated resources)
39  *
40  *  @param[in/out] repo - pointer to opaque pointer acting as a PDR repo handle
41  */
42 void pldm_pdr_destroy(pldm_pdr *repo);
43 
44 /** @brief Get number of records in a PDR repository
45  *
46  *  @pre repo must point to a valid object
47  *
48  *  @param[in] repo - opaque pointer acting as a PDR repo handle
49  *
50  *  @return uint32_t - number of records
51  */
52 uint32_t pldm_pdr_get_record_count(const pldm_pdr *repo);
53 
54 /** @brief Get size of a PDR repository, in bytes
55  *
56  *  @pre repo must point to a valid object
57  *
58  *  @param[in] repo - opaque pointer acting as a PDR repo handle
59  *
60  *  @return uint32_t - size in bytes
61  */
62 uint32_t pldm_pdr_get_repo_size(const pldm_pdr *repo);
63 
64 /** @brief Add a PDR record to a PDR repository, or return an error
65  *
66  *  @param[in/out] repo - opaque pointer acting as a PDR repo handle
67  *  @param[in] data - pointer to a PDR record, pointing to a PDR definition as
68  *  per DSP0248. This data is memcpy'd.
69  *  @param[in] size - size of input PDR record in bytes
70  *  @param[in] is_remote - if true, then the PDR is not from this terminus
71  *  @param[in] terminus_handle - terminus handle of the input PDR record
72  *  @param[in,out] record_handle - record handle of input PDR record. If this is set to 0 then a
73  *  record handle is computed. The computed handle is assigned to both the PDR record and back into
74  *  record_handle for the caller to consume.
75  *
76  *  @return 0 on success, -EINVAL if the arguments are invalid, -ENOMEM if an internal memory
77  *  allocation fails, or -EOVERFLOW if a record handle could not be allocated
78  */
79 int pldm_pdr_add_check(pldm_pdr *repo, const uint8_t *data, uint32_t size,
80 		       bool is_remote, uint16_t terminus_handle,
81 		       uint32_t *record_handle);
82 
83 /** @brief Get record handle of a PDR record
84  *
85  *  @pre repo must point to a valid object
86  *  @pre record must point to a valid object
87  *
88  *  @param[in] repo - opaque pointer acting as a PDR repo handle
89  *  @param[in] record - opaque pointer acting as a PDR record handle
90  *
91  *  @return uint32_t - record handle assigned to PDR record; 0 if record is not
92  *  found
93  */
94 uint32_t pldm_pdr_get_record_handle(const pldm_pdr *repo,
95 				    const pldm_pdr_record *record);
96 
97 /** @brief Find PDR record by record handle
98  *
99  *  @param[in] repo - opaque pointer acting as a PDR repo handle
100  *  @param[in] record_handle - input record handle
101  *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
102  *                        return
103  *  @param[out] size - *size will be size of PDR record
104  *  @param[out] next_record_handle - *next_record_handle will be the record
105  *  handle of record next to the returned PDR record
106  *
107  *  @return opaque pointer acting as PDR record handle, will be NULL if record
108  *  was not found
109  */
110 const pldm_pdr_record *pldm_pdr_find_record(const pldm_pdr *repo,
111 					    uint32_t record_handle,
112 					    uint8_t **data, uint32_t *size,
113 					    uint32_t *next_record_handle);
114 
115 /** @brief Get PDR record next to input PDR record
116  *
117  *  @param[in] repo - opaque pointer acting as a PDR repo handle
118  *  @param[in] curr_record - opaque pointer acting as a PDR record handle
119  *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
120  *                        return
121  *  @param[out] size - *size will be size of PDR record
122  *  @param[out] next_record_handle - *next_record_handle will be the record
123  *  handle of record nect to the returned PDR record
124  *
125  *  @return opaque pointer acting as PDR record handle, will be NULL if record
126  *  was not found
127  */
128 const pldm_pdr_record *
129 pldm_pdr_get_next_record(const pldm_pdr *repo,
130 			 const pldm_pdr_record *curr_record, uint8_t **data,
131 			 uint32_t *size, uint32_t *next_record_handle);
132 
133 /** @brief Find (first) PDR record by PDR type
134  *
135  *  @param[in] repo - opaque pointer acting as a PDR repo handle
136  *  @param[in] pdr_type - PDR type number as per DSP0248
137  *  @param[in] curr_record - opaque pointer acting as a PDR record handle; if
138  *  not NULL, then search will begin from this record's next record
139  *  @param[in/out] data - will point to PDR record data (as per DSP0248) on
140  *                        return, if input is not NULL
141  *  @param[out] size - *size will be size of PDR record, if input is not NULL
142  *
143  *  @return opaque pointer acting as PDR record handle, will be NULL if record
144  *  was not found
145  */
146 const pldm_pdr_record *
147 pldm_pdr_find_record_by_type(const pldm_pdr *repo, uint8_t pdr_type,
148 			     const pldm_pdr_record *curr_record, uint8_t **data,
149 			     uint32_t *size);
150 
151 /** @brief Determine if a record is a remote record
152  *
153  *  @pre record must point to a valid object
154  *
155  *  @return true if the record is a remote record, false otherwise.
156  */
157 bool pldm_pdr_record_is_remote(const pldm_pdr_record *record);
158 
159 /** @brief Remove all PDR records that belong to a remote terminus
160  *
161  *  @param[in] repo - opaque pointer acting as a PDR repo handle
162  *
163  *  If repo is NULL then there are no PDRs that can be removed.
164  */
165 void pldm_pdr_remove_remote_pdrs(pldm_pdr *repo);
166 
167 /** @brief Remove all remote PDR's that belong to a specific terminus
168  *         handle
169  *  @param[in] repo - opaque pointer acting as a PDR repo handle
170  *  @param[in] terminus_handle - Terminus Handle of the remove PLDM terminus
171  *
172  *  If repo is NULL there are no PDRs that can be removed.
173  */
174 void pldm_pdr_remove_pdrs_by_terminus_handle(pldm_pdr *repo,
175 					     uint16_t terminus_handle);
176 
177 /** @brief Update the validity of TL PDR - the validity is decided based on
178  * whether the valid bit is set or not as per the spec DSP0248
179  *
180  * @param[in] repo - opaque pointer acting as a PDR repo handle
181  * @param[in] terminus_handle - PLDM terminus handle
182  * @param[in] tid - Terminus ID
183  * @param[in] tl_eid - MCTP endpoint EID
184  * @param[in] valid - validity bit of TLPDR
185  */
186 /* NOLINTNEXTLINE(readability-identifier-naming) */
187 void pldm_pdr_update_TL_pdr(const pldm_pdr *repo, uint16_t terminus_handle,
188 			    uint8_t tid, uint8_t tl_eid, bool valid);
189 
190 /** @brief Find the last record within the particular range
191  * of record handles
192  *
193  *  @param[in] repo - pointer acting as a PDR repo handle
194  *  @param[in] first - first record handle value of the records in the range
195  *  @param[in] last - last record handle value of the records in the range
196  *
197  *  @return pointer to the PDR record,will be NULL if record was not
198  *  found
199  */
200 pldm_pdr_record *pldm_pdr_find_last_in_range(const pldm_pdr *repo,
201 					     uint32_t first, uint32_t last);
202 
203 /** @brief find the container ID of the contained entity which is not in the
204  *  particular range of record handles given
205  *
206  * @param[in] repo - opaque pointer acting as a PDR repo handle
207  * @param[in] entity_type - entity type
208  * @param[in] entity_instance - instance of the entity
209  * @param[in] child_index - index of the child entity whose container id needs to be found
210  * @param[in] range_exclude_start_handle - first record handle in the range of the remote endpoint
211  * 	      which is ignored
212  * @param[in] range_exclude_end_handle - last record handle in the range of the remote endpoint
213  * 	      which is ignored
214  * @param[out] container_id - container id of the contained entity
215  *
216  * @return container id of the PDR record found on success,-EINVAL when repo is NULL
217  * or -ENOKEY if the container id is not found.
218  */
219 int pldm_pdr_find_child_container_id_index_range_exclude(
220 	const pldm_pdr *repo, uint16_t entity_type, uint16_t entity_instance,
221 	uint8_t child_index, uint32_t range_exclude_start_handle,
222 	uint32_t range_exclude_end_handle, uint16_t *container_id);
223 
224 /* ======================= */
225 /* FRU Record Set PDR APIs */
226 /* ======================= */
227 
228 /** @brief Add a FRU record set PDR record to a PDR repository, or return an error
229  *
230  *  @param[in/out] repo - opaque pointer acting as a PDR repo handle
231  *  @param[in] terminus_handle - PLDM terminus handle of terminus owning the PDR
232  *  record
233  *  @param[in] fru_rsi - FRU record set identifier
234  *  @param[in] entity_type - entity type of FRU
235  *  @param[in] entity_instance_num - entity instance number of FRU
236  *  @param[in] container_id - container id of FRU
237  *  @param[in,out] bmc_record_handle - A pointer to the handle used to construct the next record. If
238  *  		   the value is zero on input then a new handle is automatically allocated.
239  *  		   Otherwise, the provided handle is used. If a new handle is automatically
240  *  		   allocated then the object pointed to by bmc_record_handle will contain its value
241  *  		   as output.
242  *  @return 0 on success, -EINVAL if the arguments are invalid, or -ENOMEM if an internal allocation
243  *  	    fails.
244  */
245 int pldm_pdr_add_fru_record_set_check(pldm_pdr *repo, uint16_t terminus_handle,
246 				      uint16_t fru_rsi, uint16_t entity_type,
247 				      uint16_t entity_instance_num,
248 				      uint16_t container_id,
249 				      uint32_t *bmc_record_handle);
250 
251 /** @brief Find a FRU record set PDR by FRU record set identifier
252  *
253  *  @param[in] repo - opaque pointer acting as a PDR repo handle
254  *  @param[in] fru_rsi - FRU record set identifier
255  *  @param[in] terminus_handle - *terminus_handle will be FRU terminus handle of
256  *  found PDR, or 0 if not found
257  *  @param[in] entity_type - *entity_type will be FRU entity type of found PDR,
258  *  or 0 if not found
259  *  @param[in] entity_instance_num - *entity_instance_num will be FRU entity
260  *  instance number of found PDR, or 0 if not found
261  *  @param[in] container_id - *cintainer_id will be FRU container id of found
262  *  PDR, or 0 if not found
263  *
264  *  @return An opaque pointer to the PDR record on success, or NULL on failure
265  */
266 const pldm_pdr_record *pldm_pdr_fru_record_set_find_by_rsi(
267 	const pldm_pdr *repo, uint16_t fru_rsi, uint16_t *terminus_handle,
268 	uint16_t *entity_type, uint16_t *entity_instance_num,
269 	uint16_t *container_id);
270 
271 /* =========================== */
272 /* Entity Association PDR APIs */
273 /* =========================== */
274 
275 typedef struct pldm_entity {
276 	uint16_t entity_type;
277 	uint16_t entity_instance_num;
278 	uint16_t entity_container_id;
279 } __attribute__((packed)) pldm_entity;
280 
281 enum entity_association_containment_type {
282 	PLDM_ENTITY_ASSOCIAION_PHYSICAL = 0x0,
283 	PLDM_ENTITY_ASSOCIAION_LOGICAL = 0x1,
284 };
285 
286 /** @struct pldm_entity_association_tree
287  *  opaque structure that represents the entity association hierarchy
288  */
289 typedef struct pldm_entity_association_tree pldm_entity_association_tree;
290 
291 /** @struct pldm_entity_node
292  *  opaque structure that represents a node in the entity association hierarchy
293  */
294 typedef struct pldm_entity_node pldm_entity_node;
295 
296 /** @brief Make a new entity association tree
297  *
298  *  @return opaque pointer that acts as a handle to the tree; NULL if no
299  *  tree could be created
300  */
301 pldm_entity_association_tree *pldm_entity_association_tree_init(void);
302 
303 /** @brief Add a local entity into the entity association tree
304  *
305  *  @param[in/out] tree - opaque pointer acting as a handle to the tree
306  *  @param[in/out] entity - pointer to the entity to be added. Input has the
307  *                          entity type. On output, instance number and the
308  *                          container id are populated.
309  *  @param[in] entity_instance_number - entity instance number, we can use the
310  *                                      entity instance number of the entity by
311  *                                      default if its value is equal 0xffff.
312  *  @param[in] parent - pointer to the node that should be the parent of input
313  *                      entity. If this is NULL, then the entity is the root
314  *  @param[in] association_type - relation with the parent : logical or physical
315  *
316  *  @return pldm_entity_node* - opaque pointer to added entity
317  */
318 pldm_entity_node *pldm_entity_association_tree_add(
319 	pldm_entity_association_tree *tree, pldm_entity *entity,
320 	uint16_t entity_instance_number, pldm_entity_node *parent,
321 	uint8_t association_type);
322 
323 /** @brief Add an entity into the entity association tree based on remote field
324  *  set or unset.
325  *
326  *  @param[in/out] tree - opaque pointer acting as a handle to the tree
327  *  @param[in/out] entity - pointer to the entity to be added. Input has the
328  *                          entity type. On output, instance number and the
329  *                          container id are populated.
330  *  @param[in] entity_instance_number - entity instance number, we can use the
331  *                                      entity instance number of the entity by
332  *                                      default if its value is equal 0xffff.
333  *  @param[in] parent - pointer to the node that should be the parent of input
334  *                      entity. If this is NULL, then the entity is the root
335  *  @param[in] association_type - relation with the parent : logical or physical
336  *  @param[in] is_remote - used to denote whether we are adding a BMC entity to
337  *                         the tree or a host entity
338  *  @param[in] is_update_contanier_id - Used to determine whether need to update
339  *                                      contanier id.
340  *                                      true: should be changed
341  *                                      false: should not be changed
342  *  @param[in] container_id - container id of the entity added.
343  *
344  *  @return pldm_entity_node* - opaque pointer to added entity
345  */
346 pldm_entity_node *pldm_entity_association_tree_add_entity(
347 	pldm_entity_association_tree *tree, pldm_entity *entity,
348 	uint16_t entity_instance_number, pldm_entity_node *parent,
349 	uint8_t association_type, bool is_remote, bool is_update_container_id,
350 	uint16_t container_id);
351 
352 /** @brief Visit and note each entity in the entity association tree
353  *
354  *  @pre `*entities == NULL` and `*size == 0` must hold at the time of invocation.
355  *
356  *  Callers must inspect the values of `*entities` and `*size` post-invocation to determine if the
357  *  invocation was a success or failure.
358  *
359  *  @param[in] tree - opaque pointer acting as a handle to the tree
360  *  @param[out] entities - pointer to list of pldm_entity's. To be free()'d by
361  *                         the caller
362  *  @param[out] size - number of pldm_entity's
363  */
364 void pldm_entity_association_tree_visit(pldm_entity_association_tree *tree,
365 					pldm_entity **entities, size_t *size);
366 
367 /** @brief Extract pldm entity by the pldm_entity_node
368  *
369  *  @pre node must point to a valid object
370  *
371  *  @param[in] node     - opaque pointer to added entity
372  *
373  *  @return pldm_entity - pldm entity
374  */
375 pldm_entity pldm_entity_extract(pldm_entity_node *node);
376 
377 /** @brief Extract remote container id from the pldm_entity_node
378  *
379  *  @pre entity must point to a valid object
380  *
381  *  @param[in] entity - pointer to existing entity
382  *
383  *  @return The remote container id
384  */
385 uint16_t
386 pldm_entity_node_get_remote_container_id(const pldm_entity_node *entity);
387 
388 /** @brief Destroy entity association tree
389  *
390  *  @param[in] tree - opaque pointer acting as a handle to the tree
391  */
392 void pldm_entity_association_tree_destroy(pldm_entity_association_tree *tree);
393 
394 /** @brief Check if input entity node is a parent
395  *
396  *  @pre node must point to a valid object
397  *
398  *  @param[in] node - opaque pointer acting as a handle to an entity node
399  *
400  *  @return bool true if node is a parent, false otherwise
401  */
402 bool pldm_entity_is_node_parent(pldm_entity_node *node);
403 
404 /** @brief Get parent of entity
405  *
406  *  @pre node must point to a valid object
407  *
408  *  @param[in] node - opaque pointer acting as a handle to an entity node
409  *
410  *  @return pldm_entity - pldm entity
411  */
412 pldm_entity pldm_entity_get_parent(pldm_entity_node *node);
413 
414 /** @brief Check the current pldm entity is exist parent
415  *
416  *  @pre node must point to a valid object
417  *
418  *  @param[in] node - opaque pointer acting as a handle to an entity node
419  *
420  *  @return bool true if exist parent, false otherwise
421  */
422 bool pldm_entity_is_exist_parent(pldm_entity_node *node);
423 
424 /** @brief Convert entity association tree to PDR
425  *
426  *  No conversion takes place if one or both of tree or repo are NULL.
427  *
428  *  @param[in] tree - opaque pointer to entity association tree
429  *  @param[in] repo - PDR repo where entity association records should be added
430  *  @param[in] is_remote - if true, then the PDR is not from this terminus
431  *  @param[in] terminus_handle - terminus handle of the terminus
432  */
433 void pldm_entity_association_pdr_add(pldm_entity_association_tree *tree,
434 				     pldm_pdr *repo, bool is_remote,
435 				     uint16_t terminus_handle);
436 
437 /** @brief Convert entity association tree to PDR, or return an error
438  *
439  *  No conversion takes place if one or both of tree or repo are NULL.
440  *
441  *  If an error is returned then the state and consistency of the PDR repository is undefined.
442  *
443  *  @param[in] tree - opaque pointer to entity association tree
444  *  @param[in] repo - PDR repo where entity association records should be added
445  *  @param[in] is_remote - if true, then the PDR is not from this terminus
446  *  @param[in] terminus_handle - terminus handle of the terminus
447  *
448  *  @return 0 on success, -EINVAL if the arguments are invalid, -ENOMEM if an internal memory
449  *  allocation fails, or -EOVERFLOW if a record handle could not be allocated
450  */
451 int pldm_entity_association_pdr_add_check(pldm_entity_association_tree *tree,
452 					  pldm_pdr *repo, bool is_remote,
453 					  uint16_t terminus_handle);
454 
455 /** @brief Add a contained entity as a remote PDR to an existing entity association PDR.
456  *
457  *  Remote PDRs are PDRs added as a child to an entity in the entity association tree and
458  *  not to the tree directly. This means remote PDRs have a parent PDR in the entity
459  *  association tree to which they are linked.
460  *
461  *  @param[in] repo - opaque pointer to pldm PDR repo
462  *  @param[in] entity - the contained entity to be added
463  *  @param[in] pdr_record_handle - record handle of the container entity to which the remote
464  *  PDR is to be added as a child
465  *
466  *  @return 0 on success, -EINVAL if the arguments are invalid, -ENOMEM if an internal memory
467  *  allocation fails, or -EOVERFLOW if a record handle could not be allocated
468  */
469 int pldm_entity_association_pdr_add_contained_entity_to_remote_pdr(
470 	pldm_pdr *repo, pldm_entity *entity, uint32_t pdr_record_handle);
471 
472 /** @brief Creates a new entity association PDR with contained entity & its parent.
473  *
474  *  @param[in] repo - opaque pointer to pldm PDR repo
475  *  @param[in] pdr_record_handle - record handle of the PDR after which the new container
476  *  entity has to be added
477  *  @param[in] parent - the container entity
478  *  @param[in] entity - the contained entity to be added
479  *  @param[in-out] entity_record_handle - record handle of a container entity added to the
480  *  entity association PDR
481  *
482  *  @return 0 on success, -EINVAL if the arguments are invalid, -ENOMEM if an internal memory
483  *  allocation fails, or -EOVERFLOW if a record handle could not be allocated
484  */
485 int pldm_entity_association_pdr_create_new(pldm_pdr *repo,
486 					   uint32_t pdr_record_handle,
487 					   pldm_entity *parent,
488 					   pldm_entity *entity,
489 					   uint32_t *entity_record_handle);
490 
491 /** @brief Add entity association pdr from node, or return an error
492  *
493  *  @param[in] node - opaque pointer acting as a handle to an entity node
494  *  @param[in] repo - PDR repo where entity association records should be added
495  *  @param[in] is_remote  - if true, then the PDR is not from this terminus
496  *  @param[in] terminus_handle - terminus handle of the terminus
497  *
498  *  @return 0 on success, -EINVAL if the provided arguments are invalid.
499  */
500 int pldm_entity_association_pdr_add_from_node_check(
501 	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
502 	size_t num_entities, bool is_remote, uint16_t terminus_handle);
503 
504 /** @brief Add entity association pdr record based on record handle
505  *  earlier the records where added in a sequential way alone, with
506  *  this change the entity association PDR records gets the new record
507  *  handle based on the input value given.
508  *
509  *  @param[in] node - opaque pointer acting as a handle to an entity node
510  *  @param[in] repo - PDR repo where entity association records should be added
511  *  @param[in] is_remote  - if true, then the PDR is not from this terminus
512  *  @param[in] terminus_handle - terminus handle of the terminus
513  *  @param[in] record_handle - record handle of the PDR
514  *
515  *  @return 0 on success, -EINVAL if the provided arguments are invalid.
516  */
517 int pldm_entity_association_pdr_add_from_node_with_record_handle(
518 	pldm_entity_node *node, pldm_pdr *repo, pldm_entity **entities,
519 	size_t num_entities, bool is_remote, uint16_t terminus_handle,
520 	uint32_t record_handle);
521 
522 /** @brief Find entity reference in tree
523  *
524  *  @param[in] tree - opaque pointer to entity association tree
525  *  @param[in] entity - PLDM entity
526  *  @param[in] node - node to the entity
527  */
528 void pldm_find_entity_ref_in_tree(pldm_entity_association_tree *tree,
529 				  pldm_entity entity, pldm_entity_node **node);
530 
531 /** @brief Get number of children of entity
532  *
533  *  @param[in] node - opaque pointer acting as a handle to an entity node
534  *  @param[in] association_type - relation type filter : logical or physical
535  *
536  *  @return uint8_t number of children. The returned value is zero if node is NULL or
537  *  	    association_type is not one of PLDM_ENTITY_ASSOCIAION_PHYSICAL or
538  *  	    PLDM_ENTITY_ASSOCIAION_LOGICAL.
539  */
540 uint8_t pldm_entity_get_num_children(pldm_entity_node *node,
541 				     uint8_t association_type);
542 
543 /** @brief Verify that the current node is a child of the current parent
544  *
545  *  @pre parent must point to a valid object
546  *  @pre node must point to a valid object
547  *
548  *  @param[in] parent    - opaque pointer acting as a handle to an entity parent
549  *  @param[in] node      - pointer to the node of the pldm entity
550  *
551  *  @return True if the node is a child of parent, false otherwise, including if one or both of
552  *  parent or node are NULL.
553  */
554 bool pldm_is_current_parent_child(pldm_entity_node *parent, pldm_entity *node);
555 
556 /** @brief Find an entity in the entity association tree
557  *
558  *  @param[in] tree - pointer to entity association tree
559  *  @param[in/out] entity - entity type and instance id set on input, container
560  *                 id set on output
561  *  @return pldm_entity_node* pointer to entity if found, NULL otherwise
562  *
563  *  There are no entity nodes to search if tree is NULL, nor are there entity nodes to find if the
564  *  search criteria are unspecified when entity is NULL.
565  */
566 pldm_entity_node *
567 pldm_entity_association_tree_find(pldm_entity_association_tree *tree,
568 				  pldm_entity *entity);
569 
570 /** @brief Find an entity in the entity association tree with locality specified,
571  *         ie - remote entity or local entity
572  *
573  *  @param[in] tree - pointer to entity association tree
574  *  @param[in/out] entity - entity type and instance id set on input, container
575  *                          id set on output
576  *  @param[in] is_remote - variable to denote whether we are finding a remote
577  *                         entity or a local entity
578  *
579  *  @return pldm_entity_node* pointer to entity if found, NULL otherwise
580  */
581 pldm_entity_node *pldm_entity_association_tree_find_with_locality(
582 	pldm_entity_association_tree *tree, pldm_entity *entity,
583 	bool is_remote);
584 
585 /** @brief Create a copy of an existing entity association tree
586  *
587  *  @pre org_tree must point to a valid object
588  *  @pre new_tree must point to a valid object
589  *
590  *  @param[in] org_tree - pointer to source tree
591  *  @param[in/out] new_tree - pointer to destination tree
592  */
593 void pldm_entity_association_tree_copy_root(
594 	pldm_entity_association_tree *org_tree,
595 	pldm_entity_association_tree *new_tree);
596 
597 /** @brief Destroy all the nodes of the entity association tree
598  *
599  *  @param[in] tree - pointer to entity association tree
600  *
601  *  There is no tree to destroy if tree is NULL.
602  */
603 void pldm_entity_association_tree_destroy_root(
604 	pldm_entity_association_tree *tree);
605 
606 /** @brief Check whether the entity association tree is empty
607  *
608  *  @pre tree must point to a valid object
609  *
610  *  @param[in] tree - pointer to entity association tree
611  *  @return bool, true if tree is empty
612  */
613 bool pldm_is_empty_entity_assoc_tree(pldm_entity_association_tree *tree);
614 
615 /** @brief Extract entities from entity association PDR
616  *
617  *  @pre `*entities == NULL` and `*num_entities == 0` must hold at the time of invocation.
618  *
619  *  @param[in] pdr - entity association PDR
620  *  @param[in] pdr_len - size of entity association PDR in bytes
621  *  @param[out] num_entities - number of entities found, including the container
622  *  @param[out] entities - extracted entities, container is *entities[0]. Caller
623  *              must free *entities
624  */
625 void pldm_entity_association_pdr_extract(const uint8_t *pdr, uint16_t pdr_len,
626 					 size_t *num_entities,
627 					 pldm_entity **entities);
628 
629 #ifdef __cplusplus
630 }
631 #endif
632 
633 #endif /* PDR_H */
634