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>
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
, 1, imc_id
, actual_version
);
56 return TNC_RESULT_FATAL
;
58 if (min_version
> TNC_IFIMC_VERSION_1
|| max_version
< TNC_IFIMC_VERSION_1
)
60 DBG1(DBG_IMC
, "no common IF-IMC version");
61 return TNC_RESULT_NO_COMMON_VERSION
;
63 return TNC_RESULT_SUCCESS
;
67 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
69 TNC_Result
TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id
,
70 TNC_ConnectionID connection_id
,
71 TNC_ConnectionState new_state
)
74 imc_test_state_t
*test_state
;
76 TNC_UInt32 additional_id
;
80 enumerator_t
*enumerator
;
81 int dummy_size
, additional_ids
;
85 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
86 return TNC_RESULT_NOT_INITIALIZED
;
91 case TNC_CONNECTION_STATE_CREATE
:
92 command
= lib
->settings
->get_str(lib
->settings
,
93 "libimcv.plugins.imc-test.command", "none");
94 dummy_size
= lib
->settings
->get_int(lib
->settings
,
95 "libimcv.plugins.imc-test.dummy_size", 0);
96 retry
= lib
->settings
->get_bool(lib
->settings
,
97 "libimcv.plugins.imc-test.retry", FALSE
);
98 state
= imc_test_state_create(connection_id
, command
, dummy_size
,
101 result
= imc_test
->create_state(imc_test
, state
);
102 if (result
!= TNC_RESULT_SUCCESS
)
107 /* Optionally reserve additional IMC IDs */
108 additional_ids
= lib
->settings
->get_int(lib
->settings
,
109 "libimcv.plugins.imc-test.additional_ids", 0);
110 imc_test
->reserve_additional_ids(imc_test
, additional_ids
-
111 imc_test
->count_additional_ids(imc_test
));
113 return TNC_RESULT_SUCCESS
;
115 case TNC_CONNECTION_STATE_HANDSHAKE
:
116 /* get updated IMC state */
117 result
= imc_test
->change_state(imc_test
, connection_id
,
119 if (result
!= TNC_RESULT_SUCCESS
)
121 return TNC_RESULT_FATAL
;
123 test_state
= (imc_test_state_t
*)state
;
125 /* is it the first handshake or a retry ? */
126 if (!test_state
->is_first_handshake(test_state
))
128 command
= lib
->settings
->get_str(lib
->settings
,
129 "libimcv.plugins.imc-test.retry_command",
130 test_state
->get_command(test_state
));
131 test_state
->set_command(test_state
, command
);
134 state
->set_result(state
, imc_id
, TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
136 /* Exit if there are no additional IMC IDs */
137 if (!imc_test
->count_additional_ids(imc_test
))
142 enumerator
= imc_test
->create_id_enumerator(imc_test
);
143 while (enumerator
->enumerate(enumerator
, &pointer
))
145 /* interpret pointer as scalar value */
146 additional_id
= (TNC_UInt32
)pointer
;
148 state
->set_result(state
, additional_id
,
149 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
151 enumerator
->destroy(enumerator
);
153 return TNC_RESULT_SUCCESS
;
155 case TNC_CONNECTION_STATE_DELETE
:
156 return imc_test
->delete_state(imc_test
, connection_id
);
158 case TNC_CONNECTION_STATE_ACCESS_ISOLATED
:
159 case TNC_CONNECTION_STATE_ACCESS_NONE
:
160 /* get updated IMC state */
161 result
= imc_test
->change_state(imc_test
, connection_id
,
163 if (result
!= TNC_RESULT_SUCCESS
)
165 return TNC_RESULT_FATAL
;
167 test_state
= (imc_test_state_t
*)state
;
169 /* do a handshake retry? */
170 if (test_state
->do_handshake_retry(test_state
))
172 return imc_test
->request_handshake_retry(imc_id
, connection_id
,
173 TNC_RETRY_REASON_IMC_REMEDIATION_COMPLETE
);
175 return TNC_RESULT_SUCCESS
;
178 return imc_test
->change_state(imc_test
, connection_id
,
183 static TNC_Result
send_message(imc_state_t
*state
, imc_msg_t
*out_msg
)
185 imc_test_state_t
*test_state
;
188 test_state
= (imc_test_state_t
*)state
;
189 if (test_state
->get_dummy_size(test_state
))
191 attr
= ita_attr_dummy_create(test_state
->get_dummy_size(test_state
));
192 attr
->set_noskip_flag(attr
, TRUE
);
193 out_msg
->add_attribute(out_msg
, attr
);
195 attr
= ita_attr_command_create(test_state
->get_command(test_state
));
196 attr
->set_noskip_flag(attr
, TRUE
);
197 out_msg
->add_attribute(out_msg
, attr
);
199 /* send PA-TNC message with the excl flag set */
200 return out_msg
->send(out_msg
, TRUE
);
204 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
206 TNC_Result
TNC_IMC_BeginHandshake(TNC_IMCID imc_id
,
207 TNC_ConnectionID connection_id
)
211 enumerator_t
*enumerator
;
213 TNC_UInt32 additional_id
;
218 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
219 return TNC_RESULT_NOT_INITIALIZED
;
221 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
223 return TNC_RESULT_FATAL
;
226 /* send PA message for primary IMC ID */
227 out_msg
= imc_msg_create(imc_test
, state
, connection_id
, imc_id
,
228 TNC_IMVID_ANY
, msg_types
[0]);
229 result
= send_message(state
, out_msg
);
230 out_msg
->destroy(out_msg
);
232 /* Exit if there are no additional IMC IDs */
233 if (!imc_test
->count_additional_ids(imc_test
))
238 /* Do we have support for transporting multiple IMC IDs? */
239 if (!state
->has_long(state
))
241 DBG1(DBG_IMC
, "IMC %u \"%s\" did not detect support for transporting "
242 "multiple IMC IDs", imc_id
, imc_name
);
246 /* send PA messages for additional IMC IDs */
247 enumerator
= imc_test
->create_id_enumerator(imc_test
);
248 while (result
== TNC_RESULT_SUCCESS
&&
249 enumerator
->enumerate(enumerator
, &pointer
))
251 /* interpret pointer as scalar value */
252 additional_id
= (TNC_UInt32
)pointer
;
253 out_msg
= imc_msg_create(imc_test
, state
, connection_id
, additional_id
,
254 TNC_IMVID_ANY
, msg_types
[0]);
255 result
= send_message(state
, out_msg
);
256 out_msg
->destroy(out_msg
);
258 enumerator
->destroy(enumerator
);
263 static TNC_Result
receive_message(imc_state_t
*state
, imc_msg_t
*in_msg
)
266 enumerator_t
*enumerator
;
268 pen_type_t attr_type
;
270 bool fatal_error
= FALSE
;
272 /* parse received PA-TNC message and handle local and remote errors */
273 result
= in_msg
->receive(in_msg
, &fatal_error
);
274 if (result
!= TNC_RESULT_SUCCESS
)
279 /* analyze PA-TNC attributes */
280 enumerator
= in_msg
->create_attribute_enumerator(in_msg
);
281 while (enumerator
->enumerate(enumerator
, &attr
))
283 attr_type
= attr
->get_type(attr
);
285 if (attr_type
.vendor_id
!= PEN_ITA
)
289 if (attr_type
.type
== ITA_ATTR_COMMAND
)
291 ita_attr_command_t
*ita_attr
;
293 ita_attr
= (ita_attr_command_t
*)attr
;
294 DBG1(DBG_IMC
, "received command '%s'",
295 ita_attr
->get_command(ita_attr
));
297 else if (attr_type
.type
== ITA_ATTR_DUMMY
)
299 ita_attr_dummy_t
*ita_attr
;
301 ita_attr
= (ita_attr_dummy_t
*)attr
;
302 DBG1(DBG_IMC
, "received dummy attribute value (%d bytes)",
303 ita_attr
->get_size(ita_attr
));
306 enumerator
->destroy(enumerator
);
310 return TNC_RESULT_FATAL
;
313 /* if no assessment result is known then repeat the measurement */
314 if (state
->get_result(state
, in_msg
->get_dst_id(in_msg
), NULL
))
316 return TNC_RESULT_SUCCESS
;
318 out_msg
= imc_msg_create_as_reply(in_msg
);
319 result
= send_message(state
, out_msg
);
320 out_msg
->destroy(out_msg
);
326 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
328 TNC_Result
TNC_IMC_ReceiveMessage(TNC_IMCID imc_id
,
329 TNC_ConnectionID connection_id
,
330 TNC_BufferReference msg
,
332 TNC_MessageType msg_type
)
340 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
341 return TNC_RESULT_NOT_INITIALIZED
;
343 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
345 return TNC_RESULT_FATAL
;
348 in_msg
= imc_msg_create_from_data(imc_test
, state
, connection_id
, msg_type
,
349 chunk_create(msg
, msg_len
));
350 result
= receive_message(state
, in_msg
);
351 in_msg
->destroy(in_msg
);
357 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
359 TNC_Result
TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id
,
360 TNC_ConnectionID connection_id
,
361 TNC_UInt32 msg_flags
,
362 TNC_BufferReference msg
,
364 TNC_VendorID msg_vid
,
365 TNC_MessageSubtype msg_subtype
,
366 TNC_UInt32 src_imv_id
,
367 TNC_UInt32 dst_imc_id
)
375 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
376 return TNC_RESULT_NOT_INITIALIZED
;
378 if (!imc_test
->get_state(imc_test
, connection_id
, &state
))
380 return TNC_RESULT_FATAL
;
382 in_msg
= imc_msg_create_from_long_data(imc_test
, state
, connection_id
,
383 src_imv_id
, dst_imc_id
, msg_vid
, msg_subtype
,
384 chunk_create(msg
, msg_len
));
385 result
=receive_message(state
, in_msg
);
386 in_msg
->destroy(in_msg
);
392 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
394 TNC_Result
TNC_IMC_BatchEnding(TNC_IMCID imc_id
,
395 TNC_ConnectionID connection_id
)
399 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
400 return TNC_RESULT_NOT_INITIALIZED
;
402 return TNC_RESULT_SUCCESS
;
406 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
408 TNC_Result
TNC_IMC_Terminate(TNC_IMCID imc_id
)
412 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
413 return TNC_RESULT_NOT_INITIALIZED
;
415 imc_test
->destroy(imc_test
);
418 return TNC_RESULT_SUCCESS
;
422 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
424 TNC_Result
TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id
,
425 TNC_TNCC_BindFunctionPointer bind_function
)
429 DBG1(DBG_IMC
, "IMC \"%s\" has not been initialized", imc_name
);
430 return TNC_RESULT_NOT_INITIALIZED
;
432 return imc_test
->bind_functions(imc_test
, bind_function
);