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