Moved data structures to new collections subfolder
[strongswan.git] / src / libimcv / imc / imc_msg.c
1 /*
2 * Copyright (C) 2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include "imc_msg.h"
17
18 #include "ietf/ietf_attr.h"
19 #include "ietf/ietf_attr_assess_result.h"
20
21 #include <tncif_names.h>
22
23 #include <pen/pen.h>
24 #include <collections/linked_list.h>
25 #include <debug.h>
26
27 typedef struct private_imc_msg_t private_imc_msg_t;
28
29 /**
30 * Private data of a imc_msg_t object.
31 *
32 */
33 struct private_imc_msg_t {
34
35 /**
36 * Public imc_msg_t interface.
37 */
38 imc_msg_t public;
39
40 /**
41 * Connection ID
42 */
43 TNC_ConnectionID connection_id;
44
45 /**
46 * source ID
47 */
48 TNC_UInt32 src_id;
49
50 /**
51 * destination ID
52 */
53 TNC_UInt32 dst_id;
54
55 /**
56 * PA-TNC message type
57 */
58 pen_type_t msg_type;
59
60 /**
61 * List of PA-TNC attributes to be sent
62 */
63 linked_list_t *attr_list;
64
65 /**
66 * PA-TNC message
67 */
68 pa_tnc_msg_t *pa_msg;
69
70 /**
71 * Assigned IMC agent
72 */
73 imc_agent_t *agent;
74
75 /**
76 * Assigned IMC state
77 */
78 imc_state_t *state;
79 };
80
81 METHOD(imc_msg_t, get_src_id, TNC_UInt32,
82 private_imc_msg_t *this)
83 {
84 return this->src_id;
85 }
86
87 METHOD(imc_msg_t, get_dst_id, TNC_UInt32,
88 private_imc_msg_t *this)
89 {
90 return this->dst_id;
91 }
92
93 METHOD(imc_msg_t, send_, TNC_Result,
94 private_imc_msg_t *this, bool excl)
95 {
96 pa_tnc_msg_t *pa_tnc_msg;
97 pa_tnc_attr_t *attr;
98 TNC_UInt32 msg_flags;
99 TNC_MessageType msg_type;
100 bool attr_added;
101 chunk_t msg;
102 enumerator_t *enumerator;
103 TNC_Result result = TNC_RESULT_SUCCESS;
104
105 while (this->attr_list->get_count(this->attr_list))
106 {
107 pa_tnc_msg = pa_tnc_msg_create(this->state->get_max_msg_len(this->state));
108 attr_added = FALSE;
109
110 enumerator = this->attr_list->create_enumerator(this->attr_list);
111 while (enumerator->enumerate(enumerator, &attr))
112 {
113 if (pa_tnc_msg->add_attribute(pa_tnc_msg, attr))
114 {
115 attr_added = TRUE;
116 }
117 else
118 {
119 if (attr_added)
120 {
121 break;
122 }
123 else
124 {
125 DBG1(DBG_IMC, "PA-TNC attribute too large to send, deleted");
126 attr->destroy(attr);
127 }
128 }
129 this->attr_list->remove_at(this->attr_list, enumerator);
130 }
131 enumerator->destroy(enumerator);
132
133 /* build and send the PA-TNC message via the IF-IMC interface */
134 if (!pa_tnc_msg->build(pa_tnc_msg))
135 {
136 pa_tnc_msg->destroy(pa_tnc_msg);
137 return TNC_RESULT_FATAL;
138 }
139 msg = pa_tnc_msg->get_encoding(pa_tnc_msg);
140 DBG3(DBG_IMC, "created PA-TNC message: %B", &msg);
141
142 if (this->state->has_long(this->state) && this->agent->send_message_long)
143 {
144 excl = excl && this->state->has_excl(this->state) &&
145 this->dst_id != TNC_IMVID_ANY;
146 msg_flags = excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE : 0;
147 result = this->agent->send_message_long(this->src_id,
148 this->connection_id, msg_flags, msg.ptr, msg.len,
149 this->msg_type.vendor_id, this->msg_type.type,
150 this->dst_id);
151 }
152 else if (this->agent->send_message)
153 {
154 msg_type = (this->msg_type.vendor_id << 8) |
155 (this->msg_type.type & 0x000000ff);
156 result = this->agent->send_message(this->src_id, this->connection_id,
157 msg.ptr, msg.len, msg_type);
158 }
159
160 pa_tnc_msg->destroy(pa_tnc_msg);
161
162 if (result != TNC_RESULT_SUCCESS)
163 {
164 break;
165 }
166 }
167 return result;
168 }
169
170 METHOD(imc_msg_t, receive, TNC_Result,
171 private_imc_msg_t *this, bool *fatal_error)
172 {
173 enumerator_t *enumerator;
174 pa_tnc_attr_t *attr;
175 pen_type_t attr_type;
176 chunk_t msg;
177
178 if (this->state->has_long(this->state))
179 {
180 if (this->dst_id != TNC_IMCID_ANY)
181 {
182 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
183 "from IMV %u to IMC %u",
184 this->agent->get_id(this->agent),
185 this->agent->get_name(this->agent),
186 this->connection_id, this->src_id, this->dst_id);
187 }
188 else
189 {
190 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u "
191 "from IMV %u", this->agent->get_id(this->agent),
192 this->agent->get_name(this->agent),
193 this->connection_id, this->src_id);
194 }
195 }
196 else
197 {
198 DBG2(DBG_IMC, "IMC %u \"%s\" received message for Connection ID %u",
199 this->agent->get_id(this->agent),
200 this->agent->get_name(this->agent),
201 this->connection_id);
202 }
203 msg = this->pa_msg->get_encoding(this->pa_msg);
204 DBG3(DBG_IMC, "%B", &msg);
205
206 switch (this->pa_msg->process(this->pa_msg))
207 {
208 case SUCCESS:
209 break;
210 case VERIFY_ERROR:
211 {
212 imc_msg_t *error_msg;
213 TNC_Result result;
214
215 error_msg = imc_msg_create_as_reply(&this->public);
216
217 /* extract and copy by reference all error attributes */
218 enumerator = this->pa_msg->create_error_enumerator(this->pa_msg);
219 while (enumerator->enumerate(enumerator, &attr))
220 {
221 error_msg->add_attribute(error_msg, attr->get_ref(attr));
222 }
223 enumerator->destroy(enumerator);
224
225 /*
226 * send the PA-TNC message containing all error attributes
227 * with the excl flag set
228 */
229 result = error_msg->send(error_msg, TRUE);
230 error_msg->destroy(error_msg);
231 return result;
232 }
233 case FAILED:
234 default:
235 return TNC_RESULT_FATAL;
236 }
237
238 /* preprocess any received IETF standard error attributes */
239 *fatal_error = this->pa_msg->process_ietf_std_errors(this->pa_msg);
240
241 /* preprocess any received IETF assessment result attribute */
242 enumerator = this->pa_msg->create_attribute_enumerator(this->pa_msg);
243 while (enumerator->enumerate(enumerator, &attr))
244 {
245 attr_type = attr->get_type(attr);
246
247 if (attr_type.vendor_id == PEN_IETF &&
248 attr_type.type == IETF_ATTR_ASSESSMENT_RESULT)
249 {
250 ietf_attr_assess_result_t *attr_cast;
251 TNC_UInt32 target_imc_id;
252 TNC_IMV_Evaluation_Result result;
253
254 attr_cast = (ietf_attr_assess_result_t*)attr;
255 result = attr_cast->get_result(attr_cast);
256 target_imc_id = (this->dst_id != TNC_IMCID_ANY) ?
257 this->dst_id : this->agent->get_id(this->agent);
258 this->state->set_result(this->state, target_imc_id, result);
259
260 DBG1(DBG_IMC, "set assessment result for IMC %u to '%N'",
261 target_imc_id, TNC_IMV_Evaluation_Result_names, result);
262 }
263 }
264 enumerator->destroy(enumerator);
265
266 return TNC_RESULT_SUCCESS;
267 }
268
269 METHOD(imc_msg_t, add_attribute, void,
270 private_imc_msg_t *this, pa_tnc_attr_t *attr)
271 {
272 this->attr_list->insert_last(this->attr_list, attr);
273 }
274
275 METHOD(imc_msg_t, create_attribute_enumerator, enumerator_t*,
276 private_imc_msg_t *this)
277 {
278 return this->pa_msg->create_attribute_enumerator(this->pa_msg);
279 }
280
281 METHOD(imc_msg_t, destroy, void,
282 private_imc_msg_t *this)
283 {
284 this->attr_list->destroy_offset(this->attr_list,
285 offsetof(pa_tnc_attr_t, destroy));
286 DESTROY_IF(this->pa_msg);
287 free(this);
288 }
289
290 /**
291 * See header
292 */
293 imc_msg_t *imc_msg_create(imc_agent_t *agent, imc_state_t *state,
294 TNC_ConnectionID connection_id,
295 TNC_UInt32 src_id, TNC_UInt32 dst_id,
296 pen_type_t msg_type)
297 {
298 private_imc_msg_t *this;
299
300 INIT(this,
301 .public = {
302 .get_src_id = _get_src_id,
303 .get_dst_id = _get_dst_id,
304 .send = _send_,
305 .receive = _receive,
306 .add_attribute = _add_attribute,
307 .create_attribute_enumerator = _create_attribute_enumerator,
308 .destroy = _destroy,
309 },
310 .connection_id = connection_id,
311 .src_id = src_id,
312 .dst_id = dst_id,
313 .msg_type = msg_type,
314 .attr_list = linked_list_create(),
315 .agent = agent,
316 .state = state,
317 );
318
319 return &this->public;
320 }
321
322 /**
323 * See header
324 */
325 imc_msg_t* imc_msg_create_as_reply(imc_msg_t *msg)
326 {
327 private_imc_msg_t *in;
328 TNC_UInt32 src_id;
329
330 in = (private_imc_msg_t*)msg;
331 src_id = (in->dst_id != TNC_IMCID_ANY) ?
332 in->dst_id : in->agent->get_id(in->agent);
333
334 return imc_msg_create(in->agent, in->state, in->connection_id, src_id,
335 in->src_id, in->msg_type);
336 }
337
338 /**
339 * See header
340 */
341 imc_msg_t *imc_msg_create_from_data(imc_agent_t *agent, imc_state_t *state,
342 TNC_ConnectionID connection_id,
343 TNC_MessageType msg_type,
344 chunk_t msg)
345 {
346 TNC_VendorID msg_vid;
347 TNC_MessageSubtype msg_subtype;
348
349 msg_vid = msg_type >> 8;
350 msg_subtype = msg_type & TNC_SUBTYPE_ANY;
351
352 return imc_msg_create_from_long_data(agent, state, connection_id,
353 TNC_IMVID_ANY, agent->get_id(agent),
354 msg_vid, msg_subtype, msg);
355 }
356
357 /**
358 * See header
359 */
360 imc_msg_t *imc_msg_create_from_long_data(imc_agent_t *agent, imc_state_t *state,
361 TNC_ConnectionID connection_id,
362 TNC_UInt32 src_id,
363 TNC_UInt32 dst_id,
364 TNC_VendorID msg_vid,
365 TNC_MessageSubtype msg_subtype,
366 chunk_t msg)
367 {
368 private_imc_msg_t *this;
369
370 INIT(this,
371 .public = {
372 .get_src_id = _get_src_id,
373 .get_dst_id = _get_dst_id,
374 .send = _send_,
375 .receive = _receive,
376 .add_attribute = _add_attribute,
377 .create_attribute_enumerator = _create_attribute_enumerator,
378 .destroy = _destroy,
379 },
380 .connection_id = connection_id,
381 .src_id = src_id,
382 .dst_id = dst_id,
383 .msg_type = pen_type_create(msg_vid, msg_subtype),
384 .attr_list = linked_list_create(),
385 .pa_msg = pa_tnc_msg_create_from_data(msg),
386 .agent = agent,
387 .state = state,
388 );
389
390 return &this->public;
391 }
392