return offset value
[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 *offset = 0;
163 return FAILED;
164 }
165
166 /* process message header */
167 reader = bio_reader_create(this->encoding);
168 reader->read_uint8 (reader, &flags);
169 reader->read_uint24(reader, &this->vendor_id);
170 reader->read_uint16(reader, &this->error_code);
171 reader->read_uint16(reader, &reserved);
172 this->fatal = (flags & ERROR_FLAG_FATAL) != ERROR_FLAG_NONE;
173
174 if (this->vendor_id == PEN_IETF && reader->remaining(reader) == 4)
175 {
176 if (this->error_code == PB_ERROR_VERSION_NOT_SUPPORTED)
177 {
178 reader->read_uint8(reader, &this->bad_version);
179 reader->read_uint8(reader, &max_version);
180 reader->read_uint8(reader, &min_version);
181 }
182 else
183 {
184 reader->read_uint32(reader, &this->error_offset);
185 }
186 }
187 reader->destroy(reader);
188
189 return SUCCESS;
190 }
191
192 METHOD(pb_tnc_msg_t, get_ref, pb_tnc_msg_t*,
193 private_pb_error_msg_t *this)
194 {
195 ref_get(&this->ref);
196 return &this->public.pb_interface;
197 }
198
199 METHOD(pb_tnc_msg_t, destroy, void,
200 private_pb_error_msg_t *this)
201 {
202 if (ref_put(&this->ref))
203 {
204 free(this->encoding.ptr);
205 free(this);
206 }
207 }
208
209 METHOD(pb_error_msg_t, get_fatal_flag, bool,
210 private_pb_error_msg_t *this)
211 {
212 return this->fatal;
213 }
214
215 METHOD(pb_error_msg_t, get_vendor_id, u_int32_t,
216 private_pb_error_msg_t *this)
217 {
218 return this->vendor_id;
219 }
220
221 METHOD(pb_error_msg_t, get_error_code, u_int16_t,
222 private_pb_error_msg_t *this)
223 {
224 return this->error_code;
225 }
226
227 METHOD(pb_error_msg_t, get_offset, u_int32_t,
228 private_pb_error_msg_t *this)
229 {
230 return this->error_offset;
231 }
232
233 METHOD(pb_error_msg_t, get_bad_version, u_int8_t,
234 private_pb_error_msg_t *this)
235 {
236 return this->bad_version;
237 }
238
239 METHOD(pb_error_msg_t, set_bad_version, void,
240 private_pb_error_msg_t *this, u_int8_t version)
241 {
242 this->bad_version = version;
243 }
244
245 /**
246 * See header
247 */
248 pb_tnc_msg_t* pb_error_msg_create(bool fatal, u_int32_t vendor_id,
249 pb_tnc_error_code_t error_code)
250 {
251 private_pb_error_msg_t *this;
252
253 INIT(this,
254 .public = {
255 .pb_interface = {
256 .get_type = _get_type,
257 .get_encoding = _get_encoding,
258 .build = _build,
259 .process = _process,
260 .get_ref = _get_ref,
261 .destroy = _destroy,
262 },
263 .get_fatal_flag = _get_fatal_flag,
264 .get_vendor_id = _get_vendor_id,
265 .get_error_code = _get_error_code,
266 .get_offset = _get_offset,
267 .get_bad_version = _get_bad_version,
268 .set_bad_version = _set_bad_version,
269 },
270 .type = PB_MSG_ERROR,
271 .ref = 1,
272 .fatal = fatal,
273 .vendor_id = vendor_id,
274 .error_code = error_code,
275 );
276
277 return &this->public.pb_interface;
278 }
279
280 /**
281 * See header
282 */
283 pb_tnc_msg_t* pb_error_msg_create_with_offset(bool fatal, u_int32_t vendor_id,
284 pb_tnc_error_code_t error_code,
285 u_int32_t error_offset)
286 {
287 private_pb_error_msg_t *this;
288
289 INIT(this,
290 .public = {
291 .pb_interface = {
292 .get_type = _get_type,
293 .get_encoding = _get_encoding,
294 .build = _build,
295 .process = _process,
296 .get_ref = _get_ref,
297 .destroy = _destroy,
298 },
299 .get_fatal_flag = _get_fatal_flag,
300 .get_vendor_id = _get_vendor_id,
301 .get_error_code = _get_error_code,
302 .get_offset = _get_offset,
303 .get_bad_version = _get_bad_version,
304 .set_bad_version = _set_bad_version,
305 },
306 .type = PB_MSG_ERROR,
307 .ref = 1,
308 .fatal = fatal,
309 .vendor_id = vendor_id,
310 .error_code = error_code,
311 .error_offset = error_offset,
312 );
313
314 return &this->public.pb_interface;
315 }
316
317 /**
318 * See header
319 */
320 pb_tnc_msg_t *pb_error_msg_create_from_data(chunk_t data)
321 {
322 private_pb_error_msg_t *this;
323
324 INIT(this,
325 .public = {
326 .pb_interface = {
327 .get_type = _get_type,
328 .get_encoding = _get_encoding,
329 .build = _build,
330 .process = _process,
331 .get_ref = _get_ref,
332 .destroy = _destroy,
333 },
334 .get_fatal_flag = _get_fatal_flag,
335 .get_vendor_id = _get_vendor_id,
336 .get_error_code = _get_error_code,
337 .get_offset = _get_offset,
338 .get_bad_version = _get_bad_version,
339 .set_bad_version = _set_bad_version,
340 },
341 .type = PB_MSG_ERROR,
342 .ref = 1,
343 .encoding = chunk_clone(data),
344 );
345
346 return &this->public.pb_interface;
347 }
348