read PDP server name from strongswan.conf
[strongswan.git] / src / libimcv / ietf / ietf_attr_pa_tnc_error.c
1 /*
2 * Copyright (C) 2011 Andreas Steffen, HSR Hochschule fuer Technik Rapperswil
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 */
14
15 #include "ietf_attr_pa_tnc_error.h"
16
17 #include <pa_tnc/pa_tnc_msg.h>
18 #include <bio/bio_writer.h>
19 #include <bio/bio_reader.h>
20 #include <debug.h>
21
22 ENUM(pa_tnc_error_code_names, PA_ERROR_RESERVED,
23 PA_ERROR_ATTR_TYPE_NOT_SUPPORTED,
24 "Reserved",
25 "Invalid Parameter",
26 "Version Not Supported",
27 "Attribute Type Not Supported"
28 );
29
30 typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t;
31
32 /**
33 * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792)
34 *
35 * 1 2 3
36 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
37 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 * | Reserved | PA-TNC Error Code Vendor ID |
39 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 * | PA-TNC Error Code |
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Error Information (Variable Length) |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 */
45
46 #define PA_ERROR_HEADER_SIZE 8
47 #define PA_ERROR_RESERVED 0x00
48
49 /**
50 * All IETF Error Types return the first 8 bytes of the erroneous PA-TNC message
51 *
52 * 1 2 3
53 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * | Version | Copy of Reserved |
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57 * | Message Identifier |
58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 */
60
61 #define PA_ERROR_MSG_INFO_SIZE 8
62 #define PA_ERROR_MSG_INFO_MAX_SIZE 1024
63
64 /**
65 * "Invalid Parameter" Error Code
66 * 1 2 3
67 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
68 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 * | Offset |
70 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 */
72
73 /**
74 * "Version Not Supported" Error Code
75 *
76 * 1 2 3
77 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
78 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79 * | Max Version | Min Version | Reserved |
80 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81 */
82
83 #define PA_ERROR_VERSION_RESERVED 0x0000
84
85 /**
86 * "Attribute Type Not Supported" Error Code
87 *
88 * 1 2 3
89 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
90 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91 * | Flags | PA-TNC Attribute Vendor ID |
92 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93 * | PA-TNC Attribute Type |
94 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95 */
96
97 #define PA_ERROR_ATTR_INFO_SIZE 8
98
99 /**
100 * Private data of an ietf_attr_pa_tnc_error_t object.
101 */
102 struct private_ietf_attr_pa_tnc_error_t {
103
104 /**
105 * Public members of ietf_attr_pa_tnc_error_t
106 */
107 ietf_attr_pa_tnc_error_t public;
108
109 /**
110 * Attribute vendor ID
111 */
112 pen_t vendor_id;
113
114 /**
115 * Attribute type
116 */
117 u_int32_t type;
118
119 /**
120 * Attribute value
121 */
122 chunk_t value;
123
124 /**
125 * Noskip flag
126 */
127 bool noskip_flag;
128
129 /**
130 * Error code vendor ID
131 */
132 pen_t error_vendor_id;
133
134 /**
135 * Error code
136 */
137 u_int32_t error_code;
138
139 /**
140 * First 8 bytes of erroneous PA-TNC message
141 */
142 chunk_t msg_info;
143
144 /**
145 * First 8 bytes of unsupported PA-TNC attribute
146 */
147 chunk_t attr_info;
148
149 /**
150 * PA-TNC error offset
151 */
152 u_int32_t error_offset;
153
154 /**
155 * Reference count
156 */
157 refcount_t ref;
158 };
159
160 METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
161 private_ietf_attr_pa_tnc_error_t *this)
162 {
163 return this->vendor_id;
164 }
165
166 METHOD(pa_tnc_attr_t, get_type, u_int32_t,
167 private_ietf_attr_pa_tnc_error_t *this)
168 {
169 return this->type;
170 }
171
172 METHOD(pa_tnc_attr_t, get_value, chunk_t,
173 private_ietf_attr_pa_tnc_error_t *this)
174 {
175 return this->value;
176 }
177
178 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
179 private_ietf_attr_pa_tnc_error_t *this)
180 {
181 return this->noskip_flag;
182 }
183
184 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
185 private_ietf_attr_pa_tnc_error_t *this, bool noskip)
186 {
187 this->noskip_flag = noskip;
188 }
189
190 METHOD(pa_tnc_attr_t, build, void,
191 private_ietf_attr_pa_tnc_error_t *this)
192 {
193 bio_writer_t *writer;
194
195 writer = bio_writer_create(PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE);
196 writer->write_uint8 (writer, PA_ERROR_RESERVED);
197 writer->write_uint24(writer, this->error_vendor_id);
198 writer->write_uint32(writer, this->error_code);
199 writer->write_data (writer, this->msg_info);
200
201 if (this->error_vendor_id == PEN_IETF)
202 {
203 switch (this->error_code)
204 {
205 case PA_ERROR_INVALID_PARAMETER:
206 writer->write_uint32(writer, this->error_offset);
207 break;
208 case PA_ERROR_VERSION_NOT_SUPPORTED:
209 writer->write_uint8 (writer, PA_TNC_VERSION);
210 writer->write_uint8 (writer, PA_TNC_VERSION);
211 writer->write_uint16(writer, PA_ERROR_VERSION_RESERVED);
212 break;
213 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
214 writer->write_data(writer, this->attr_info);
215 break;
216 default:
217 break;
218 }
219 }
220 this->value = chunk_clone(writer->get_buf(writer));
221 writer->destroy(writer);
222 }
223
224 METHOD(pa_tnc_attr_t, process, status_t,
225 private_ietf_attr_pa_tnc_error_t *this, u_int32_t *offset)
226 {
227 bio_reader_t *reader;
228 u_int8_t reserved;
229
230 if (this->value.len < PA_ERROR_HEADER_SIZE)
231 {
232 DBG1(DBG_TNC, "insufficient data for PA-TNC error header");
233 *offset = 0;
234 return FAILED;
235 }
236 reader = bio_reader_create(this->value);
237 reader->read_uint8 (reader, &reserved);
238 reader->read_uint24(reader, &this->error_vendor_id);
239 reader->read_uint32(reader, &this->error_code);
240
241 if (this->error_vendor_id == PEN_IETF)
242 {
243 if (!reader->read_data(reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info))
244 {
245 reader->destroy(reader);
246 DBG1(DBG_TNC, "insufficient data for IETF error information");
247 *offset = PA_ERROR_HEADER_SIZE;
248 return FAILED;
249 }
250 this->msg_info = chunk_clone(this->msg_info);
251
252 switch (this->error_code)
253 {
254 case PA_ERROR_INVALID_PARAMETER:
255 if (!reader->read_uint32(reader, &this->error_offset))
256 {
257 reader->destroy(reader);
258 DBG1(DBG_TNC, "insufficient data for error offset field");
259 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
260 return FAILED;
261 }
262 break;
263 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
264 if (!reader->read_data(reader, PA_ERROR_ATTR_INFO_SIZE,
265 &this->attr_info))
266 {
267 reader->destroy(reader);
268 DBG1(DBG_TNC, "insufficient data for unsupported attribute "
269 "information");
270 *offset = PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE;
271 return FAILED;
272 }
273 this->attr_info = chunk_clone(this->attr_info);
274 break;
275 default:
276 break;
277 }
278 }
279 else
280 {
281 reader->read_data(reader, reader->remaining(reader), &this->msg_info);
282 this->msg_info = chunk_clone(this->msg_info);
283 }
284 reader->destroy(reader);
285
286 return SUCCESS;
287 }
288
289 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
290 private_ietf_attr_pa_tnc_error_t *this)
291 {
292 ref_get(&this->ref);
293 return &this->public.pa_tnc_attribute;
294 }
295
296 METHOD(pa_tnc_attr_t, destroy, void,
297 private_ietf_attr_pa_tnc_error_t *this)
298 {
299 if (ref_put(&this->ref))
300 {
301 free(this->value.ptr);
302 free(this->msg_info.ptr);
303 free(this->attr_info.ptr);
304 free(this);
305 }
306 }
307
308 METHOD(ietf_attr_pa_tnc_error_t, get_error_vendor_id, pen_t,
309 private_ietf_attr_pa_tnc_error_t *this)
310 {
311 return this->error_vendor_id;
312 }
313
314 METHOD(ietf_attr_pa_tnc_error_t, get_error_code, u_int32_t,
315 private_ietf_attr_pa_tnc_error_t *this)
316 {
317 return this->error_code;
318 }
319
320 METHOD(ietf_attr_pa_tnc_error_t, get_msg_info, chunk_t,
321 private_ietf_attr_pa_tnc_error_t *this)
322 {
323 return this->msg_info;
324 }
325
326 METHOD(ietf_attr_pa_tnc_error_t, get_attr_info, chunk_t,
327 private_ietf_attr_pa_tnc_error_t *this)
328 {
329 return this->attr_info;
330 }
331
332 METHOD(ietf_attr_pa_tnc_error_t, set_attr_info, void,
333 private_ietf_attr_pa_tnc_error_t *this, chunk_t attr_info)
334 {
335 this->attr_info = chunk_clone(attr_info);
336 }
337
338 METHOD(ietf_attr_pa_tnc_error_t, get_offset, u_int32_t,
339 private_ietf_attr_pa_tnc_error_t *this)
340 {
341 return this->error_offset;
342 }
343
344 /**
345 * Described in header.
346 */
347 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id,
348 u_int32_t error_code,
349 chunk_t msg_info)
350 {
351 private_ietf_attr_pa_tnc_error_t *this;
352
353 if (vendor_id == PEN_IETF)
354 {
355 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
356 }
357 else if (msg_info.len > PA_ERROR_MSG_INFO_MAX_SIZE)
358 {
359 msg_info.len = PA_ERROR_MSG_INFO_MAX_SIZE;
360 }
361
362 INIT(this,
363 .public = {
364 .pa_tnc_attribute = {
365 .get_vendor_id = _get_vendor_id,
366 .get_type = _get_type,
367 .get_value = _get_value,
368 .get_noskip_flag = _get_noskip_flag,
369 .set_noskip_flag = _set_noskip_flag,
370 .build = _build,
371 .process = _process,
372 .get_ref = _get_ref,
373 .destroy = _destroy,
374 },
375 .get_vendor_id = _get_error_vendor_id,
376 .get_error_code = _get_error_code,
377 .get_msg_info = _get_msg_info,
378 .get_attr_info = _get_attr_info,
379 .set_attr_info = _set_attr_info,
380 .get_offset = _get_offset,
381 },
382 .vendor_id = PEN_IETF,
383 .type = IETF_ATTR_PA_TNC_ERROR,
384 .error_vendor_id = vendor_id,
385 .error_code = error_code,
386 .msg_info = chunk_clone(msg_info),
387 .ref = 1,
388 );
389
390 return &this->public.pa_tnc_attribute;
391 }
392
393 /**
394 * Described in header.
395 */
396 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_with_offset(pen_t vendor_id,
397 u_int32_t error_code,
398 chunk_t msg_info,
399 u_int32_t error_offset)
400 {
401 private_ietf_attr_pa_tnc_error_t *this;
402
403 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
404 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
405
406 INIT(this,
407 .public = {
408 .pa_tnc_attribute = {
409 .get_vendor_id = _get_vendor_id,
410 .get_type = _get_type,
411 .get_value = _get_value,
412 .get_noskip_flag = _get_noskip_flag,
413 .set_noskip_flag = _set_noskip_flag,
414 .build = _build,
415 .process = _process,
416 .get_ref = _get_ref,
417 .destroy = _destroy,
418 },
419 .get_vendor_id = _get_error_vendor_id,
420 .get_error_code = _get_error_code,
421 .get_msg_info = _get_msg_info,
422 .get_attr_info = _get_attr_info,
423 .set_attr_info = _set_attr_info,
424 .get_offset = _get_offset,
425 },
426 .vendor_id = PEN_IETF,
427 .type = IETF_ATTR_PA_TNC_ERROR,
428 .error_vendor_id = vendor_id,
429 .error_code = error_code,
430 .msg_info = chunk_clone(msg_info),
431 .error_offset = error_offset,
432 .ref = 1,
433 );
434
435 return &this->public.pa_tnc_attribute;
436 }
437
438 /**
439 * Described in header.
440 */
441 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data)
442 {
443 private_ietf_attr_pa_tnc_error_t *this;
444
445 INIT(this,
446 .public = {
447 .pa_tnc_attribute = {
448 .get_vendor_id = _get_vendor_id,
449 .get_type = _get_type,
450 .get_value = _get_value,
451 .build = _build,
452 .process = _process,
453 .get_ref = _get_ref,
454 .destroy = _destroy,
455 },
456 .get_vendor_id = _get_error_vendor_id,
457 .get_error_code = _get_error_code,
458 .get_msg_info = _get_msg_info,
459 .get_attr_info = _get_attr_info,
460 .set_attr_info = _set_attr_info,
461 .get_offset = _get_offset,
462 },
463 .vendor_id = PEN_IETF,
464 .type = IETF_ATTR_PA_TNC_ERROR,
465 .value = chunk_clone(data),
466 .ref = 1,
467 );
468
469 return &this->public.pa_tnc_attribute;
470 }
471
472