2 * Copyright (C) 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
18 #include "ietf/ietf_attr.h"
19 #include "ietf/ietf_attr_assess_result.h"
20 #include "ietf/ietf_attr_remediation_instr.h"
22 #include <tncif_names.h>
25 #include <collections/linked_list.h>
26 #include <utils/debug.h>
28 typedef struct private_imv_msg_t private_imv_msg_t
;
31 * Private data of a imv_msg_t object.
34 struct private_imv_msg_t
{
37 * Public imv_msg_t interface.
44 TNC_ConnectionID connection_id
;
62 * List of PA-TNC attributes to be sent
64 linked_list_t
*attr_list
;
82 METHOD(imv_msg_t
, get_src_id
, TNC_UInt32
,
83 private_imv_msg_t
*this)
88 METHOD(imv_msg_t
, get_dst_id
, TNC_UInt32
,
89 private_imv_msg_t
*this)
94 METHOD(imv_msg_t
, set_msg_type
, void,
95 private_imv_msg_t
*this, pen_type_t msg_type
)
97 if (msg_type
.vendor_id
!= this->msg_type
.vendor_id
||
98 msg_type
.type
!= this->msg_type
.type
)
100 this->msg_type
= msg_type
;
101 this->dst_id
= TNC_IMCID_ANY
;
105 METHOD(imv_msg_t
, get_msg_type
, pen_type_t
,
106 private_imv_msg_t
*this)
108 return this->msg_type
;
111 METHOD(imv_msg_t
, add_attribute
, void,
112 private_imv_msg_t
*this, pa_tnc_attr_t
*attr
)
114 this->attr_list
->insert_last(this->attr_list
, attr
);
117 METHOD(imv_msg_t
, send_
, TNC_Result
,
118 private_imv_msg_t
*this, bool excl
)
120 pa_tnc_msg_t
*pa_tnc_msg
;
122 TNC_UInt32 msg_flags
;
123 TNC_MessageType msg_type
;
126 enumerator_t
*enumerator
;
127 TNC_Result result
= TNC_RESULT_SUCCESS
;
129 while (this->attr_list
->get_count(this->attr_list
))
131 pa_tnc_msg
= pa_tnc_msg_create(this->state
->get_max_msg_len(this->state
));
134 enumerator
= this->attr_list
->create_enumerator(this->attr_list
);
135 while (enumerator
->enumerate(enumerator
, &attr
))
137 if (pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
))
149 DBG1(DBG_IMV
, "PA-TNC attribute too large to send, deleted");
153 this->attr_list
->remove_at(this->attr_list
, enumerator
);
155 enumerator
->destroy(enumerator
);
157 /* build and send the PA-TNC message via the IF-IMV interface */
158 if (!pa_tnc_msg
->build(pa_tnc_msg
))
160 pa_tnc_msg
->destroy(pa_tnc_msg
);
161 return TNC_RESULT_FATAL
;
163 msg
= pa_tnc_msg
->get_encoding(pa_tnc_msg
);
164 DBG3(DBG_IMV
, "created PA-TNC message: %B", &msg
);
166 if (this->state
->has_long(this->state
) && this->agent
->send_message_long
)
168 excl
= excl
&& this->state
->has_excl(this->state
) &&
169 this->dst_id
!= TNC_IMCID_ANY
;
170 msg_flags
= excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
171 result
= this->agent
->send_message_long(this->src_id
,
172 this->connection_id
, msg_flags
, msg
.ptr
, msg
.len
,
173 this->msg_type
.vendor_id
, this->msg_type
.type
,
176 else if (this->agent
->send_message
)
178 msg_type
= (this->msg_type
.vendor_id
<< 8) |
179 (this->msg_type
.type
& 0x000000ff);
180 result
= this->agent
->send_message(this->src_id
, this->connection_id
,
181 msg
.ptr
, msg
.len
, msg_type
);
184 pa_tnc_msg
->destroy(pa_tnc_msg
);
186 if (result
!= TNC_RESULT_SUCCESS
)
194 METHOD(imv_msg_t
, send_assessment
, TNC_Result
,
195 private_imv_msg_t
*this)
197 TNC_IMV_Action_Recommendation rec
;
198 TNC_IMV_Evaluation_Result eval
;
200 chunk_t string
= chunk_empty
;
201 char *lang_code
= NULL
, *uri
= NULL
;
204 /* Remove any attributes that have already been constructed */
205 while (this->attr_list
->remove_last(this->attr_list
, (void**)&attr
) == SUCCESS
)
210 /* Send an IETF Assessment Result attribute if enabled */
211 if (lib
->settings
->get_bool(lib
->settings
, "%s.imcv.assessment_result",
214 this->state
->get_recommendation(this->state
, &rec
, &eval
);
215 attr
= ietf_attr_assess_result_create(eval
);
216 add_attribute(this, attr
);
218 /* Send IETF Remediation Instructions if available */
219 if (eval
!= TNC_IMV_EVALUATION_RESULT_COMPLIANT
)
221 e
= this->agent
->create_language_enumerator(this->agent
,
223 if (this->state
->get_remediation_instructions(this->state
,
224 e
, &string
, &lang_code
, &uri
))
226 if (string
.len
&& lang_code
)
228 attr
= ietf_attr_remediation_instr_create_from_string(string
,
229 chunk_create(lang_code
, strlen(lang_code
)));
230 add_attribute(this, attr
);
234 attr
= ietf_attr_remediation_instr_create_from_uri(
235 chunk_create(uri
, strlen(uri
)));
236 add_attribute(this, attr
);
242 /* send PA-TNC message with the excl flag set */
243 return send_(this, TRUE
);
245 return TNC_RESULT_SUCCESS
;
248 METHOD(imv_msg_t
, receive
, TNC_Result
,
249 private_imv_msg_t
*this, bool *fatal_error
)
251 enumerator_t
*enumerator
;
255 if (this->state
->has_long(this->state
))
257 if (this->dst_id
!= TNC_IMVID_ANY
)
259 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
260 "from IMC %u to IMV %u",
261 this->agent
->get_id(this->agent
),
262 this->agent
->get_name(this->agent
),
263 this->connection_id
, this->src_id
, this->dst_id
);
267 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
268 "from IMC %u", this->agent
->get_id(this->agent
),
269 this->agent
->get_name(this->agent
),
270 this->connection_id
, this->src_id
);
275 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
276 this->agent
->get_id(this->agent
),
277 this->agent
->get_name(this->agent
),
278 this->connection_id
);
280 msg
= this->pa_msg
->get_encoding(this->pa_msg
);
281 DBG3(DBG_IMV
, "%B", &msg
);
283 switch (this->pa_msg
->process(this->pa_msg
))
289 imv_msg_t
*error_msg
;
292 error_msg
= imv_msg_create_as_reply(&this->public);
294 /* extract and copy by reference all error attributes */
295 enumerator
= this->pa_msg
->create_error_enumerator(this->pa_msg
);
296 while (enumerator
->enumerate(enumerator
, &attr
))
298 error_msg
->add_attribute(error_msg
, attr
->get_ref(attr
));
300 enumerator
->destroy(enumerator
);
303 * send the PA-TNC message containing all error attributes
304 * with the excl flag set
306 result
= error_msg
->send(error_msg
, TRUE
);
307 error_msg
->destroy(error_msg
);
312 return TNC_RESULT_FATAL
;
315 /* preprocess any received IETF standard error attributes */
316 *fatal_error
= this->pa_msg
->process_ietf_std_errors(this->pa_msg
);
318 return TNC_RESULT_SUCCESS
;
321 METHOD(imv_msg_t
, get_attribute_count
, int,
322 private_imv_msg_t
*this)
324 return this->attr_list
->get_count(this->attr_list
);
327 METHOD(imv_msg_t
, create_attribute_enumerator
, enumerator_t
*,
328 private_imv_msg_t
*this)
330 return this->pa_msg
->create_attribute_enumerator(this->pa_msg
);
333 METHOD(imv_msg_t
, get_encoding
, chunk_t
,
334 private_imv_msg_t
*this)
338 return this->pa_msg
->get_encoding(this->pa_msg
);
343 METHOD(imv_msg_t
, destroy
, void,
344 private_imv_msg_t
*this)
346 this->attr_list
->destroy_offset(this->attr_list
,
347 offsetof(pa_tnc_attr_t
, destroy
));
348 DESTROY_IF(this->pa_msg
);
355 imv_msg_t
*imv_msg_create(imv_agent_t
*agent
, imv_state_t
*state
,
356 TNC_ConnectionID connection_id
,
357 TNC_UInt32 src_id
, TNC_UInt32 dst_id
,
360 private_imv_msg_t
*this;
364 .get_src_id
= _get_src_id
,
365 .get_dst_id
= _get_dst_id
,
366 .set_msg_type
= _set_msg_type
,
367 .get_msg_type
= _get_msg_type
,
369 .send_assessment
= _send_assessment
,
371 .add_attribute
= _add_attribute
,
372 .get_attribute_count
= _get_attribute_count
,
373 .create_attribute_enumerator
= _create_attribute_enumerator
,
374 .get_encoding
= _get_encoding
,
377 .connection_id
= connection_id
,
380 .msg_type
= msg_type
,
381 .attr_list
= linked_list_create(),
386 return &this->public;
392 imv_msg_t
* imv_msg_create_as_reply(imv_msg_t
*msg
)
394 private_imv_msg_t
*in
;
397 in
= (private_imv_msg_t
*)msg
;
398 src_id
= (in
->dst_id
!= TNC_IMVID_ANY
) ?
399 in
->dst_id
: in
->agent
->get_id(in
->agent
);
401 return imv_msg_create(in
->agent
, in
->state
, in
->connection_id
, src_id
,
402 in
->src_id
, in
->msg_type
);
408 imv_msg_t
*imv_msg_create_from_data(imv_agent_t
*agent
, imv_state_t
*state
,
409 TNC_ConnectionID connection_id
,
410 TNC_MessageType msg_type
,
413 TNC_VendorID msg_vid
;
414 TNC_MessageSubtype msg_subtype
;
416 msg_vid
= msg_type
>> 8;
417 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
419 return imv_msg_create_from_long_data(agent
, state
, connection_id
,
420 TNC_IMCID_ANY
, agent
->get_id(agent
),
421 msg_vid
, msg_subtype
, msg
);
427 imv_msg_t
*imv_msg_create_from_long_data(imv_agent_t
*agent
, imv_state_t
*state
,
428 TNC_ConnectionID connection_id
,
431 TNC_VendorID msg_vid
,
432 TNC_MessageSubtype msg_subtype
,
435 private_imv_msg_t
*this;
437 this = (private_imv_msg_t
*)imv_msg_create(agent
, state
,
438 connection_id
, src_id
, dst_id
,
439 pen_type_create(msg_vid
, msg_subtype
));
440 this->pa_msg
= pa_tnc_msg_create_from_data(msg
);
442 return &this->public;