Add wrappers to IMC/IMV managers loading IMC/IMVs from function pointers
[strongswan.git] / src / libcharon / plugins / tnc_imc / tnc_imc_manager.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_imc_manager.h"
18 #include "tnc_imc.h"
19
20 #include <tncifimc.h>
21
22 #include <collections/linked_list.h>
23 #include <utils/debug.h>
24 #include <daemon.h>
25
26 typedef struct private_tnc_imc_manager_t private_tnc_imc_manager_t;
27
28 /**
29 * Private data of an imc_manager_t object.
30 */
31 struct private_tnc_imc_manager_t {
32
33 /**
34 * Public members of imc_manager_t.
35 */
36 imc_manager_t public;
37
38 /**
39 * Linked list of IMCs
40 */
41 linked_list_t *imcs;
42
43 /**
44 * Next IMC ID to be assigned
45 */
46 TNC_IMCID next_imc_id;
47 };
48
49 METHOD(imc_manager_t, add, bool,
50 private_tnc_imc_manager_t *this, imc_t *imc)
51 {
52 TNC_Version version;
53
54 imc->set_id(imc, this->next_imc_id);
55 if (imc->initialize(imc->get_id(imc), TNC_IFIMC_VERSION_1,
56 TNC_IFIMC_VERSION_1, &version) != TNC_RESULT_SUCCESS)
57 {
58 DBG1(DBG_TNC, "IMC \"%s\" failed to initialize", imc->get_name(imc));
59 return FALSE;
60 }
61 this->imcs->insert_last(this->imcs, imc);
62 this->next_imc_id++;
63
64 if (imc->provide_bind_function(imc->get_id(imc),
65 TNC_TNCC_BindFunction) != TNC_RESULT_SUCCESS)
66 {
67 if (imc->terminate)
68 {
69 imc->terminate(imc->get_id(imc));
70 }
71 DBG1(DBG_TNC, "IMC \"%s\" failed to obtain bind function",
72 imc->get_name(imc));
73 this->imcs->remove_last(this->imcs, (void**)&imc);
74 return FALSE;
75 }
76 return TRUE;
77 }
78
79 METHOD(imc_manager_t, remove_, imc_t*,
80 private_tnc_imc_manager_t *this, TNC_IMCID id)
81 {
82 enumerator_t *enumerator;
83 imc_t *imc, *removed_imc = NULL;
84
85 enumerator = this->imcs->create_enumerator(this->imcs);
86 while (enumerator->enumerate(enumerator, &imc))
87 {
88 if (id == imc->get_id(imc))
89 {
90 this->imcs->remove_at(this->imcs, enumerator);
91 removed_imc = imc;
92 break;
93 }
94 }
95 enumerator->destroy(enumerator);
96
97 return removed_imc;
98 }
99
100 METHOD(imc_manager_t, load, bool,
101 private_tnc_imc_manager_t *this, char *name, char *path)
102 {
103 imc_t *imc;
104
105 imc = tnc_imc_create(name, path);
106 if (!imc)
107 {
108 return FALSE;
109 }
110 if (!add(this, imc))
111 {
112 imc->destroy(imc);
113 return FALSE;
114 }
115 DBG1(DBG_TNC, "IMC %u \"%s\" loaded from '%s'", imc->get_id(imc), name, path);
116 return TRUE;
117 }
118
119 METHOD(imc_manager_t, load_from_functions, bool,
120 private_tnc_imc_manager_t *this, char *name,
121 TNC_IMC_InitializePointer initialize,
122 TNC_IMC_NotifyConnectionChangePointer notify_connection_change,
123 TNC_IMC_BeginHandshakePointer begin_handshake,
124 TNC_IMC_ReceiveMessagePointer receive_message,
125 TNC_IMC_ReceiveMessageLongPointer receive_message_long,
126 TNC_IMC_BatchEndingPointer batch_ending,
127 TNC_IMC_TerminatePointer terminate,
128 TNC_IMC_ProvideBindFunctionPointer provide_bind_function)
129 {
130 imc_t *imc;
131
132 imc = tnc_imc_create_from_functions(name,
133 initialize, notify_connection_change,
134 begin_handshake, receive_message,
135 receive_message_long, batch_ending,
136 terminate, provide_bind_function);
137 if (!imc)
138 {
139 return FALSE;
140 }
141 if (!add(this, imc))
142 {
143 imc->destroy(imc);
144 return FALSE;
145 }
146 DBG1(DBG_TNC, "IMC %u \"%s\" loaded", imc->get_id(imc), name);
147 return TRUE;
148 }
149
150 METHOD(imc_manager_t, is_registered, bool,
151 private_tnc_imc_manager_t *this, TNC_IMCID id)
152 {
153 enumerator_t *enumerator;
154 imc_t *imc;
155 bool found = FALSE;
156
157 enumerator = this->imcs->create_enumerator(this->imcs);
158 while (enumerator->enumerate(enumerator, &imc))
159 {
160 if (imc->has_id(imc, id))
161 {
162 found = TRUE;
163 break;
164 }
165 }
166 enumerator->destroy(enumerator);
167
168 return found;
169 }
170
171 METHOD(imc_manager_t, reserve_id, bool,
172 private_tnc_imc_manager_t *this, TNC_IMCID id, TNC_UInt32 *new_id)
173 {
174 enumerator_t *enumerator;
175 imc_t *imc;
176 bool found = FALSE;
177
178 enumerator = this->imcs->create_enumerator(this->imcs);
179 while (enumerator->enumerate(enumerator, &imc))
180 {
181 if (imc->get_id(imc))
182 {
183 found = TRUE;
184 *new_id = this->next_imc_id++;
185 imc->add_id(imc, *new_id);
186 DBG2(DBG_TNC, "additional ID %u reserved for IMC with primary ID %u",
187 *new_id, id);
188 break;
189 }
190 }
191 enumerator->destroy(enumerator);
192
193 return found;
194 }
195
196 METHOD(imc_manager_t, get_preferred_language, char*,
197 private_tnc_imc_manager_t *this)
198 {
199 return lib->settings->get_str(lib->settings,
200 "%s.plugins.tnc-imc.preferred_language", "en", charon->name);
201 }
202
203 METHOD(imc_manager_t, notify_connection_change, void,
204 private_tnc_imc_manager_t *this, TNC_ConnectionID id,
205 TNC_ConnectionState state)
206 {
207 enumerator_t *enumerator;
208 imc_t *imc;
209
210 enumerator = this->imcs->create_enumerator(this->imcs);
211 while (enumerator->enumerate(enumerator, &imc))
212 {
213 if (imc->notify_connection_change)
214 {
215 imc->notify_connection_change(imc->get_id(imc), id, state);
216 }
217 }
218 enumerator->destroy(enumerator);
219 }
220
221 METHOD(imc_manager_t, begin_handshake, void,
222 private_tnc_imc_manager_t *this, TNC_ConnectionID id)
223 {
224 enumerator_t *enumerator;
225 imc_t *imc;
226
227 enumerator = this->imcs->create_enumerator(this->imcs);
228 while (enumerator->enumerate(enumerator, &imc))
229 {
230 imc->begin_handshake(imc->get_id(imc), id);
231 }
232 enumerator->destroy(enumerator);
233 }
234
235 METHOD(imc_manager_t, set_message_types, TNC_Result,
236 private_tnc_imc_manager_t *this, TNC_IMCID id,
237 TNC_MessageTypeList supported_types,
238 TNC_UInt32 type_count)
239 {
240 enumerator_t *enumerator;
241 imc_t *imc;
242 TNC_Result result = TNC_RESULT_FATAL;
243
244 enumerator = this->imcs->create_enumerator(this->imcs);
245 while (enumerator->enumerate(enumerator, &imc))
246 {
247 if (id == imc->get_id(imc))
248 {
249 imc->set_message_types(imc, supported_types, type_count);
250 result = TNC_RESULT_SUCCESS;
251 break;
252 }
253 }
254 enumerator->destroy(enumerator);
255 return result;
256 }
257
258 METHOD(imc_manager_t, set_message_types_long, TNC_Result,
259 private_tnc_imc_manager_t *this, TNC_IMCID id,
260 TNC_VendorIDList supported_vids,
261 TNC_MessageSubtypeList supported_subtypes,
262 TNC_UInt32 type_count)
263 {
264 enumerator_t *enumerator;
265 imc_t *imc;
266 TNC_Result result = TNC_RESULT_FATAL;
267
268 enumerator = this->imcs->create_enumerator(this->imcs);
269 while (enumerator->enumerate(enumerator, &imc))
270 {
271 if (id == imc->get_id(imc))
272 {
273 imc->set_message_types_long(imc, supported_vids, supported_subtypes,
274 type_count);
275 result = TNC_RESULT_SUCCESS;
276 break;
277 }
278 }
279 enumerator->destroy(enumerator);
280 return result;
281 }
282
283 METHOD(imc_manager_t, receive_message, void,
284 private_tnc_imc_manager_t *this, TNC_ConnectionID connection_id,
285 bool excl,
286 TNC_BufferReference msg,
287 TNC_UInt32 msg_len,
288 TNC_VendorID msg_vid,
289 TNC_MessageSubtype msg_subtype,
290 TNC_UInt32 src_imv_id,
291 TNC_UInt32 dst_imc_id)
292 {
293 bool type_supported = FALSE;
294 TNC_MessageType msg_type;
295 TNC_UInt32 msg_flags;
296 enumerator_t *enumerator;
297 imc_t *imc;
298
299 enumerator = this->imcs->create_enumerator(this->imcs);
300 while (enumerator->enumerate(enumerator, &imc))
301 {
302 if (imc->type_supported(imc, msg_vid, msg_subtype) &&
303 (!excl || (excl && imc->has_id(imc, dst_imc_id)) ))
304 {
305 if (imc->receive_message_long && src_imv_id)
306 {
307 type_supported = TRUE;
308 msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
309 imc->receive_message_long(imc->get_id(imc), connection_id,
310 msg_flags, msg, msg_len, msg_vid, msg_subtype,
311 src_imv_id, dst_imc_id);
312
313 }
314 else if (imc->receive_message && msg_vid <= TNC_VENDORID_ANY &&
315 msg_subtype <= TNC_SUBTYPE_ANY)
316 {
317 type_supported = TRUE;
318 msg_type = (msg_vid << 8) | msg_subtype;
319 imc->receive_message(imc->get_id(imc), connection_id,
320 msg, msg_len, msg_type);
321 }
322 }
323 }
324 enumerator->destroy(enumerator);
325 if (!type_supported)
326 {
327 DBG2(DBG_TNC, "message type 0x%06x/0x%08x not supported by any IMC",
328 msg_vid, msg_subtype);
329 }
330 }
331
332 METHOD(imc_manager_t, batch_ending, void,
333 private_tnc_imc_manager_t *this, TNC_ConnectionID id)
334 {
335 enumerator_t *enumerator;
336 imc_t *imc;
337
338 enumerator = this->imcs->create_enumerator(this->imcs);
339 while (enumerator->enumerate(enumerator, &imc))
340 {
341 if (imc->batch_ending)
342 {
343 imc->batch_ending(imc->get_id(imc), id);
344 }
345 }
346 enumerator->destroy(enumerator);
347 }
348
349 METHOD(imc_manager_t, destroy, void,
350 private_tnc_imc_manager_t *this)
351 {
352 imc_t *imc;
353
354 while (this->imcs->remove_last(this->imcs, (void**)&imc) == SUCCESS)
355 {
356 if (imc->terminate &&
357 imc->terminate(imc->get_id(imc)) != TNC_RESULT_SUCCESS)
358 {
359 DBG1(DBG_TNC, "IMC \"%s\" not terminated successfully",
360 imc->get_name(imc));
361 }
362 imc->destroy(imc);
363 }
364 this->imcs->destroy(this->imcs);
365 free(this);
366 }
367
368 /**
369 * Described in header.
370 */
371 imc_manager_t* tnc_imc_manager_create(void)
372 {
373 private_tnc_imc_manager_t *this;
374
375 INIT(this,
376 .public = {
377 .add = _add,
378 .remove = _remove_, /* avoid name conflict with stdio.h */
379 .load = _load,
380 .load_from_functions = _load_from_functions,
381 .is_registered = _is_registered,
382 .reserve_id = _reserve_id,
383 .get_preferred_language = _get_preferred_language,
384 .notify_connection_change = _notify_connection_change,
385 .begin_handshake = _begin_handshake,
386 .set_message_types = _set_message_types,
387 .set_message_types_long = _set_message_types_long,
388 .receive_message = _receive_message,
389 .batch_ending = _batch_ending,
390 .destroy = _destroy,
391 },
392 .imcs = linked_list_create(),
393 .next_imc_id = 1,
394 );
395
396 return &this->public;
397 }