]>
Commit | Line | Data |
---|---|---|
4333c48a AS |
1 | /* |
2 | * Copyright (C) 2010 Sansar Choinyanbuu | |
22e97e4f | 3 | * Copyright (C) 2010-2012 Andreas Steffen |
4333c48a AS |
4 | * HSR Hochschule fuer Technik Rapperswil |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2 of the License, or (at your | |
9 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
13 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | * for more details. | |
15 | */ | |
16 | ||
4333c48a | 17 | #include "pb_tnc_batch.h" |
54eb669d | 18 | #include "messages/pb_error_msg.h" |
5988fc0d | 19 | #include "state_machine/pb_tnc_state_machine.h" |
4333c48a | 20 | |
f0a8bf47 AS |
21 | #include <tnc/tnccs/tnccs.h> |
22 | ||
12642a68 | 23 | #include <collections/linked_list.h> |
7e432eff AS |
24 | #include <bio/bio_writer.h> |
25 | #include <bio/bio_reader.h> | |
7c4d4d20 | 26 | #include <pen/pen.h> |
f05b4272 | 27 | #include <utils/debug.h> |
4333c48a | 28 | |
4333c48a AS |
29 | ENUM(pb_tnc_batch_type_names, PB_BATCH_CDATA, PB_BATCH_CLOSE, |
30 | "CDATA", | |
31 | "SDATA", | |
32 | "RESULT", | |
33 | "CRETRY", | |
34 | "SRETRY", | |
35 | "CLOSE" | |
36 | ); | |
37 | ||
38 | typedef struct private_pb_tnc_batch_t private_pb_tnc_batch_t; | |
39 | ||
40 | /** | |
41 | * PB-Batch Header (see section 4.1 of RFC 5793) | |
42 | * | |
43 | * 0 1 2 3 | |
44 | * 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 | |
45 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
46 | * | Version |D| Reserved | B-Type| | |
47 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
48 | * | Batch Length | | |
49 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
50 | */ | |
51 | ||
52 | #define PB_TNC_BATCH_FLAG_NONE 0x00 | |
53 | #define PB_TNC_BATCH_FLAG_D (1<<7) | |
a5c79d01 | 54 | #define PB_TNC_BATCH_HEADER_SIZE 8 |
4333c48a AS |
55 | |
56 | /** | |
57 | * PB-TNC Message (see section 4.2 of RFC 5793) | |
58 | * | |
59 | * 0 1 2 3 | |
60 | * 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 | |
61 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
62 | * | Flags | PB-TNC Vendor ID | | |
63 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
64 | * | PB-TNC Message Type | | |
65 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
66 | * | PB-TNC Message Length | | |
67 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
68 | * | PB-TNC Message Value (Variable Length) | | |
69 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
70 | */ | |
71 | ||
72 | #define PB_TNC_FLAG_NONE 0x00 | |
73 | #define PB_TNC_FLAG_NOSKIP (1<<7) | |
a5c79d01 | 74 | #define PB_TNC_HEADER_SIZE 12 |
4333c48a AS |
75 | |
76 | #define PB_TNC_RESERVED_MSG_TYPE 0xffffffff | |
77 | ||
78 | /** | |
79 | * Private data of a pb_tnc_batch_t object. | |
80 | * | |
81 | */ | |
82 | struct private_pb_tnc_batch_t { | |
83 | /** | |
54eb669d | 84 | * Public pb_pa_msg_t interface. |
4333c48a AS |
85 | */ |
86 | pb_tnc_batch_t public; | |
87 | ||
88 | /** | |
89 | * TNCC if TRUE, TNCS if FALSE | |
90 | */ | |
91 | bool is_server; | |
92 | ||
93 | /** | |
94 | * PB-TNC Batch type | |
95 | */ | |
96 | pb_tnc_batch_type_t type; | |
97 | ||
a5c79d01 AS |
98 | /** |
99 | * Current PB-TNC Batch size | |
100 | */ | |
101 | size_t batch_len; | |
102 | ||
103 | /** | |
104 | * Maximum PB-TNC Batch size | |
105 | */ | |
106 | size_t max_batch_len; | |
107 | ||
4333c48a AS |
108 | /** |
109 | * linked list of PB-TNC messages | |
110 | */ | |
111 | linked_list_t *messages; | |
112 | ||
113 | /** | |
114 | * linked list of PB-TNC error messages | |
115 | */ | |
116 | linked_list_t *errors; | |
117 | ||
118 | /** | |
119 | * Encoded message | |
120 | */ | |
121 | chunk_t encoding; | |
122 | ||
123 | /** | |
124 | * Offset into encoding (used for error reporting) | |
125 | */ | |
54eb669d | 126 | u_int32_t offset; |
4333c48a AS |
127 | }; |
128 | ||
129 | METHOD(pb_tnc_batch_t, get_type, pb_tnc_batch_type_t, | |
130 | private_pb_tnc_batch_t *this) | |
131 | { | |
132 | return this->type; | |
133 | } | |
134 | ||
135 | METHOD(pb_tnc_batch_t, get_encoding, chunk_t, | |
136 | private_pb_tnc_batch_t *this) | |
137 | { | |
138 | return this->encoding; | |
139 | } | |
140 | ||
a5c79d01 | 141 | METHOD(pb_tnc_batch_t, add_msg, bool, |
54eb669d | 142 | private_pb_tnc_batch_t *this, pb_tnc_msg_t* msg) |
4333c48a | 143 | { |
a5c79d01 AS |
144 | chunk_t msg_value; |
145 | size_t msg_len; | |
146 | ||
147 | msg->build(msg); | |
148 | msg_value = msg->get_encoding(msg); | |
149 | msg_len = PB_TNC_HEADER_SIZE + msg_value.len; | |
150 | ||
151 | if (this->batch_len + msg_len > this->max_batch_len) | |
152 | { | |
153 | /* message just does not fit into this batch */ | |
154 | return FALSE; | |
155 | } | |
156 | this->batch_len += msg_len; | |
157 | ||
41216e65 | 158 | DBG2(DBG_TNC, "adding %N message", pb_tnc_msg_type_names, |
4ca368d2 | 159 | msg->get_type(msg)); |
4333c48a | 160 | this->messages->insert_last(this->messages, msg); |
a5c79d01 | 161 | return TRUE; |
4333c48a AS |
162 | } |
163 | ||
164 | METHOD(pb_tnc_batch_t, build, void, | |
165 | private_pb_tnc_batch_t *this) | |
166 | { | |
a5c79d01 | 167 | u_int32_t msg_len; |
4333c48a AS |
168 | chunk_t msg_value; |
169 | enumerator_t *enumerator; | |
170 | pb_tnc_msg_type_t msg_type; | |
54eb669d | 171 | pb_tnc_msg_t *msg; |
7e432eff | 172 | bio_writer_t *writer; |
4333c48a | 173 | |
4333c48a | 174 | /* build PB-TNC batch header */ |
12642a68 | 175 | writer = bio_writer_create(this->batch_len); |
4333c48a AS |
176 | writer->write_uint8 (writer, PB_TNC_VERSION); |
177 | writer->write_uint8 (writer, this->is_server ? | |
178 | PB_TNC_BATCH_FLAG_D : PB_TNC_BATCH_FLAG_NONE); | |
179 | writer->write_uint16(writer, this->type); | |
12642a68 | 180 | writer->write_uint32(writer, this->batch_len); |
4333c48a AS |
181 | |
182 | /* build PB-TNC messages */ | |
183 | enumerator = this->messages->create_enumerator(this->messages); | |
184 | while (enumerator->enumerate(enumerator, &msg)) | |
185 | { | |
54eb669d AS |
186 | u_int8_t flags = PB_TNC_FLAG_NONE; |
187 | ||
4333c48a AS |
188 | /* build PB-TNC message */ |
189 | msg_value = msg->get_encoding(msg); | |
190 | msg_len = PB_TNC_HEADER_SIZE + msg_value.len; | |
191 | msg_type = msg->get_type(msg); | |
54eb669d | 192 | if (pb_tnc_msg_infos[msg_type].has_noskip_flag) |
4333c48a | 193 | { |
54eb669d AS |
194 | flags |= PB_TNC_FLAG_NOSKIP; |
195 | } | |
4333c48a | 196 | writer->write_uint8 (writer, flags); |
425a3a26 | 197 | writer->write_uint24(writer, PEN_IETF); |
4333c48a AS |
198 | writer->write_uint32(writer, msg_type); |
199 | writer->write_uint32(writer, msg_len); | |
200 | writer->write_data (writer, msg_value); | |
201 | } | |
202 | enumerator->destroy(enumerator); | |
203 | ||
1a9dee5d | 204 | this->encoding = writer->extract_buf(writer); |
4333c48a AS |
205 | writer->destroy(writer); |
206 | } | |
207 | ||
208 | static status_t process_batch_header(private_pb_tnc_batch_t *this, | |
5988fc0d | 209 | pb_tnc_state_machine_t *state_machine) |
4333c48a | 210 | { |
7e432eff | 211 | bio_reader_t *reader; |
54eb669d AS |
212 | pb_tnc_msg_t *msg; |
213 | pb_error_msg_t *err_msg; | |
4333c48a AS |
214 | u_int8_t version, flags, reserved, type; |
215 | u_int32_t batch_len; | |
68fada37 | 216 | bool directionality; |
4333c48a AS |
217 | |
218 | if (this->encoding.len < PB_TNC_BATCH_HEADER_SIZE) | |
219 | { | |
220 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC batch header", | |
221 | this->encoding.len); | |
425a3a26 | 222 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 223 | PB_ERROR_INVALID_PARAMETER, 0); |
4333c48a AS |
224 | goto fatal; |
225 | } | |
226 | ||
7e432eff | 227 | reader = bio_reader_create(this->encoding); |
4333c48a AS |
228 | reader->read_uint8 (reader, &version); |
229 | reader->read_uint8 (reader, &flags); | |
230 | reader->read_uint8 (reader, &reserved); | |
231 | reader->read_uint8 (reader, &type); | |
232 | reader->read_uint32(reader, &batch_len); | |
233 | reader->destroy(reader); | |
234 | ||
235 | /* Version */ | |
236 | if (version != PB_TNC_VERSION) | |
237 | { | |
c56667f1 | 238 | DBG1(DBG_TNC, "unsupported TNCCS batch version 0x%02x", version); |
425a3a26 | 239 | msg = pb_error_msg_create(TRUE, PEN_IETF, |
54eb669d AS |
240 | PB_ERROR_VERSION_NOT_SUPPORTED); |
241 | err_msg = (pb_error_msg_t*)msg; | |
4333c48a AS |
242 | err_msg->set_bad_version(err_msg, version); |
243 | goto fatal; | |
244 | } | |
245 | ||
246 | /* Directionality */ | |
247 | directionality = (flags & PB_TNC_BATCH_FLAG_D) != PB_TNC_BATCH_FLAG_NONE; | |
248 | if (directionality == this->is_server) | |
249 | { | |
41216e65 AS |
250 | DBG1(DBG_TNC, "wrong Directionality: batch is from a PB %s", |
251 | directionality ? "server" : "client"); | |
425a3a26 | 252 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 253 | PB_ERROR_INVALID_PARAMETER, 1); |
4333c48a AS |
254 | goto fatal; |
255 | } | |
256 | ||
257 | /* Batch Type */ | |
258 | this->type = type & 0x0F; | |
259 | if (this->type > PB_BATCH_ROOF) | |
260 | { | |
41216e65 | 261 | DBG1(DBG_TNC, "unknown PB-TNC batch type: %d", this->type); |
425a3a26 | 262 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 263 | PB_ERROR_INVALID_PARAMETER, 3); |
4333c48a AS |
264 | goto fatal; |
265 | } | |
68fada37 | 266 | |
5988fc0d | 267 | if (!state_machine->receive_batch(state_machine, this->type)) |
4333c48a | 268 | { |
41216e65 | 269 | DBG1(DBG_TNC, "unexpected PB-TNC batch type: %N", |
4333c48a | 270 | pb_tnc_batch_type_names, this->type); |
425a3a26 | 271 | msg = pb_error_msg_create(TRUE, PEN_IETF, |
54eb669d | 272 | PB_ERROR_UNEXPECTED_BATCH_TYPE); |
4333c48a AS |
273 | goto fatal; |
274 | } | |
b8b678a5 AS |
275 | DBG1(DBG_TNC, "processing PB-TNC %N batch", pb_tnc_batch_type_names, |
276 | this->type); | |
4333c48a AS |
277 | |
278 | /* Batch Length */ | |
279 | if (this->encoding.len != batch_len) | |
280 | { | |
281 | DBG1(DBG_TNC, "%u bytes of data is not equal to batch length of %u bytes", | |
282 | this->encoding.len, batch_len); | |
425a3a26 | 283 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 284 | PB_ERROR_INVALID_PARAMETER, 4); |
4333c48a AS |
285 | goto fatal; |
286 | } | |
287 | ||
288 | this->offset = PB_TNC_BATCH_HEADER_SIZE; | |
b8b678a5 AS |
289 | |
290 | /* Register an empty CDATA batch with the state machine */ | |
291 | if (this->type == PB_BATCH_CDATA) | |
292 | { | |
293 | state_machine->set_empty_cdata(state_machine, | |
294 | this->offset == this->encoding.len); | |
295 | } | |
4333c48a AS |
296 | return SUCCESS; |
297 | ||
298 | fatal: | |
299 | this->errors->insert_last(this->errors, msg); | |
12642a68 | 300 | return FAILED; |
4333c48a AS |
301 | } |
302 | ||
54eb669d | 303 | static status_t process_tnc_msg(private_pb_tnc_batch_t *this) |
4333c48a | 304 | { |
7e432eff | 305 | bio_reader_t *reader; |
54eb669d | 306 | pb_tnc_msg_t *pb_tnc_msg, *msg; |
4333c48a | 307 | u_int8_t flags; |
54eb669d | 308 | u_int32_t vendor_id, msg_type, msg_len, offset; |
4333c48a | 309 | chunk_t data, msg_value; |
54eb669d | 310 | bool noskip_flag; |
4333c48a AS |
311 | status_t status; |
312 | ||
313 | data = chunk_skip(this->encoding, this->offset); | |
314 | ||
315 | if (data.len < PB_TNC_HEADER_SIZE) | |
316 | { | |
317 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message header", | |
318 | data.len); | |
425a3a26 | 319 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 320 | PB_ERROR_INVALID_PARAMETER, this->offset); |
4333c48a AS |
321 | goto fatal; |
322 | } | |
323 | ||
7e432eff | 324 | reader = bio_reader_create(data); |
4333c48a AS |
325 | reader->read_uint8 (reader, &flags); |
326 | reader->read_uint24(reader, &vendor_id); | |
327 | reader->read_uint32(reader, &msg_type); | |
328 | reader->read_uint32(reader, &msg_len); | |
329 | reader->destroy(reader); | |
330 | ||
54eb669d | 331 | noskip_flag = (flags & PB_TNC_FLAG_NOSKIP) != PB_TNC_FLAG_NONE; |
12642a68 | 332 | |
4333c48a AS |
333 | if (msg_len > data.len) |
334 | { | |
335 | DBG1(DBG_TNC, "%u bytes insufficient to parse PB-TNC message", data.len); | |
425a3a26 | 336 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 337 | PB_ERROR_INVALID_PARAMETER, this->offset + 8); |
4333c48a AS |
338 | goto fatal; |
339 | } | |
340 | ||
425a3a26 | 341 | if (vendor_id == PEN_RESERVED) |
4333c48a | 342 | { |
425a3a26 AS |
343 | DBG1(DBG_TNC, "Vendor ID 0x%06x is reserved", PEN_RESERVED); |
344 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
54eb669d | 345 | PB_ERROR_INVALID_PARAMETER, this->offset + 1); |
4333c48a AS |
346 | goto fatal; |
347 | ||
348 | } | |
349 | ||
350 | if (msg_type == PB_TNC_RESERVED_MSG_TYPE) | |
351 | { | |
41216e65 | 352 | DBG1(DBG_TNC, "PB-TNC message Type 0x%08x is reserved", |
4333c48a | 353 | PB_TNC_RESERVED_MSG_TYPE); |
425a3a26 | 354 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 355 | PB_ERROR_INVALID_PARAMETER, this->offset + 4); |
4333c48a AS |
356 | goto fatal; |
357 | } | |
358 | ||
54eb669d | 359 | |
425a3a26 | 360 | if (vendor_id != PEN_IETF || msg_type > PB_MSG_ROOF) |
4333c48a | 361 | { |
54eb669d AS |
362 | if (msg_len < PB_TNC_HEADER_SIZE) |
363 | { | |
364 | DBG1(DBG_TNC, "%u bytes too small for PB-TNC message length", | |
365 | msg_len); | |
425a3a26 | 366 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d AS |
367 | PB_ERROR_INVALID_PARAMETER, this->offset + 8); |
368 | goto fatal; | |
369 | } | |
370 | ||
371 | if (noskip_flag) | |
4333c48a | 372 | { |
41216e65 | 373 | DBG1(DBG_TNC, "reject PB-TNC message (Vendor ID 0x%06x / " |
4ca368d2 | 374 | "Type 0x%08x)", vendor_id, msg_type); |
425a3a26 | 375 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 376 | PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); |
4333c48a AS |
377 | goto fatal; |
378 | } | |
379 | else | |
380 | { | |
41216e65 | 381 | DBG1(DBG_TNC, "ignore PB-TNC message (Vendor ID 0x%06x / " |
4ca368d2 | 382 | "Type 0x%08x)", vendor_id, msg_type); |
4333c48a | 383 | this->offset += msg_len; |
af1e3ff5 | 384 | return SUCCESS; |
4333c48a AS |
385 | } |
386 | } | |
54eb669d AS |
387 | else |
388 | { | |
0f7cb0ca AS |
389 | if (msg_type == PB_MSG_EXPERIMENTAL && noskip_flag) |
390 | { | |
391 | DBG1(DBG_TNC, "reject PB-Experimental message with NOSKIP flag set"); | |
392 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, | |
393 | PB_ERROR_UNSUPPORTED_MANDATORY_MSG, this->offset); | |
394 | goto fatal; | |
395 | } | |
54eb669d AS |
396 | if (pb_tnc_msg_infos[msg_type].has_noskip_flag != TRUE_OR_FALSE && |
397 | pb_tnc_msg_infos[msg_type].has_noskip_flag != noskip_flag) | |
398 | { | |
41216e65 | 399 | DBG1(DBG_TNC, "%N message must%s have NOSKIP flag set", |
54eb669d AS |
400 | pb_tnc_msg_type_names, msg_type, |
401 | pb_tnc_msg_infos[msg_type].has_noskip_flag ? "" : " not"); | |
425a3a26 | 402 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d AS |
403 | PB_ERROR_INVALID_PARAMETER, this->offset); |
404 | goto fatal; | |
405 | } | |
4333c48a | 406 | |
54eb669d AS |
407 | if (msg_len < pb_tnc_msg_infos[msg_type].min_size || |
408 | (pb_tnc_msg_infos[msg_type].exact_size && | |
409 | msg_len != pb_tnc_msg_infos[msg_type].min_size)) | |
410 | { | |
41216e65 | 411 | DBG1(DBG_TNC, "%N message length must be %s %u bytes but is %u bytes", |
54eb669d AS |
412 | pb_tnc_msg_type_names, msg_type, |
413 | pb_tnc_msg_infos[msg_type].exact_size ? "exactly" : "at least", | |
414 | pb_tnc_msg_infos[msg_type].min_size, msg_len); | |
425a3a26 | 415 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d AS |
416 | PB_ERROR_INVALID_PARAMETER, this->offset); |
417 | goto fatal; | |
418 | } | |
419 | } | |
420 | ||
421 | if (pb_tnc_msg_infos[msg_type].in_result_batch && | |
422 | this->type != PB_BATCH_RESULT) | |
7e7efa64 | 423 | { |
af1e3ff5 AS |
424 | if (this->is_server) |
425 | { | |
41216e65 | 426 | DBG1(DBG_TNC,"reject %N message received from a PB-TNC client", |
af1e3ff5 | 427 | pb_tnc_msg_type_names, msg_type); |
425a3a26 | 428 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
54eb669d | 429 | PB_ERROR_INVALID_PARAMETER, this->offset); |
af1e3ff5 AS |
430 | goto fatal; |
431 | } | |
432 | else | |
433 | { | |
41216e65 | 434 | DBG1(DBG_TNC,"ignore %N message not received within RESULT batch", |
af1e3ff5 AS |
435 | pb_tnc_msg_type_names, msg_type); |
436 | this->offset += msg_len; | |
437 | return SUCCESS; | |
438 | } | |
7e7efa64 AS |
439 | } |
440 | ||
41216e65 | 441 | DBG2(DBG_TNC, "processing %N message (%u bytes)", pb_tnc_msg_type_names, |
4333c48a AS |
442 | msg_type, msg_len); |
443 | data.len = msg_len; | |
4333c48a | 444 | msg_value = chunk_skip(data, PB_TNC_HEADER_SIZE); |
54eb669d | 445 | pb_tnc_msg = pb_tnc_msg_create_from_data(msg_type, msg_value); |
4333c48a | 446 | |
54eb669d AS |
447 | status = pb_tnc_msg->process(pb_tnc_msg, &offset); |
448 | if (status == FAILED || status == VERIFY_ERROR) | |
449 | { | |
425a3a26 | 450 | msg = pb_error_msg_create_with_offset(TRUE, PEN_IETF, |
a96d9abf | 451 | PB_ERROR_INVALID_PARAMETER, this->offset + offset); |
54eb669d AS |
452 | this->errors->insert_last(this->errors, msg); |
453 | } | |
4333c48a AS |
454 | if (status == FAILED) |
455 | { | |
456 | pb_tnc_msg->destroy(pb_tnc_msg); | |
457 | return FAILED; | |
458 | } | |
459 | this->messages->insert_last(this->messages, pb_tnc_msg); | |
460 | this->offset += msg_len; | |
54eb669d | 461 | return status; |
4333c48a AS |
462 | |
463 | fatal: | |
464 | this->errors->insert_last(this->errors, msg); | |
12642a68 | 465 | return FAILED; |
4333c48a AS |
466 | } |
467 | ||
468 | METHOD(pb_tnc_batch_t, process, status_t, | |
5988fc0d | 469 | private_pb_tnc_batch_t *this, pb_tnc_state_machine_t *state_machine) |
4333c48a AS |
470 | { |
471 | status_t status; | |
472 | ||
5988fc0d | 473 | status = process_batch_header(this, state_machine); |
af1e3ff5 | 474 | if (status != SUCCESS) |
4333c48a AS |
475 | { |
476 | return FAILED; | |
477 | } | |
b8b678a5 | 478 | |
4333c48a AS |
479 | while (this->offset < this->encoding.len) |
480 | { | |
54eb669d | 481 | switch (process_tnc_msg(this)) |
4333c48a | 482 | { |
af1e3ff5 AS |
483 | case FAILED: |
484 | return FAILED; | |
485 | case VERIFY_ERROR: | |
486 | status = VERIFY_ERROR; | |
487 | break; | |
488 | case SUCCESS: | |
489 | default: | |
490 | break; | |
4333c48a AS |
491 | } |
492 | } | |
af1e3ff5 | 493 | return status; |
4333c48a AS |
494 | } |
495 | ||
496 | METHOD(pb_tnc_batch_t, create_msg_enumerator, enumerator_t*, | |
497 | private_pb_tnc_batch_t *this) | |
498 | { | |
499 | return this->messages->create_enumerator(this->messages); | |
500 | } | |
501 | ||
502 | METHOD(pb_tnc_batch_t, create_error_enumerator, enumerator_t*, | |
503 | private_pb_tnc_batch_t *this) | |
504 | { | |
505 | return this->errors->create_enumerator(this->errors); | |
506 | } | |
507 | ||
508 | METHOD(pb_tnc_batch_t, destroy, void, | |
509 | private_pb_tnc_batch_t *this) | |
510 | { | |
511 | this->messages->destroy_offset(this->messages, | |
54eb669d | 512 | offsetof(pb_tnc_msg_t, destroy)); |
4333c48a | 513 | this->errors->destroy_offset(this->errors, |
54eb669d | 514 | offsetof(pb_tnc_msg_t, destroy)); |
4333c48a AS |
515 | free(this->encoding.ptr); |
516 | free(this); | |
517 | } | |
518 | ||
519 | /** | |
520 | * See header | |
521 | */ | |
a5c79d01 AS |
522 | pb_tnc_batch_t* pb_tnc_batch_create(bool is_server, pb_tnc_batch_type_t type, |
523 | size_t max_batch_len) | |
4333c48a AS |
524 | { |
525 | private_pb_tnc_batch_t *this; | |
526 | ||
527 | INIT(this, | |
528 | .public = { | |
529 | .get_type = _get_type, | |
530 | .get_encoding = _get_encoding, | |
54eb669d | 531 | .add_msg = _add_msg, |
4333c48a AS |
532 | .build = _build, |
533 | .process = _process, | |
534 | .create_msg_enumerator = _create_msg_enumerator, | |
535 | .create_error_enumerator = _create_error_enumerator, | |
536 | .destroy = _destroy, | |
537 | }, | |
538 | .is_server = is_server, | |
539 | .type = type, | |
a5c79d01 AS |
540 | .max_batch_len = max_batch_len, |
541 | .batch_len = PB_TNC_BATCH_HEADER_SIZE, | |
4333c48a AS |
542 | .messages = linked_list_create(), |
543 | .errors = linked_list_create(), | |
544 | ); | |
545 | ||
41216e65 | 546 | DBG2(DBG_TNC, "creating PB-TNC %N batch", pb_tnc_batch_type_names, type); |
4333c48a AS |
547 | |
548 | return &this->public; | |
549 | } | |
550 | ||
551 | /** | |
552 | * See header | |
553 | */ | |
554 | pb_tnc_batch_t* pb_tnc_batch_create_from_data(bool is_server, chunk_t data) | |
555 | { | |
556 | private_pb_tnc_batch_t *this; | |
557 | ||
558 | INIT(this, | |
559 | .public = { | |
560 | .get_type = _get_type, | |
561 | .get_encoding = _get_encoding, | |
54eb669d | 562 | .add_msg = _add_msg, |
4333c48a AS |
563 | .build = _build, |
564 | .process = _process, | |
565 | .create_msg_enumerator = _create_msg_enumerator, | |
566 | .create_error_enumerator = _create_error_enumerator, | |
567 | .destroy = _destroy, | |
568 | }, | |
569 | .is_server = is_server, | |
570 | .messages = linked_list_create(), | |
571 | .errors = linked_list_create(), | |
572 | .encoding = chunk_clone(data), | |
573 | ); | |
574 | ||
575 | return &this->public; | |
576 | } | |
577 |