unload the IMCs and IMVs using dlclose()
[strongswan.git] / src / libcharon / plugins / tnc_imc / tnc_imc.c
1 /*
2 * Copyright (C) 2006 Mike McCauley
3 * Copyright (C) 2010 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tnc_imc.h"
17
18 #include <dlfcn.h>
19
20 #include <debug.h>
21 #include <library.h>
22
23 typedef struct private_tnc_imc_t private_tnc_imc_t;
24
25 /**
26 * Private data of an imv_t object.
27 */
28 struct private_tnc_imc_t {
29
30 /**
31 * Public members of imc_t.
32 */
33 imc_t public;
34
35 /**
36 * Name of loaded IMC
37 */
38 char *name;
39
40 /**
41 * Handle of loaded IMC
42 */
43 void *handle;
44
45 /**
46 * ID of loaded IMC
47 */
48 TNC_IMCID id;
49
50 /**
51 * List of message types supported by IMC
52 */
53 TNC_MessageTypeList supported_types;
54
55 /**
56 * Number of supported message types
57 */
58 TNC_UInt32 type_count;
59 };
60
61 METHOD(imc_t, set_id, void,
62 private_tnc_imc_t *this, TNC_IMCID id)
63 {
64 this->id = id;
65 }
66
67 METHOD(imc_t, get_id, TNC_IMCID,
68 private_tnc_imc_t *this)
69 {
70 return this->id;
71 }
72
73 METHOD(imc_t, get_name, char*,
74 private_tnc_imc_t *this)
75 {
76 return this->name;
77 }
78
79 METHOD(imc_t, set_message_types, void,
80 private_tnc_imc_t *this, TNC_MessageTypeList supported_types,
81 TNC_UInt32 type_count)
82 {
83 /* Free an existing MessageType list */
84 free(this->supported_types);
85 this->supported_types = NULL;
86
87 /* Store the new MessageType list */
88 this->type_count = type_count;
89 if (type_count && supported_types)
90 {
91 size_t size = type_count * sizeof(TNC_MessageType);
92
93 this->supported_types = malloc(size);
94 memcpy(this->supported_types, supported_types, size);
95 }
96 DBG2(DBG_TNC, "IMC %u supports %u message types", this->id, type_count);
97 }
98
99 METHOD(imc_t, type_supported, bool,
100 private_tnc_imc_t *this, TNC_MessageType message_type)
101 {
102 TNC_VendorID msg_vid, vid;
103 TNC_MessageSubtype msg_subtype, subtype;
104 int i;
105
106 msg_vid = (message_type >> 8) & TNC_VENDORID_ANY;
107 msg_subtype = message_type & TNC_SUBTYPE_ANY;
108
109 for (i = 0; i < this->type_count; i++)
110 {
111 vid = (this->supported_types[i] >> 8) & TNC_VENDORID_ANY;
112 subtype = this->supported_types[i] & TNC_SUBTYPE_ANY;
113
114 if (this->supported_types[i] == message_type
115 || (subtype == TNC_SUBTYPE_ANY
116 && (msg_vid == vid || vid == TNC_VENDORID_ANY))
117 || (vid == TNC_VENDORID_ANY
118 && (msg_subtype == subtype || subtype == TNC_SUBTYPE_ANY)))
119 {
120 return TRUE;
121 }
122 }
123 return FALSE;
124 }
125
126 METHOD(imc_t, destroy, void,
127 private_tnc_imc_t *this)
128 {
129 dlclose(this->handle);
130 free(this->supported_types);
131 free(this->name);
132 free(this);
133 }
134
135 /**
136 * Described in header.
137 */
138 imc_t* tnc_imc_create(char* name, char *filename)
139 {
140 private_tnc_imc_t *this;
141
142 INIT(this,
143 .public = {
144 .set_id = _set_id,
145 .get_id = _get_id,
146 .get_name = _get_name,
147 .set_message_types = _set_message_types,
148 .type_supported = _type_supported,
149 .destroy = _destroy,
150 },
151 );
152
153 this->handle = dlopen(filename, RTLD_NOW);
154 if (!this->handle)
155 {
156 DBG1(DBG_TNC, "IMC '%s' failed to load from '%s': %s",
157 name, filename, dlerror());
158 free(this);
159 return NULL;
160 }
161
162 /* we do not store or free dlopen() this->handles, leak_detective requires
163 * the modules to keep loaded until leak report */
164
165 this->public.initialize = dlsym(this->handle, "TNC_IMC_Initialize");
166 if (!this->public.initialize)
167 {
168 DBG1(DBG_TNC, "could not resolve TNC_IMC_Initialize in %s: %s\n",
169 filename, dlerror());
170 dlclose(this->handle);
171 free(this);
172 return NULL;
173 }
174 this->public.notify_connection_change =
175 dlsym(this->handle, "TNC_IMC_NotifyConnectionChange");
176 this->public.begin_handshake = dlsym(this->handle, "TNC_IMC_BeginHandshake");
177 if (!this->public.begin_handshake)
178 {
179 DBG1(DBG_TNC, "could not resolve TNC_IMC_BeginHandshake in %s: %s\n",
180 filename, dlerror());
181 dlclose(this->handle);
182 free(this);
183 return NULL;
184 }
185 this->public.receive_message =
186 dlsym(this->handle, "TNC_IMC_ReceiveMessage");
187 this->public.batch_ending =
188 dlsym(this->handle, "TNC_IMC_BatchEnding");
189 this->public.terminate =
190 dlsym(this->handle, "TNC_IMC_Terminate");
191 this->public.provide_bind_function =
192 dlsym(this->handle, "TNC_IMC_ProvideBindFunction");
193 if (!this->public.provide_bind_function)
194 {
195 DBG1(DBG_TNC, "could not resolve TNC_IMC_ProvideBindFunction in %s: %s\n",
196 filename, dlerror());
197 dlclose(this->handle);
198 free(this);
199 return NULL;
200 }
201 this->name = strdup(name);
202
203 return &this->public;
204 }