9702f4187c30a66456c8a0093eca0961ee15c93c
[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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * | Reserved | PA-TNC Error Code Vendor ID |
40 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41 * | PA-TNC Error Code |
42 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43 * | Error Information (Variable Length) |
44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 */
46
47 #define PA_ERROR_HEADER_SIZE 8
48 #define PA_ERROR_RESERVED 0x00
49
50 /**
51 * All Error Types return the first 8 bytes of the erroneous PA-TNC message
52 *
53 * 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 */
61
62 #define PA_ERROR_MSG_INFO_SIZE 8
63
64 /**
65 * "Version Not Supported" Error Code
66 *
67 * 1 2 3
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70 * | Max Version | Min Version | Reserved |
71 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72 */
73
74 #define PA_ERROR_VERSION_RESERVED 0x0000
75
76 /**
77 * "Attribute Type Not Supported" Error Code
78 *
79 * 1 2 3
80 * 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
81 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82 * | Flags | PA-TNC Attribute Vendor ID |
83 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84 * | PA-TNC Attribute Type |
85 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86 */
87
88 #define PA_ERROR_ATTR_INFO_SIZE 8
89
90 /**
91 * Private data of an ietf_attr_pa_tnc_error_t object.
92 */
93 struct private_ietf_attr_pa_tnc_error_t {
94
95 /**
96 * Public members of ietf_attr_pa_tnc_error_t
97 */
98 ietf_attr_pa_tnc_error_t public;
99
100 /**
101 * Attribute vendor ID
102 */
103 pen_t vendor_id;
104
105 /**
106 * Attribute type
107 */
108 u_int32_t type;
109
110 /**
111 * Attribute value
112 */
113 chunk_t value;
114
115 /**
116 * Noskip flag
117 */
118 bool noskip_flag;
119
120 /**
121 * Error code vendor ID
122 */
123 pen_t error_vendor_id;
124
125 /**
126 * Error code
127 */
128 u_int32_t error_code;
129
130 /**
131 * First 8 bytes of erroneous PA-TNC message
132 */
133 chunk_t msg_info;
134
135 /**
136 * First 8 bytes of unsupported PA-TNC attribute
137 */
138 chunk_t attr_info;
139
140 /**
141 * Reference count
142 */
143 refcount_t ref;
144 };
145
146 METHOD(pa_tnc_attr_t, get_vendor_id, pen_t,
147 private_ietf_attr_pa_tnc_error_t *this)
148 {
149 return this->vendor_id;
150 }
151
152 METHOD(pa_tnc_attr_t, get_type, u_int32_t,
153 private_ietf_attr_pa_tnc_error_t *this)
154 {
155 return this->type;
156 }
157
158 METHOD(pa_tnc_attr_t, get_value, chunk_t,
159 private_ietf_attr_pa_tnc_error_t *this)
160 {
161 return this->value;
162 }
163
164 METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
165 private_ietf_attr_pa_tnc_error_t *this)
166 {
167 return this->noskip_flag;
168 }
169
170 METHOD(pa_tnc_attr_t, set_noskip_flag,void,
171 private_ietf_attr_pa_tnc_error_t *this, bool noskip)
172 {
173 this->noskip_flag = noskip;
174 }
175
176 METHOD(pa_tnc_attr_t, build, void,
177 private_ietf_attr_pa_tnc_error_t *this)
178 {
179 bio_writer_t *writer;
180
181 writer = bio_writer_create(PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE);
182 writer->write_uint8 (writer, PA_ERROR_RESERVED);
183 writer->write_uint24(writer, this->error_vendor_id);
184 writer->write_uint32(writer, this->error_code);
185 writer->write_data (writer, this->msg_info);
186
187 switch (this->error_code)
188 {
189 case PA_ERROR_INVALID_PARAMETER:
190 break;
191 case PA_ERROR_VERSION_NOT_SUPPORTED:
192 writer->write_uint8 (writer, PA_TNC_VERSION);
193 writer->write_uint8 (writer, PA_TNC_VERSION);
194 writer->write_uint16(writer, PA_ERROR_VERSION_RESERVED);
195 break;
196 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
197 writer->write_data(writer, this->attr_info);
198 break;
199 default:
200 break;
201 }
202
203 this->value = chunk_clone(writer->get_buf(writer));
204 writer->destroy(writer);
205 }
206
207 METHOD(pa_tnc_attr_t, process, status_t,
208 private_ietf_attr_pa_tnc_error_t *this)
209 {
210 bio_reader_t *reader;
211 u_int8_t reserved;
212
213 if (this->value.len < PA_ERROR_HEADER_SIZE + PA_ERROR_MSG_INFO_SIZE)
214 {
215 return FAILED;
216 }
217 reader = bio_reader_create(this->value);
218 reader->read_uint8 (reader, &reserved);
219 reader->read_uint24(reader, &this->error_vendor_id);
220 reader->read_uint32(reader, &this->error_code);
221 reader->read_data (reader, PA_ERROR_MSG_INFO_SIZE, &this->msg_info);
222 this->msg_info = chunk_clone(this->msg_info);
223
224 switch (this->error_code)
225 {
226 case PA_ERROR_ATTR_TYPE_NOT_SUPPORTED:
227 if (!reader->read_data(reader, PA_ERROR_ATTR_INFO_SIZE,
228 &this->attr_info))
229 {
230 reader->destroy(reader);
231 DBG1(DBG_TNC, "insufficient data for unsupported attribute "
232 "information");
233 return FAILED;
234 }
235 this->attr_info = chunk_clone(this->attr_info);
236 break;
237 default:
238 break;
239 }
240 reader->destroy(reader);
241
242 return SUCCESS;
243 }
244
245 METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
246 private_ietf_attr_pa_tnc_error_t *this)
247 {
248 ref_get(&this->ref);
249 return &this->public.pa_tnc_attribute;
250 }
251
252 METHOD(pa_tnc_attr_t, destroy, void,
253 private_ietf_attr_pa_tnc_error_t *this)
254 {
255 if (ref_put(&this->ref))
256 {
257 free(this->value.ptr);
258 free(this->msg_info.ptr);
259 free(this->attr_info.ptr);
260 free(this);
261 }
262 }
263
264 METHOD(ietf_attr_pa_tnc_error_t, get_error_vendor_id, pen_t,
265 private_ietf_attr_pa_tnc_error_t *this)
266 {
267 return this->error_vendor_id;
268 }
269
270 METHOD(ietf_attr_pa_tnc_error_t, get_error_code, u_int32_t,
271 private_ietf_attr_pa_tnc_error_t *this)
272 {
273 return this->error_code;
274 }
275
276 METHOD(ietf_attr_pa_tnc_error_t, get_msg_info, chunk_t,
277 private_ietf_attr_pa_tnc_error_t *this)
278 {
279 return this->msg_info;
280 }
281
282 METHOD(ietf_attr_pa_tnc_error_t, get_attr_info, chunk_t,
283 private_ietf_attr_pa_tnc_error_t *this)
284 {
285 return this->attr_info;
286 }
287
288 METHOD(ietf_attr_pa_tnc_error_t, set_attr_info, void,
289 private_ietf_attr_pa_tnc_error_t *this, chunk_t attr_info)
290 {
291 this->attr_info = chunk_clone(attr_info);
292 }
293
294 /**
295 * Described in header.
296 */
297 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create(pen_t vendor_id,
298 u_int32_t error_code,
299 chunk_t msg_info)
300 {
301 private_ietf_attr_pa_tnc_error_t *this;
302
303 /* the first 8 bytes of the erroneous PA-TNC message are sent back */
304 msg_info.len = PA_ERROR_MSG_INFO_SIZE;
305
306 INIT(this,
307 .public = {
308 .pa_tnc_attribute = {
309 .get_vendor_id = _get_vendor_id,
310 .get_type = _get_type,
311 .get_value = _get_value,
312 .get_noskip_flag = _get_noskip_flag,
313 .set_noskip_flag = _set_noskip_flag,
314 .build = _build,
315 .process = _process,
316 .get_ref = _get_ref,
317 .destroy = _destroy,
318 },
319 .get_vendor_id = _get_error_vendor_id,
320 .get_error_code = _get_error_code,
321 .get_msg_info = _get_msg_info,
322 .get_attr_info = _get_attr_info,
323 .set_attr_info = _set_attr_info,
324 },
325 .vendor_id = PEN_IETF,
326 .type = IETF_ATTR_PA_TNC_ERROR,
327 .error_vendor_id = vendor_id,
328 .error_code = error_code,
329 .msg_info = chunk_clone(msg_info),
330 .ref = 1,
331 );
332
333 return &this->public.pa_tnc_attribute;
334 }
335
336 /**
337 * Described in header.
338 */
339 pa_tnc_attr_t *ietf_attr_pa_tnc_error_create_from_data(chunk_t data)
340 {
341 private_ietf_attr_pa_tnc_error_t *this;
342
343 INIT(this,
344 .public = {
345 .pa_tnc_attribute = {
346 .get_vendor_id = _get_vendor_id,
347 .get_type = _get_type,
348 .get_value = _get_value,
349 .build = _build,
350 .process = _process,
351 .get_ref = _get_ref,
352 .destroy = _destroy,
353 },
354 .get_vendor_id = _get_error_vendor_id,
355 .get_error_code = _get_error_code,
356 .get_msg_info = _get_msg_info,
357 .get_attr_info = _get_attr_info,
358 .set_attr_info = _set_attr_info,
359 },
360 .vendor_id = PEN_IETF,
361 .type = IETF_ATTR_PA_TNC_ERROR,
362 .value = chunk_clone(data),
363 .ref = 1,
364 );
365
366 return &this->public.pa_tnc_attribute;
367 }
368
369