2 * Copyright (C) 2011-2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
17 #include "imv_agent.h"
18 #include "ietf/ietf_attr_assess_result.h"
20 #include <tncif_names.h>
23 #include <threading/rwlock.h>
25 typedef struct private_imv_agent_t private_imv_agent_t
;
28 * Private data of an imv_agent_t object.
30 struct private_imv_agent_t
{
33 * Public members of imv_agent_t
43 * message vendor ID of IMV
45 TNC_VendorID vendor_id
;
48 * message subtype of IMV
50 TNC_MessageSubtype subtype
;
53 * Maximum PA-TNC Message size
58 * ID of IMV as assigned by TNCS
63 * List of additional IMV IDs assigned by TNCS
65 linked_list_t
*additional_ids
;
68 * list of TNCS connection entries
70 linked_list_t
*connections
;
73 * rwlock to lock TNCS connection entries
75 rwlock_t
*connection_lock
;
78 * Inform a TNCS about the set of message types the IMV is able to receive
80 * @param imv_id IMV ID assigned by TNCS
81 * @param supported_types list of supported message types
82 * @param type_count number of list elements
83 * @return TNC result code
85 TNC_Result (*report_message_types
)(TNC_IMVID imv_id
,
86 TNC_MessageTypeList supported_types
,
87 TNC_UInt32 type_count
);
90 * Inform a TNCS about the set of message types the IMV is able to receive
92 * @param imv_id IMV ID assigned by TNCS
93 * @param supported_vids list of supported message vendor IDs
94 * @param supported_subtypes list of supported message subtypes
95 * @param type_count number of list elements
96 * @return TNC result code
98 TNC_Result (*report_message_types_long
)(TNC_IMVID imv_id
,
99 TNC_VendorIDList supported_vids
,
100 TNC_MessageSubtypeList supported_subtypes
,
101 TNC_UInt32 type_count
);
104 * Call when an IMV-IMC message is to be sent
106 * @param imv_id IMV ID assigned by TNCS
107 * @param connection_id network connection ID assigned by TNCS
108 * @param msg message to send
109 * @param msg_len message length in bytes
110 * @param msg_type message type
111 * @return TNC result code
113 TNC_Result (*send_message
)(TNC_IMVID imv_id
,
114 TNC_ConnectionID connection_id
,
115 TNC_BufferReference msg
,
117 TNC_MessageType msg_type
);
120 * Call when an IMV-IMC message is to be sent with long message types
122 * @param imv_id IMV ID assigned by TNCS
123 * @param connection_id network connection ID assigned by TNCS
124 * @param msg_flags message flags
125 * @param msg message to send
126 * @param msg_len message length in bytes
127 * @param msg_vid message vendor ID
128 * @param msg_subtype message subtype
129 * @param dst_imc_id destination IMC ID
130 * @return TNC result code
132 TNC_Result (*send_message_long
)(TNC_IMVID imv_id
,
133 TNC_ConnectionID connection_id
,
134 TNC_UInt32 msg_flags
,
135 TNC_BufferReference msg
,
137 TNC_VendorID msg_vid
,
138 TNC_MessageSubtype msg_subtype
,
139 TNC_UInt32 dst_imc_id
);
142 * Deliver IMV Action Recommendation and IMV Evaluation Results to the TNCS
144 * @param imv_id IMV ID assigned by TNCS
145 # @param connection_id network connection ID assigned by TNCS
146 * @param rec IMV action recommendation
147 * @param eval IMV evaluation result
148 * @return TNC result code
150 TNC_Result (*provide_recommendation
)(TNC_IMVID imv_id
,
151 TNC_ConnectionID connection_id
,
152 TNC_IMV_Action_Recommendation rec
,
153 TNC_IMV_Evaluation_Result eval
);
156 * Get the value of an attribute associated with a connection
157 * or with the TNCS as a whole.
159 * @param imv_id IMV ID assigned by TNCS
160 * @param connection_id network connection ID assigned by TNCS
161 * @param attribute_id attribute ID
162 * @param buffer_len length of buffer in bytes
163 * @param buffer buffer
164 * @param out_value_len size in bytes of attribute stored in buffer
165 * @return TNC result code
167 TNC_Result (*get_attribute
)(TNC_IMVID imv_id
,
168 TNC_ConnectionID connection_id
,
169 TNC_AttributeID attribute_id
,
170 TNC_UInt32 buffer_len
,
171 TNC_BufferReference buffer
,
172 TNC_UInt32
*out_value_len
);
175 * Set the value of an attribute associated with a connection
176 * or with the TNCS as a whole.
178 * @param imv_id IMV ID assigned by TNCS
179 * @param connection_id network connection ID assigned by TNCS
180 * @param attribute_id attribute ID
181 * @param buffer_len length of buffer in bytes
182 * @param buffer buffer
183 * @return TNC result code
185 TNC_Result (*set_attribute
)(TNC_IMVID imv_id
,
186 TNC_ConnectionID connection_id
,
187 TNC_AttributeID attribute_id
,
188 TNC_UInt32 buffer_len
,
189 TNC_BufferReference buffer
);
192 * Reserve an additional IMV ID
194 * @param imv_id primary IMV ID assigned by TNCS
195 * @param out_imv_id additional IMV ID assigned by TNCS
196 * @return TNC result code
198 TNC_Result (*reserve_additional_id
)(TNC_IMVID imv_id
,
199 TNC_UInt32
*out_imv_id
);
203 METHOD(imv_agent_t
, bind_functions
, TNC_Result
,
204 private_imv_agent_t
*this, TNC_TNCS_BindFunctionPointer bind_function
)
208 DBG1(DBG_IMV
, "TNC server failed to provide bind function");
209 return TNC_RESULT_INVALID_PARAMETER
;
211 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypes",
212 (void**)&this->report_message_types
) != TNC_RESULT_SUCCESS
)
214 this->report_message_types
= NULL
;
216 if (bind_function(this->id
, "TNC_TNCS_ReportMessageTypesLong",
217 (void**)&this->report_message_types_long
) != TNC_RESULT_SUCCESS
)
219 this->report_message_types_long
= NULL
;
221 if (bind_function(this->id
, "TNC_TNCS_RequestHandshakeRetry",
222 (void**)&this->public.request_handshake_retry
) != TNC_RESULT_SUCCESS
)
224 this->public.request_handshake_retry
= NULL
;
226 if (bind_function(this->id
, "TNC_TNCS_SendMessage",
227 (void**)&this->send_message
) != TNC_RESULT_SUCCESS
)
229 this->send_message
= NULL
;
231 if (bind_function(this->id
, "TNC_TNCS_SendMessageLong",
232 (void**)&this->send_message_long
) != TNC_RESULT_SUCCESS
)
234 this->send_message_long
= NULL
;
236 if (bind_function(this->id
, "TNC_TNCS_ProvideRecommendation",
237 (void**)&this->provide_recommendation
) != TNC_RESULT_SUCCESS
)
239 this->provide_recommendation
= NULL
;
241 if (bind_function(this->id
, "TNC_TNCS_GetAttribute",
242 (void**)&this->get_attribute
) != TNC_RESULT_SUCCESS
)
244 this->get_attribute
= NULL
;
246 if (bind_function(this->id
, "TNC_TNCS_SetAttribute",
247 (void**)&this->set_attribute
) != TNC_RESULT_SUCCESS
)
249 this->set_attribute
= NULL
;
251 if (bind_function(this->id
, "TNC_TNCC_ReserveAdditionalIMVID",
252 (void**)&this->reserve_additional_id
) != TNC_RESULT_SUCCESS
)
254 this->reserve_additional_id
= NULL
;
256 DBG2(DBG_IMV
, "IMV %u \"%s\" provided with bind function",
257 this->id
, this->name
);
259 if (this->report_message_types_long
)
261 this->report_message_types_long(this->id
, &this->vendor_id
,
264 else if (this->report_message_types
&&
265 this->vendor_id
<= TNC_VENDORID_ANY
&&
266 this->subtype
<= TNC_SUBTYPE_ANY
)
268 TNC_MessageType type
;
270 type
= (this->vendor_id
<< 8) | this->subtype
;
271 this->report_message_types(this->id
, &type
, 1);
273 return TNC_RESULT_SUCCESS
;
277 * finds a connection state based on its Connection ID
279 static imv_state_t
* find_connection(private_imv_agent_t
*this,
282 enumerator_t
*enumerator
;
283 imv_state_t
*state
, *found
= NULL
;
285 this->connection_lock
->read_lock(this->connection_lock
);
286 enumerator
= this->connections
->create_enumerator(this->connections
);
287 while (enumerator
->enumerate(enumerator
, &state
))
289 if (id
== state
->get_connection_id(state
))
295 enumerator
->destroy(enumerator
);
296 this->connection_lock
->unlock(this->connection_lock
);
302 * delete a connection state with a given Connection ID
304 static bool delete_connection(private_imv_agent_t
*this, TNC_ConnectionID id
)
306 enumerator_t
*enumerator
;
310 this->connection_lock
->write_lock(this->connection_lock
);
311 enumerator
= this->connections
->create_enumerator(this->connections
);
312 while (enumerator
->enumerate(enumerator
, &state
))
314 if (id
== state
->get_connection_id(state
))
317 state
->destroy(state
);
318 this->connections
->remove_at(this->connections
, enumerator
);
322 enumerator
->destroy(enumerator
);
323 this->connection_lock
->unlock(this->connection_lock
);
329 * Read a boolean attribute
331 static bool get_bool_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
332 TNC_AttributeID attribute_id
)
337 return this->get_attribute
&&
338 this->get_attribute(this->id
, id
, attribute_id
, 4, buf
, &len
) ==
339 TNC_RESULT_SUCCESS
&& len
== 1 && *buf
== 0x01;
343 * Read a string attribute
345 static char* get_str_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
346 TNC_AttributeID attribute_id
)
351 if (this->get_attribute
&&
352 this->get_attribute(this->id
, id
, attribute_id
, BUF_LEN
, buf
, &len
) ==
353 TNC_RESULT_SUCCESS
&& len
<= BUF_LEN
)
361 * Read an UInt32 attribute
363 static u_int32_t
get_uint_attribute(private_imv_agent_t
*this, TNC_ConnectionID id
,
364 TNC_AttributeID attribute_id
)
369 if (this->get_attribute
&&
370 this->get_attribute(this->id
, id
, attribute_id
, 4, buf
, &len
) ==
371 TNC_RESULT_SUCCESS
&& len
== 4)
378 METHOD(imv_agent_t
, create_state
, TNC_Result
,
379 private_imv_agent_t
*this, imv_state_t
*state
)
381 TNC_ConnectionID conn_id
;
382 char *tnccs_p
= NULL
, *tnccs_v
= NULL
, *t_p
= NULL
, *t_v
= NULL
;
383 bool has_long
= FALSE
, has_excl
= FALSE
, has_soh
= FALSE
;
384 u_int32_t max_msg_len
;
386 conn_id
= state
->get_connection_id(state
);
387 if (find_connection(this, conn_id
))
389 DBG1(DBG_IMV
, "IMV %u \"%s\" already created a state for Connection ID %u",
390 this->id
, this->name
, conn_id
);
391 state
->destroy(state
);
392 return TNC_RESULT_OTHER
;
395 /* Get and display attributes from TNCS via IF-IMV */
396 has_long
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_LONG_TYPES
);
397 has_excl
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_EXCLUSIVE
);
398 has_soh
= get_bool_attribute(this, conn_id
, TNC_ATTRIBUTEID_HAS_SOH
);
399 tnccs_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_PROTOCOL
);
400 tnccs_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFTNCCS_VERSION
);
401 t_p
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_PROTOCOL
);
402 t_v
= get_str_attribute(this, conn_id
, TNC_ATTRIBUTEID_IFT_VERSION
);
403 max_msg_len
= get_uint_attribute(this, conn_id
, TNC_ATTRIBUTEID_MAX_MESSAGE_SIZE
);
405 state
->set_flags(state
, has_long
, has_excl
);
406 state
->set_max_msg_len(state
, max_msg_len
);
408 DBG2(DBG_IMV
, "IMV %u \"%s\" created a state for %s %s Connection ID %u: "
409 "%slong %sexcl %ssoh", this->id
, this->name
,
410 tnccs_p ? tnccs_p
:"?", tnccs_v ? tnccs_v
:"?", conn_id
,
411 has_long ?
"+":"-", has_excl ?
"+":"-", has_soh ?
"+":"-");
412 DBG2(DBG_IMV
, " over %s %s with maximum PA-TNC message size of %u bytes",
413 t_p ? t_p
:"?", t_v ? t_v
:"?", max_msg_len
);
420 this->connection_lock
->write_lock(this->connection_lock
);
421 this->connections
->insert_last(this->connections
, state
);
422 this->connection_lock
->unlock(this->connection_lock
);
423 return TNC_RESULT_SUCCESS
;
426 METHOD(imv_agent_t
, delete_state
, TNC_Result
,
427 private_imv_agent_t
*this, TNC_ConnectionID connection_id
)
429 if (!delete_connection(this, connection_id
))
431 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
432 this->id
, this->name
, connection_id
);
433 return TNC_RESULT_FATAL
;
435 DBG2(DBG_IMV
, "IMV %u \"%s\" deleted the state of Connection ID %u",
436 this->id
, this->name
, connection_id
);
437 return TNC_RESULT_SUCCESS
;
440 METHOD(imv_agent_t
, change_state
, TNC_Result
,
441 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
442 TNC_ConnectionState new_state
,
443 imv_state_t
**state_p
)
449 case TNC_CONNECTION_STATE_HANDSHAKE
:
450 case TNC_CONNECTION_STATE_ACCESS_ALLOWED
:
451 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
452 case TNC_CONNECTION_STATE_ACCESS_NONE
:
453 state
= find_connection(this, connection_id
);
456 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
457 this->id
, this->name
, connection_id
);
458 return TNC_RESULT_FATAL
;
460 state
->change_state(state
, new_state
);
461 DBG2(DBG_IMV
, "IMV %u \"%s\" changed state of Connection ID %u to '%N'",
462 this->id
, this->name
, connection_id
,
463 TNC_Connection_State_names
, new_state
);
469 case TNC_CONNECTION_STATE_CREATE
:
470 DBG1(DBG_IMV
, "state '%N' should be handled by create_state()",
471 TNC_Connection_State_names
, new_state
);
472 return TNC_RESULT_FATAL
;
473 case TNC_CONNECTION_STATE_DELETE
:
474 DBG1(DBG_IMV
, "state '%N' should be handled by delete_state()",
475 TNC_Connection_State_names
, new_state
);
476 return TNC_RESULT_FATAL
;
478 DBG1(DBG_IMV
, "IMV %u \"%s\" was notified of unknown state %u "
479 "for Connection ID %u",
480 this->id
, this->name
, new_state
, connection_id
);
481 return TNC_RESULT_INVALID_PARAMETER
;
483 return TNC_RESULT_SUCCESS
;
486 METHOD(imv_agent_t
, get_state
, bool,
487 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
490 *state
= find_connection(this, connection_id
);
493 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
494 this->id
, this->name
, connection_id
);
500 METHOD(imv_agent_t
, send_message
, TNC_Result
,
501 private_imv_agent_t
*this, TNC_ConnectionID connection_id
, bool excl
,
502 TNC_UInt32 src_imv_id
, TNC_UInt32 dst_imc_id
, linked_list_t
*attr_list
)
504 TNC_MessageType type
;
505 TNC_UInt32 msg_flags
;
506 TNC_Result result
= TNC_RESULT_FATAL
;
509 pa_tnc_msg_t
*pa_tnc_msg
;
511 enumerator_t
*enumerator
;
514 state
= find_connection(this, connection_id
);
517 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
518 this->id
, this->name
, connection_id
);
519 return TNC_RESULT_FATAL
;
522 while (attr_list
->get_count(attr_list
))
524 pa_tnc_msg
= pa_tnc_msg_create(this->max_msg_len
);
527 enumerator
= attr_list
->create_enumerator(attr_list
);
528 while (enumerator
->enumerate(enumerator
, &attr
))
530 if (pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
))
542 DBG1(DBG_IMV
, "PA-TNC attribute too large to send, deleted");
546 attr_list
->remove_at(attr_list
, enumerator
);
548 enumerator
->destroy(enumerator
);
550 /* build and send the PA-TNC message via the IF-IMV interface */
551 if (!pa_tnc_msg
->build(pa_tnc_msg
))
553 pa_tnc_msg
->destroy(pa_tnc_msg
);
554 return TNC_RESULT_FATAL
;
556 msg
= pa_tnc_msg
->get_encoding(pa_tnc_msg
);
558 if (state
->has_long(state
) && this->send_message_long
)
562 src_imv_id
= this->id
;
564 msg_flags
= excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
566 result
= this->send_message_long(src_imv_id
, connection_id
,
567 msg_flags
, msg
.ptr
, msg
.len
, this->vendor_id
,
568 this->subtype
, dst_imc_id
);
570 else if (this->send_message
)
572 type
= (this->vendor_id
<< 8) | this->subtype
;
574 result
= this->send_message(this->id
, connection_id
, msg
.ptr
,
578 pa_tnc_msg
->destroy(pa_tnc_msg
);
580 if (result
!= TNC_RESULT_SUCCESS
)
588 METHOD(imv_agent_t
, set_recommendation
, TNC_Result
,
589 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
590 TNC_IMV_Action_Recommendation rec
,
591 TNC_IMV_Evaluation_Result eval
)
595 state
= find_connection(this, connection_id
);
598 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
599 this->id
, this->name
, connection_id
);
600 return TNC_RESULT_FATAL
;
603 state
->set_recommendation(state
, rec
, eval
);
604 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
607 METHOD(imv_agent_t
, receive_message
, TNC_Result
,
608 private_imv_agent_t
*this, imv_state_t
*state
, chunk_t msg
,
609 TNC_VendorID msg_vid
, TNC_MessageSubtype msg_subtype
,
610 TNC_UInt32 src_imc_id
, TNC_UInt32 dst_imv_id
, pa_tnc_msg_t
**pa_tnc_msg
)
612 pa_tnc_msg_t
*pa_msg
;
613 pa_tnc_attr_t
*error_attr
;
614 linked_list_t
*error_attr_list
;
615 enumerator_t
*enumerator
;
616 TNC_UInt32 src_imv_id
, dst_imc_id
;
617 TNC_ConnectionID connection_id
;
620 connection_id
= state
->get_connection_id(state
);
622 if (state
->has_long(state
))
624 if (dst_imv_id
!= TNC_IMVID_ANY
)
626 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
627 "from IMC %u to IMV %u", this->id
, this->name
,
628 connection_id
, src_imc_id
, dst_imv_id
);
632 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
633 "from IMC %u", this->id
, this->name
, connection_id
,
639 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
640 this->id
, this->name
, connection_id
);
644 pa_msg
= pa_tnc_msg_create_from_data(msg
);
646 switch (pa_msg
->process(pa_msg
))
649 *pa_tnc_msg
= pa_msg
;
652 /* extract and copy by refence all error attributes */
653 error_attr_list
= linked_list_create();
655 enumerator
= pa_msg
->create_error_enumerator(pa_msg
);
656 while (enumerator
->enumerate(enumerator
, &error_attr
))
658 error_attr_list
->insert_last(error_attr_list
,
659 error_attr
->get_ref(error_attr
));
661 enumerator
->destroy(enumerator
);
663 src_imv_id
= (dst_imv_id
== TNC_IMVID_ANY
) ?
this->id
: dst_imv_id
;
664 dst_imc_id
= state
->has_excl(state
) ? src_imc_id
: TNC_IMCID_ANY
;
666 result
= send_message(this, connection_id
, state
->has_excl(state
),
667 src_imv_id
, dst_imc_id
, error_attr_list
);
669 error_attr_list
->destroy(error_attr_list
);
670 pa_msg
->destroy(pa_msg
);
674 pa_msg
->destroy(pa_msg
);
675 state
->set_recommendation(state
,
676 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
677 TNC_IMV_EVALUATION_RESULT_ERROR
);
678 return this->provide_recommendation(this->id
, connection_id
,
679 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
680 TNC_IMV_EVALUATION_RESULT_ERROR
);
682 return TNC_RESULT_SUCCESS
;
685 METHOD(imv_agent_t
, provide_recommendation
, TNC_Result
,
686 private_imv_agent_t
*this, TNC_ConnectionID connection_id
,
687 TNC_UInt32 dst_imc_id
)
690 linked_list_t
*attr_list
;
693 TNC_IMV_Action_Recommendation rec
;
694 TNC_IMV_Evaluation_Result eval
;
697 chunk_t pref_lang
= { buf
, 0 }, reason_string
, reason_lang
;
699 state
= find_connection(this, connection_id
);
702 DBG1(DBG_IMV
, "IMV %u \"%s\" has no state for Connection ID %u",
703 this->id
, this->name
, connection_id
);
704 return TNC_RESULT_FATAL
;
706 state
->get_recommendation(state
, &rec
, &eval
);
708 /* send a reason string if action recommendation is not allow */
709 if (rec
!= TNC_IMV_ACTION_RECOMMENDATION_ALLOW
)
711 /* check if there a preferred language has been requested */
712 if (this->get_attribute
&&
713 this->get_attribute(this->id
, connection_id
,
714 TNC_ATTRIBUTEID_PREFERRED_LANGUAGE
, BUF_LEN
,
715 buf
, &lang_len
) == TNC_RESULT_SUCCESS
&&
718 pref_lang
.len
= lang_len
;
719 DBG2(DBG_IMV
, "preferred language is '%.*s'",
720 pref_lang
.len
, pref_lang
.ptr
);
723 /* find a reason string for the preferred or default language and set it */
724 if (this->set_attribute
&&
725 state
->get_reason_string(state
, pref_lang
, &reason_string
,
728 this->set_attribute(this->id
, connection_id
,
729 TNC_ATTRIBUTEID_REASON_STRING
,
730 reason_string
.len
, reason_string
.ptr
);
731 this->set_attribute(this->id
, connection_id
,
732 TNC_ATTRIBUTEID_REASON_LANGUAGE
,
733 reason_lang
.len
, reason_lang
.ptr
);
737 /* Send an IETF Assessment Result attribute if enabled */
738 if (lib
->settings
->get_bool(lib
->settings
, "libimcv.assessment_result", TRUE
))
740 attr
= ietf_attr_assess_result_create(eval
);
741 attr_list
= linked_list_create();
742 attr_list
->insert_last(attr_list
, attr
);
743 result
= send_message(this, connection_id
, FALSE
, this->id
, dst_imc_id
,
745 attr_list
->destroy(attr_list
);
746 if (result
!= TNC_RESULT_SUCCESS
)
751 return this->provide_recommendation(this->id
, connection_id
, rec
, eval
);
754 METHOD(imv_agent_t
, reserve_additional_ids
, TNC_Result
,
755 private_imv_agent_t
*this, int count
)
761 if (!this->reserve_additional_id
)
763 DBG1(DBG_IMV
, "IMV %u \"%s\" did not detect the capability to reserve "
764 "additional IMV IDs from the TNCS", this->id
, this->name
);
765 return TNC_RESULT_ILLEGAL_OPERATION
;
769 result
= this->reserve_additional_id(this->id
, &id
);
770 if (result
!= TNC_RESULT_SUCCESS
)
772 DBG1(DBG_IMV
, "IMV %u \"%s\" failed to reserve %d additional IMV IDs",
773 this->id
, this->name
, count
);
778 /* store the scalar value in the pointer */
780 this->additional_ids
->insert_last(this->additional_ids
, pointer
);
781 DBG2(DBG_IMV
, "IMV %u \"%s\" reserved additional ID %u",
782 this->id
, this->name
, id
);
784 return TNC_RESULT_SUCCESS
;
787 METHOD(imv_agent_t
, count_additional_ids
, int,
788 private_imv_agent_t
*this)
790 return this->additional_ids
->get_count(this->additional_ids
);
793 METHOD(imv_agent_t
, create_id_enumerator
, enumerator_t
*,
794 private_imv_agent_t
*this)
796 return this->additional_ids
->create_enumerator(this->additional_ids
);
799 METHOD(imv_agent_t
, destroy
, void,
800 private_imv_agent_t
*this)
802 DBG1(DBG_IMV
, "IMV %u \"%s\" terminated", this->id
, this->name
);
803 this->additional_ids
->destroy(this->additional_ids
);
804 this->connections
->destroy_offset(this->connections
,
805 offsetof(imv_state_t
, destroy
));
806 this->connection_lock
->destroy(this->connection_lock
);
809 /* decrease the reference count or terminate */
814 * Described in header.
816 imv_agent_t
*imv_agent_create(const char *name
,
817 pen_t vendor_id
, u_int32_t subtype
,
818 TNC_IMVID id
, TNC_Version
*actual_version
)
820 private_imv_agent_t
*this;
822 /* initialize or increase the reference count */
830 .bind_functions
= _bind_functions
,
831 .create_state
= _create_state
,
832 .delete_state
= _delete_state
,
833 .change_state
= _change_state
,
834 .get_state
= _get_state
,
835 .send_message
= _send_message
,
836 .receive_message
= _receive_message
,
837 .set_recommendation
= _set_recommendation
,
838 .provide_recommendation
= _provide_recommendation
,
839 .reserve_additional_ids
= _reserve_additional_ids
,
840 .count_additional_ids
= _count_additional_ids
,
841 .create_id_enumerator
= _create_id_enumerator
,
845 .vendor_id
= vendor_id
,
847 .max_msg_len
= 65490,
849 .additional_ids
= linked_list_create(),
850 .connections
= linked_list_create(),
851 .connection_lock
= rwlock_create(RWLOCK_TYPE_DEFAULT
),
854 *actual_version
= TNC_IFIMV_VERSION_1
;
855 DBG1(DBG_IMV
, "IMV %u \"%s\" initialized", this->id
, this->name
);
857 return &this->public;