pb_tnc_batch_t class implements parsing and building of PB-TNC batches
[strongswan.git] / src / libcharon / plugins / tnccs_20 / messages / pb_error_message.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_message.h"
17 #include "../tnccs_20_types.h"
18
19 #include <debug.h>
20 #include <tls_writer.h>
21 #include <tls_reader.h>
22 #include <tnc/tnccs/tnccs.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_message_t private_pb_error_message_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_message_t object.
56 *
57 */
58 struct private_pb_error_message_t {
59 /**
60 * Public pb_error_message_t interface.
61 */
62 pb_error_message_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_message_t, get_type, pb_tnc_msg_type_t,
106 private_pb_error_message_t *this)
107 {
108 return this->type;
109 }
110
111 METHOD(pb_tnc_message_t, get_encoding, chunk_t,
112 private_pb_error_message_t *this)
113 {
114 return this->encoding;
115 }
116
117 METHOD(pb_tnc_message_t, build, void,
118 private_pb_error_message_t *this)
119 {
120 tls_writer_t *writer;
121
122 /* build message header */
123 writer = tls_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_message_t, process, status_t,
152 private_pb_error_message_t *this)
153 {
154 u_int8_t flags, max_version, min_version;
155 u_int16_t reserved;
156 tls_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 = tls_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 == IETF_VENDOR_ID && 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_message_t, get_ref, pb_tnc_message_t*,
192 private_pb_error_message_t *this)
193 {
194 ref_get(&this->ref);
195 return &this->public.pb_interface;
196 }
197
198 METHOD(pb_tnc_message_t, destroy, void,
199 private_pb_error_message_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_message_t, get_fatal_flag, bool,
209 private_pb_error_message_t *this)
210 {
211 return this->fatal;
212 }
213
214 METHOD(pb_error_message_t, get_vendor_id, u_int32_t,
215 private_pb_error_message_t *this)
216 {
217 return this->vendor_id;
218 }
219
220 METHOD(pb_error_message_t, get_error_code, u_int16_t,
221 private_pb_error_message_t *this)
222 {
223 return this->error_code;
224 }
225
226 METHOD(pb_error_message_t, get_offset, u_int32_t,
227 private_pb_error_message_t *this)
228 {
229 return this->error_offset;
230 }
231
232 METHOD(pb_error_message_t, set_offset, void,
233 private_pb_error_message_t *this, u_int32_t offset)
234 {
235 this->error_offset = offset;
236 }
237
238 METHOD(pb_error_message_t, get_bad_version, u_int8_t,
239 private_pb_error_message_t *this)
240 {
241 return this->bad_version;
242 }
243
244 METHOD(pb_error_message_t, set_bad_version, void,
245 private_pb_error_message_t *this, u_int8_t version)
246 {
247 this->bad_version = version;
248 }
249
250 /**
251 * See header
252 */
253 pb_tnc_message_t* pb_error_message_create(bool fatal, u_int32_t vendor_id,
254 pb_tnc_error_code_t error_code)
255 {
256 private_pb_error_message_t *this;
257
258 INIT(this,
259 .public = {
260 .pb_interface = {
261 .get_type = _get_type,
262 .get_encoding = _get_encoding,
263 .build = _build,
264 .process = _process,
265 .get_ref = _get_ref,
266 .destroy = _destroy,
267 },
268 .get_fatal_flag = _get_fatal_flag,
269 .get_vendor_id = _get_vendor_id,
270 .get_error_code = _get_error_code,
271 .get_offset = _get_offset,
272 .set_offset = _set_offset,
273 .get_bad_version = _get_bad_version,
274 .set_bad_version = _set_bad_version,
275 },
276 .type = PB_MSG_ERROR,
277 .ref = 1,
278 .fatal = fatal,
279 .vendor_id = vendor_id,
280 .error_code = error_code,
281 );
282
283 return &this->public.pb_interface;
284 }
285
286 /**
287 * See header
288 */
289 pb_tnc_message_t *pb_error_message_create_from_data(chunk_t data)
290 {
291 private_pb_error_message_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 .set_offset = _set_offset,
308 .get_bad_version = _get_bad_version,
309 .set_bad_version = _set_bad_version,
310 },
311 .type = PB_MSG_ERROR,
312 .ref = 1,
313 .encoding = chunk_clone(data),
314 );
315
316 return &this->public.pb_interface;
317 }
318