Add an IMV constructor taking a set of custom TNC_IMV functions
[strongswan.git] / src / libcharon / plugins / tnc_imv / tnc_imv.c
1 /*
2 * Copyright (C) 2006 Mike McCauley
3 * Copyright (C) 2010-2011 Andreas Steffen,
4 * HSR Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "tnc_imv.h"
18
19 #include <dlfcn.h>
20
21 #include <tncif_pa_subtypes.h>
22
23 #include <utils/debug.h>
24 #include <library.h>
25 #include <collections/linked_list.h>
26 #include <threading/mutex.h>
27
28 typedef struct private_tnc_imv_t private_tnc_imv_t;
29
30 /**
31 * Private data of an imv_t object.
32 */
33 struct private_tnc_imv_t {
34
35 /**
36 * Public members of imv_t.
37 */
38 imv_t public;
39
40 /**
41 * Name of loaded IMV
42 */
43 char *name;
44
45 /**
46 * Handle of loaded IMV
47 */
48 void *handle;
49
50 /**
51 * ID of loaded IMV
52 */
53 TNC_IMVID id;
54
55 /**
56 * List of additional IMV IDs
57 */
58 linked_list_t *additional_ids;
59
60 /**
61 * List of message types supported by IMV - Vendor ID part
62 */
63 TNC_VendorIDList supported_vids;
64
65 /**
66 * List of message types supported by IMV - Subtype part
67 */
68 TNC_MessageSubtypeList supported_subtypes;
69
70 /**
71 * Number of supported message types
72 */
73 TNC_UInt32 type_count;
74
75 /**
76 * mutex to lock the imv_t object
77 */
78 mutex_t *mutex;
79 };
80
81 METHOD(imv_t, set_id, void,
82 private_tnc_imv_t *this, TNC_IMVID id)
83 {
84 this->id = id;
85 }
86
87 METHOD(imv_t, get_id, TNC_IMVID,
88 private_tnc_imv_t *this)
89 {
90 return this->id;
91 }
92
93 METHOD(imv_t, add_id, void,
94 private_tnc_imv_t *this, TNC_IMVID id)
95 {
96 TNC_IMVID *new_id;
97
98 new_id = malloc_thing(TNC_IMVID);
99 *new_id = id;
100 this->additional_ids->insert_last(this->additional_ids, new_id);
101 }
102
103 METHOD(imv_t, has_id, bool,
104 private_tnc_imv_t *this, TNC_IMVID id)
105 {
106 enumerator_t *enumerator;
107 TNC_IMVID *additional_id;
108 bool found = FALSE;
109
110 /* check primary IMV ID */
111 if (id == this->id)
112 {
113 return TRUE;
114 }
115
116 /* return if there are no additional IMV IDs */
117 if (this->additional_ids->get_count(this->additional_ids) == 0)
118 {
119 return FALSE;
120 }
121
122 /* check additional IMV IDs */
123 enumerator = this->additional_ids->create_enumerator(this->additional_ids);
124 while (enumerator->enumerate(enumerator, &additional_id))
125 {
126 if (id == *additional_id)
127 {
128 found = TRUE;
129 break;
130 }
131 }
132 enumerator->destroy(enumerator);
133
134 return found;
135 }
136
137 METHOD(imv_t, get_name, char*,
138 private_tnc_imv_t *this)
139 {
140 return this->name;
141 }
142
143 METHOD(imv_t, set_message_types, void,
144 private_tnc_imv_t *this, TNC_MessageTypeList supported_types,
145 TNC_UInt32 type_count)
146 {
147 char buf[BUF_LEN];
148 char *pos = buf;
149 int len = sizeof(buf);
150 int i, written;
151 size_t size;
152 TNC_VendorID vid;
153 TNC_MessageSubtype subtype;
154 enum_name_t *pa_subtype_names;
155
156 /* lock the imv_t instance */
157 this->mutex->lock(this->mutex);
158
159 /* Free existing VendorID and MessageSubtype lists */
160 free(this->supported_vids);
161 this->supported_vids = NULL;
162 free(this->supported_subtypes);
163 this->supported_subtypes = NULL;
164
165 /* Store the new MessageType list */
166 this->type_count = type_count;
167 if (type_count && supported_types)
168 {
169 size = type_count * sizeof(TNC_VendorID);
170 this->supported_vids = malloc(size);
171 size = type_count * sizeof(TNC_MessageSubtype);
172 this->supported_subtypes = malloc(size);
173
174 for (i = 0; i < type_count; i++)
175 {
176 vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
177 subtype = supported_types[i] & TNC_SUBTYPE_ANY;
178
179 pa_subtype_names = get_pa_subtype_names(vid);
180 if (pa_subtype_names)
181 {
182 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
183 pen_names, vid, pa_subtype_names, subtype,
184 vid, subtype);
185 }
186 else
187 {
188 written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
189 pen_names, vid, vid, subtype);
190 }
191 if (written >= len)
192 {
193 break;
194 }
195 pos += written;
196 len -= written;
197
198 this->supported_vids[i] = vid;
199 this->supported_subtypes[i] = subtype;
200 }
201 }
202 *pos = '\0';
203 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
204 this->id, type_count, (type_count == 1) ? "":"s", buf);
205
206 /* unlock the imv_t instance */
207 this->mutex->unlock(this->mutex);
208 }
209
210 METHOD(imv_t, set_message_types_long, void,
211 private_tnc_imv_t *this, TNC_VendorIDList supported_vids,
212 TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
213 {
214 char buf[BUF_LEN];
215 char *pos = buf;
216 int len = sizeof(buf);
217 int i, written;
218 size_t size;
219 TNC_VendorID vid;
220 TNC_MessageSubtype subtype;
221 enum_name_t *pa_subtype_names;
222
223 /* lock the imv_t instance */
224 this->mutex->lock(this->mutex);
225
226 /* Free existing VendorID and MessageSubtype lists */
227 free(this->supported_vids);
228 this->supported_vids = NULL;
229 free(this->supported_subtypes);
230 this->supported_subtypes = NULL;
231
232 /* Store the new MessageType list */
233 this->type_count = type_count;
234 if (type_count && supported_vids && supported_subtypes)
235 {
236 size = type_count * sizeof(TNC_VendorID);
237 this->supported_vids = malloc(size);
238 memcpy(this->supported_vids, supported_vids, size);
239 size = type_count * sizeof(TNC_MessageSubtype);
240 this->supported_subtypes = malloc(size);
241 memcpy(this->supported_subtypes, supported_subtypes, size);
242
243 for (i = 0; i < type_count; i++)
244 {
245 vid = supported_vids[i];
246 subtype = supported_subtypes[i];
247
248 pa_subtype_names = get_pa_subtype_names(vid);
249 if (pa_subtype_names)
250 {
251 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
252 pen_names, vid, pa_subtype_names, subtype,
253 vid, subtype);
254 }
255 else
256 {
257 written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
258 pen_names, vid, vid, subtype);
259 }
260 if (written >= len)
261 {
262 break;
263 }
264 pos += written;
265 len -= written;
266 }
267 }
268 *pos = '\0';
269 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
270 this->id, type_count, (type_count == 1) ? "":"s", buf);
271
272 /* unlock the imv_t instance */
273 this->mutex->unlock(this->mutex);
274 }
275
276 METHOD(imv_t, type_supported, bool,
277 private_tnc_imv_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
278 {
279 TNC_VendorID vid;
280 TNC_MessageSubtype subtype;
281 int i;
282
283 for (i = 0; i < this->type_count; i++)
284 {
285 vid = this->supported_vids[i];
286 subtype = this->supported_subtypes[i];
287
288 if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
289 (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
290 subtype == msg_subtype)))
291 {
292 return TRUE;
293 }
294 }
295 return FALSE;
296 }
297
298 METHOD(imv_t, destroy, void,
299 private_tnc_imv_t *this)
300 {
301 if (this->handle)
302 {
303 dlclose(this->handle);
304 }
305 this->mutex->destroy(this->mutex);
306 this->additional_ids->destroy_function(this->additional_ids, free);
307 free(this->supported_vids);
308 free(this->supported_subtypes);
309 free(this->name);
310 free(this);
311 }
312
313 /**
314 * Generic constructor.
315 */
316 static private_tnc_imv_t* tnc_imv_create_empty(char *name)
317 {
318 private_tnc_imv_t *this;
319
320 INIT(this,
321 .public = {
322 .set_id = _set_id,
323 .get_id = _get_id,
324 .add_id = _add_id,
325 .has_id = _has_id,
326 .get_name = _get_name,
327 .set_message_types = _set_message_types,
328 .set_message_types_long = _set_message_types_long,
329 .type_supported = _type_supported,
330 .destroy = _destroy,
331 },
332 .name = strdup(name),
333 .additional_ids = linked_list_create(),
334 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
335 );
336
337 return this;
338 }
339
340 /**
341 * Described in header.
342 */
343 imv_t* tnc_imv_create(char *name, char *path)
344 {
345 private_tnc_imv_t *this;
346
347 this = tnc_imv_create_empty(name);
348
349 this->handle = dlopen(path, RTLD_LAZY);
350 if (!this->handle)
351 {
352 DBG1(DBG_TNC, "IMV \"%s\" failed to load: %s", name, dlerror());
353 destroy(this);
354 return NULL;
355 }
356
357 this->public.initialize = dlsym(this->handle, "TNC_IMV_Initialize");
358 if (!this->public.initialize)
359 {
360 DBG1(DBG_TNC, "could not resolve TNC_IMV_Initialize in %s: %s\n",
361 path, dlerror());
362 destroy(this);
363 return NULL;
364 }
365 this->public.notify_connection_change =
366 dlsym(this->handle, "TNC_IMV_NotifyConnectionChange");
367 this->public.solicit_recommendation =
368 dlsym(this->handle, "TNC_IMV_SolicitRecommendation");
369 if (!this->public.solicit_recommendation)
370 {
371 DBG1(DBG_TNC, "could not resolve TNC_IMV_SolicitRecommendation in %s: %s\n",
372 path, dlerror());
373 destroy(this);
374 return NULL;
375 }
376 this->public.receive_message =
377 dlsym(this->handle, "TNC_IMV_ReceiveMessage");
378 this->public.receive_message_long =
379 dlsym(this->handle, "TNC_IMV_ReceiveMessageLong");
380 this->public.batch_ending =
381 dlsym(this->handle, "TNC_IMV_BatchEnding");
382 this->public.terminate =
383 dlsym(this->handle, "TNC_IMV_Terminate");
384 this->public.provide_bind_function =
385 dlsym(this->handle, "TNC_IMV_ProvideBindFunction");
386 if (!this->public.provide_bind_function)
387 {
388 DBG1(DBG_TNC, "could not resolve TNC_IMV_ProvideBindFunction in %s: %s\n",
389 path, dlerror());
390 destroy(this);
391 return NULL;
392 }
393
394 return &this->public;
395 }
396
397 /**
398 * Described in header.
399 */
400 imv_t* tnc_imv_create_from_functions(char *name,
401 TNC_IMV_InitializePointer initialize,
402 TNC_IMV_NotifyConnectionChangePointer notify_connection_change,
403 TNC_IMV_ReceiveMessagePointer receive_message,
404 TNC_IMV_ReceiveMessageLongPointer receive_message_long,
405 TNC_IMV_SolicitRecommendationPointer solicit_recommendation,
406 TNC_IMV_BatchEndingPointer batch_ending,
407 TNC_IMV_TerminatePointer terminate,
408 TNC_IMV_ProvideBindFunctionPointer provide_bind_function)
409 {
410 private_tnc_imv_t *this;
411
412 this = tnc_imv_create_empty(name);
413
414 this->public.initialize = initialize;
415 this->public.notify_connection_change = notify_connection_change;
416 this->public.receive_message = receive_message;
417 this->public.receive_message_long = receive_message_long;
418 this->public.solicit_recommendation = solicit_recommendation;
419 this->public.batch_ending = batch_ending;
420 this->public.terminate = terminate;
421 this->public.provide_bind_function = provide_bind_function;
422
423 return &this->public;
424 }