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"
21 #include <tncif_names.h>
24 #include <collections/linked_list.h>
25 #include <utils/debug.h>
27 typedef struct private_imv_msg_t private_imv_msg_t
;
30 * Private data of a imv_msg_t object.
33 struct private_imv_msg_t
{
36 * Public imv_msg_t interface.
43 TNC_ConnectionID connection_id
;
61 * List of PA-TNC attributes to be sent
63 linked_list_t
*attr_list
;
81 METHOD(imv_msg_t
, get_src_id
, TNC_UInt32
,
82 private_imv_msg_t
*this)
87 METHOD(imv_msg_t
, get_dst_id
, TNC_UInt32
,
88 private_imv_msg_t
*this)
93 METHOD(imv_msg_t
, set_msg_type
, void,
94 private_imv_msg_t
*this, pen_type_t msg_type
)
96 if (msg_type
.vendor_id
!= this->msg_type
.vendor_id
||
97 msg_type
.type
!= this->msg_type
.type
)
99 this->msg_type
= msg_type
;
100 this->dst_id
= TNC_IMCID_ANY
;
104 METHOD(imv_msg_t
, add_attribute
, void,
105 private_imv_msg_t
*this, pa_tnc_attr_t
*attr
)
107 this->attr_list
->insert_last(this->attr_list
, attr
);
110 METHOD(imv_msg_t
, send_
, TNC_Result
,
111 private_imv_msg_t
*this, bool excl
)
113 pa_tnc_msg_t
*pa_tnc_msg
;
115 TNC_UInt32 msg_flags
;
116 TNC_MessageType msg_type
;
119 enumerator_t
*enumerator
;
120 TNC_Result result
= TNC_RESULT_SUCCESS
;
122 while (this->attr_list
->get_count(this->attr_list
))
124 pa_tnc_msg
= pa_tnc_msg_create(this->state
->get_max_msg_len(this->state
));
127 enumerator
= this->attr_list
->create_enumerator(this->attr_list
);
128 while (enumerator
->enumerate(enumerator
, &attr
))
130 if (pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
))
142 DBG1(DBG_IMV
, "PA-TNC attribute too large to send, deleted");
146 this->attr_list
->remove_at(this->attr_list
, enumerator
);
148 enumerator
->destroy(enumerator
);
150 /* build and send the PA-TNC message via the IF-IMV interface */
151 if (!pa_tnc_msg
->build(pa_tnc_msg
))
153 pa_tnc_msg
->destroy(pa_tnc_msg
);
154 return TNC_RESULT_FATAL
;
156 msg
= pa_tnc_msg
->get_encoding(pa_tnc_msg
);
157 DBG3(DBG_IMV
, "created PA-TNC message: %B", &msg
);
159 if (this->state
->has_long(this->state
) && this->agent
->send_message_long
)
161 excl
= excl
&& this->state
->has_excl(this->state
) &&
162 this->dst_id
!= TNC_IMCID_ANY
;
163 msg_flags
= excl
? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
164 result
= this->agent
->send_message_long(this->src_id
,
165 this->connection_id
, msg_flags
, msg
.ptr
, msg
.len
,
166 this->msg_type
.vendor_id
, this->msg_type
.type
,
169 else if (this->agent
->send_message
)
171 msg_type
= (this->msg_type
.vendor_id
<< 8) |
172 (this->msg_type
.type
& 0x000000ff);
173 result
= this->agent
->send_message(this->src_id
, this->connection_id
,
174 msg
.ptr
, msg
.len
, msg_type
);
177 pa_tnc_msg
->destroy(pa_tnc_msg
);
179 if (result
!= TNC_RESULT_SUCCESS
)
187 METHOD(imv_msg_t
, send_assessment
, TNC_Result
,
188 private_imv_msg_t
*this)
190 TNC_IMV_Action_Recommendation rec
;
191 TNC_IMV_Evaluation_Result eval
;
194 /* Send an IETF Assessment Result attribute if enabled */
195 if (lib
->settings
->get_bool(lib
->settings
, "libimcv.assessment_result",
198 this->state
->get_recommendation(this->state
, &rec
, &eval
);
199 attr
= ietf_attr_assess_result_create(eval
);
200 add_attribute(this, attr
);
202 /* send PA-TNC message with the excl flag set */
203 return send_(this, TRUE
);
205 return TNC_RESULT_SUCCESS
;
208 METHOD(imv_msg_t
, receive
, TNC_Result
,
209 private_imv_msg_t
*this, bool *fatal_error
)
211 enumerator_t
*enumerator
;
215 if (this->state
->has_long(this->state
))
217 if (this->dst_id
!= TNC_IMVID_ANY
)
219 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
220 "from IMC %u to IMV %u",
221 this->agent
->get_id(this->agent
),
222 this->agent
->get_name(this->agent
),
223 this->connection_id
, this->src_id
, this->dst_id
);
227 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
228 "from IMC %u", this->agent
->get_id(this->agent
),
229 this->agent
->get_name(this->agent
),
230 this->connection_id
, this->src_id
);
235 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
236 this->agent
->get_id(this->agent
),
237 this->agent
->get_name(this->agent
),
238 this->connection_id
);
240 msg
= this->pa_msg
->get_encoding(this->pa_msg
);
241 DBG3(DBG_IMV
, "%B", &msg
);
243 switch (this->pa_msg
->process(this->pa_msg
))
249 imv_msg_t
*error_msg
;
252 error_msg
= imv_msg_create_as_reply(&this->public);
254 /* extract and copy by reference all error attributes */
255 enumerator
= this->pa_msg
->create_error_enumerator(this->pa_msg
);
256 while (enumerator
->enumerate(enumerator
, &attr
))
258 error_msg
->add_attribute(error_msg
, attr
->get_ref(attr
));
260 enumerator
->destroy(enumerator
);
263 * send the PA-TNC message containing all error attributes
264 * with the excl flag set
266 result
= error_msg
->send(error_msg
, TRUE
);
267 error_msg
->destroy(error_msg
);
272 return TNC_RESULT_FATAL
;
275 /* preprocess any received IETF standard error attributes */
276 *fatal_error
= this->pa_msg
->process_ietf_std_errors(this->pa_msg
);
278 return TNC_RESULT_SUCCESS
;
281 METHOD(imv_msg_t
, delete_attributes
, void,
282 private_imv_msg_t
*this)
286 while (this->attr_list
->remove_last(this->attr_list
, (void**)&attr
) == SUCCESS
)
292 METHOD(imv_msg_t
, create_attribute_enumerator
, enumerator_t
*,
293 private_imv_msg_t
*this)
295 return this->pa_msg
->create_attribute_enumerator(this->pa_msg
);
298 METHOD(imv_msg_t
, destroy
, void,
299 private_imv_msg_t
*this)
301 this->attr_list
->destroy_offset(this->attr_list
,
302 offsetof(pa_tnc_attr_t
, destroy
));
303 DESTROY_IF(this->pa_msg
);
310 imv_msg_t
*imv_msg_create(imv_agent_t
*agent
, imv_state_t
*state
,
311 TNC_ConnectionID connection_id
,
312 TNC_UInt32 src_id
, TNC_UInt32 dst_id
,
315 private_imv_msg_t
*this;
319 .get_src_id
= _get_src_id
,
320 .get_dst_id
= _get_dst_id
,
321 .set_msg_type
= _set_msg_type
,
323 .send_assessment
= _send_assessment
,
325 .add_attribute
= _add_attribute
,
326 .create_attribute_enumerator
= _create_attribute_enumerator
,
329 .connection_id
= connection_id
,
332 .msg_type
= msg_type
,
333 .attr_list
= linked_list_create(),
338 return &this->public;
344 imv_msg_t
* imv_msg_create_as_reply(imv_msg_t
*msg
)
346 private_imv_msg_t
*in
;
349 in
= (private_imv_msg_t
*)msg
;
350 src_id
= (in
->dst_id
!= TNC_IMVID_ANY
) ?
351 in
->dst_id
: in
->agent
->get_id(in
->agent
);
353 return imv_msg_create(in
->agent
, in
->state
, in
->connection_id
, src_id
,
354 in
->src_id
, in
->msg_type
);
360 imv_msg_t
*imv_msg_create_from_data(imv_agent_t
*agent
, imv_state_t
*state
,
361 TNC_ConnectionID connection_id
,
362 TNC_MessageType msg_type
,
365 TNC_VendorID msg_vid
;
366 TNC_MessageSubtype msg_subtype
;
368 msg_vid
= msg_type
>> 8;
369 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
371 return imv_msg_create_from_long_data(agent
, state
, connection_id
,
372 TNC_IMCID_ANY
, agent
->get_id(agent
),
373 msg_vid
, msg_subtype
, msg
);
379 imv_msg_t
*imv_msg_create_from_long_data(imv_agent_t
*agent
, imv_state_t
*state
,
380 TNC_ConnectionID connection_id
,
383 TNC_VendorID msg_vid
,
384 TNC_MessageSubtype msg_subtype
,
387 private_imv_msg_t
*this;
391 .get_src_id
= _get_src_id
,
392 .get_dst_id
= _get_dst_id
,
393 .set_msg_type
= _set_msg_type
,
396 .add_attribute
= _add_attribute
,
397 .delete_attributes
= _delete_attributes
,
398 .create_attribute_enumerator
= _create_attribute_enumerator
,
401 .connection_id
= connection_id
,
404 .msg_type
= pen_type_create(msg_vid
, msg_subtype
),
405 .attr_list
= linked_list_create(),
406 .pa_msg
= pa_tnc_msg_create_from_data(msg
),
411 return &this->public;