added TNC_IMC_ReceiveMessageLong() and TNC_IMV_ReceiveMessageLong() support
[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 <debug.h>
24 #include <library.h>
25 #include <utils/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 * Path of loaded IMV
42 */
43 char *path;
44
45 /**
46 * Name of loaded IMV
47 */
48 char *name;
49
50 /**
51 * Handle of loaded IMV
52 */
53 void *handle;
54
55 /**
56 * ID of loaded IMV
57 */
58 TNC_IMVID id;
59
60 /**
61 * List of additional IMV IDs
62 */
63 linked_list_t *additional_ids;
64
65 /**
66 * List of message types supported by IMV - Vendor ID part
67 */
68 TNC_VendorIDList supported_vids;
69
70 /**
71 * List of message types supported by IMV - Subtype part
72 */
73 TNC_MessageSubtypeList supported_subtypes;
74
75 /**
76 * Number of supported message types
77 */
78 TNC_UInt32 type_count;
79
80 /**
81 * mutex to lock the imv_t object
82 */
83 mutex_t *mutex;
84 };
85
86 METHOD(imv_t, set_id, void,
87 private_tnc_imv_t *this, TNC_IMVID id)
88 {
89 this->id = id;
90 }
91
92 METHOD(imv_t, get_id, TNC_IMVID,
93 private_tnc_imv_t *this)
94 {
95 return this->id;
96 }
97
98 METHOD(imv_t, add_id, void,
99 private_tnc_imv_t *this, TNC_IMVID id)
100 {
101 TNC_IMVID *new_id;
102
103 new_id = malloc_thing(TNC_IMVID);
104 *new_id = id;
105 this->additional_ids->insert_last(this->additional_ids, new_id);
106 }
107
108 METHOD(imv_t, has_id, bool,
109 private_tnc_imv_t *this, TNC_IMVID id)
110 {
111 enumerator_t *enumerator;
112 TNC_IMVID *additional_id;
113 bool found = FALSE;
114
115 /* check primary IMV ID */
116 if (id == this->id)
117 {
118 return TRUE;
119 }
120
121 /* return if there are no additional IMV IDs */
122 if (this->additional_ids->get_count(this->additional_ids) == 0)
123 {
124 return FALSE;
125 }
126
127 /* check additional IMV IDs */
128 enumerator = this->additional_ids->create_enumerator(this->additional_ids);
129 while (enumerator->enumerate(enumerator, &additional_id))
130 {
131 if (id == *additional_id)
132 {
133 found = TRUE;
134 break;
135 }
136 }
137 enumerator->destroy(enumerator);
138
139 return found;
140 }
141
142 METHOD(imv_t, get_name, char*,
143 private_tnc_imv_t *this)
144 {
145 return this->name;
146 }
147
148 METHOD(imv_t, set_message_types, void,
149 private_tnc_imv_t *this, TNC_MessageTypeList supported_types,
150 TNC_UInt32 type_count)
151 {
152 char buf[BUF_LEN];
153 char *pos = buf;
154 int len = sizeof(buf);
155 int i, written;
156 size_t size;
157 TNC_VendorID vid;
158 TNC_MessageSubtype subtype;
159 enum_name_t *pa_subtype_names;
160
161 /* lock the imv_t instance */
162 this->mutex->lock(this->mutex);
163
164 /* Free existing VendorID and MessageSubtype lists */
165 free(this->supported_vids);
166 this->supported_vids = NULL;
167 free(this->supported_subtypes);
168 this->supported_subtypes = NULL;
169
170 /* Store the new MessageType list */
171 this->type_count = type_count;
172 if (type_count && supported_types)
173 {
174 size = type_count * sizeof(TNC_VendorID);
175 this->supported_vids = malloc(size);
176 size = type_count * sizeof(TNC_MessageSubtype);
177 this->supported_subtypes = malloc(size);
178
179 for (i = 0; i < type_count; i++)
180 {
181 vid = (supported_types[i] >> 8) & TNC_VENDORID_ANY;
182 subtype = supported_types[i] & TNC_SUBTYPE_ANY;
183
184 pa_subtype_names = get_pa_subtype_names(vid);
185 if (pa_subtype_names)
186 {
187 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%02x",
188 pen_names, vid, pa_subtype_names, subtype,
189 vid, subtype);
190 }
191 else
192 {
193 written = snprintf(pos, len," '%N' 0x%06x/0x%02x",
194 pen_names, vid, vid, subtype);
195 }
196 if (written >= len)
197 {
198 break;
199 }
200 pos += written;
201 len -= written;
202
203 this->supported_vids[i] = vid;
204 this->supported_subtypes[i] = subtype;
205 }
206 }
207 *pos = '\0';
208 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
209 this->id, type_count, (type_count == 1) ? "":"s", buf);
210
211 /* unlock the imv_t instance */
212 this->mutex->unlock(this->mutex);
213 }
214
215 METHOD(imv_t, set_message_types_long, void,
216 private_tnc_imv_t *this, TNC_VendorIDList supported_vids,
217 TNC_MessageSubtypeList supported_subtypes, TNC_UInt32 type_count)
218 {
219 char buf[BUF_LEN];
220 char *pos = buf;
221 int len = sizeof(buf);
222 int i, written;
223 size_t size;
224 TNC_VendorID vid;
225 TNC_MessageSubtype subtype;
226 enum_name_t *pa_subtype_names;
227
228 /* lock the imv_t instance */
229 this->mutex->lock(this->mutex);
230
231 /* Free existing VendorID and MessageSubtype lists */
232 free(this->supported_vids);
233 this->supported_vids = NULL;
234 free(this->supported_subtypes);
235 this->supported_subtypes = NULL;
236
237 /* Store the new MessageType list */
238 this->type_count = type_count;
239 if (type_count && supported_vids && supported_subtypes)
240 {
241 size = type_count * sizeof(TNC_VendorID);
242 this->supported_vids = malloc(size);
243 memcpy(this->supported_vids, supported_vids, size);
244 size = type_count * sizeof(TNC_MessageSubtype);
245 this->supported_subtypes = malloc(size);
246 memcpy(this->supported_subtypes, supported_subtypes, size);
247
248 for (i = 0; i < type_count; i++)
249 {
250 vid = supported_vids[i];
251 subtype = supported_subtypes[i];
252
253 pa_subtype_names = get_pa_subtype_names(vid);
254 if (pa_subtype_names)
255 {
256 written = snprintf(pos, len," '%N/%N' 0x%06x/0x%08x",
257 pen_names, vid, pa_subtype_names, subtype,
258 vid, subtype);
259 }
260 else
261 {
262 written = snprintf(pos, len," '%N' 0x%06x/0x%08x",
263 pen_names, vid, vid, subtype);
264 }
265 if (written >= len)
266 {
267 break;
268 }
269 pos += written;
270 len -= written;
271 }
272 }
273 *pos = '\0';
274 DBG2(DBG_TNC, "IMV %u supports %u message type%s:%s",
275 this->id, type_count, (type_count == 1) ? "":"s", buf);
276
277 /* unlock the imv_t instance */
278 this->mutex->unlock(this->mutex);
279 }
280
281 METHOD(imv_t, type_supported, bool,
282 private_tnc_imv_t *this, TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype)
283 {
284 TNC_VendorID vid;
285 TNC_MessageSubtype subtype;
286 int i;
287
288 for (i = 0; i < this->type_count; i++)
289 {
290 vid = this->supported_vids[i];
291 subtype = this->supported_subtypes[i];
292
293 if ((vid == TNC_VENDORID_ANY && subtype == TNC_SUBTYPE_ANY) ||
294 (vid == msg_vid && (subtype == TNC_SUBTYPE_ANY ||
295 subtype == msg_subtype)))
296 {
297 return TRUE;
298 }
299 }
300 return FALSE;
301 }
302
303 METHOD(imv_t, destroy, void,
304 private_tnc_imv_t *this)
305 {
306 dlclose(this->handle);
307 this->mutex->destroy(this->mutex);
308 this->additional_ids->destroy_function(this->additional_ids, free);
309 free(this->supported_vids);
310 free(this->supported_subtypes);
311 free(this->name);
312 free(this->path);
313 free(this);
314 }
315
316 /**
317 * Described in header.
318 */
319 imv_t* tnc_imv_create(char *name, char *path)
320 {
321 private_tnc_imv_t *this;
322
323 INIT(this,
324 .public = {
325 .set_id = _set_id,
326 .get_id = _get_id,
327 .add_id = _add_id,
328 .has_id = _has_id,
329 .get_name = _get_name,
330 .set_message_types = _set_message_types,
331 .set_message_types_long = _set_message_types_long,
332 .type_supported = _type_supported,
333 .destroy = _destroy,
334 },
335 .name = name,
336 .path = path,
337 .additional_ids = linked_list_create(),
338 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
339 );
340
341 this->handle = dlopen(path, RTLD_LAZY);
342 if (!this->handle)
343 {
344 DBG1(DBG_TNC, "IMV \"%s\" failed to load: %s", name, dlerror());
345 free(this);
346 return NULL;
347 }
348
349 this->public.initialize = dlsym(this->handle, "TNC_IMV_Initialize");
350 if (!this->public.initialize)
351 {
352 DBG1(DBG_TNC, "could not resolve TNC_IMV_Initialize in %s: %s\n",
353 path, dlerror());
354 dlclose(this->handle);
355 free(this);
356 return NULL;
357 }
358 this->public.notify_connection_change =
359 dlsym(this->handle, "TNC_IMV_NotifyConnectionChange");
360 this->public.solicit_recommendation =
361 dlsym(this->handle, "TNC_IMV_SolicitRecommendation");
362 if (!this->public.solicit_recommendation)
363 {
364 DBG1(DBG_TNC, "could not resolve TNC_IMV_SolicitRecommendation in %s: %s\n",
365 path, dlerror());
366 dlclose(this->handle);
367 free(this);
368 return NULL;
369 }
370 this->public.receive_message =
371 dlsym(this->handle, "TNC_IMV_ReceiveMessage");
372 this->public.batch_ending =
373 dlsym(this->handle, "TNC_IMV_BatchEnding");
374 this->public.terminate =
375 dlsym(this->handle, "TNC_IMV_Terminate");
376 this->public.provide_bind_function =
377 dlsym(this->handle, "TNC_IMV_ProvideBindFunction");
378 if (!this->public.provide_bind_function)
379 {
380 DBG1(DBG_TNC, "could not resolve TNC_IMV_ProvideBindFunction in %s: %s\n",
381 path, dlerror());
382 dlclose(this->handle);
383 free(this);
384 return NULL;
385 }
386
387 return &this->public;
388 }