2 * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "imv_agent.h"
18 #include <tncif_names.h>
21 #include <utils/linked_list.h>
22 #include <threading/rwlock.h>
24 typedef struct private_imv_agent_t private_imv_agent_t
;
27 * Private data of an imv_agent_t object.
29 struct private_imv_agent_t
{
32 * Public members of imv_agent_t
42 * message vendor ID of IMV
44 TNC_VendorID vendor_id
;
47 * message subtype of IMV
49 TNC_MessageSubtype subtype
;
52 * ID of IMV as assigned by TNCS
57 * List of additional IMV IDs assigned by TNCS
59 linked_list_t
*additional_ids
;
62 * list of TNCS connection entries
64 linked_list_t
*connections
;
67 * rwlock to lock TNCS connection entries
69 rwlock_t
*connection_lock
;
72 * Inform a TNCS about the set of message types the IMV is able to receive
74 * @param imv_id IMV ID assigned by TNCS
75 * @param supported_types list of supported message types
76 * @param type_count number of list elements
77 * @return TNC result code
79 TNC_Result (*report_message_types
)(TNC_IMVID imv_id
,
80 TNC_MessageTypeList supported_types
,
81 TNC_UInt32 type_count
);
84 * Inform a TNCS about the set of message types the IMV is able to receive
86 * @param imv_id IMV ID assigned by TNCS
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
92 TNC_Result (*report_message_types_long
)(TNC_IMVID imv_id
,
93 TNC_VendorIDList supported_vids
,
94 TNC_MessageSubtypeList supported_subtypes
,
95 TNC_UInt32 type_count
);
98 * Call when an IMV-IMC message is to be sent
100 * @param imv_id IMV ID assigned by TNCS
101 * @param connection_id network connection ID assigned by TNCS
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
107 TNC_Result (*send_message
)(TNC_IMVID imv_id
,
108 TNC_ConnectionID connection_id
,
109 TNC_BufferReference msg
,
111 TNC_MessageType msg_type
);
114 * Call when an IMV-IMC message is to be sent with long message types
116 * @param imv_id IMV ID assigned by TNCS
117 * @param connection_id network connection ID assigned by TNCS
118 * @param msg_flags message flags
119 * @param msg message to send
120 * @param msg_len message length in bytes
121 * @param msg_vid message vendor ID
122 * @param msg_subtype message subtype
123 * @param dst_imc_id destination IMC ID
124 * @return TNC result code
126 TNC_Result (*send_message_long
)(TNC_IMVID imv_id
,
127 TNC_ConnectionID connection_id
,
128 TNC_UInt32 msg_flags
,
129 TNC_BufferReference msg
,
131 TNC_VendorID msg_vid
,
132 TNC_MessageSubtype msg_subtype
,
133 TNC_UInt32 dst_imc_id
);
136 * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
138 * @param imv_id IMV ID assigned by TNCS
139 # @param connection_id network connection ID assigned by TNCS
140 * @param rec IMV action recommendation
141 * @param eval IMV evaluation result
142 * @return TNC result code
144 TNC_Result (*provide_recommendation
)(TNC_IMVID imv_id
,
145 TNC_ConnectionID connection_id
,
146 TNC_IMV_Action_Recommendation rec
,
147 TNC_IMV_Evaluation_Result eval
);
150 * Get the value of an attribute associated with a connection
151 * or with the TNCS as a whole.
153 * @param imv_id IMV ID assigned by TNCS
154 * @param connection_id network connection ID assigned by TNCS
155 * @param attribute_id attribute ID
156 * @param buffer_len length of buffer in bytes
157 * @param buffer buffer
158 * @param out_value_len size in bytes of attribute stored in buffer
159 * @return TNC result code
161 TNC_Result (*get_attribute
)(TNC_IMVID imv_id
,
162 TNC_ConnectionID connection_id
,
163 TNC_AttributeID attribute_id
,
164 TNC_UInt32 buffer_len
,
165 TNC_BufferReference buffer
,
166 TNC_UInt32
*out_value_len
);
169 * Set the value of an attribute associated with a connection
170 * or with the TNCS as a whole.
172 * @param imv_id IMV ID assigned by TNCS
173 * @param connection_id network connection ID assigned by TNCS
174 * @param attribute_id attribute ID
175 * @param buffer_len length of buffer in bytes
176 * @param buffer buffer
177 * @return TNC result code
179 TNC_Result (*set_attribute
)(TNC_IMVID imv_id
,
180 TNC_ConnectionID connection_id
,
181 TNC_AttributeID attribute_id
,
182 TNC_UInt32 buffer_len
,
183 TNC_BufferReference buffer
);
186 * Reserve an additional IMV ID
188 * @param imv_id primary IMV ID assigned by TNCS
189 * @param out_imv_id additional IMV ID assigned by TNCS
190 * @return TNC result code
192 TNC_Result (*reserve_additional_id
)(TNC_IMVID imv_id
,
193 TNC_UInt32
*out_imv_id
);
197 METHOD(imv_agent_t
, bind_functions
, TNC_Result
,
198 private_imv_agent_t
*this, TNC_TNCS_BindFunctionPointer bind_function
)
202 DBG1(DBG_IMV
, "TNC server failed to provide bind function");
203 return TNC_RESULT_INVALID_PARAMETER
;
205 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypes",
206 (void**)&this->report_message_types
) != TNC_RESULT_SUCCESS
)
208 this->report_message_types
= NULL
;
210 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypesLong",
211 (void**)&this->report_message_types_long
) != TNC_RESULT_SUCCESS
)
213 this->report_message_types_long
= NULL
;
215 if (bind_function(this->id
, "TNC_TNCS_RequestHandshakeRetry",
216 (void**)&this->public.request_handshake_retry
) != TNC_RESULT_SUCCESS
)
218 this->public.request_handshake_retry
= NULL
;
220 if (bind_function(this->id
, "TNC_TNCS_SendMessage",
221 (void**)&this->send_message
) != TNC_RESULT_SUCCESS
)
223 this->send_message
= NULL
;
225 if (bind_function(this->id
, "TNC_TNCS_SendMessageLong",
226 (void**)&this->send_message_long
) != TNC_RESULT_SUCCESS
)
228 this->send_message_long
= NULL
;
230 if (bind_function(this->id
, "TNC_TNCS_ProvideRecommendation",
231 (void**)&this->provide_recommendation
) != TNC_RESULT_SUCCESS
)
233 this->provide_recommendation
= NULL
;
235 if (bind_function(this->id
, "TNC_TNCS_GetAttribute",
236 (void**)&this->get_attribute
) != TNC_RESULT_SUCCESS
)
238 this->get_attribute
= NULL
;
240 if (bind_function(this->id
, "TNC_TNCS_SetAttribute",
241 (void**)&this->set_attribute
) != TNC_RESULT_SUCCESS
)
243 this->set_attribute
= NULL
;
245 if (bind_function(this->id
, "TNC_TNCC_ReserveAdditionalIMVID",
246 (void**)&this->reserve_additional_id
) != TNC_RESULT_SUCCESS
)
248 this->reserve_additional_id
= NULL
;
250 DBG2(DBG_IMV
, "IMV %u \"%s\" provided with bind function",
251 this->id
, this->name
);
253 if (this->report_message_types_long
)
255 this->report_message_types_long(this->id
, &this->vendor_id
,
258 else if (this->report_message_types
&&
259 this->vendor_id
<= TNC_VENDORID_ANY
&&
260 this->subtype
<= TNC_SUBTYPE_ANY
)
262 TNC_MessageType type
;
264 type
= (this->vendor_id
<< 8) | this->subtype
;
265 this->report_message_types(this->id
, &type
, 1);
267 return TNC_RESULT_SUCCESS
;
271 * finds a connection state based on its Connection ID
273 static imv_state_t
* find_connection(private_imv_agent_t
*this,
276 enumerator_t
*enumerator
;
277 imv_state_t
*state
, *found
= NULL
;
279 this->connection_lock
->read_lock(this->connection_lock
);
280 enumerator
= this->connections
->create_enumerator(this->connections
);
281 while (enumerator
->enumerate(enumerator
, &state
))
283 if (id
== state
->get_connection_id(state
))
289 enumerator
->destroy(enumerator
);
290 this->connection_lock
->unlock(this->connection_lock
);
296 * delete a connection state with a given Connection ID
298 static bool delete_connection(private_imv_agent_t
*this, TNC_ConnectionID id
)
300 enumerator_t
*enumerator
;
304 this->connection_lock
->write_lock(this->connection_lock
);
305 enumerator
= this->connections
->create_enumerator(this->connections
);
306 while (enumerator
->enumerate(enumerator
, &state
))
308 if (id
== state
->get_connection_id(state
))
311 state
->destroy(state
);
312 this->connections
->remove_at(this->connections
, enumerator
);
316 enumerator
->destroy(enumerator
);
317 this->connection_lock
->unlock(this->connection_lock
);
323 * Read a boolean attribute
325 static bool get_bool_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
326 TNC_AttributeID attribute_id
)
331 return this->get_attribute
&&
332 this->get_attribute(this->id
, id
, attribute_id
, 4, buf
, &len
) ==
333 TNC_RESULT_SUCCESS
&& len
== 1 && *buf
== 0x01;
337 * Read a string attribute
339 static char* get_str_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
340 TNC_AttributeID attribute_id
)
345 if (this->get_attribute
&&
346 this->get_attribute(this->id
, id
, attribute_id
, BUF_LEN
, buf
, &len
) ==
347 TNC_RESULT_SUCCESS
&& len
<= BUF_LEN
)
354 METHOD(imv_agent_t
, create_state
, TNC_Result
,
355 private_imv_agent_t
*this, imv_state_t
*state
)
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
;
361 conn_id
= state
->get_connection_id(state
);
362 if (find_connection(this, conn_id
))
364 DBG1(DBG_IMV
, "IMV %u \"%s\" already created a state for Connection ID %u",
365 this->id
, this->name
, conn_id
);
366 state
->destroy(state
);
367 return TNC_RESULT_OTHER
;
370 /* Get and display attributes from TNCS via IF-IMV */
371 has_long
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_LONG_TYPES
);
372 has_excl
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_EXCLUSIVE
);
373 has_soh
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_SOH
);
374 tnccs_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL
);
375 tnccs_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_VERSION
);
376 t_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_PROTOCOL
);
377 t_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_VERSION
);
379 state
->set_flags(state
, has_long
, has_excl
);
381 DBG2(DBG_IMV
, "IMV %u \"%s\" created a state for Connection ID %u: "
382 "%s %s with %slong %sexcl %ssoh over %s %s",
383 this->id
, this->name
, conn_id
, tnccs_p ? tnccs_p
:"?",
384 tnccs_v ? tnccs_v
:"?", has_long ?
"+":"-", has_excl ?
"+":"-",
385 has_soh ?
"+":"-", t_p ? t_p
:"?", t_v ? t_v
:"?");
391 this->connection_lock
->write_lock(this->connection_lock
);
392 this->connections
->insert_last(this->connections
, state
);
393 this->connection_lock
->unlock(this->connection_lock
);
394 return TNC_RESULT_SUCCESS
;
397 METHOD(imv_agent_t
, delete_state
, TNC_Result
,
398 private_imv_agent_t
*this, TNC_ConnectionID connection_id
)
400 if (!delete_connection(this, connection_id
))
402 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
403 this->id
, this->name
, connection_id
);
404 return TNC_RESULT_FATAL
;
406 DBG2(DBG_IMV
, "IMV %u \"%s\" deleted the state of Connection ID %u",
407 this->id
, this->name
, connection_id
);
408 return TNC_RESULT_SUCCESS
;
411 METHOD(imv_agent_t
, change_state
, TNC_Result
,
412 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
413 TNC_ConnectionState new_state
,
414 imv_state_t
**state_p
)
420 case TNC_CONNECTION_STATE_HANDSHAKE
:
421 case TNC_CONNECTION_STATE_ACCESS_ALLOWED
:
422 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
423 case TNC_CONNECTION_STATE_ACCESS_NONE
:
424 state
= find_connection(this, connection_id
);
427 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
428 this->id
, this->name
, connection_id
);
429 return TNC_RESULT_FATAL
;
431 state
->change_state(state
, new_state
);
432 DBG2(DBG_IMV
, "IMV %u \"%s\" changed state of Connection ID %u to '%N'",
433 this->id
, this->name
, connection_id
,
434 TNC_Connection_State_names
, new_state
);
440 case TNC_CONNECTION_STATE_CREATE
:
441 DBG1(DBG_IMV
, "state '%N' should be handled by create_state()",
442 TNC_Connection_State_names
, new_state
);
443 return TNC_RESULT_FATAL
;
444 case TNC_CONNECTION_STATE_DELETE
:
445 DBG1(DBG_IMV
, "state '%N' should be handled by delete_state()",
446 TNC_Connection_State_names
, new_state
);
447 return TNC_RESULT_FATAL
;
449 DBG1(DBG_IMV
, "IMV %u \"%s\" was notified of unknown state %u "
450 "for Connection ID %u",
451 this->id
, this->name
, new_state
, connection_id
);
452 return TNC_RESULT_INVALID_PARAMETER
;
454 return TNC_RESULT_SUCCESS
;
457 METHOD(imv_agent_t
, get_state
, bool,
458 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
461 *state
= find_connection(this, connection_id
);
464 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
465 this->id
, this->name
, connection_id
);
471 METHOD(imv_agent_t
, send_message
, TNC_Result
,
472 private_imv_agent_t
*this, TNC_ConnectionID connection_id
, bool excl
,
473 TNC_UInt32 src_imv_id
, TNC_UInt32 dst_imc_id
, chunk_t msg
)
475 TNC_MessageType type
;
476 TNC_UInt32 msg_flags
;
479 state
= find_connection(this, connection_id
);
482 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
483 this->id
, this->name
, connection_id
);
484 return TNC_RESULT_FATAL
;
487 if (state
->has_long(state
) && this->send_message_long
)
491 src_imv_id
= this->id
;
493 msg_flags
= excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
495 return this->send_message_long(src_imv_id
, connection_id
, msg_flags
,
496 msg
.ptr
, msg
.len
, this->vendor_id
,
497 this->subtype
, dst_imc_id
);
499 if (this->send_message
)
501 type
= (this->vendor_id
<< 8) | this->subtype
;
503 return this->send_message(this->id
, connection_id
, msg
.ptr
, msg
.len
,
506 return TNC_RESULT_FATAL
;
509 METHOD(imv_agent_t
, set_recommendation
, TNC_Result
,
510 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
511 TNC_IMV_Action_Recommendation rec
,
512 TNC_IMV_Evaluation_Result eval
)
516 state
= find_connection(this, connection_id
);
519 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
520 this->id
, this->name
, connection_id
);
521 return TNC_RESULT_FATAL
;
524 state
->set_recommendation(state
, rec
, eval
);
525 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
528 METHOD(imv_agent_t
, receive_message
, TNC_Result
,
529 private_imv_agent_t
*this, imv_state_t
*state
, chunk_t msg
,
530 TNC_VendorID msg_vid
, TNC_MessageSubtype msg_subtype
,
531 TNC_UInt32 src_imc_id
, TNC_UInt32 dst_imv_id
, pa_tnc_msg_t
**pa_tnc_msg
)
533 pa_tnc_msg_t
*pa_msg
, *error_msg
;
534 pa_tnc_attr_t
*error_attr
;
535 enumerator_t
*enumerator
;
536 TNC_MessageType msg_type
;
537 TNC_UInt32 msg_flags
, src_imv_id
, dst_imc_id
;
538 TNC_ConnectionID connection_id
;
541 connection_id
= state
->get_connection_id(state
);
543 if (state
->has_long(state
))
545 if (dst_imv_id
!= TNC_IMVID_ANY
)
547 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
548 "from IMC %u to IMV %u", this->id
, this->name
,
549 connection_id
, src_imc_id
, dst_imv_id
);
553 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
554 "from IMC %u", this->id
, this->name
, connection_id
,
560 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
561 this->id
, this->name
, connection_id
);
565 pa_msg
= pa_tnc_msg_create_from_data(msg
);
567 switch (pa_msg
->process(pa_msg
))
570 *pa_tnc_msg
= pa_msg
;
573 /* build error message */
574 error_msg
= pa_tnc_msg_create();
575 enumerator
= pa_msg
->create_error_enumerator(pa_msg
);
576 while (enumerator
->enumerate(enumerator
, &error_attr
))
578 error_msg
->add_attribute(error_msg
,
579 error_attr
->get_ref(error_attr
));
581 enumerator
->destroy(enumerator
);
582 error_msg
->build(error_msg
);
584 /* send error message */
585 msg
= error_msg
->get_encoding(error_msg
);
587 if (state
->has_long(state
) && this->send_message_long
)
589 if (state
->has_excl(state
))
591 msg_flags
= TNC_MESSAGE_FLAGS_EXCLUSIVE
;
592 dst_imc_id
= src_imc_id
;
597 dst_imc_id
= TNC_IMCID_ANY
;
599 src_imv_id
= (dst_imv_id
== TNC_IMVID_ANY
) ?
this->id
602 result
= this->send_message_long(src_imv_id
, connection_id
,
603 msg_flags
, msg
.ptr
, msg
.len
, msg_vid
,
604 msg_subtype
, dst_imc_id
);
606 else if (this->send_message
)
608 msg_type
= (msg_vid
<< 8) | msg_subtype
;
610 result
= this->send_message(this->id
, connection_id
,
611 msg
.ptr
, msg
.len
, msg_type
);
615 result
= TNC_RESULT_FATAL
;
619 error_msg
->destroy(error_msg
);
620 pa_msg
->destroy(pa_msg
);
624 pa_msg
->destroy(pa_msg
);
625 state
->set_recommendation(state
,
626 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
627 TNC_IMV_EVALUATION_RESULT_ERROR
);
628 return this->provide_recommendation(this->id
, connection_id
,
629 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
630 TNC_IMV_EVALUATION_RESULT_ERROR
);
632 return TNC_RESULT_SUCCESS
;
635 METHOD(imv_agent_t
, provide_recommendation
, TNC_Result
,
636 private_imv_agent_t
*this, TNC_ConnectionID connection_id
)
639 TNC_IMV_Action_Recommendation rec
;
640 TNC_IMV_Evaluation_Result eval
;
643 chunk_t pref_lang
= { buf
, 0 }, reason_string
, reason_lang
;
645 state
= find_connection(this, connection_id
);
648 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
649 this->id
, this->name
, connection_id
);
650 return TNC_RESULT_FATAL
;
652 state
->get_recommendation(state
, &rec
, &eval
);
655 /* send a reason string if action recommendation is not allow */
656 if (rec
!= TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
658 /* check if there a preferred language has been requested */
659 if (this->get_attribute
&&
660 this->get_attribute(this->id
, connection_id
,
661 TNC_ATTRIBUTEID_PREFERRED_LANGUAGE
, BUF_LEN
,
662 buf
, &lang_len
) == TNC_RESULT_SUCCESS
&&
665 pref_lang
.len
= lang_len
;
666 DBG2(DBG_IMV
, "preferred language is '%.*s'",
667 pref_lang
.len
, pref_lang
.ptr
);
670 /* find a reason string for the preferred or default language and set it */
671 if (this->set_attribute
&&
672 state
->get_reason_string(state
, pref_lang
, &reason_string
,
675 this->set_attribute(this->id
, connection_id
,
676 TNC_ATTRIBUTEID_REASON_STRING
,
677 reason_string
.len
, reason_string
.ptr
);
678 this->set_attribute(this->id
, connection_id
,
679 TNC_ATTRIBUTEID_REASON_LANGUAGE
,
680 reason_lang
.len
, reason_lang
.ptr
);
684 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
687 METHOD(imv_agent_t
, reserve_additional_ids
, TNC_Result
,
688 private_imv_agent_t
*this, int count
)
694 if (!this->reserve_additional_id
)
696 DBG1(DBG_IMV
, "IMV %u \"%s\" did not detect the capability to reserve "
697 "additional IMV IDs from the TNCS", this->id
, this->name
);
698 return TNC_RESULT_ILLEGAL_OPERATION
;
702 result
= this->reserve_additional_id(this->id
, &id
);
703 if (result
!= TNC_RESULT_SUCCESS
)
705 DBG1(DBG_IMV
, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
706 this->id
, this->name
, count
);
711 /* store the scalar value in the pointer */
713 this->additional_ids
->insert_last(this->additional_ids
, pointer
);
714 DBG2(DBG_IMV
, "IMV %u \"%s\" reserved additional ID %u",
715 this->id
, this->name
, id
);
717 return TNC_RESULT_SUCCESS
;
720 METHOD(imv_agent_t
, count_additional_ids
, int,
721 private_imv_agent_t
*this)
723 return this->additional_ids
->get_count(this->additional_ids
);
726 METHOD(imv_agent_t
, create_id_enumerator
, enumerator_t
*,
727 private_imv_agent_t
*this)
729 return this->additional_ids
->create_enumerator(this->additional_ids
);
732 METHOD(imv_agent_t
, destroy
, void,
733 private_imv_agent_t
*this)
735 DBG1(DBG_IMV
, "IMV %u \"%s\" terminated", this->id
, this->name
);
736 this->additional_ids
->destroy(this->additional_ids
);
737 this->connections
->destroy_offset(this->connections
,
738 offsetof(imv_state_t
, destroy
));
739 this->connection_lock
->destroy(this->connection_lock
);
742 /* decrease the reference count or terminate */
747 * Described in header.
749 imv_agent_t
*imv_agent_create(const char *name
,
750 pen_t vendor_id
, u_int32_t subtype
,
751 TNC_IMVID id
, TNC_Version
*actual_version
)
753 private_imv_agent_t
*this;
755 /* initialize or increase the reference count */
763 .bind_functions
= _bind_functions
,
764 .create_state
= _create_state
,
765 .delete_state
= _delete_state
,
766 .change_state
= _change_state
,
767 .get_state
= _get_state
,
768 .send_message
= _send_message
,
769 .receive_message
= _receive_message
,
770 .set_recommendation
= _set_recommendation
,
771 .provide_recommendation
= _provide_recommendation
,
772 .reserve_additional_ids
= _reserve_additional_ids
,
773 .count_additional_ids
= _count_additional_ids
,
774 .create_id_enumerator
= _create_id_enumerator
,
778 .vendor_id
= vendor_id
,
781 .additional_ids
= linked_list_create(),
782 .connections
= linked_list_create(),
783 .connection_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
786 *actual_version
= TNC_IFIMV_VERSION_1
;
787 DBG1(DBG_IMV
, "IMV %u \"%s\" initialized", this->id
, this->name
);
789 return &this->public;