]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/plugins/tnccs_20/messages/pb_error_msg.c
rapid PT-TLS AR/PDP prototype
[thirdparty/strongswan.git] / src / libcharon / plugins / tnccs_20 / messages / pb_error_msg.c
1 /*
2 * Copyright (C) 2010 Sansar Choinyambuu
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 "pb_error_msg.h"
17
18 #include <tnc/tnccs/tnccs.h>
19
20 #include <bio/bio_writer.h>
21 #include <bio/bio_reader.h>
22 #include <pen/pen.h>
23 #include <utils/debug.h>
24
25 ENUM(pb_tnc_error_code_names, PB_ERROR_UNEXPECTED_BATCH_TYPE,
26 PB_ERROR_VERSION_NOT_SUPPORTED,
27 "Unexpected Batch Type",
28 "Invalid Parameter",
29 "Local Error",
30 "Unsupported Mandatory Message",
31 "Version Not Supported"
32 );
33
34 typedef struct private_pb_error_msg_t private_pb_error_msg_t;
35
36 /**
37 * PB-Error message (see section 4.9 of RFC 5793)
38 *
39 * 0 1 2 3
40 * 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
41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 * | Flags | Error Code Vendor ID |
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Error Code | Reserved |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | Error Parameters (Variable Length) |
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 */
49
50 #define ERROR_FLAG_NONE 0x00
51 #define ERROR_FLAG_FATAL (1<<7)
52 #define ERROR_RESERVED 0x0000
53 #define ERROR_HEADER_SIZE 8
54
55 /**
56 * Private data of a pb_error_msg_t object.
57 *
58 */
59 struct private_pb_error_msg_t {
60 /**
61 * Public pb_error_msg_t interface.
62 */
63 pb_error_msg_t public;
64
65 /**
66 * PB-TNC message type
67 */
68 pb_tnc_msg_type_t type;
69
70 /**
71 * Fatal flag
72 */
73 bool fatal;
74
75 /**
76 * PB Error Code Vendor ID
77 */
78 u_int32_t vendor_id;
79
80 /**
81 * PB Error Code
82 */
83 u_int16_t error_code;
84
85 /**
86 * PB Error Offset
87 */
88 u_int32_t error_offset;
89
90 /**
91 * Bad PB-TNC version received
92 */
93 u_int8_t bad_version;
94
95 /**
96 * Encoded message
97 */
98 chunk_t encoding;
99
100 /**
101 * reference count
102 */
103 refcount_t ref;
104 };
105
106 METHOD(pb_tnc_msg_t, get_type, pb_tnc_msg_type_t,
107 private_pb_error_msg_t *this)
108 {
109 return this->type;
110 }
111
112 METHOD(pb_tnc_msg_t, get_encoding, chunk_t,
113 private_pb_error_msg_t *this)
114 {
115 return this->encoding;
116 }
117
118 METHOD(pb_tnc_msg_t, build, void,
119 private_pb_error_msg_t *this)
120 {
121 bio_writer_t *writer;
122
123 if (this->encoding.ptr)
124 {
125 return;
126 }
127
128 /* build message header */
129 writer = bio_writer_create(ERROR_HEADER_SIZE);
130 writer->write_uint8 (writer, this->fatal ?
131 ERROR_FLAG_FATAL : ERROR_FLAG_NONE);
132 writer->write_uint24(writer, this->vendor_id);
133 writer->write_uint16(writer, this->error_code);
134 writer->write_uint16(writer, ERROR_RESERVED);
135
136 /* build message body */
137 if (this->error_code == PB_ERROR_VERSION_NOT_SUPPORTED)
138 {
139 /* Bad version */
140 writer->write_uint8(writer, this->bad_version);
141 writer->write_uint8(writer, PB_TNC_VERSION); /* Max version */
142 writer->write_uint8(writer, PB_TNC_VERSION); /* Min version */
143 writer->write_uint8(writer, 0x00); /* Reserved */
144 }
145 else
146 {
147 /* Error Offset */
148 writer->write_uint32(writer, this->error_offset);
149 }
150 this->encoding = writer->get_buf(writer);
151 this->encoding = chunk_clone(this->encoding);
152 writer->destroy(writer);
153 }
154
155 METHOD(pb_tnc_msg_t, process, status_t,
156 private_pb_error_msg_t *this, u_int32_t *offset)
157 {
158 u_int8_t flags, max_version, min_version;
159 u_int16_t reserved;
160 bio_reader_t *reader;
161
162 if (this->encoding.len < ERROR_HEADER_SIZE)
163 {
164 DBG1(DBG_TNC,"%N message is shorter than header size of %u bytes",
165 pb_tnc_msg_type_names, PB_MSG_ERROR, ERROR_HEADER_SIZE);
166 *offset = 0;
167 return FAILED;
168 }
169
170 /* process message header */
171 reader = bio_reader_create(this->encoding);
172 reader->read_uint8 (reader, &flags);
173 reader->read_uint24(reader, &this->vendor_id);
174 reader->read_uint16(reader, &this->error_code);
175 reader->read_uint16(reader, &reserved);
176 this->fatal = (flags & ERROR_FLAG_FATAL) != ERROR_FLAG_NONE;
177
178 if (this->vendor_id == PEN_IETF && reader->remaining(reader) == 4)
179 {
180 if (this->error_code == PB_ERROR_VERSION_NOT_SUPPORTED)
181 {
182 reader->read_uint8(reader, &this->bad_version);
183 reader->read_uint8(reader, &max_version);
184 reader->read_uint8(reader, &min_version);
185 }
186 else
187 {
188 reader->read_uint32(reader, &this->error_offset);
189 }
190 }
191 reader->destroy(reader);
192
193 return SUCCESS;
194 }
195
196 METHOD(pb_tnc_msg_t, get_ref, pb_tnc_msg_t*,
197 private_pb_error_msg_t *this)
198 {
199 ref_get(&this->ref);
200 return &this->public.pb_interface;
201 }
202
203 METHOD(pb_tnc_msg_t, destroy, void,
204 private_pb_error_msg_t *this)
205 {
206 if (ref_put(&this->ref))
207 {
208 free(this->encoding.ptr);
209 free(this);
210 }
211 }
212
213 METHOD(pb_error_msg_t, get_fatal_flag, bool,
214 private_pb_error_msg_t *this)
215 {
216 return this->fatal;
217 }
218
219 METHOD(pb_error_msg_t, get_vendor_id, u_int32_t,
220 private_pb_error_msg_t *this)
221 {
222 return this->vendor_id;
223 }
224
225 METHOD(pb_error_msg_t, get_error_code, u_int16_t,
226 private_pb_error_msg_t *this)
227 {
228 return this->error_code;
229 }
230
231 METHOD(pb_error_msg_t, get_offset, u_int32_t,
232 private_pb_error_msg_t *this)
233 {
234 return this->error_offset;
235 }
236
237 METHOD(pb_error_msg_t, get_bad_version, u_int8_t,
238 private_pb_error_msg_t *this)
239 {
240 return this->bad_version;
241 }
242
243 METHOD(pb_error_msg_t, set_bad_version, void,
244 private_pb_error_msg_t *this, u_int8_t version)
245 {
246 this->bad_version = version;
247 }
248
249 /**
250 * See header
251 */
252 pb_tnc_msg_t* pb_error_msg_create(bool fatal, u_int32_t vendor_id,
253 pb_tnc_error_code_t error_code)
254 {
255 private_pb_error_msg_t *this;
256
257 INIT(this,
258 .public = {
259 .pb_interface = {
260 .get_type = _get_type,
261 .get_encoding = _get_encoding,
262 .build = _build,
263 .process = _process,
264 .get_ref = _get_ref,
265 .destroy = _destroy,
266 },
267 .get_fatal_flag = _get_fatal_flag,
268 .get_vendor_id = _get_vendor_id,
269 .get_error_code = _get_error_code,
270 .get_offset = _get_offset,
271 .get_bad_version = _get_bad_version,
272 .set_bad_version = _set_bad_version,
273 },
274 .type = PB_MSG_ERROR,
275 .ref = 1,
276 .fatal = fatal,
277 .vendor_id = vendor_id,
278 .error_code = error_code,
279 );
280
281 return &this->public.pb_interface;
282 }
283
284 /**
285 * See header
286 */
287 pb_tnc_msg_t* pb_error_msg_create_with_offset(bool fatal, u_int32_t vendor_id,
288 pb_tnc_error_code_t error_code,
289 u_int32_t error_offset)
290 {
291 private_pb_error_msg_t *this;
292
293 INIT(this,
294 .public = {
295 .pb_interface = {
296 .get_type = _get_type,
297 .get_encoding = _get_encoding,
298 .build = _build,
299 .process = _process,
300 .get_ref = _get_ref,
301 .destroy = _destroy,
302 },
303 .get_fatal_flag = _get_fatal_flag,
304 .get_vendor_id = _get_vendor_id,
305 .get_error_code = _get_error_code,
306 .get_offset = _get_offset,
307 .get_bad_version = _get_bad_version,
308 .set_bad_version = _set_bad_version,
309 },
310 .type = PB_MSG_ERROR,
311 .ref = 1,
312 .fatal = fatal,
313 .vendor_id = vendor_id,
314 .error_code = error_code,
315 .error_offset = error_offset,
316 );
317
318 return &this->public.pb_interface;
319 }
320
321 /**
322 * See header
323 */
324 pb_tnc_msg_t *pb_error_msg_create_from_data(chunk_t data)
325 {
326 private_pb_error_msg_t *this;
327
328 INIT(this,
329 .public = {
330 .pb_interface = {
331 .get_type = _get_type,
332 .get_encoding = _get_encoding,
333 .build = _build,
334 .process = _process,
335 .get_ref = _get_ref,
336 .destroy = _destroy,
337 },
338 .get_fatal_flag = _get_fatal_flag,
339 .get_vendor_id = _get_vendor_id,
340 .get_error_code = _get_error_code,
341 .get_offset = _get_offset,
342 .get_bad_version = _get_bad_version,
343 .set_bad_version = _set_bad_version,
344 },
345 .type = PB_MSG_ERROR,
346 .ref = 1,
347 .encoding = chunk_clone(data),
348 );
349
350 return &this->public.pb_interface;
351 }
352