2 * Copyright (C) 2011-2018 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_SWIMA_SUBSCRIPTION_ID_REUSE
,
27 "Version Not Supported",
28 "Attribute Type Not Supported",
30 "SWIMA Subscription Denied",
31 "SWIMA Response Too Large",
32 "SWIMA Subscription Fulfillment Error",
33 "SWIMA Subscription ID Reuse"
36 typedef struct private_ietf_attr_pa_tnc_error_t private_ietf_attr_pa_tnc_error_t
;
39 * PA-TNC Error Attribute Type (see section 4.2.8 of RFC 5792)
42 * 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
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Reserved | PA-TNC Error Code Vendor ID |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | PA-TNC Error Code |
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 * | Error Information (Variable Length) |
49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52 #define PA_ERROR_HEADER_SIZE 8
53 #define PA_ERROR_RESERVED 0x00
56 * All IETF Error Types return the first 8 bytes of the erroneous PA-TNC message
59 * 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
60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 * | Version | Copy of Reserved |
62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 * | Message Identifier |
64 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 #define PA_ERROR_MSG_INFO_SIZE 8
68 #define PA_ERROR_MSG_INFO_MAX_SIZE 1024
71 * "Invalid Parameter" Error Code
73 * 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
74 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80 * "Version Not Supported" Error Code
83 * 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
84 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85 * | Max Version | Min Version | Reserved |
86 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89 #define PA_ERROR_VERSION_RESERVED 0x0000
92 * "Attribute Type Not Supported" Error Code
95 * 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
96 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97 * | Flags | PA-TNC Attribute Vendor ID |
98 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99 * | PA-TNC Attribute Type |
100 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103 #define PA_ERROR_ATTR_INFO_SIZE 8
106 * Private data of an ietf_attr_pa_tnc_error_t object.
108 struct private_ietf_attr_pa_tnc_error_t
{
111 * Public members of ietf_attr_pa_tnc_error_t
113 ietf_attr_pa_tnc_error_t
public;
116 * Vendor-specific attribute type
121 * Length of attribute value
126 * Attribute value or segment
136 * Vendor-specific error code
138 pen_type_t error_code
;
141 * First 8 bytes of erroneous PA-TNC message
146 * Flags of unsupported PA-TNC attribute
151 * Vendor ID and type of unsupported PA-TNC attribute
153 pen_type_t unsupported_type
;
156 * PA-TNC error offset
158 uint32_t error_offset
;
166 METHOD(pa_tnc_attr_t
, get_type
, pen_type_t
,
167 private_ietf_attr_pa_tnc_error_t
*this)
172 METHOD(pa_tnc_attr_t
, get_value
, chunk_t
,
173 private_ietf_attr_pa_tnc_error_t
*this)
178 METHOD(pa_tnc_attr_t
, get_noskip_flag
, bool,
179 private_ietf_attr_pa_tnc_error_t
*this)
181 return this->noskip_flag
;
184 METHOD(pa_tnc_attr_t
, set_noskip_flag
,void,
185 private_ietf_attr_pa_tnc_error_t
*this, bool noskip
)
187 this->noskip_flag
= noskip
;
190 METHOD(pa_tnc_attr_t
, build
, void,
191 private_ietf_attr_pa_tnc_error_t
*this)
193 bio_writer_t
*writer
;
199 writer
= bio_writer_create(PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
);
200 writer
->write_uint8 (writer
, PA_ERROR_RESERVED
);
201 writer
->write_uint24(writer
, this->error_code
.vendor_id
);
202 writer
->write_uint32(writer
, this->error_code
.type
);
203 writer
->write_data (writer
, this->msg_info
);
205 if (this->error_code
.vendor_id
== PEN_IETF
)
207 switch (this->error_code
.type
)
209 case PA_ERROR_INVALID_PARAMETER
:
210 writer
->write_uint32(writer
, this->error_offset
);
212 case PA_ERROR_VERSION_NOT_SUPPORTED
:
213 writer
->write_uint8 (writer
, PA_TNC_VERSION
);
214 writer
->write_uint8 (writer
, PA_TNC_VERSION
);
215 writer
->write_uint16(writer
, PA_ERROR_VERSION_RESERVED
);
217 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
218 writer
->write_uint8 (writer
, this->flags
);
219 writer
->write_uint24(writer
, this->unsupported_type
.vendor_id
);
220 writer
->write_uint32(writer
, this->unsupported_type
.type
);
226 this->value
= writer
->extract_buf(writer
);
227 this->length
= this->value
.len
;
228 writer
->destroy(writer
);
231 METHOD(pa_tnc_attr_t
, process
, status_t
,
232 private_ietf_attr_pa_tnc_error_t
*this, uint32_t *offset
)
234 bio_reader_t
*reader
;
236 uint32_t vendor_id
, type
;
240 if (this->value
.len
< this->length
)
244 if (this->value
.len
< PA_ERROR_HEADER_SIZE
)
246 DBG1(DBG_TNC
, "insufficient data for PA-TNC error header");
249 reader
= bio_reader_create(this->value
);
250 reader
->read_uint8 (reader
, &reserved
);
251 reader
->read_uint24(reader
, &this->error_code
.vendor_id
);
252 reader
->read_uint32(reader
, &this->error_code
.type
);
254 if (this->error_code
.vendor_id
== PEN_IETF
&&
255 this->error_code
.type
<= PA_ERROR_PA_TNC_MSG_ROOF
)
257 if (!reader
->read_data(reader
, PA_ERROR_MSG_INFO_SIZE
, &this->msg_info
))
259 reader
->destroy(reader
);
260 DBG1(DBG_TNC
, "insufficient data for IETF error information");
261 *offset
= PA_ERROR_HEADER_SIZE
;
264 this->msg_info
= chunk_clone(this->msg_info
);
266 switch (this->error_code
.type
)
268 case PA_ERROR_INVALID_PARAMETER
:
269 if (!reader
->read_uint32(reader
, &this->error_offset
))
271 reader
->destroy(reader
);
272 DBG1(DBG_TNC
, "insufficient data for error offset field");
273 *offset
= PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
;
277 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED
:
278 if (reader
->remaining(reader
) < PA_ERROR_ATTR_INFO_SIZE
)
280 reader
->destroy(reader
);
281 DBG1(DBG_TNC
, "insufficient data for unsupported attribute "
283 *offset
= PA_ERROR_HEADER_SIZE
+ PA_ERROR_MSG_INFO_SIZE
;
286 reader
->read_uint8 (reader
, &this->flags
);
287 reader
->read_uint24(reader
, &vendor_id
);
288 reader
->read_uint32(reader
, &type
);
289 this->unsupported_type
= pen_type_create(vendor_id
, type
);
297 reader
->read_data(reader
, reader
->remaining(reader
), &this->msg_info
);
298 this->msg_info
= chunk_clone(this->msg_info
);
300 reader
->destroy(reader
);
305 METHOD(pa_tnc_attr_t
, add_segment
, void,
306 private_ietf_attr_pa_tnc_error_t
*this, chunk_t segment
)
308 this->value
= chunk_cat("mc", this->value
, segment
);
311 METHOD(pa_tnc_attr_t
, get_ref
, pa_tnc_attr_t
*,
312 private_ietf_attr_pa_tnc_error_t
*this)
315 return &this->public.pa_tnc_attribute
;
318 METHOD(pa_tnc_attr_t
, destroy
, void,
319 private_ietf_attr_pa_tnc_error_t
*this)
321 if (ref_put(&this->ref
))
323 free(this->value
.ptr
);
324 free(this->msg_info
.ptr
);
329 METHOD(ietf_attr_pa_tnc_error_t
, get_error_code
, pen_type_t
,
330 private_ietf_attr_pa_tnc_error_t
*this)
332 return this->error_code
;
335 METHOD(ietf_attr_pa_tnc_error_t
, get_msg_info
, chunk_t
,
336 private_ietf_attr_pa_tnc_error_t
*this)
338 return this->msg_info
;
341 METHOD(ietf_attr_pa_tnc_error_t
, get_unsupported_attr
, pen_type_t
,
342 private_ietf_attr_pa_tnc_error_t
*this, uint8_t *flags
)
346 *flags
= this->flags
;
348 return this->unsupported_type
;
351 METHOD(ietf_attr_pa_tnc_error_t
, set_unsupported_attr
, void,
352 private_ietf_attr_pa_tnc_error_t
*this, uint8_t flags
, pen_type_t type
)
355 this->unsupported_type
= type
;
358 METHOD(ietf_attr_pa_tnc_error_t
, get_offset
, uint32_t,
359 private_ietf_attr_pa_tnc_error_t
*this)
361 return this->error_offset
;
365 * Generic constructor
367 static private_ietf_attr_pa_tnc_error_t
* create_generic()
369 private_ietf_attr_pa_tnc_error_t
*this;
373 .pa_tnc_attribute
= {
374 .get_type
= _get_type
,
375 .get_value
= _get_value
,
376 .get_noskip_flag
= _get_noskip_flag
,
377 .set_noskip_flag
= _set_noskip_flag
,
380 .add_segment
= _add_segment
,
384 .get_error_code
= _get_error_code
,
385 .get_msg_info
= _get_msg_info
,
386 .get_unsupported_attr
= _get_unsupported_attr
,
387 .set_unsupported_attr
= _set_unsupported_attr
,
388 .get_offset
= _get_offset
,
390 .type
= { PEN_IETF
, IETF_ATTR_PA_TNC_ERROR
},
398 * Described in header.
400 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create(pen_type_t error_code
,
403 private_ietf_attr_pa_tnc_error_t
*this;
405 if (error_code
.vendor_id
== PEN_IETF
&&
406 error_code
.type
<= PA_ERROR_PA_TNC_MSG_ROOF
)
408 msg_info
.len
= PA_ERROR_MSG_INFO_SIZE
;
410 else if (msg_info
.len
> PA_ERROR_MSG_INFO_MAX_SIZE
)
412 msg_info
.len
= PA_ERROR_MSG_INFO_MAX_SIZE
;
415 this = create_generic();
416 this->error_code
= error_code
;
417 this->msg_info
= chunk_clone(msg_info
);
419 return &this->public.pa_tnc_attribute
;
423 * Described in header.
425 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create_with_offset(pen_type_t error_code
,
427 uint32_t error_offset
)
429 private_ietf_attr_pa_tnc_error_t
*this;
431 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
432 msg_info
.len
= PA_ERROR_MSG_INFO_SIZE
;
434 this = create_generic();
435 this->error_code
= error_code
;
436 this->msg_info
= chunk_clone(msg_info
);
437 this->error_offset
= error_offset
;
439 return &this->public.pa_tnc_attribute
;
443 * Described in header.
445 pa_tnc_attr_t
*ietf_attr_pa_tnc_error_create_from_data(size_t length
,
448 private_ietf_attr_pa_tnc_error_t
*this;
450 this = create_generic();
451 this->length
= length
;
452 this->value
= chunk_clone(data
);
454 return &this->public.pa_tnc_attribute
;