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