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 <threading/rwlock.h>
23 typedef struct private_imv_agent_t private_imv_agent_t
;
26 * Private data of an imv_agent_t object.
28 struct private_imv_agent_t
{
31 * Public members of imv_agent_t
41 * message vendor ID of IMV
43 TNC_VendorID vendor_id
;
46 * message subtype of IMV
48 TNC_MessageSubtype subtype
;
51 * Maximum PA-TNC Message size
56 * ID of IMV as assigned by TNCS
61 * List of additional IMV IDs assigned by TNCS
63 linked_list_t
*additional_ids
;
66 * list of TNCS connection entries
68 linked_list_t
*connections
;
71 * rwlock to lock TNCS connection entries
73 rwlock_t
*connection_lock
;
76 * Inform a TNCS about the set of message types the IMV is able to receive
78 * @param imv_id IMV ID assigned by TNCS
79 * @param supported_types list of supported message types
80 * @param type_count number of list elements
81 * @return TNC result code
83 TNC_Result (*report_message_types
)(TNC_IMVID imv_id
,
84 TNC_MessageTypeList supported_types
,
85 TNC_UInt32 type_count
);
88 * Inform a TNCS about the set of message types the IMV is able to receive
90 * @param imv_id IMV ID assigned by TNCS
91 * @param supported_vids list of supported message vendor IDs
92 * @param supported_subtypes list of supported message subtypes
93 * @param type_count number of list elements
94 * @return TNC result code
96 TNC_Result (*report_message_types_long
)(TNC_IMVID imv_id
,
97 TNC_VendorIDList supported_vids
,
98 TNC_MessageSubtypeList supported_subtypes
,
99 TNC_UInt32 type_count
);
102 * Call when an IMV-IMC message is to be sent
104 * @param imv_id IMV ID assigned by TNCS
105 * @param connection_id network connection ID assigned by TNCS
106 * @param msg message to send
107 * @param msg_len message length in bytes
108 * @param msg_type message type
109 * @return TNC result code
111 TNC_Result (*send_message
)(TNC_IMVID imv_id
,
112 TNC_ConnectionID connection_id
,
113 TNC_BufferReference msg
,
115 TNC_MessageType msg_type
);
118 * Call when an IMV-IMC message is to be sent with long message types
120 * @param imv_id IMV ID assigned by TNCS
121 * @param connection_id network connection ID assigned by TNCS
122 * @param msg_flags message flags
123 * @param msg message to send
124 * @param msg_len message length in bytes
125 * @param msg_vid message vendor ID
126 * @param msg_subtype message subtype
127 * @param dst_imc_id destination IMC ID
128 * @return TNC result code
130 TNC_Result (*send_message_long
)(TNC_IMVID imv_id
,
131 TNC_ConnectionID connection_id
,
132 TNC_UInt32 msg_flags
,
133 TNC_BufferReference msg
,
135 TNC_VendorID msg_vid
,
136 TNC_MessageSubtype msg_subtype
,
137 TNC_UInt32 dst_imc_id
);
140 * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
142 * @param imv_id IMV ID assigned by TNCS
143 # @param connection_id network connection ID assigned by TNCS
144 * @param rec IMV action recommendation
145 * @param eval IMV evaluation result
146 * @return TNC result code
148 TNC_Result (*provide_recommendation
)(TNC_IMVID imv_id
,
149 TNC_ConnectionID connection_id
,
150 TNC_IMV_Action_Recommendation rec
,
151 TNC_IMV_Evaluation_Result eval
);
154 * Get the value of an attribute associated with a connection
155 * or with the TNCS as a whole.
157 * @param imv_id IMV ID assigned by TNCS
158 * @param connection_id network connection ID assigned by TNCS
159 * @param attribute_id attribute ID
160 * @param buffer_len length of buffer in bytes
161 * @param buffer buffer
162 * @param out_value_len size in bytes of attribute stored in buffer
163 * @return TNC result code
165 TNC_Result (*get_attribute
)(TNC_IMVID imv_id
,
166 TNC_ConnectionID connection_id
,
167 TNC_AttributeID attribute_id
,
168 TNC_UInt32 buffer_len
,
169 TNC_BufferReference buffer
,
170 TNC_UInt32
*out_value_len
);
173 * Set the value of an attribute associated with a connection
174 * or with the TNCS as a whole.
176 * @param imv_id IMV ID assigned by TNCS
177 * @param connection_id network connection ID assigned by TNCS
178 * @param attribute_id attribute ID
179 * @param buffer_len length of buffer in bytes
180 * @param buffer buffer
181 * @return TNC result code
183 TNC_Result (*set_attribute
)(TNC_IMVID imv_id
,
184 TNC_ConnectionID connection_id
,
185 TNC_AttributeID attribute_id
,
186 TNC_UInt32 buffer_len
,
187 TNC_BufferReference buffer
);
190 * Reserve an additional IMV ID
192 * @param imv_id primary IMV ID assigned by TNCS
193 * @param out_imv_id additional IMV ID assigned by TNCS
194 * @return TNC result code
196 TNC_Result (*reserve_additional_id
)(TNC_IMVID imv_id
,
197 TNC_UInt32
*out_imv_id
);
201 METHOD(imv_agent_t
, bind_functions
, TNC_Result
,
202 private_imv_agent_t
*this, TNC_TNCS_BindFunctionPointer bind_function
)
206 DBG1(DBG_IMV
, "TNC server failed to provide bind function");
207 return TNC_RESULT_INVALID_PARAMETER
;
209 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypes",
210 (void**)&this->report_message_types
) != TNC_RESULT_SUCCESS
)
212 this->report_message_types
= NULL
;
214 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypesLong",
215 (void**)&this->report_message_types_long
) != TNC_RESULT_SUCCESS
)
217 this->report_message_types_long
= NULL
;
219 if (bind_function(this->id
, "TNC_TNCS_RequestHandshakeRetry",
220 (void**)&this->public.request_handshake_retry
) != TNC_RESULT_SUCCESS
)
222 this->public.request_handshake_retry
= NULL
;
224 if (bind_function(this->id
, "TNC_TNCS_SendMessage",
225 (void**)&this->send_message
) != TNC_RESULT_SUCCESS
)
227 this->send_message
= NULL
;
229 if (bind_function(this->id
, "TNC_TNCS_SendMessageLong",
230 (void**)&this->send_message_long
) != TNC_RESULT_SUCCESS
)
232 this->send_message_long
= NULL
;
234 if (bind_function(this->id
, "TNC_TNCS_ProvideRecommendation",
235 (void**)&this->provide_recommendation
) != TNC_RESULT_SUCCESS
)
237 this->provide_recommendation
= NULL
;
239 if (bind_function(this->id
, "TNC_TNCS_GetAttribute",
240 (void**)&this->get_attribute
) != TNC_RESULT_SUCCESS
)
242 this->get_attribute
= NULL
;
244 if (bind_function(this->id
, "TNC_TNCS_SetAttribute",
245 (void**)&this->set_attribute
) != TNC_RESULT_SUCCESS
)
247 this->set_attribute
= NULL
;
249 if (bind_function(this->id
, "TNC_TNCC_ReserveAdditionalIMVID",
250 (void**)&this->reserve_additional_id
) != TNC_RESULT_SUCCESS
)
252 this->reserve_additional_id
= NULL
;
254 DBG2(DBG_IMV
, "IMV %u \"%s\" provided with bind function",
255 this->id
, this->name
);
257 if (this->report_message_types_long
)
259 this->report_message_types_long(this->id
, &this->vendor_id
,
262 else if (this->report_message_types
&&
263 this->vendor_id
<= TNC_VENDORID_ANY
&&
264 this->subtype
<= TNC_SUBTYPE_ANY
)
266 TNC_MessageType type
;
268 type
= (this->vendor_id
<< 8) | this->subtype
;
269 this->report_message_types(this->id
, &type
, 1);
271 return TNC_RESULT_SUCCESS
;
275 * finds a connection state based on its Connection ID
277 static imv_state_t
* find_connection(private_imv_agent_t
*this,
280 enumerator_t
*enumerator
;
281 imv_state_t
*state
, *found
= NULL
;
283 this->connection_lock
->read_lock(this->connection_lock
);
284 enumerator
= this->connections
->create_enumerator(this->connections
);
285 while (enumerator
->enumerate(enumerator
, &state
))
287 if (id
== state
->get_connection_id(state
))
293 enumerator
->destroy(enumerator
);
294 this->connection_lock
->unlock(this->connection_lock
);
300 * delete a connection state with a given Connection ID
302 static bool delete_connection(private_imv_agent_t
*this, TNC_ConnectionID id
)
304 enumerator_t
*enumerator
;
308 this->connection_lock
->write_lock(this->connection_lock
);
309 enumerator
= this->connections
->create_enumerator(this->connections
);
310 while (enumerator
->enumerate(enumerator
, &state
))
312 if (id
== state
->get_connection_id(state
))
315 state
->destroy(state
);
316 this->connections
->remove_at(this->connections
, enumerator
);
320 enumerator
->destroy(enumerator
);
321 this->connection_lock
->unlock(this->connection_lock
);
327 * Read a boolean attribute
329 static bool get_bool_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
330 TNC_AttributeID attribute_id
)
335 return this->get_attribute
&&
336 this->get_attribute(this->id
, id
, attribute_id
, 4, buf
, &len
) ==
337 TNC_RESULT_SUCCESS
&& len
== 1 && *buf
== 0x01;
341 * Read a string attribute
343 static char* get_str_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
344 TNC_AttributeID attribute_id
)
349 if (this->get_attribute
&&
350 this->get_attribute(this->id
, id
, attribute_id
, BUF_LEN
, buf
, &len
) ==
351 TNC_RESULT_SUCCESS
&& len
<= BUF_LEN
)
359 * Read an UInt32 attribute
361 static u_int32_t
get_uint_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
362 TNC_AttributeID attribute_id
)
367 if (this->get_attribute
&&
368 this->get_attribute(this->id
, id
, attribute_id
, 4, buf
, &len
) ==
369 TNC_RESULT_SUCCESS
&& len
== 4)
376 METHOD(imv_agent_t
, create_state
, TNC_Result
,
377 private_imv_agent_t
*this, imv_state_t
*state
)
379 TNC_ConnectionID conn_id
;
380 char *tnccs_p
= NULL
, *tnccs_v
= NULL
, *t_p
= NULL
, *t_v
= NULL
;
381 bool has_long
= FALSE
, has_excl
= FALSE
, has_soh
= FALSE
;
382 u_int32_t max_msg_len
;
384 conn_id
= state
->get_connection_id(state
);
385 if (find_connection(this, conn_id
))
387 DBG1(DBG_IMV
, "IMV %u \"%s\" already created a state for Connection ID %u",
388 this->id
, this->name
, conn_id
);
389 state
->destroy(state
);
390 return TNC_RESULT_OTHER
;
393 /* Get and display attributes from TNCS via IF-IMV */
394 has_long
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_LONG_TYPES
);
395 has_excl
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_EXCLUSIVE
);
396 has_soh
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_SOH
);
397 tnccs_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL
);
398 tnccs_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_VERSION
);
399 t_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_PROTOCOL
);
400 t_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_VERSION
);
401 max_msg_len
= get_uint_attribute(this, conn_id
, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE
);
403 state
->set_flags(state
, has_long
, has_excl
);
404 state
->set_max_msg_len(state
, max_msg_len
);
406 DBG2(DBG_IMV
, "IMV %u \"%s\" created a state for %s %s Connection ID %u: "
407 "%slong %sexcl %ssoh", this->id
, this->name
,
408 tnccs_p ? tnccs_p
:"?", tnccs_v ? tnccs_v
:"?", conn_id
,
409 has_long ?
"+":"-", has_excl ?
"+":"-", has_soh ?
"+":"-");
410 DBG2(DBG_IMV
, " over %s %s with maximum PA-TNC message size of %u bytes",
411 t_p ? t_p
:"?", t_v ? t_v
:"?", max_msg_len
);
418 this->connection_lock
->write_lock(this->connection_lock
);
419 this->connections
->insert_last(this->connections
, state
);
420 this->connection_lock
->unlock(this->connection_lock
);
421 return TNC_RESULT_SUCCESS
;
424 METHOD(imv_agent_t
, delete_state
, TNC_Result
,
425 private_imv_agent_t
*this, TNC_ConnectionID connection_id
)
427 if (!delete_connection(this, connection_id
))
429 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
430 this->id
, this->name
, connection_id
);
431 return TNC_RESULT_FATAL
;
433 DBG2(DBG_IMV
, "IMV %u \"%s\" deleted the state of Connection ID %u",
434 this->id
, this->name
, connection_id
);
435 return TNC_RESULT_SUCCESS
;
438 METHOD(imv_agent_t
, change_state
, TNC_Result
,
439 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
440 TNC_ConnectionState new_state
,
441 imv_state_t
**state_p
)
447 case TNC_CONNECTION_STATE_HANDSHAKE
:
448 case TNC_CONNECTION_STATE_ACCESS_ALLOWED
:
449 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
450 case TNC_CONNECTION_STATE_ACCESS_NONE
:
451 state
= find_connection(this, connection_id
);
454 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
455 this->id
, this->name
, connection_id
);
456 return TNC_RESULT_FATAL
;
458 state
->change_state(state
, new_state
);
459 DBG2(DBG_IMV
, "IMV %u \"%s\" changed state of Connection ID %u to '%N'",
460 this->id
, this->name
, connection_id
,
461 TNC_Connection_State_names
, new_state
);
467 case TNC_CONNECTION_STATE_CREATE
:
468 DBG1(DBG_IMV
, "state '%N' should be handled by create_state()",
469 TNC_Connection_State_names
, new_state
);
470 return TNC_RESULT_FATAL
;
471 case TNC_CONNECTION_STATE_DELETE
:
472 DBG1(DBG_IMV
, "state '%N' should be handled by delete_state()",
473 TNC_Connection_State_names
, new_state
);
474 return TNC_RESULT_FATAL
;
476 DBG1(DBG_IMV
, "IMV %u \"%s\" was notified of unknown state %u "
477 "for Connection ID %u",
478 this->id
, this->name
, new_state
, connection_id
);
479 return TNC_RESULT_INVALID_PARAMETER
;
481 return TNC_RESULT_SUCCESS
;
484 METHOD(imv_agent_t
, get_state
, bool,
485 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
488 *state
= find_connection(this, connection_id
);
491 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
492 this->id
, this->name
, connection_id
);
498 METHOD(imv_agent_t
, send_message
, TNC_Result
,
499 private_imv_agent_t
*this, TNC_ConnectionID connection_id
, bool excl
,
500 TNC_UInt32 src_imv_id
, TNC_UInt32 dst_imc_id
, linked_list_t
*attr_list
)
502 TNC_MessageType type
;
503 TNC_UInt32 msg_flags
;
504 TNC_Result result
= TNC_RESULT_FATAL
;
507 pa_tnc_msg_t
*pa_tnc_msg
;
509 enumerator_t
*enumerator
;
512 state
= find_connection(this, connection_id
);
515 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
516 this->id
, this->name
, connection_id
);
517 return TNC_RESULT_FATAL
;
520 while (attr_list
->get_count(attr_list
))
522 pa_tnc_msg
= pa_tnc_msg_create(this->max_msg_len
);
525 enumerator
= attr_list
->create_enumerator(attr_list
);
526 while (enumerator
->enumerate(enumerator
, &attr
))
527 if (pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
))
539 DBG1(DBG_IMV
, "PA-TNC attribute too large to send, deleted");
543 attr_list
->remove_at(attr_list
, enumerator
);
545 enumerator
->destroy(enumerator
);
547 /* build and send the PA-TNC message via the IF-IMV interface */
548 pa_tnc_msg
->build(pa_tnc_msg
);
549 msg
= pa_tnc_msg
->get_encoding(pa_tnc_msg
);
551 if (state
->has_long(state
) && this->send_message_long
)
555 src_imv_id
= this->id
;
557 msg_flags
= excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
559 result
= this->send_message_long(src_imv_id
, connection_id
,
560 msg_flags
, msg
.ptr
, msg
.len
, this->vendor_id
,
561 this->subtype
, dst_imc_id
);
563 else if (this->send_message
)
565 type
= (this->vendor_id
<< 8) | this->subtype
;
567 result
= this->send_message(this->id
, connection_id
, msg
.ptr
,
571 pa_tnc_msg
->destroy(pa_tnc_msg
);
573 if (result
!= TNC_RESULT_SUCCESS
)
581 METHOD(imv_agent_t
, set_recommendation
, TNC_Result
,
582 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
583 TNC_IMV_Action_Recommendation rec
,
584 TNC_IMV_Evaluation_Result eval
)
588 state
= find_connection(this, connection_id
);
591 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
592 this->id
, this->name
, connection_id
);
593 return TNC_RESULT_FATAL
;
596 state
->set_recommendation(state
, rec
, eval
);
597 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
600 METHOD(imv_agent_t
, receive_message
, TNC_Result
,
601 private_imv_agent_t
*this, imv_state_t
*state
, chunk_t msg
,
602 TNC_VendorID msg_vid
, TNC_MessageSubtype msg_subtype
,
603 TNC_UInt32 src_imc_id
, TNC_UInt32 dst_imv_id
, pa_tnc_msg_t
**pa_tnc_msg
)
605 pa_tnc_msg_t
*pa_msg
;
606 pa_tnc_attr_t
*error_attr
;
607 linked_list_t
*error_attr_list
;
608 enumerator_t
*enumerator
;
609 TNC_UInt32 src_imv_id
, dst_imc_id
;
610 TNC_ConnectionID connection_id
;
613 connection_id
= state
->get_connection_id(state
);
615 if (state
->has_long(state
))
617 if (dst_imv_id
!= TNC_IMVID_ANY
)
619 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
620 "from IMC %u to IMV %u", this->id
, this->name
,
621 connection_id
, src_imc_id
, dst_imv_id
);
625 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
626 "from IMC %u", this->id
, this->name
, connection_id
,
632 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
633 this->id
, this->name
, connection_id
);
637 pa_msg
= pa_tnc_msg_create_from_data(msg
);
639 switch (pa_msg
->process(pa_msg
))
642 *pa_tnc_msg
= pa_msg
;
645 /* extract and copy by refence all error attributes */
646 error_attr_list
= linked_list_create();
648 enumerator
= pa_msg
->create_error_enumerator(pa_msg
);
649 while (enumerator
->enumerate(enumerator
, &error_attr
))
651 error_attr_list
->insert_last(error_attr_list
,
652 error_attr
->get_ref(error_attr
));
654 enumerator
->destroy(enumerator
);
656 src_imv_id
= (dst_imv_id
== TNC_IMVID_ANY
) ?
this->id
: dst_imv_id
;
657 dst_imc_id
= state
->has_excl(state
) ? src_imc_id
: TNC_IMCID_ANY
;
659 result
= send_message(this, connection_id
, state
->has_excl(state
),
660 src_imv_id
, dst_imc_id
, error_attr_list
);
662 error_attr_list
->destroy(error_attr_list
);
663 pa_msg
->destroy(pa_msg
);
667 pa_msg
->destroy(pa_msg
);
668 state
->set_recommendation(state
,
669 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
670 TNC_IMV_EVALUATION_RESULT_ERROR
);
671 return this->provide_recommendation(this->id
, connection_id
,
672 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
673 TNC_IMV_EVALUATION_RESULT_ERROR
);
675 return TNC_RESULT_SUCCESS
;
678 METHOD(imv_agent_t
, provide_recommendation
, TNC_Result
,
679 private_imv_agent_t
*this, TNC_ConnectionID connection_id
)
682 TNC_IMV_Action_Recommendation rec
;
683 TNC_IMV_Evaluation_Result eval
;
686 chunk_t pref_lang
= { buf
, 0 }, reason_string
, reason_lang
;
688 state
= find_connection(this, connection_id
);
691 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
692 this->id
, this->name
, connection_id
);
693 return TNC_RESULT_FATAL
;
695 state
->get_recommendation(state
, &rec
, &eval
);
698 /* send a reason string if action recommendation is not allow */
699 if (rec
!= TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
701 /* check if there a preferred language has been requested */
702 if (this->get_attribute
&&
703 this->get_attribute(this->id
, connection_id
,
704 TNC_ATTRIBUTEID_PREFERRED_LANGUAGE
, BUF_LEN
,
705 buf
, &lang_len
) == TNC_RESULT_SUCCESS
&&
708 pref_lang
.len
= lang_len
;
709 DBG2(DBG_IMV
, "preferred language is '%.*s'",
710 pref_lang
.len
, pref_lang
.ptr
);
713 /* find a reason string for the preferred or default language and set it */
714 if (this->set_attribute
&&
715 state
->get_reason_string(state
, pref_lang
, &reason_string
,
718 this->set_attribute(this->id
, connection_id
,
719 TNC_ATTRIBUTEID_REASON_STRING
,
720 reason_string
.len
, reason_string
.ptr
);
721 this->set_attribute(this->id
, connection_id
,
722 TNC_ATTRIBUTEID_REASON_LANGUAGE
,
723 reason_lang
.len
, reason_lang
.ptr
);
727 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
730 METHOD(imv_agent_t
, reserve_additional_ids
, TNC_Result
,
731 private_imv_agent_t
*this, int count
)
737 if (!this->reserve_additional_id
)
739 DBG1(DBG_IMV
, "IMV %u \"%s\" did not detect the capability to reserve "
740 "additional IMV IDs from the TNCS", this->id
, this->name
);
741 return TNC_RESULT_ILLEGAL_OPERATION
;
745 result
= this->reserve_additional_id(this->id
, &id
);
746 if (result
!= TNC_RESULT_SUCCESS
)
748 DBG1(DBG_IMV
, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
749 this->id
, this->name
, count
);
754 /* store the scalar value in the pointer */
756 this->additional_ids
->insert_last(this->additional_ids
, pointer
);
757 DBG2(DBG_IMV
, "IMV %u \"%s\" reserved additional ID %u",
758 this->id
, this->name
, id
);
760 return TNC_RESULT_SUCCESS
;
763 METHOD(imv_agent_t
, count_additional_ids
, int,
764 private_imv_agent_t
*this)
766 return this->additional_ids
->get_count(this->additional_ids
);
769 METHOD(imv_agent_t
, create_id_enumerator
, enumerator_t
*,
770 private_imv_agent_t
*this)
772 return this->additional_ids
->create_enumerator(this->additional_ids
);
775 METHOD(imv_agent_t
, destroy
, void,
776 private_imv_agent_t
*this)
778 DBG1(DBG_IMV
, "IMV %u \"%s\" terminated", this->id
, this->name
);
779 this->additional_ids
->destroy(this->additional_ids
);
780 this->connections
->destroy_offset(this->connections
,
781 offsetof(imv_state_t
, destroy
));
782 this->connection_lock
->destroy(this->connection_lock
);
785 /* decrease the reference count or terminate */
790 * Described in header.
792 imv_agent_t
*imv_agent_create(const char *name
,
793 pen_t vendor_id
, u_int32_t subtype
,
794 TNC_IMVID id
, TNC_Version
*actual_version
)
796 private_imv_agent_t
*this;
798 /* initialize or increase the reference count */
806 .bind_functions
= _bind_functions
,
807 .create_state
= _create_state
,
808 .delete_state
= _delete_state
,
809 .change_state
= _change_state
,
810 .get_state
= _get_state
,
811 .send_message
= _send_message
,
812 .receive_message
= _receive_message
,
813 .set_recommendation
= _set_recommendation
,
814 .provide_recommendation
= _provide_recommendation
,
815 .reserve_additional_ids
= _reserve_additional_ids
,
816 .count_additional_ids
= _count_additional_ids
,
817 .create_id_enumerator
= _create_id_enumerator
,
821 .vendor_id
= vendor_id
,
823 .max_msg_len
= 65490,
825 .additional_ids
= linked_list_create(),
826 .connections
= linked_list_create(),
827 .connection_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
830 *actual_version
= TNC_IFIMV_VERSION_1
;
831 DBG1(DBG_IMV
, "IMV %u \"%s\" initialized", this->id
, this->name
);
833 return &this->public;