updated Copyright info
[strongswan.git] / src / libimcv / imc / imc_agent.c
1 /*
2 * Copyright (C) 2011-2012 Andreas Steffen
3 * 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 "imcv.h"
17 #include "imc_agent.h"
18
19 #include <tncif_names.h>
20
21 #include <debug.h>
22 #include <threading/rwlock.h>
23
24 typedef struct private_imc_agent_t private_imc_agent_t;
25
26 /**
27 * Private data of an imc_agent_t object.
28 */
29 struct private_imc_agent_t {
30
31 /**
32 * Public members of imc_agent_t
33 */
34 imc_agent_t public;
35
36 /**
37 * name of IMC
38 */
39 const char *name;
40
41 /**
42 * message vendor ID of IMC
43 */
44 TNC_VendorID vendor_id;
45
46 /**
47 * message subtype of IMC
48 */
49 TNC_MessageSubtype subtype;
50
51 /**
52 * ID of IMC as assigned by TNCC
53 */
54 TNC_IMCID id;
55
56 /**
57 * List of additional IMC IDs assigned by TNCC
58 */
59 linked_list_t *additional_ids;
60
61 /**
62 * list of TNCC connection entries
63 */
64 linked_list_t *connections;
65
66 /**
67 * rwlock to lock TNCC connection entries
68 */
69 rwlock_t *connection_lock;
70
71 /**
72 * Inform a TNCC about the set of message types the IMC is able to receive
73 *
74 * @param imc_id IMC ID assigned by TNCC
75 * @param supported_types list of supported message types
76 * @param type_count number of list elements
77 * @return TNC result code
78 */
79 TNC_Result (*report_message_types)(TNC_IMCID imc_id,
80 TNC_MessageTypeList supported_types,
81 TNC_UInt32 type_count);
82
83 /**
84 * Inform a TNCC about the set of message types the IMC is able to receive
85 *
86 * @param imc_id IMC ID assigned by TNCC
87 * @param supported_vids list of supported message vendor IDs
88 * @param supported_subtypes list of supported message subtypes
89 * @param type_count number of list elements
90 * @return TNC result code
91 */
92 TNC_Result (*report_message_types_long)(TNC_IMCID imc_id,
93 TNC_VendorIDList supported_vids,
94 TNC_MessageSubtypeList supported_subtypes,
95 TNC_UInt32 type_count);
96
97 /**
98 * Call when an IMC-IMC message is to be sent
99 *
100 * @param imc_id IMC ID assigned by TNCC
101 * @param connection_id network connection ID assigned by TNCC
102 * @param msg message to send
103 * @param msg_len message length in bytes
104 * @param msg_type message type
105 * @return TNC result code
106 */
107 TNC_Result (*send_message)(TNC_IMCID imc_id,
108 TNC_ConnectionID connection_id,
109 TNC_BufferReference msg,
110 TNC_UInt32 msg_len,
111 TNC_MessageType msg_type);
112
113
114 /**
115 * Call when an IMC-IMC message is to be sent with long message types
116 *
117 * @param imc_id IMC ID assigned by TNCC
118 * @param connection_id network connection ID assigned by TNCC
119 * @param msg_flags message flags
120 * @param msg message to send
121 * @param msg_len message length in bytes
122 * @param msg_vid message vendor ID
123 * @param msg_subtype message subtype
124 * @param dst_imc_id destination IMV ID
125 * @return TNC result code
126 */
127 TNC_Result (*send_message_long)(TNC_IMCID imc_id,
128 TNC_ConnectionID connection_id,
129 TNC_UInt32 msg_flags,
130 TNC_BufferReference msg,
131 TNC_UInt32 msg_len,
132 TNC_VendorID msg_vid,
133 TNC_MessageSubtype msg_subtype,
134 TNC_UInt32 dst_imv_id);
135
136 /**
137 * Get the value of an attribute associated with a connection
138 * or with the TNCC as a whole.
139 *
140 * @param imc_id IMC ID assigned by TNCC
141 * @param connection_id network connection ID assigned by TNCC
142 * @param attribute_id attribute ID
143 * @param buffer_len length of buffer in bytes
144 * @param buffer buffer
145 * @param out_value_len size in bytes of attribute stored in buffer
146 * @return TNC result code
147 */
148 TNC_Result (*get_attribute)(TNC_IMCID imc_id,
149 TNC_ConnectionID connection_id,
150 TNC_AttributeID attribute_id,
151 TNC_UInt32 buffer_len,
152 TNC_BufferReference buffer,
153 TNC_UInt32 *out_value_len);
154
155 /**
156 * Set the value of an attribute associated with a connection
157 * or with the TNCC as a whole.
158 *
159 * @param imc_id IMV ID assigned by TNCC
160 * @param connection_id network connection ID assigned by TNCC
161 * @param attribute_id attribute ID
162 * @param buffer_len length of buffer in bytes
163 * @param buffer buffer
164 * @return TNC result code
165 */
166 TNC_Result (*set_attribute)(TNC_IMCID imc_id,
167 TNC_ConnectionID connection_id,
168 TNC_AttributeID attribute_id,
169 TNC_UInt32 buffer_len,
170 TNC_BufferReference buffer);
171
172 /**
173 * Reserve an additional IMC ID
174 *
175 * @param imc_id primary IMC ID assigned by TNCC
176 * @param out_imc_id additional IMC ID assigned by TNCC
177 * @return TNC result code
178 */
179 TNC_Result (*reserve_additional_id)(TNC_IMCID imc_id,
180 TNC_UInt32 *out_imc_id);
181
182 };
183
184 METHOD(imc_agent_t, bind_functions, TNC_Result,
185 private_imc_agent_t *this, TNC_TNCC_BindFunctionPointer bind_function)
186 {
187 if (!bind_function)
188 {
189 DBG1(DBG_IMC, "TNC client failed to provide bind function");
190 return TNC_RESULT_INVALID_PARAMETER;
191 }
192 if (bind_function(this->id, "TNC_TNCC_ReportMessageTypes",
193 (void**)&this->report_message_types) != TNC_RESULT_SUCCESS)
194 {
195 this->report_message_types = NULL;
196 }
197 if (bind_function(this->id, "TNC_TNCC_ReportMessageTypesLong",
198 (void**)&this->report_message_types_long) != TNC_RESULT_SUCCESS)
199 {
200 this->report_message_types_long = NULL;
201 }
202 if (bind_function(this->id, "TNC_TNCC_RequestHandshakeRetry",
203 (void**)&this->public.request_handshake_retry) != TNC_RESULT_SUCCESS)
204 {
205 this->public.request_handshake_retry = NULL;
206 }
207 if (bind_function(this->id, "TNC_TNCC_SendMessage",
208 (void**)&this->send_message) != TNC_RESULT_SUCCESS)
209 {
210 this->send_message = NULL;
211 }
212 if (bind_function(this->id, "TNC_TNCC_SendMessageLong",
213 (void**)&this->send_message_long) != TNC_RESULT_SUCCESS)
214 {
215 this->send_message_long = NULL;
216 }
217 if (bind_function(this->id, "TNC_TNCC_GetAttribute",
218 (void**)&this->get_attribute) != TNC_RESULT_SUCCESS)
219 {
220 this->get_attribute = NULL;
221 }
222 if (bind_function(this->id, "TNC_TNCC_SetAttribute",
223 (void**)&this->set_attribute) != TNC_RESULT_SUCCESS)
224 {
225 this->set_attribute = NULL;
226 }
227 if (bind_function(this->id, "TNC_TNCC_ReserveAdditionalIMCID",
228 (void**)&this->reserve_additional_id) != TNC_RESULT_SUCCESS)
229 {
230 this->reserve_additional_id = NULL;
231 }
232 DBG2(DBG_IMC, "IMC %u \"%s\" provided with bind function",
233 this->id, this->name);
234
235 if (this->report_message_types_long)
236 {
237 this->report_message_types_long(this->id, &this->vendor_id,
238 &this->subtype, 1);
239 }
240 else if (this->report_message_types &&
241 this->vendor_id <= TNC_VENDORID_ANY &&
242 this->subtype <= TNC_SUBTYPE_ANY)
243 {
244 TNC_MessageType type;
245
246 type = (this->vendor_id << 8) | this->subtype;
247 this->report_message_types(this->id, &type, 1);
248 }
249 return TNC_RESULT_SUCCESS;
250 }
251
252 /**
253 * finds a connection state based on its Connection ID
254 */
255 static imc_state_t* find_connection(private_imc_agent_t *this,
256 TNC_ConnectionID id)
257 {
258 enumerator_t *enumerator;
259 imc_state_t *state, *found = NULL;
260
261 this->connection_lock->read_lock(this->connection_lock);
262 enumerator = this->connections->create_enumerator(this->connections);
263 while (enumerator->enumerate(enumerator, &state))
264 {
265 if (id == state->get_connection_id(state))
266 {
267 found = state;
268 break;
269 }
270 }
271 enumerator->destroy(enumerator);
272 this->connection_lock->unlock(this->connection_lock);
273
274 return found;
275 }
276
277 /**
278 * delete a connection state with a given Connection ID
279 */
280 static bool delete_connection(private_imc_agent_t *this, TNC_ConnectionID id)
281 {
282 enumerator_t *enumerator;
283 imc_state_t *state;
284 bool found = FALSE;
285
286 this->connection_lock->write_lock(this->connection_lock);
287 enumerator = this->connections->create_enumerator(this->connections);
288 while (enumerator->enumerate(enumerator, &state))
289 {
290 if (id == state->get_connection_id(state))
291 {
292 found = TRUE;
293 state->destroy(state);
294 this->connections->remove_at(this->connections, enumerator);
295 break;
296 }
297 }
298 enumerator->destroy(enumerator);
299 this->connection_lock->unlock(this->connection_lock);
300
301 return found;
302 }
303
304 /**
305 * Read a boolean attribute
306 */
307 static bool get_bool_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
308 TNC_AttributeID attribute_id)
309 {
310 TNC_UInt32 len;
311 char buf[4];
312
313 return this->get_attribute &&
314 this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
315 TNC_RESULT_SUCCESS && len == 1 && *buf == 0x01;
316 }
317
318 /**
319 * Read a string attribute
320 */
321 static char* get_str_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
322 TNC_AttributeID attribute_id)
323 {
324 TNC_UInt32 len;
325 char buf[BUF_LEN];
326
327 if (this->get_attribute &&
328 this->get_attribute(this->id, id, attribute_id, BUF_LEN, buf, &len) ==
329 TNC_RESULT_SUCCESS && len <= BUF_LEN)
330 {
331 return strdup(buf);
332 }
333 return NULL;
334 }
335
336 /**
337 * Read an UInt32 attribute
338 */
339 static u_int32_t get_uint_attribute(private_imc_agent_t *this, TNC_ConnectionID id,
340 TNC_AttributeID attribute_id)
341 {
342 TNC_UInt32 len;
343 char buf[4];
344
345 if (this->get_attribute &&
346 this->get_attribute(this->id, id, attribute_id, 4, buf, &len) ==
347 TNC_RESULT_SUCCESS && len == 4)
348 {
349 return untoh32(buf);
350 }
351 return 0;
352 }
353
354 METHOD(imc_agent_t, create_state, TNC_Result,
355 private_imc_agent_t *this, imc_state_t *state)
356 {
357 TNC_ConnectionID conn_id;
358 char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL;
359 bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE;
360 u_int32_t max_msg_len;
361
362 conn_id = state->get_connection_id(state);
363 if (find_connection(this, conn_id))
364 {
365 DBG1(DBG_IMC, "IMC %u \"%s\" already created a state for Connection ID %u",
366 this->id, this->name, conn_id);
367 state->destroy(state);
368 return TNC_RESULT_OTHER;
369 }
370
371 /* Get and display attributes from TNCC via IF-IMC */
372 has_long = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_LONG_TYPES);
373 has_excl = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_EXCLUSIVE);
374 has_soh = get_bool_attribute(this, conn_id, TNC_ATTRIBUTEID_HAS_SOH);
375 tnccs_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL);
376 tnccs_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFTNCCS_VERSION);
377 t_p = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_PROTOCOL);
378 t_v = get_str_attribute(this, conn_id, TNC_ATTRIBUTEID_IFT_VERSION);
379 max_msg_len = get_uint_attribute(this, conn_id, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE);
380
381 state->set_flags(state, has_long, has_excl);
382 state->set_max_msg_len(state, max_msg_len);
383
384 DBG2(DBG_IMC, "IMC %u \"%s\" created a state for %s %s Connection ID %u: "
385 "%slong %sexcl %ssoh", this->id, this->name,
386 tnccs_p ? tnccs_p:"?", tnccs_v ? tnccs_v:"?", conn_id,
387 has_long ? "+":"-", has_excl ? "+":"-", has_soh ? "+":"-");
388 DBG2(DBG_IMC, " over %s %s with maximum PA-TNC message size of %u bytes",
389 t_p ? t_p:"?", t_v ? t_v :"?", max_msg_len);
390
391 free(tnccs_p);
392 free(tnccs_v);
393 free(t_p);
394 free(t_v);
395
396 this->connection_lock->write_lock(this->connection_lock);
397 this->connections->insert_last(this->connections, state);
398 this->connection_lock->unlock(this->connection_lock);
399 return TNC_RESULT_SUCCESS;
400 }
401
402 METHOD(imc_agent_t, delete_state, TNC_Result,
403 private_imc_agent_t *this, TNC_ConnectionID connection_id)
404 {
405 if (!delete_connection(this, connection_id))
406 {
407 DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
408 this->id, this->name, connection_id);
409 return TNC_RESULT_FATAL;
410 }
411 DBG2(DBG_IMC, "IMC %u \"%s\" deleted the state of Connection ID %u",
412 this->id, this->name, connection_id);
413 return TNC_RESULT_SUCCESS;
414 }
415
416 METHOD(imc_agent_t, change_state, TNC_Result,
417 private_imc_agent_t *this, TNC_ConnectionID connection_id,
418 TNC_ConnectionState new_state,
419 imc_state_t **state_p)
420 {
421 imc_state_t *state;
422
423 switch (new_state)
424 {
425 case TNC_CONNECTION_STATE_HANDSHAKE:
426 case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
427 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
428 case TNC_CONNECTION_STATE_ACCESS_NONE:
429 state = find_connection(this, connection_id);
430
431 if (!state)
432 {
433 DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
434 this->id, this->name, connection_id);
435 return TNC_RESULT_FATAL;
436 }
437 state->change_state(state, new_state);
438 DBG2(DBG_IMC, "IMC %u \"%s\" changed state of Connection ID %u to '%N'",
439 this->id, this->name, connection_id,
440 TNC_Connection_State_names, new_state);
441 if (state_p)
442 {
443 *state_p = state;
444 }
445 break;
446 case TNC_CONNECTION_STATE_CREATE:
447 DBG1(DBG_IMC, "state '%N' should be handled by create_state()",
448 TNC_Connection_State_names, new_state);
449 return TNC_RESULT_FATAL;
450 case TNC_CONNECTION_STATE_DELETE:
451 DBG1(DBG_IMC, "state '%N' should be handled by delete_state()",
452 TNC_Connection_State_names, new_state);
453 return TNC_RESULT_FATAL;
454 default:
455 DBG1(DBG_IMC, "IMC %u \"%s\" was notified of unknown state %u "
456 "for Connection ID %u",
457 this->id, this->name, new_state, connection_id);
458 return TNC_RESULT_INVALID_PARAMETER;
459 }
460 return TNC_RESULT_SUCCESS;
461 }
462
463 METHOD(imc_agent_t, get_state, bool,
464 private_imc_agent_t *this, TNC_ConnectionID connection_id,
465 imc_state_t **state)
466 {
467 *state = find_connection(this, connection_id);
468 if (!*state)
469 {
470 DBG1(DBG_IMC, "IMC %u \"%s\" has no state for Connection ID %u",
471 this->id, this->name, connection_id);
472 return FALSE;
473 }
474 return TRUE;
475 }
476
477 METHOD(imc_agent_t, send_message, TNC_Result,
478 private_imc_agent_t *this, TNC_ConnectionID connection_id, bool excl,
479 TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id, linked_list_t *attr_list)
480 {
481 TNC_MessageType type;
482 TNC_UInt32 msg_flags;
483 TNC_Result result = TNC_RESULT_FATAL;
484 imc_state_t *state;
485 pa_tnc_attr_t *attr;
486 pa_tnc_msg_t *pa_tnc_msg;
487 chunk_t msg;
488 enumerator_t *enumerator;
489 bool attr_added;
490
491 state = find_connection(this, connection_id);
492 if (!state)
493 {
494 DBG1(DBG_IMV, "IMC %u \"%s\" has no state for Connection ID %u",
495 this->id, this->name, connection_id);
496 return TNC_RESULT_FATAL;
497 }
498
499 while (attr_list->get_count(attr_list))
500 {
501 pa_tnc_msg = pa_tnc_msg_create(state->get_max_msg_len(state));
502 attr_added = FALSE;
503
504 enumerator = attr_list->create_enumerator(attr_list);
505 while (enumerator->enumerate(enumerator, &attr))
506 {
507 if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
508 {
509 attr_added = TRUE;
510 }
511 else
512 {
513 if (attr_added)
514 {
515 break;
516 }
517 else
518 {
519 DBG1(DBG_IMC, "PA-TNC attribute too large to send, deleted");
520 attr->destroy(attr);
521 }
522 }
523 attr_list->remove_at(attr_list, enumerator);
524 }
525 enumerator->destroy(enumerator);
526
527 /* build and send the PA-TNC message via the IF-IMC interface */
528 pa_tnc_msg->build(pa_tnc_msg);
529 msg = pa_tnc_msg->get_encoding(pa_tnc_msg);
530
531 if (state->has_long(state) && this->send_message_long)
532 {
533 if (!src_imc_id)
534 {
535 src_imc_id = this->id;
536 }
537 msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
538
539 result = this->send_message_long(src_imc_id, connection_id,
540 msg_flags, msg.ptr, msg.len, this->vendor_id,
541 this->subtype, dst_imv_id);
542 }
543 else if (this->send_message)
544 {
545 type = (this->vendor_id << 8) | this->subtype;
546
547 result = this->send_message(this->id, connection_id, msg.ptr,
548 msg.len, type);
549 }
550
551 pa_tnc_msg->destroy(pa_tnc_msg);
552
553 if (result != TNC_RESULT_SUCCESS)
554 {
555 break;
556 }
557 }
558 return result;
559 }
560
561 METHOD(imc_agent_t, receive_message, TNC_Result,
562 private_imc_agent_t *this, imc_state_t *state, chunk_t msg,
563 TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype,
564 TNC_UInt32 src_imv_id, TNC_UInt32 dst_imc_id, pa_tnc_msg_t **pa_tnc_msg)
565 {
566 pa_tnc_msg_t *pa_msg;
567 pa_tnc_attr_t *error_attr;
568 linked_list_t *error_attr_list;
569 enumerator_t *enumerator;
570 TNC_UInt32 src_imc_id, dst_imv_id;
571 TNC_ConnectionID connection_id;
572 TNC_Result result;
573
574 connection_id = state->get_connection_id(state);
575
576 if (state->has_long(state))
577 {
578 if (dst_imc_id != TNC_IMCID_ANY)
579 {
580 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
581 "from IMV %u to IMC %u", this->id, this->name,
582 connection_id, src_imv_id, dst_imc_id);
583 }
584 else
585 {
586 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
587 "from IMV %u", this->id, this->name, connection_id,
588 src_imv_id);
589 }
590 }
591 else
592 {
593 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u",
594 this->id, this->name, connection_id);
595 }
596
597 *pa_tnc_msg = NULL;
598 pa_msg = pa_tnc_msg_create_from_data(msg);
599
600 switch (pa_msg->process(pa_msg))
601 {
602 case SUCCESS:
603 *pa_tnc_msg = pa_msg;
604 break;
605 case VERIFY_ERROR:
606 /* extract and copy by refence all error attributes */
607 error_attr_list = linked_list_create();
608
609 enumerator = pa_msg->create_error_enumerator(pa_msg);
610 while (enumerator->enumerate(enumerator, &error_attr))
611 {
612 error_attr_list->insert_last(error_attr_list,
613 error_attr->get_ref(error_attr));
614 }
615 enumerator->destroy(enumerator);
616
617 src_imc_id = (dst_imc_id == TNC_IMCID_ANY) ? this->id : dst_imc_id;
618 dst_imv_id = state->has_excl(state) ? src_imv_id : TNC_IMVID_ANY;
619
620 result = send_message(this, connection_id, state->has_excl(state),
621 src_imc_id, dst_imv_id, error_attr_list);
622
623 error_attr_list->destroy(error_attr_list);
624 pa_msg->destroy(pa_msg);
625 return result;
626 case FAILED:
627 default:
628 pa_msg->destroy(pa_msg);
629 return TNC_RESULT_FATAL;
630 }
631 return TNC_RESULT_SUCCESS;
632 }
633
634 METHOD(imc_agent_t, reserve_additional_ids, TNC_Result,
635 private_imc_agent_t *this, int count)
636 {
637 TNC_Result result;
638 TNC_UInt32 id;
639 void *pointer;
640
641 if (!this->reserve_additional_id)
642 {
643 DBG1(DBG_IMC, "IMC %u \"%s\" did not detect the capability to reserve "
644 "additional IMC IDs from the TNCC", this->id, this->name);
645 return TNC_RESULT_ILLEGAL_OPERATION;
646 }
647 while (count > 0)
648 {
649 result = this->reserve_additional_id(this->id, &id);
650 if (result != TNC_RESULT_SUCCESS)
651 {
652 DBG1(DBG_IMC, "IMC %u \"%s\" failed to reserve %d additional IMC IDs",
653 this->id, this->name, count);
654 return result;
655 }
656 count--;
657
658 /* store the scalar value in the pointer */
659 pointer = (void*)id;
660 this->additional_ids->insert_last(this->additional_ids, pointer);
661 DBG2(DBG_IMC, "IMC %u \"%s\" reserved additional ID %u",
662 this->id, this->name, id);
663 }
664 return TNC_RESULT_SUCCESS;
665 }
666
667 METHOD(imc_agent_t, count_additional_ids, int,
668 private_imc_agent_t *this)
669 {
670 return this->additional_ids->get_count(this->additional_ids);
671 }
672
673 METHOD(imc_agent_t, create_id_enumerator, enumerator_t*,
674 private_imc_agent_t *this)
675 {
676 return this->additional_ids->create_enumerator(this->additional_ids);
677 }
678
679 METHOD(imc_agent_t, destroy, void,
680 private_imc_agent_t *this)
681 {
682 DBG1(DBG_IMC, "IMC %u \"%s\" terminated", this->id, this->name);
683 this->additional_ids->destroy(this->additional_ids);
684 this->connections->destroy_function(this->connections, free);
685 this->connection_lock->destroy(this->connection_lock);
686 free(this);
687
688 /* decrease the reference count or terminate */
689 libimcv_deinit();
690 }
691
692 /**
693 * Described in header.
694 */
695 imc_agent_t *imc_agent_create(const char *name,
696 pen_t vendor_id, u_int32_t subtype,
697 TNC_IMCID id, TNC_Version *actual_version)
698 {
699 private_imc_agent_t *this;
700
701 /* initialize or increase the reference count */
702 if (!libimcv_init())
703 {
704 return NULL;
705 }
706
707 INIT(this,
708 .public = {
709 .bind_functions = _bind_functions,
710 .create_state = _create_state,
711 .delete_state = _delete_state,
712 .change_state = _change_state,
713 .get_state = _get_state,
714 .send_message = _send_message,
715 .receive_message = _receive_message,
716 .reserve_additional_ids = _reserve_additional_ids,
717 .count_additional_ids = _count_additional_ids,
718 .create_id_enumerator = _create_id_enumerator,
719 .destroy = _destroy,
720 },
721 .name = name,
722 .vendor_id = vendor_id,
723 .subtype = subtype,
724 .id = id,
725 .additional_ids = linked_list_create(),
726 .connections = linked_list_create(),
727 .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
728 );
729
730 *actual_version = TNC_IFIMC_VERSION_1;
731 DBG1(DBG_IMC, "IMC %u \"%s\" initialized", this->id, this->name);
732
733 return &this->public;
734 }
735