2 * Copyright (C) 2011-2014 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 "ietf_attr_pa_tnc_error.h"
18 #include <pa_tnc/pa_tnc_msg.h>
19 #include <bio/bio_writer.h>
20 #include <bio/bio_reader.h>
21 #include <utils/debug.h>
23 ENUM(pa_tnc_error_code_names
, PA_ERROR_RESERVED
,
24 PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
,
27 "Version Not Supported",
28 "Attribute Type Not Supported"
31 typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t
;
34 * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792)
37 * 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
38 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * | Reserved | PA-TNC Error Code Vendor ID |
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | PA-TNC Error Code |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Error Information (Variable Length) |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 #define PA_ERROR_HEADER_SIZE 8
48 #define PA_ERROR_RESERVED 0x00
51 * All IETF Error Types return the first 8 bytes of the erroneous PA-TNC message
54 * 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
55 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56 * | Version | Copy of Reserved |
57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58 * | Message Identifier |
59 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 #define PA_ERROR_MSG_INFO_SIZE 8
63 #define PA_ERROR_MSG_INFO_MAX_SIZE 1024
66 * "Invalid Parameter" Error Code
68 * 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
69 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
71 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75 * "Version Not Supported" Error Code
78 * 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
79 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80 * | Max Version | Min Version | Reserved |
81 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 #define PA_ERROR_VERSION_RESERVED 0x0000
87 * "Attribute Type Not Supported" Error Code
90 * 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
91 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92 * | Flags | PA-TNC Attribute Vendor ID |
93 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94 * | PA-TNC Attribute Type |
95 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98 #define PA_ERROR_ATTR_INFO_SIZE 8
101 * Private data of an ietf_attr_pa_tnc_error_t object.
103 struct private_ietf_attr_pa_tnc_error_t
{
106 * Public members of ietf_attr_pa_tnc_error_t
108 ietf_attr_pa_tnc_error_t
public;
111 * Vendor-specific attribute type
116 * Length of attribute value
121 * Attribute value or segment
131 * Vendor-specific error code
133 pen_type_t error_code
;
136 * First 8 bytes of erroneous PA-TNC message
141 * Flags of unsupported PA-TNC attribute
146 * Vendor ID and type of unsupported PA-TNC attribute
148 pen_type_t unsupported_type
;
151 * PA-TNC error offset
153 uint32_t error_offset
;
161 METHOD(pa_tnc_attr_t
, get_type
, pen_type_t
,
162 private_ietf_attr_pa_tnc_error_t
*this)
167 METHOD(pa_tnc_attr_t
, get_value
, chunk_t
,
168 private_ietf_attr_pa_tnc_error_t
*this)
173 METHOD(pa_tnc_attr_t
, get_noskip_flag
, bool,
174 private_ietf_attr_pa_tnc_error_t
*this)
176 return this->noskip_flag
;
179 METHOD(pa_tnc_attr_t
, set_noskip_flag
,void,
180 private_ietf_attr_pa_tnc_error_t
*this, bool noskip
)
182 this->noskip_flag
= noskip
;
185 METHOD(pa_tnc_attr_t
, build
, void,
186 private_ietf_attr_pa_tnc_error_t
*this)
188 bio_writer_t
*writer
;
194 writer
= bio_writer_create(PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
);
195 writer
->write_uint8 (writer
, PA_ERROR_RESERVED
);
196 writer
->write_uint24(writer
, this->error_code
.vendor_id
);
197 writer
->write_uint32(writer
, this->error_code
.type
);
198 writer
->write_data (writer
, this->msg_info
);
200 if (this->error_code
.vendor_id
== PEN_IETF
)
202 switch (this->error_code
.type
)
204 case PA_ERROR_INVALID_PARAMETER
:
205 writer
->write_uint32(writer
, this->error_offset
);
207 case PA_ERROR_VERSION_NOT_SUPPORTED
:
208 writer
->write_uint8 (writer
, PA_TNC_VERSION
);
209 writer
->write_uint8 (writer
, PA_TNC_VERSION
);
210 writer
->write_uint16(writer
, PA_ERROR_VERSION_RESERVED
);
212 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
213 writer
->write_uint8 (writer
, this->flags
);
214 writer
->write_uint24(writer
, this->unsupported_type
.vendor_id
);
215 writer
->write_uint32(writer
, this->unsupported_type
.type
);
221 this->value
= writer
->extract_buf(writer
);
222 this->length
= this->value
.len
;
223 writer
->destroy(writer
);
226 METHOD(pa_tnc_attr_t
, process
, status_t
,
227 private_ietf_attr_pa_tnc_error_t
*this, uint32_t *offset
)
229 bio_reader_t
*reader
;
231 uint32_t vendor_id
, type
;
235 if (this->value
.len
< this->length
)
239 if (this->value
.len
< PA_ERROR_HEADER_SIZE
)
241 DBG1(DBG_TNC
, "insufficient data for PA-TNC error header");
244 reader
= bio_reader_create(this->value
);
245 reader
->read_uint8 (reader
, &reserved
);
246 reader
->read_uint24(reader
, &this->error_code
.vendor_id
);
247 reader
->read_uint32(reader
, &this->error_code
.type
);
249 if (this->error_code
.vendor_id
== PEN_IETF
)
251 if (!reader
->read_data(reader
, PA_ERROR_MSG_INFO_SIZE
, &this->msg_info
))
253 reader
->destroy(reader
);
254 DBG1(DBG_TNC
, "insufficient data for IETF error information");
255 *offset
= PA_ERROR_HEADER_SIZE
;
258 this->msg_info
= chunk_clone(this->msg_info
);
260 switch (this->error_code
.type
)
262 case PA_ERROR_INVALID_PARAMETER
:
263 if (!reader
->read_uint32(reader
, &this->error_offset
))
265 reader
->destroy(reader
);
266 DBG1(DBG_TNC
, "insufficient data for error offset field");
267 *offset
= PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
;
271 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
272 if (reader
->remaining(reader
) < PA_ERROR_ATTR_INFO_SIZE
)
274 reader
->destroy(reader
);
275 DBG1(DBG_TNC
, "insufficient data for unsupported attribute "
277 *offset
= PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
;
280 reader
->read_uint8 (reader
, &this->flags
);
281 reader
->read_uint24(reader
, &vendor_id
);
282 reader
->read_uint32(reader
, &type
);
283 this->unsupported_type
= pen_type_create(vendor_id
, type
);
291 reader
->read_data(reader
, reader
->remaining(reader
), &this->msg_info
);
292 this->msg_info
= chunk_clone(this->msg_info
);
294 reader
->destroy(reader
);
299 METHOD(pa_tnc_attr_t
, get_ref
, pa_tnc_attr_t
*,
300 private_ietf_attr_pa_tnc_error_t
*this)
303 return &this->public.pa_tnc_attribute
;
306 METHOD(pa_tnc_attr_t
, destroy
, void,
307 private_ietf_attr_pa_tnc_error_t
*this)
309 if (ref_put(&this->ref
))
311 free(this->value
.ptr
);
312 free(this->msg_info
.ptr
);
317 METHOD(ietf_attr_pa_tnc_error_t
, get_error_code
, pen_type_t
,
318 private_ietf_attr_pa_tnc_error_t
*this)
320 return this->error_code
;
323 METHOD(ietf_attr_pa_tnc_error_t
, get_msg_info
, chunk_t
,
324 private_ietf_attr_pa_tnc_error_t
*this)
326 return this->msg_info
;
329 METHOD(ietf_attr_pa_tnc_error_t
, get_unsupported_attr
, pen_type_t
,
330 private_ietf_attr_pa_tnc_error_t
*this, uint8_t *flags
)
334 *flags
= this->flags
;
336 return this->unsupported_type
;
339 METHOD(ietf_attr_pa_tnc_error_t
, set_unsupported_attr
, void,
340 private_ietf_attr_pa_tnc_error_t
*this, uint8_t flags
, pen_type_t type
)
343 this->unsupported_type
= type
;
346 METHOD(ietf_attr_pa_tnc_error_t
, get_offset
, uint32_t,
347 private_ietf_attr_pa_tnc_error_t
*this)
349 return this->error_offset
;
353 * Generic constructor
355 static private_ietf_attr_pa_tnc_error_t
* create_generic()
357 private_ietf_attr_pa_tnc_error_t
*this;
361 .pa_tnc_attribute
= {
362 .get_type
= _get_type
,
363 .get_value
= _get_value
,
364 .get_noskip_flag
= _get_noskip_flag
,
365 .set_noskip_flag
= _set_noskip_flag
,
371 .get_error_code
= _get_error_code
,
372 .get_msg_info
= _get_msg_info
,
373 .get_unsupported_attr
= _get_unsupported_attr
,
374 .set_unsupported_attr
= _set_unsupported_attr
,
375 .get_offset
= _get_offset
,
377 .type
= { PEN_IETF
, IETF_ATTR_PA_TNC_ERROR
},
385 * Described in header.
387 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create(pen_type_t error_code
,
390 private_ietf_attr_pa_tnc_error_t
*this;
392 if (error_code
.vendor_id
== PEN_IETF
)
394 msg_info
.len
= PA_ERROR_MSG_INFO_SIZE
;
396 else if (msg_info
.len
> PA_ERROR_MSG_INFO_MAX_SIZE
)
398 msg_info
.len
= PA_ERROR_MSG_INFO_MAX_SIZE
;
401 this = create_generic();
402 this->error_code
= error_code
;
403 this->msg_info
= chunk_clone(msg_info
);
405 return &this->public.pa_tnc_attribute
;
409 * Described in header.
411 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create_with_offset(pen_type_t error_code
,
413 uint32_t error_offset
)
415 private_ietf_attr_pa_tnc_error_t
*this;
417 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
418 msg_info
.len
= PA_ERROR_MSG_INFO_SIZE
;
420 this = create_generic();
421 this->error_code
= error_code
;
422 this->msg_info
= chunk_clone(msg_info
);
423 this->error_offset
= error_offset
;
425 return &this->public.pa_tnc_attribute
;
429 * Described in header.
431 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create_from_data(size_t length
,
434 private_ietf_attr_pa_tnc_error_t
*this;
436 this = create_generic();
437 this->length
= length
;
438 this->value
= chunk_clone(data
);
440 return &this->public.pa_tnc_attribute
;