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
16 #include "imc_test_state.h"
18 #include <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ita/ita_attr.h>
22 #include <ita/ita_attr_command.h>
23 #include <ita/ita_attr_dummy.h>
25 #include <tncif_pa_subtypes.h>
28 #include <utils/debug.h>
32 static const char imc_name
[] = "Test";
34 static pen_type_t msg_types
[] = {
35 { PEN_ITA
, PA_SUBTYPE_ITA_TEST
}
38 static imc_agent_t
*imc_test
;
41 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
43 TNC_Result
TNC_IMC_Initialize(TNC_IMCID imc_id
,
44 TNC_Version min_version
,
45 TNC_Version max_version
,
46 TNC_Version
*actual_version
)
50 DBG1(DBG_IMC
, "IMC \"%s\" has already been initialized", imc_name
);
51 return TNC_RESULT_ALREADY_INITIALIZED
;
53 imc_test
= imc_agent_create(imc_name
, msg_types
, countof(msg_types
),
54 imc_id
, actual_version
);
57 return TNC_RESULT_FATAL
;
59 if (min_version
> TNC_IFIMC_VERSION_1
|| max_version
< TNC_IFIMC_VERSION_1
)
61 DBG1(DBG_IMC
, "no common IF-IMC version");
62 return TNC_RESULT_NO_COMMON_VERSION
;
64 return TNC_RESULT_SUCCESS
;
68 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
70 TNC_Result
TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id
,
71 TNC_ConnectionID connection_id
,
72 TNC_ConnectionState new_state
)
75 imc_test_state_t
*test_state
;
77 TNC_UInt32 additional_id
;
81 enumerator_t
*enumerator
;
82 int dummy_size
, additional_ids
;
86 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
87 return TNC_RESULT_NOT_INITIALIZED
;
92 case TNC_CONNECTION_STATE_CREATE
:
93 command
= lib
->settings
->get_str(lib
->settings
,
94 "%s.plugins.imc-test.command", "none", lib
->ns
);
95 dummy_size
= lib
->settings
->get_int(lib
->settings
,
96 "%s.plugins.imc-test.dummy_size", 0, lib
->ns
);
97 retry
= lib
->settings
->get_bool(lib
->settings
,
98 "%s.plugins.imc-test.retry", FALSE
, lib
->ns
);
99 state
= imc_test_state_create(connection_id
, command
, dummy_size
,
102 result
= imc_test
->create_state(imc_test
, state
);
103 if (result
!= TNC_RESULT_SUCCESS
)
108 /* Optionally reserve additional IMC IDs */
109 additional_ids
= lib
->settings
->get_int(lib
->settings
,
110 "%s.plugins.imc-test.additional_ids", 0, lib
->ns
);
111 imc_test
->reserve_additional_ids(imc_test
, additional_ids
-
112 imc_test
->count_additional_ids(imc_test
));
114 return TNC_RESULT_SUCCESS
;
116 case TNC_CONNECTION_STATE_HANDSHAKE
:
117 /* get updated IMC state */
118 result
= imc_test
->change_state(imc_test
, connection_id
,
120 if (result
!= TNC_RESULT_SUCCESS
)
122 return TNC_RESULT_FATAL
;
124 test_state
= (imc_test_state_t
*)state
;
126 /* is it the first handshake or a retry ? */
127 if (!test_state
->is_first_handshake(test_state
))
129 command
= lib
->settings
->get_str(lib
->settings
,
130 "%s.plugins.imc-test.retry_command",
131 test_state
->get_command(test_state
), lib
->ns
);
132 test_state
->set_command(test_state
, command
);
135 state
->set_result(state
, imc_id
, TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
137 /* Exit if there are no additional IMC IDs */
138 if (!imc_test
->count_additional_ids(imc_test
))
143 enumerator
= imc_test
->create_id_enumerator(imc_test
);
144 while (enumerator
->enumerate(enumerator
, &pointer
))
146 /* interpret pointer as scalar value */
147 additional_id
= (TNC_UInt32
)pointer
;
149 state
->set_result(state
, additional_id
,
150 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
152 enumerator
->destroy(enumerator
);
154 return TNC_RESULT_SUCCESS
;
156 case TNC_CONNECTION_STATE_DELETE
:
157 return imc_test
->delete_state(imc_test
, connection_id
);
159 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
160 case TNC_CONNECTION_STATE_ACCESS_NONE
:
161 /* get updated IMC state */
162 result
= imc_test
->change_state(imc_test
, connection_id
,
164 if (result
!= TNC_RESULT_SUCCESS
)
166 return TNC_RESULT_FATAL
;
168 test_state
= (imc_test_state_t
*)state
;
170 /* do a handshake retry? */
171 if (test_state
->do_handshake_retry(test_state
))
173 return imc_test
->request_handshake_retry(imc_id
, connection_id
,
174 TNC_RETRY_REASON_IMC_REMEDIATION_COMPLETE
);
176 return TNC_RESULT_SUCCESS
;
179 return imc_test
->change_state(imc_test
, connection_id
,
184 static TNC_Result
send_message(imc_state_t
*state
, imc_msg_t
*out_msg
)
186 imc_test_state_t
*test_state
;
189 test_state
= (imc_test_state_t
*)state
;
190 if (test_state
->get_dummy_size(test_state
))
192 attr
= ita_attr_dummy_create(test_state
->get_dummy_size(test_state
));
193 attr
->set_noskip_flag(attr
, TRUE
);
194 out_msg
->add_attribute(out_msg
, attr
);
196 attr
= ita_attr_command_create(test_state
->get_command(test_state
));
197 attr
->set_noskip_flag(attr
, TRUE
);
198 out_msg
->add_attribute(out_msg
, attr
);
200 /* send PA-TNC message with the excl flag set */
201 return out_msg
->send(out_msg
, TRUE
);
205 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
207 TNC_Result
TNC_IMC_BeginHandshake(TNC_IMCID imc_id
,
208 TNC_ConnectionID connection_id
)
212 enumerator_t
*enumerator
;
214 TNC_UInt32 additional_id
;
219 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
220 return TNC_RESULT_NOT_INITIALIZED
;
222 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
224 return TNC_RESULT_FATAL
;
227 /* send PA message for primary IMC ID */
228 out_msg
= imc_msg_create(imc_test
, state
, connection_id
, imc_id
,
229 TNC_IMVID_ANY
, msg_types
[0]);
230 result
= send_message(state
, out_msg
);
231 out_msg
->destroy(out_msg
);
233 /* Exit if there are no additional IMC IDs */
234 if (!imc_test
->count_additional_ids(imc_test
))
239 /* Do we have support for transporting multiple IMC IDs? */
240 if (!state
->has_long(state
))
242 DBG1(DBG_IMC
, "IMC %u \"%s\" did not detect support for transporting "
243 "multiple IMC IDs", imc_id
, imc_name
);
247 /* send PA messages for additional IMC IDs */
248 enumerator
= imc_test
->create_id_enumerator(imc_test
);
249 while (result
== TNC_RESULT_SUCCESS
&&
250 enumerator
->enumerate(enumerator
, &pointer
))
252 /* interpret pointer as scalar value */
253 additional_id
= (TNC_UInt32
)pointer
;
254 out_msg
= imc_msg_create(imc_test
, state
, connection_id
, additional_id
,
255 TNC_IMVID_ANY
, msg_types
[0]);
256 result
= send_message(state
, out_msg
);
257 out_msg
->destroy(out_msg
);
259 enumerator
->destroy(enumerator
);
264 static TNC_Result
receive_message(imc_state_t
*state
, imc_msg_t
*in_msg
)
267 enumerator_t
*enumerator
;
269 pen_type_t attr_type
;
271 bool fatal_error
= FALSE
;
273 /* parse received PA-TNC message and handle local and remote errors */
274 result
= in_msg
->receive(in_msg
, &fatal_error
);
275 if (result
!= TNC_RESULT_SUCCESS
)
280 /* analyze PA-TNC attributes */
281 enumerator
= in_msg
->create_attribute_enumerator(in_msg
);
282 while (enumerator
->enumerate(enumerator
, &attr
))
284 attr_type
= attr
->get_type(attr
);
286 if (attr_type
.vendor_id
!= PEN_ITA
)
290 if (attr_type
.type
== ITA_ATTR_COMMAND
)
292 ita_attr_command_t
*ita_attr
;
294 ita_attr
= (ita_attr_command_t
*)attr
;
295 DBG1(DBG_IMC
, "received command '%s'",
296 ita_attr
->get_command(ita_attr
));
298 else if (attr_type
.type
== ITA_ATTR_DUMMY
)
300 ita_attr_dummy_t
*ita_attr
;
302 ita_attr
= (ita_attr_dummy_t
*)attr
;
303 DBG1(DBG_IMC
, "received dummy attribute value (%d bytes)",
304 ita_attr
->get_size(ita_attr
));
307 enumerator
->destroy(enumerator
);
311 return TNC_RESULT_FATAL
;
314 /* if no assessment result is known then repeat the measurement */
315 if (state
->get_result(state
, in_msg
->get_dst_id(in_msg
), NULL
))
317 return TNC_RESULT_SUCCESS
;
319 out_msg
= imc_msg_create_as_reply(in_msg
);
320 result
= send_message(state
, out_msg
);
321 out_msg
->destroy(out_msg
);
327 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
329 TNC_Result
TNC_IMC_ReceiveMessage(TNC_IMCID imc_id
,
330 TNC_ConnectionID connection_id
,
331 TNC_BufferReference msg
,
333 TNC_MessageType msg_type
)
341 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
342 return TNC_RESULT_NOT_INITIALIZED
;
344 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
346 return TNC_RESULT_FATAL
;
349 in_msg
= imc_msg_create_from_data(imc_test
, state
, connection_id
, msg_type
,
350 chunk_create(msg
, msg_len
));
351 result
= receive_message(state
, in_msg
);
352 in_msg
->destroy(in_msg
);
358 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
360 TNC_Result
TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id
,
361 TNC_ConnectionID connection_id
,
362 TNC_UInt32 msg_flags
,
363 TNC_BufferReference msg
,
365 TNC_VendorID msg_vid
,
366 TNC_MessageSubtype msg_subtype
,
367 TNC_UInt32 src_imv_id
,
368 TNC_UInt32 dst_imc_id
)
376 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
377 return TNC_RESULT_NOT_INITIALIZED
;
379 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
381 return TNC_RESULT_FATAL
;
383 in_msg
= imc_msg_create_from_long_data(imc_test
, state
, connection_id
,
384 src_imv_id
, dst_imc_id
, msg_vid
, msg_subtype
,
385 chunk_create(msg
, msg_len
));
386 result
=receive_message(state
, in_msg
);
387 in_msg
->destroy(in_msg
);
393 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
395 TNC_Result
TNC_IMC_BatchEnding(TNC_IMCID imc_id
,
396 TNC_ConnectionID connection_id
)
400 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
401 return TNC_RESULT_NOT_INITIALIZED
;
403 return TNC_RESULT_SUCCESS
;
407 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
409 TNC_Result
TNC_IMC_Terminate(TNC_IMCID imc_id
)
413 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
414 return TNC_RESULT_NOT_INITIALIZED
;
416 imc_test
->destroy(imc_test
);
419 return TNC_RESULT_SUCCESS
;
423 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
425 TNC_Result
TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id
,
426 TNC_TNCC_BindFunctionPointer bind_function
)
430 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
431 return TNC_RESULT_NOT_INITIALIZED
;
433 return imc_test
->bind_functions(imc_test
, bind_function
);