xref: /aosp_15_r20/external/tpm2-tss/src/tss2-tcti/tctildr-dl.c (revision 758e9fba6fc9adbf15340f70c73baee7b168b1c9)
1*758e9fbaSOystein Eftevaag /* SPDX-License-Identifier: BSD-2-Clause */
2*758e9fbaSOystein Eftevaag /*******************************************************************************
3*758e9fbaSOystein Eftevaag  * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
4*758e9fbaSOystein Eftevaag  * Copyright 2019, Intel Corporation
5*758e9fbaSOystein Eftevaag  * All rights reserved.
6*758e9fbaSOystein Eftevaag  *******************************************************************************/
7*758e9fbaSOystein Eftevaag 
8*758e9fbaSOystein Eftevaag #ifdef HAVE_CONFIG_H
9*758e9fbaSOystein Eftevaag #include <config.h>
10*758e9fbaSOystein Eftevaag #endif
11*758e9fbaSOystein Eftevaag 
12*758e9fbaSOystein Eftevaag #include <stdlib.h>
13*758e9fbaSOystein Eftevaag #include <errno.h>
14*758e9fbaSOystein Eftevaag #include <string.h>
15*758e9fbaSOystein Eftevaag #include <inttypes.h>
16*758e9fbaSOystein Eftevaag #include <dlfcn.h>
17*758e9fbaSOystein Eftevaag #include <limits.h>
18*758e9fbaSOystein Eftevaag #include <stdio.h>
19*758e9fbaSOystein Eftevaag 
20*758e9fbaSOystein Eftevaag #include "tss2_tcti.h"
21*758e9fbaSOystein Eftevaag #include "tctildr-interface.h"
22*758e9fbaSOystein Eftevaag #include "tctildr.h"
23*758e9fbaSOystein Eftevaag #define LOGMODULE tcti
24*758e9fbaSOystein Eftevaag #include "util/log.h"
25*758e9fbaSOystein Eftevaag 
26*758e9fbaSOystein Eftevaag #define ARRAY_SIZE(X) (sizeof(X)/sizeof(X[0]))
27*758e9fbaSOystein Eftevaag 
28*758e9fbaSOystein Eftevaag struct {
29*758e9fbaSOystein Eftevaag     char *file;
30*758e9fbaSOystein Eftevaag     char *conf;
31*758e9fbaSOystein Eftevaag     char *description;
32*758e9fbaSOystein Eftevaag } tctis[] = {
33*758e9fbaSOystein Eftevaag     {
34*758e9fbaSOystein Eftevaag         .file = "libtss2-tcti-default.so",
35*758e9fbaSOystein Eftevaag         .description = "Access libtss2-tcti-default.so",
36*758e9fbaSOystein Eftevaag     },
37*758e9fbaSOystein Eftevaag     {
38*758e9fbaSOystein Eftevaag         .file = "libtss2-tcti-tabrmd.so.0",
39*758e9fbaSOystein Eftevaag         .description = "Access libtss2-tcti-tabrmd.so",
40*758e9fbaSOystein Eftevaag     },
41*758e9fbaSOystein Eftevaag     {
42*758e9fbaSOystein Eftevaag         .file = "libtss2-tcti-device.so.0",
43*758e9fbaSOystein Eftevaag         .conf = "/dev/tpmrm0",
44*758e9fbaSOystein Eftevaag         .description = "Access libtss2-tcti-device.so.0 with /dev/tpmrm0",
45*758e9fbaSOystein Eftevaag     },
46*758e9fbaSOystein Eftevaag     {
47*758e9fbaSOystein Eftevaag         .file = "libtss2-tcti-device.so.0",
48*758e9fbaSOystein Eftevaag         .conf = "/dev/tpm0",
49*758e9fbaSOystein Eftevaag         .description = "Access libtss2-tcti-device.so.0 with /dev/tpm0",
50*758e9fbaSOystein Eftevaag     },
51*758e9fbaSOystein Eftevaag     {
52*758e9fbaSOystein Eftevaag         .file = "libtss2-tcti-mssim.so.0",
53*758e9fbaSOystein Eftevaag         .description = "Access to libtss2-tcti-mssim.so",
54*758e9fbaSOystein Eftevaag     },
55*758e9fbaSOystein Eftevaag };
56*758e9fbaSOystein Eftevaag 
57*758e9fbaSOystein Eftevaag const TSS2_TCTI_INFO*
info_from_handle(void * dlhandle)58*758e9fbaSOystein Eftevaag info_from_handle (void *dlhandle)
59*758e9fbaSOystein Eftevaag {
60*758e9fbaSOystein Eftevaag     TSS2_TCTI_INFO_FUNC info_func;
61*758e9fbaSOystein Eftevaag 
62*758e9fbaSOystein Eftevaag     if (dlhandle == NULL)
63*758e9fbaSOystein Eftevaag         return NULL;
64*758e9fbaSOystein Eftevaag 
65*758e9fbaSOystein Eftevaag     info_func = dlsym  (dlhandle, TSS2_TCTI_INFO_SYMBOL);
66*758e9fbaSOystein Eftevaag     if (info_func == NULL) {
67*758e9fbaSOystein Eftevaag         LOG_ERROR ("Failed to get reference to TSS2_TCTI_INFO_SYMBOL: %s",
68*758e9fbaSOystein Eftevaag                    dlerror());
69*758e9fbaSOystein Eftevaag         return NULL;
70*758e9fbaSOystein Eftevaag     }
71*758e9fbaSOystein Eftevaag 
72*758e9fbaSOystein Eftevaag     return info_func ();
73*758e9fbaSOystein Eftevaag }
74*758e9fbaSOystein Eftevaag TSS2_RC
handle_from_name(const char * file,void ** handle)75*758e9fbaSOystein Eftevaag handle_from_name(const char *file,
76*758e9fbaSOystein Eftevaag                  void **handle)
77*758e9fbaSOystein Eftevaag {
78*758e9fbaSOystein Eftevaag     char file_xfrm [PATH_MAX] = { 0, };
79*758e9fbaSOystein Eftevaag     size_t size;
80*758e9fbaSOystein Eftevaag 
81*758e9fbaSOystein Eftevaag     if (handle == NULL) {
82*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
83*758e9fbaSOystein Eftevaag     }
84*758e9fbaSOystein Eftevaag     *handle = dlopen(file, RTLD_NOW);
85*758e9fbaSOystein Eftevaag     if (*handle != NULL) {
86*758e9fbaSOystein Eftevaag         return TSS2_RC_SUCCESS;
87*758e9fbaSOystein Eftevaag     } else {
88*758e9fbaSOystein Eftevaag         LOG_DEBUG("Could not load TCTI file: \"%s\": %s", file, dlerror());
89*758e9fbaSOystein Eftevaag     }
90*758e9fbaSOystein Eftevaag     /* 'name' alone didn't work, try libtss2-tcti-<name>.so.0 */
91*758e9fbaSOystein Eftevaag     size = snprintf(file_xfrm,
92*758e9fbaSOystein Eftevaag                     sizeof (file_xfrm),
93*758e9fbaSOystein Eftevaag                     TCTI_NAME_TEMPLATE_0,
94*758e9fbaSOystein Eftevaag                     file);
95*758e9fbaSOystein Eftevaag     if (size >= sizeof (file_xfrm)) {
96*758e9fbaSOystein Eftevaag         LOG_ERROR("TCTI name truncated in transform.");
97*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_VALUE;
98*758e9fbaSOystein Eftevaag     }
99*758e9fbaSOystein Eftevaag     *handle = dlopen(file_xfrm, RTLD_NOW);
100*758e9fbaSOystein Eftevaag     if (*handle != NULL) {
101*758e9fbaSOystein Eftevaag         return TSS2_RC_SUCCESS;
102*758e9fbaSOystein Eftevaag     } else {
103*758e9fbaSOystein Eftevaag         LOG_DEBUG("Could not load TCTI file \"%s\": %s", file, dlerror());
104*758e9fbaSOystein Eftevaag     }
105*758e9fbaSOystein Eftevaag     /* libtss2-tcti-<name>.so.0 didn't work, try libtss2-tcti-<name>.so */
106*758e9fbaSOystein Eftevaag     size = snprintf(file_xfrm,
107*758e9fbaSOystein Eftevaag                     sizeof (file_xfrm),
108*758e9fbaSOystein Eftevaag                     TCTI_NAME_TEMPLATE,
109*758e9fbaSOystein Eftevaag                     file);
110*758e9fbaSOystein Eftevaag     if (size >= sizeof (file_xfrm)) {
111*758e9fbaSOystein Eftevaag         LOG_ERROR("TCTI name truncated in transform.");
112*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_VALUE;
113*758e9fbaSOystein Eftevaag     }
114*758e9fbaSOystein Eftevaag     *handle = dlopen(file_xfrm, RTLD_NOW);
115*758e9fbaSOystein Eftevaag     if (*handle == NULL) {
116*758e9fbaSOystein Eftevaag         LOG_DEBUG("Failed to load TCTI for name \"%s\": %s", file, dlerror());
117*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_NOT_SUPPORTED;
118*758e9fbaSOystein Eftevaag     }
119*758e9fbaSOystein Eftevaag 
120*758e9fbaSOystein Eftevaag     return TSS2_RC_SUCCESS;
121*758e9fbaSOystein Eftevaag }
122*758e9fbaSOystein Eftevaag TSS2_RC
tcti_from_file(const char * file,const char * conf,TSS2_TCTI_CONTEXT ** tcti,void ** dlhandle)123*758e9fbaSOystein Eftevaag tcti_from_file(const char *file,
124*758e9fbaSOystein Eftevaag                const char* conf,
125*758e9fbaSOystein Eftevaag                TSS2_TCTI_CONTEXT **tcti,
126*758e9fbaSOystein Eftevaag                void **dlhandle)
127*758e9fbaSOystein Eftevaag {
128*758e9fbaSOystein Eftevaag     TSS2_RC r;
129*758e9fbaSOystein Eftevaag     void *handle;
130*758e9fbaSOystein Eftevaag     TSS2_TCTI_INFO_FUNC infof;
131*758e9fbaSOystein Eftevaag 
132*758e9fbaSOystein Eftevaag     LOG_TRACE("Attempting to load TCTI file: %s", file);
133*758e9fbaSOystein Eftevaag     if (tcti == NULL) {
134*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
135*758e9fbaSOystein Eftevaag     }
136*758e9fbaSOystein Eftevaag     r = handle_from_name(file, &handle);
137*758e9fbaSOystein Eftevaag     if (r != TSS2_RC_SUCCESS) {
138*758e9fbaSOystein Eftevaag         return r;
139*758e9fbaSOystein Eftevaag     }
140*758e9fbaSOystein Eftevaag 
141*758e9fbaSOystein Eftevaag     infof = (TSS2_TCTI_INFO_FUNC) dlsym(handle, TSS2_TCTI_INFO_SYMBOL);
142*758e9fbaSOystein Eftevaag     if (infof == NULL) {
143*758e9fbaSOystein Eftevaag         LOG_ERROR("Info not found in TCTI file: %s", file);
144*758e9fbaSOystein Eftevaag         dlclose(handle);
145*758e9fbaSOystein Eftevaag         return TSS2_ESYS_RC_BAD_REFERENCE;
146*758e9fbaSOystein Eftevaag     }
147*758e9fbaSOystein Eftevaag 
148*758e9fbaSOystein Eftevaag     r = tcti_from_info(infof, conf, tcti);
149*758e9fbaSOystein Eftevaag     if (r != TSS2_RC_SUCCESS) {
150*758e9fbaSOystein Eftevaag         LOG_ERROR("Could not initialize TCTI file: %s", file);
151*758e9fbaSOystein Eftevaag         dlclose(handle);
152*758e9fbaSOystein Eftevaag         return r;
153*758e9fbaSOystein Eftevaag     }
154*758e9fbaSOystein Eftevaag 
155*758e9fbaSOystein Eftevaag     if (dlhandle)
156*758e9fbaSOystein Eftevaag         *dlhandle = handle;
157*758e9fbaSOystein Eftevaag 
158*758e9fbaSOystein Eftevaag     LOG_DEBUG("Initialized TCTI file: %s", file);
159*758e9fbaSOystein Eftevaag 
160*758e9fbaSOystein Eftevaag     return TSS2_RC_SUCCESS;
161*758e9fbaSOystein Eftevaag }
162*758e9fbaSOystein Eftevaag TSS2_RC
get_info_default(const TSS2_TCTI_INFO ** info,void ** dlhandle)163*758e9fbaSOystein Eftevaag get_info_default(const TSS2_TCTI_INFO **info,
164*758e9fbaSOystein Eftevaag                  void **dlhandle)
165*758e9fbaSOystein Eftevaag {
166*758e9fbaSOystein Eftevaag     void *handle = NULL;
167*758e9fbaSOystein Eftevaag     const TSS2_TCTI_INFO *info_src;
168*758e9fbaSOystein Eftevaag     char *name = NULL;
169*758e9fbaSOystein Eftevaag     TSS2_RC rc = TSS2_TCTI_RC_GENERAL_FAILURE;
170*758e9fbaSOystein Eftevaag 
171*758e9fbaSOystein Eftevaag     LOG_DEBUG("%s", __func__);
172*758e9fbaSOystein Eftevaag     if (info == NULL || dlhandle == NULL) {
173*758e9fbaSOystein Eftevaag         LOG_ERROR("parameters cannot be NULL");
174*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
175*758e9fbaSOystein Eftevaag     }
176*758e9fbaSOystein Eftevaag #ifdef ESYS_TCTI_DEFAULT_MODULE
177*758e9fbaSOystein Eftevaag     name = ESYS_TCTI_DEFAULT_MODULE;
178*758e9fbaSOystein Eftevaag     LOG_DEBUG("name: %s", name);
179*758e9fbaSOystein Eftevaag     rc = handle_from_name (name, &handle);
180*758e9fbaSOystein Eftevaag     if (rc != TSS2_RC_SUCCESS)
181*758e9fbaSOystein Eftevaag         return rc;
182*758e9fbaSOystein Eftevaag     else if (handle == NULL)
183*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_IO_ERROR;
184*758e9fbaSOystein Eftevaag #else
185*758e9fbaSOystein Eftevaag     size_t i;
186*758e9fbaSOystein Eftevaag     for (i = 0; i < ARRAY_SIZE(tctis); i++) {
187*758e9fbaSOystein Eftevaag         name = tctis[i].file;
188*758e9fbaSOystein Eftevaag         LOG_DEBUG("name: %s", name);
189*758e9fbaSOystein Eftevaag         if (name == NULL) {
190*758e9fbaSOystein Eftevaag             continue;
191*758e9fbaSOystein Eftevaag         }
192*758e9fbaSOystein Eftevaag         rc = handle_from_name (name, &handle);
193*758e9fbaSOystein Eftevaag         if (rc != TSS2_RC_SUCCESS || handle == NULL) {
194*758e9fbaSOystein Eftevaag             LOG_DEBUG("Failed to get handle for TCTI with name: %s", name);
195*758e9fbaSOystein Eftevaag             continue;
196*758e9fbaSOystein Eftevaag         }
197*758e9fbaSOystein Eftevaag 
198*758e9fbaSOystein Eftevaag         break;
199*758e9fbaSOystein Eftevaag     }
200*758e9fbaSOystein Eftevaag #endif /* ESYS_TCTI_DEFAULT_MODULE */
201*758e9fbaSOystein Eftevaag 
202*758e9fbaSOystein Eftevaag     info_src = info_from_handle (handle);
203*758e9fbaSOystein Eftevaag     if (info_src != NULL) {
204*758e9fbaSOystein Eftevaag         *info = info_src;
205*758e9fbaSOystein Eftevaag     } else {
206*758e9fbaSOystein Eftevaag         tctildr_finalize_data (&handle);
207*758e9fbaSOystein Eftevaag         rc = TSS2_TCTI_RC_GENERAL_FAILURE;
208*758e9fbaSOystein Eftevaag     }
209*758e9fbaSOystein Eftevaag     *dlhandle = handle;
210*758e9fbaSOystein Eftevaag 
211*758e9fbaSOystein Eftevaag     return rc;
212*758e9fbaSOystein Eftevaag }
213*758e9fbaSOystein Eftevaag 
214*758e9fbaSOystein Eftevaag TSS2_RC
tctildr_get_default(TSS2_TCTI_CONTEXT ** tcticontext,void ** dlhandle)215*758e9fbaSOystein Eftevaag tctildr_get_default(TSS2_TCTI_CONTEXT ** tcticontext, void **dlhandle)
216*758e9fbaSOystein Eftevaag {
217*758e9fbaSOystein Eftevaag     if (tcticontext == NULL) {
218*758e9fbaSOystein Eftevaag         LOG_ERROR("tcticontext must not be NULL");
219*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
220*758e9fbaSOystein Eftevaag     }
221*758e9fbaSOystein Eftevaag     *tcticontext = NULL;
222*758e9fbaSOystein Eftevaag #ifdef ESYS_TCTI_DEFAULT_MODULE
223*758e9fbaSOystein Eftevaag 
224*758e9fbaSOystein Eftevaag #ifdef ESYS_TCTI_DEFAULT_CONFIG
225*758e9fbaSOystein Eftevaag     const char *config = ESYS_TCTI_DEFAULT_CONFIG;
226*758e9fbaSOystein Eftevaag #else /* ESYS_TCTI_DEFAULT_CONFIG */
227*758e9fbaSOystein Eftevaag     const char *config = NULL;
228*758e9fbaSOystein Eftevaag #endif /* ESYS_TCTI_DEFAULT_CONFIG */
229*758e9fbaSOystein Eftevaag 
230*758e9fbaSOystein Eftevaag     LOG_DEBUG("Attempting to initialize TCTI defined during compilation: %s:%s",
231*758e9fbaSOystein Eftevaag               ESYS_TCTI_DEFAULT_MODULE, config);
232*758e9fbaSOystein Eftevaag     return tcti_from_file(ESYS_TCTI_DEFAULT_MODULE, config, tcticontext,
233*758e9fbaSOystein Eftevaag                           dlhandle);
234*758e9fbaSOystein Eftevaag 
235*758e9fbaSOystein Eftevaag #else /* ESYS_TCTI_DEFAULT_MODULE */
236*758e9fbaSOystein Eftevaag 
237*758e9fbaSOystein Eftevaag     TSS2_RC r;
238*758e9fbaSOystein Eftevaag     size_t i;
239*758e9fbaSOystein Eftevaag 
240*758e9fbaSOystein Eftevaag     for (i = 0; i < ARRAY_SIZE(tctis); i++) {
241*758e9fbaSOystein Eftevaag         LOG_DEBUG("Attempting to connect using standard TCTI: %s",
242*758e9fbaSOystein Eftevaag                   tctis[i].description);
243*758e9fbaSOystein Eftevaag         r = tcti_from_file(tctis[i].file, tctis[i].conf, tcticontext,
244*758e9fbaSOystein Eftevaag                            dlhandle);
245*758e9fbaSOystein Eftevaag         if (r == TSS2_RC_SUCCESS)
246*758e9fbaSOystein Eftevaag             return TSS2_RC_SUCCESS;
247*758e9fbaSOystein Eftevaag         LOG_DEBUG("Failed to load standard TCTI number %zu", i);
248*758e9fbaSOystein Eftevaag     }
249*758e9fbaSOystein Eftevaag 
250*758e9fbaSOystein Eftevaag     LOG_ERROR("No standard TCTI could be loaded");
251*758e9fbaSOystein Eftevaag     return TSS2_TCTI_RC_IO_ERROR;
252*758e9fbaSOystein Eftevaag 
253*758e9fbaSOystein Eftevaag #endif /* ESYS_TCTI_DEFAULT_MODULE */
254*758e9fbaSOystein Eftevaag }
255*758e9fbaSOystein Eftevaag TSS2_RC
info_from_name(const char * name,const TSS2_TCTI_INFO ** info,void ** data)256*758e9fbaSOystein Eftevaag info_from_name (const char *name,
257*758e9fbaSOystein Eftevaag                 const TSS2_TCTI_INFO **info,
258*758e9fbaSOystein Eftevaag                 void **data)
259*758e9fbaSOystein Eftevaag {
260*758e9fbaSOystein Eftevaag     TSS2_RC rc;
261*758e9fbaSOystein Eftevaag 
262*758e9fbaSOystein Eftevaag     if (data == NULL || info == NULL)
263*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
264*758e9fbaSOystein Eftevaag     rc = handle_from_name (name, data);
265*758e9fbaSOystein Eftevaag     if (rc != TSS2_RC_SUCCESS)
266*758e9fbaSOystein Eftevaag         return rc;
267*758e9fbaSOystein Eftevaag     *info = (TSS2_TCTI_INFO*)info_from_handle (*data);
268*758e9fbaSOystein Eftevaag     if (*info == NULL) {
269*758e9fbaSOystein Eftevaag         tctildr_finalize_data (data);
270*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_IO_ERROR;
271*758e9fbaSOystein Eftevaag     }
272*758e9fbaSOystein Eftevaag     return rc;
273*758e9fbaSOystein Eftevaag }
274*758e9fbaSOystein Eftevaag TSS2_RC
tctildr_get_info(const char * name,const TSS2_TCTI_INFO ** info,void ** data)275*758e9fbaSOystein Eftevaag tctildr_get_info(const char *name,
276*758e9fbaSOystein Eftevaag                  const TSS2_TCTI_INFO **info,
277*758e9fbaSOystein Eftevaag                  void **data)
278*758e9fbaSOystein Eftevaag {
279*758e9fbaSOystein Eftevaag     if (info == NULL) {
280*758e9fbaSOystein Eftevaag         LOG_ERROR("info must not be NULL");
281*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
282*758e9fbaSOystein Eftevaag     }
283*758e9fbaSOystein Eftevaag     if (name != NULL) {
284*758e9fbaSOystein Eftevaag         return info_from_name (name, info, data);
285*758e9fbaSOystein Eftevaag     } else {
286*758e9fbaSOystein Eftevaag         return get_info_default (info, data);
287*758e9fbaSOystein Eftevaag     }
288*758e9fbaSOystein Eftevaag }
289*758e9fbaSOystein Eftevaag TSS2_RC
tctildr_get_tcti(const char * name,const char * conf,TSS2_TCTI_CONTEXT ** tcti,void ** data)290*758e9fbaSOystein Eftevaag tctildr_get_tcti(const char *name,
291*758e9fbaSOystein Eftevaag                  const char* conf,
292*758e9fbaSOystein Eftevaag                  TSS2_TCTI_CONTEXT **tcti,
293*758e9fbaSOystein Eftevaag                  void **data)
294*758e9fbaSOystein Eftevaag {
295*758e9fbaSOystein Eftevaag     LOG_DEBUG("name: \"%s\", conf: \"%s\"", name, conf);
296*758e9fbaSOystein Eftevaag     if (tcti == NULL) {
297*758e9fbaSOystein Eftevaag         LOG_ERROR("tcticontext must not be NULL");
298*758e9fbaSOystein Eftevaag         return TSS2_TCTI_RC_BAD_REFERENCE;
299*758e9fbaSOystein Eftevaag     }
300*758e9fbaSOystein Eftevaag     *tcti = NULL;
301*758e9fbaSOystein Eftevaag     if (name == NULL) {
302*758e9fbaSOystein Eftevaag         return tctildr_get_default (tcti, data);
303*758e9fbaSOystein Eftevaag     }
304*758e9fbaSOystein Eftevaag 
305*758e9fbaSOystein Eftevaag     return tcti_from_file (name, conf, tcti, data);
306*758e9fbaSOystein Eftevaag }
307*758e9fbaSOystein Eftevaag 
308*758e9fbaSOystein Eftevaag void
tctildr_finalize_data(void ** data)309*758e9fbaSOystein Eftevaag tctildr_finalize_data (void **data)
310*758e9fbaSOystein Eftevaag {
311*758e9fbaSOystein Eftevaag     if (data != NULL && *data != NULL) {
312*758e9fbaSOystein Eftevaag         dlclose(*data);
313*758e9fbaSOystein Eftevaag         *data = NULL;
314*758e9fbaSOystein Eftevaag     }
315*758e9fbaSOystein Eftevaag }
316