xref: /aosp_15_r20/external/tpm2-tss/src/tss2-fapi/api/Fapi_GetInfo.c (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
1*758e9fbaSOystein Eftevaag /* SPDX-License-Identifier: BSD-2-Clause */
2*758e9fbaSOystein Eftevaag /*******************************************************************************
3*758e9fbaSOystein Eftevaag  * Copyright 2018-2019, Fraunhofer SIT sponsored by Infineon Technologies AG
4*758e9fbaSOystein Eftevaag  * All rights reserved.
5*758e9fbaSOystein Eftevaag  ******************************************************************************/
6*758e9fbaSOystein Eftevaag 
7*758e9fbaSOystein Eftevaag #ifdef HAVE_CONFIG_H
8*758e9fbaSOystein Eftevaag #include <config.h>
9*758e9fbaSOystein Eftevaag #endif
10*758e9fbaSOystein Eftevaag 
11*758e9fbaSOystein Eftevaag #include <json-c/json_util.h>
12*758e9fbaSOystein Eftevaag #include <json-c/json_tokener.h>
13*758e9fbaSOystein Eftevaag #include <string.h>
14*758e9fbaSOystein Eftevaag 
15*758e9fbaSOystein Eftevaag #include "ifapi_json_serialize.h"
16*758e9fbaSOystein Eftevaag #include "tss2_fapi.h"
17*758e9fbaSOystein Eftevaag #include "fapi_int.h"
18*758e9fbaSOystein Eftevaag #include "fapi_util.h"
19*758e9fbaSOystein Eftevaag #include "tss2_esys.h"
20*758e9fbaSOystein Eftevaag #define LOGMODULE fapi
21*758e9fbaSOystein Eftevaag #include "util/log.h"
22*758e9fbaSOystein Eftevaag #include "util/aux_util.h"
23*758e9fbaSOystein Eftevaag 
24*758e9fbaSOystein Eftevaag typedef struct {
25*758e9fbaSOystein Eftevaag     char *description;
26*758e9fbaSOystein Eftevaag     TPMI_POLICYTYPE capability;
27*758e9fbaSOystein Eftevaag     UINT32 property;
28*758e9fbaSOystein Eftevaag     UINT32 max;
29*758e9fbaSOystein Eftevaag } IFAPI_INFO_CAP;
30*758e9fbaSOystein Eftevaag 
31*758e9fbaSOystein Eftevaag static IFAPI_INFO_CAP info_cap_tab[] = {
32*758e9fbaSOystein Eftevaag     { "algorithms", TPM2_CAP_ALGS,  TPM2_ALG_FIRST, TPM2_MAX_CAP_ALGS},
33*758e9fbaSOystein Eftevaag     { "handles-transient", TPM2_CAP_HANDLES, TPM2_TRANSIENT_FIRST, TPM2_MAX_CAP_HANDLES},
34*758e9fbaSOystein Eftevaag     { "handles-persistent", TPM2_CAP_HANDLES, TPM2_PERSISTENT_FIRST, TPM2_MAX_CAP_HANDLES},
35*758e9fbaSOystein Eftevaag     { "handles-permanent", TPM2_CAP_HANDLES, TPM2_PERMANENT_FIRST, TPM2_MAX_CAP_HANDLES},
36*758e9fbaSOystein Eftevaag     { "handles-pcr", TPM2_CAP_HANDLES, TPM2_PCR_FIRST, TPM2_MAX_CAP_HANDLES},
37*758e9fbaSOystein Eftevaag     { "handles-nv-index", TPM2_CAP_HANDLES, TPM2_NV_INDEX_FIRST, TPM2_MAX_CAP_HANDLES},
38*758e9fbaSOystein Eftevaag     { "handles-loaded-session", TPM2_CAP_HANDLES, TPM2_LOADED_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
39*758e9fbaSOystein Eftevaag     { "handles-action-session", TPM2_CAP_HANDLES, TPM2_ACTIVE_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
40*758e9fbaSOystein Eftevaag     { "handles-saved-session", TPM2_CAP_HANDLES, TPM2_ACTIVE_SESSION_FIRST, TPM2_MAX_CAP_HANDLES},
41*758e9fbaSOystein Eftevaag     { "properties-fixed", TPM2_CAP_TPM_PROPERTIES, TPM2_PT_FIXED, TPM2_MAX_TPM_PROPERTIES },
42*758e9fbaSOystein Eftevaag     { "properties-variable", TPM2_CAP_TPM_PROPERTIES, TPM2_PT_VAR, TPM2_MAX_TPM_PROPERTIES },
43*758e9fbaSOystein Eftevaag     { "commands", TPM2_CAP_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
44*758e9fbaSOystein Eftevaag     { "pp-commands", TPM2_CAP_PP_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
45*758e9fbaSOystein Eftevaag     { "audit-commands", TPM2_CAP_AUDIT_COMMANDS, TPM2_CC_FIRST, TPM2_MAX_CAP_CC },
46*758e9fbaSOystein Eftevaag     { "pcrs", TPM2_CAP_PCRS, 0, TPM2_NUM_PCR_BANKS },
47*758e9fbaSOystein Eftevaag     { "pcr-properties", TPM2_CAP_PCR_PROPERTIES, TPM2_PCR_FIRST, TPM2_MAX_PCR_PROPERTIES },
48*758e9fbaSOystein Eftevaag     { "ecc-curves", TPM2_CAP_ECC_CURVES, 0, TPM2_MAX_ECC_CURVES },
49*758e9fbaSOystein Eftevaag };
50*758e9fbaSOystein Eftevaag 
51*758e9fbaSOystein Eftevaag /** One-Call function for Fapi_GetInfo
52*758e9fbaSOystein Eftevaag  *
53*758e9fbaSOystein Eftevaag  * Returns a UTF-8 encoded string that identifies the versions of FAPI, TPM,
54*758e9fbaSOystein Eftevaag  * configurations and other relevant information.
55*758e9fbaSOystein Eftevaag  *
56*758e9fbaSOystein Eftevaag  * @param[in,out] context The FAPI_CONTEXT
57*758e9fbaSOystein Eftevaag  * @param[out] info The byte buffer for the information string
58*758e9fbaSOystein Eftevaag  *
59*758e9fbaSOystein Eftevaag  * @retval TSS2_RC_SUCCESS: if the function call was a success.
60*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or info is NULL.
61*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
62*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
63*758e9fbaSOystein Eftevaag  *         operation already pending.
64*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
65*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
66*758e9fbaSOystein Eftevaag  *         internal operations or return parameters.
67*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
68*758e9fbaSOystein Eftevaag  *         config file.
69*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_TRY_AGAIN if an I/O operation is not finished yet and
70*758e9fbaSOystein Eftevaag  *         this function needs to be called again.
71*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
72*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
73*758e9fbaSOystein Eftevaag  *         the function.
74*758e9fbaSOystein Eftevaag  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
75*758e9fbaSOystein Eftevaag  */
76*758e9fbaSOystein Eftevaag TSS2_RC
Fapi_GetInfo(FAPI_CONTEXT * context,char ** info)77*758e9fbaSOystein Eftevaag Fapi_GetInfo(
78*758e9fbaSOystein Eftevaag     FAPI_CONTEXT *context,
79*758e9fbaSOystein Eftevaag     char        **info)
80*758e9fbaSOystein Eftevaag {
81*758e9fbaSOystein Eftevaag     LOG_TRACE("called for context:%p", context);
82*758e9fbaSOystein Eftevaag 
83*758e9fbaSOystein Eftevaag     TSS2_RC r, r2;
84*758e9fbaSOystein Eftevaag 
85*758e9fbaSOystein Eftevaag     /* Check for NULL parameters */
86*758e9fbaSOystein Eftevaag     check_not_null(context);
87*758e9fbaSOystein Eftevaag     check_not_null(info);
88*758e9fbaSOystein Eftevaag 
89*758e9fbaSOystein Eftevaag     /* Check whether TCTI and ESYS are initialized */
90*758e9fbaSOystein Eftevaag     return_if_null(context->esys, "Command can't be executed in none TPM mode.",
91*758e9fbaSOystein Eftevaag                    TSS2_FAPI_RC_NO_TPM);
92*758e9fbaSOystein Eftevaag 
93*758e9fbaSOystein Eftevaag     /* If the async state automata of FAPI shall be tested, then we must not set
94*758e9fbaSOystein Eftevaag        the timeouts of ESYS to blocking mode.
95*758e9fbaSOystein Eftevaag        During testing, the mssim tcti will ensure multiple re-invocations.
96*758e9fbaSOystein Eftevaag        Usually however the synchronous invocations of FAPI shall instruct ESYS
97*758e9fbaSOystein Eftevaag        to block until a result is available. */
98*758e9fbaSOystein Eftevaag #ifndef TEST_FAPI_ASYNC
99*758e9fbaSOystein Eftevaag     r = Esys_SetTimeout(context->esys, TSS2_TCTI_TIMEOUT_BLOCK);
100*758e9fbaSOystein Eftevaag     return_if_error_reset_state(r, "Set Timeout to blocking");
101*758e9fbaSOystein Eftevaag #endif /* TEST_FAPI_ASYNC */
102*758e9fbaSOystein Eftevaag 
103*758e9fbaSOystein Eftevaag     r = Fapi_GetInfo_Async(context);
104*758e9fbaSOystein Eftevaag     return_if_error_reset_state(r, "GetTPMInfo");
105*758e9fbaSOystein Eftevaag 
106*758e9fbaSOystein Eftevaag     do {
107*758e9fbaSOystein Eftevaag         /* We wait for file I/O to be ready if the FAPI state automata
108*758e9fbaSOystein Eftevaag            are in a file I/O state. */
109*758e9fbaSOystein Eftevaag         r = ifapi_io_poll(&context->io);
110*758e9fbaSOystein Eftevaag         return_if_error(r, "Something went wrong with IO polling");
111*758e9fbaSOystein Eftevaag 
112*758e9fbaSOystein Eftevaag         /* Repeatedly call the finish function, until FAPI has transitioned
113*758e9fbaSOystein Eftevaag            through all execution stages / states of this invocation. */
114*758e9fbaSOystein Eftevaag         r = Fapi_GetInfo_Finish(context, info);
115*758e9fbaSOystein Eftevaag     } while ((r & ~TSS2_RC_LAYER_MASK) == TSS2_BASE_RC_TRY_AGAIN);
116*758e9fbaSOystein Eftevaag 
117*758e9fbaSOystein Eftevaag     /* Reset the ESYS timeout to non-blocking, immediate response. */
118*758e9fbaSOystein Eftevaag     r2 = Esys_SetTimeout(context->esys, 0);
119*758e9fbaSOystein Eftevaag     return_if_error(r2, "Set Timeout to non-blocking");
120*758e9fbaSOystein Eftevaag 
121*758e9fbaSOystein Eftevaag     return_if_error_reset_state(r, "GetTPMInfo");
122*758e9fbaSOystein Eftevaag 
123*758e9fbaSOystein Eftevaag     LOG_TRACE("finished");
124*758e9fbaSOystein Eftevaag     return TSS2_RC_SUCCESS;
125*758e9fbaSOystein Eftevaag }
126*758e9fbaSOystein Eftevaag 
127*758e9fbaSOystein Eftevaag /** Asynchronous function for Fapi_GetInfo
128*758e9fbaSOystein Eftevaag  *
129*758e9fbaSOystein Eftevaag  * Returns a UTF-8 encoded string that identifies the versions of FAPI, TPM,
130*758e9fbaSOystein Eftevaag  * configurations and other relevant information.
131*758e9fbaSOystein Eftevaag  *
132*758e9fbaSOystein Eftevaag  * Call Fapi_GetInfo_Finish to finish the execution of this command.
133*758e9fbaSOystein Eftevaag  *
134*758e9fbaSOystein Eftevaag  * @param[in,out] context The FAPI_CONTEXT
135*758e9fbaSOystein Eftevaag  *
136*758e9fbaSOystein Eftevaag  * @retval TSS2_RC_SUCCESS: if the function call was a success.
137*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context is NULL.
138*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
139*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
140*758e9fbaSOystein Eftevaag  *         operation already pending.
141*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
142*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
143*758e9fbaSOystein Eftevaag  *         internal operations or return parameters.
144*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_NO_TPM if FAPI was initialized in no-TPM-mode via its
145*758e9fbaSOystein Eftevaag  *         config file.
146*758e9fbaSOystein Eftevaag  */
147*758e9fbaSOystein Eftevaag TSS2_RC
Fapi_GetInfo_Async(FAPI_CONTEXT * context)148*758e9fbaSOystein Eftevaag Fapi_GetInfo_Async(
149*758e9fbaSOystein Eftevaag     FAPI_CONTEXT *context)
150*758e9fbaSOystein Eftevaag {
151*758e9fbaSOystein Eftevaag     LOG_TRACE("called for context:%p", context);
152*758e9fbaSOystein Eftevaag 
153*758e9fbaSOystein Eftevaag     TSS2_RC r;
154*758e9fbaSOystein Eftevaag 
155*758e9fbaSOystein Eftevaag     /* Check for NULL parameters */
156*758e9fbaSOystein Eftevaag     check_not_null(context);
157*758e9fbaSOystein Eftevaag 
158*758e9fbaSOystein Eftevaag     /* Helpful alias pointers */
159*758e9fbaSOystein Eftevaag     IFAPI_GetInfo * command = &context->cmd.GetInfo;
160*758e9fbaSOystein Eftevaag 
161*758e9fbaSOystein Eftevaag     /* Reset all context-internal session state information. */
162*758e9fbaSOystein Eftevaag     r = ifapi_session_init(context);
163*758e9fbaSOystein Eftevaag     return_if_error(r, "Initialize GetInfo");
164*758e9fbaSOystein Eftevaag 
165*758e9fbaSOystein Eftevaag     memset(command, 0, sizeof(IFAPI_GetInfo));
166*758e9fbaSOystein Eftevaag     r = ifapi_capability_init(context);
167*758e9fbaSOystein Eftevaag     return_if_error(r, "Capability init");
168*758e9fbaSOystein Eftevaag 
169*758e9fbaSOystein Eftevaag     /* Initialize the context state for this operation. */
170*758e9fbaSOystein Eftevaag     command->idx_info_cap = 0;
171*758e9fbaSOystein Eftevaag     context->state = GET_INFO_GET_CAP;
172*758e9fbaSOystein Eftevaag 
173*758e9fbaSOystein Eftevaag     LOG_TRACE("finished");
174*758e9fbaSOystein Eftevaag     return TSS2_RC_SUCCESS;
175*758e9fbaSOystein Eftevaag }
176*758e9fbaSOystein Eftevaag 
177*758e9fbaSOystein Eftevaag /** Asynchronous finish function for Fapi_GetInfo
178*758e9fbaSOystein Eftevaag  *
179*758e9fbaSOystein Eftevaag  * This function should be called after a previous Fapi_GetInfo_Async.
180*758e9fbaSOystein Eftevaag  *
181*758e9fbaSOystein Eftevaag  * @param[in,out] context The FAPI_CONTEXT
182*758e9fbaSOystein Eftevaag  * @param[out] info The byte buffer for the information string
183*758e9fbaSOystein Eftevaag  *
184*758e9fbaSOystein Eftevaag  * @retval TSS2_RC_SUCCESS: if the function call was a success.
185*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_REFERENCE: if context or info is NULL.
186*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_CONTEXT: if context corruption is detected.
187*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_SEQUENCE: if the context has an asynchronous
188*758e9fbaSOystein Eftevaag  *         operation already pending.
189*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_IO_ERROR: if the data cannot be saved.
190*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_MEMORY: if the FAPI cannot allocate enough memory for
191*758e9fbaSOystein Eftevaag  *         internal operations or return parameters.
192*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_TRY_AGAIN: if the asynchronous operation is not yet
193*758e9fbaSOystein Eftevaag  *         complete. Call this function again later.
194*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_GENERAL_FAILURE if an internal error occurred.
195*758e9fbaSOystein Eftevaag  * @retval TSS2_FAPI_RC_BAD_VALUE if an invalid value was passed into
196*758e9fbaSOystein Eftevaag  *         the function.
197*758e9fbaSOystein Eftevaag  * @retval TSS2_ESYS_RC_* possible error codes of ESAPI.
198*758e9fbaSOystein Eftevaag  */
199*758e9fbaSOystein Eftevaag TSS2_RC
Fapi_GetInfo_Finish(FAPI_CONTEXT * context,char ** info)200*758e9fbaSOystein Eftevaag Fapi_GetInfo_Finish(
201*758e9fbaSOystein Eftevaag     FAPI_CONTEXT *context,
202*758e9fbaSOystein Eftevaag     char        **info)
203*758e9fbaSOystein Eftevaag {
204*758e9fbaSOystein Eftevaag     LOG_TRACE("called for context:%p", context);
205*758e9fbaSOystein Eftevaag 
206*758e9fbaSOystein Eftevaag     TSS2_RC r;
207*758e9fbaSOystein Eftevaag     json_object *jso = NULL;
208*758e9fbaSOystein Eftevaag     size_t capIdx;
209*758e9fbaSOystein Eftevaag 
210*758e9fbaSOystein Eftevaag     /* Check for NULL parameters */
211*758e9fbaSOystein Eftevaag     check_not_null(context);
212*758e9fbaSOystein Eftevaag     check_not_null(info);
213*758e9fbaSOystein Eftevaag 
214*758e9fbaSOystein Eftevaag     /* Helpful alias pointers */
215*758e9fbaSOystein Eftevaag     IFAPI_GetInfo * command = &context->cmd.GetInfo;
216*758e9fbaSOystein Eftevaag     IFAPI_INFO *infoObj = &command->info_obj;
217*758e9fbaSOystein Eftevaag     TPMS_CAPABILITY_DATA *capabilityData = NULL;
218*758e9fbaSOystein Eftevaag 
219*758e9fbaSOystein Eftevaag     switch (context->state) {
220*758e9fbaSOystein Eftevaag     case GET_INFO_GET_CAP:
221*758e9fbaSOystein Eftevaag         /* Initialize the property for the first ESAPI call */
222*758e9fbaSOystein Eftevaag         command->property
223*758e9fbaSOystein Eftevaag             = info_cap_tab[command->idx_info_cap].property;
224*758e9fbaSOystein Eftevaag         fallthrough;
225*758e9fbaSOystein Eftevaag 
226*758e9fbaSOystein Eftevaag     case GET_INFO_GET_CAP_MORE:
227*758e9fbaSOystein Eftevaag         /* This state is a helper used from fapi_util.c */
228*758e9fbaSOystein Eftevaag         fallthrough;
229*758e9fbaSOystein Eftevaag 
230*758e9fbaSOystein Eftevaag     case GET_INFO_WAIT_FOR_CAP:
231*758e9fbaSOystein Eftevaag         /* State will be set by sub routine */
232*758e9fbaSOystein Eftevaag         capIdx = command->idx_info_cap;
233*758e9fbaSOystein Eftevaag         r = ifapi_capability_get(context,
234*758e9fbaSOystein Eftevaag                                  info_cap_tab[capIdx].capability,
235*758e9fbaSOystein Eftevaag                                  info_cap_tab[capIdx].max,
236*758e9fbaSOystein Eftevaag                                  &capabilityData);
237*758e9fbaSOystein Eftevaag         return_try_again(r);
238*758e9fbaSOystein Eftevaag         goto_if_error(r, "Get capability", cleanup);
239*758e9fbaSOystein Eftevaag 
240*758e9fbaSOystein Eftevaag         infoObj->cap[capIdx].description = info_cap_tab[capIdx].description;
241*758e9fbaSOystein Eftevaag         infoObj->cap[capIdx].capability = capabilityData;
242*758e9fbaSOystein Eftevaag         command->property_count = 0;
243*758e9fbaSOystein Eftevaag         command->idx_info_cap += 1;
244*758e9fbaSOystein Eftevaag         if (command->idx_info_cap <  sizeof(info_cap_tab)
245*758e9fbaSOystein Eftevaag                 / sizeof(info_cap_tab[0])) {
246*758e9fbaSOystein Eftevaag             /* Not all capabilities have been collected */
247*758e9fbaSOystein Eftevaag             context->state = GET_INFO_GET_CAP;
248*758e9fbaSOystein Eftevaag             return TSS2_FAPI_RC_TRY_AGAIN;
249*758e9fbaSOystein Eftevaag         }
250*758e9fbaSOystein Eftevaag 
251*758e9fbaSOystein Eftevaag         infoObj->fapi_version = "OSSTSS 2.2.x";
252*758e9fbaSOystein Eftevaag         infoObj->fapi_config = "Properties of config have to specified by TCG";
253*758e9fbaSOystein Eftevaag 
254*758e9fbaSOystein Eftevaag         /* Serialize the information. */
255*758e9fbaSOystein Eftevaag         r = ifapi_json_IFAPI_INFO_serialize(infoObj, &jso);
256*758e9fbaSOystein Eftevaag         goto_if_error(r, "Error serialize info object", cleanup);
257*758e9fbaSOystein Eftevaag 
258*758e9fbaSOystein Eftevaag         /* Duplicate the information to be returned to the caller. */
259*758e9fbaSOystein Eftevaag         *info = strdup(json_object_to_json_string_ext(jso, JSON_C_TO_STRING_PRETTY));
260*758e9fbaSOystein Eftevaag         goto_if_null2(*info, "Out of memory.", r, TSS2_FAPI_RC_MEMORY, cleanup);
261*758e9fbaSOystein Eftevaag 
262*758e9fbaSOystein Eftevaag         context->state = _FAPI_STATE_INIT;
263*758e9fbaSOystein Eftevaag         r = TSS2_RC_SUCCESS;
264*758e9fbaSOystein Eftevaag         break;
265*758e9fbaSOystein Eftevaag 
266*758e9fbaSOystein Eftevaag     statecasedefault(context->state);
267*758e9fbaSOystein Eftevaag     }
268*758e9fbaSOystein Eftevaag 
269*758e9fbaSOystein Eftevaag cleanup:
270*758e9fbaSOystein Eftevaag     /* Cleanup any intermediate results and state stored in the context. */
271*758e9fbaSOystein Eftevaag     json_object_put(jso);
272*758e9fbaSOystein Eftevaag     for (capIdx = 0; capIdx < IFAPI_MAX_CAP_INFO; capIdx++) {
273*758e9fbaSOystein Eftevaag         SAFE_FREE(infoObj->cap[capIdx].capability);
274*758e9fbaSOystein Eftevaag     }
275*758e9fbaSOystein Eftevaag     LOG_TRACE("finished");
276*758e9fbaSOystein Eftevaag     return r;
277*758e9fbaSOystein Eftevaag }
278