]> git.ipfire.org Git - thirdparty/strongswan.git/blame - Source/charon/encoding/generator.c
- created encoding package
[thirdparty/strongswan.git] / Source / charon / encoding / generator.c
CommitLineData
b82c0cab
JH
1/**
2 * @file generator.c
79538669 3 *
c7748338 4 * @brief Generic generator class used to generate IKEv2-header and payloads.
79538669 5 *
b82c0cab
JH
6 */
7
8/*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23#include <stdlib.h>
762ce218 24#include <string.h>
c7748338 25#include <arpa/inet.h>
7330c172 26#include <stdio.h>
b82c0cab 27
88878242 28
b82c0cab
JH
29#include "generator.h"
30
021c2322
MW
31#include <types.h>
32#include <globals.h>
33#include <utils/allocator.h>
34#include <utils/linked_list.h>
35#include <utils/logger_manager.h>
4a962238
MW
36#include <encoding/payloads/payload.h>
37#include <encoding/payloads/proposal_substructure.h>
38#include <encoding/payloads/transform_substructure.h>
39#include <encoding/payloads/sa_payload.h>
40#include <encoding/payloads/ke_payload.h>
41#include <encoding/payloads/notify_payload.h>
42#include <encoding/payloads/nonce_payload.h>
762ce218 43
1e8bb886
JH
44/**
45 * Private part of a generator_t object
46 */
47typedef struct private_generator_s private_generator_t;
762ce218 48
1e8bb886 49struct private_generator_s {
762ce218 50 /**
1e8bb886 51 * Public part of a generator_t object
762ce218 52 */
1e8bb886
JH
53 generator_t public;
54
55 /* private functions and fields */
c3dc6f1a 56
c3dc6f1a 57
762ce218 58 /**
7031a50b 59 * Generates a U_INT-Field type and writes it to buffer.
1e8bb886
JH
60 *
61 * @param this private_generator_t object
62 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
7031a50b 63 * ATTRIBUTE_TYPE is also generated in this function
1e8bb886
JH
64 * @param offset offset of value in data struct
65 * @param generator_contexts generator_contexts_t object where the context is written or read from
66 * @return - SUCCESS if succeeded
67 * - OUT_OF_RES if out of ressources
762ce218 68 */
1e8bb886 69 status_t (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset);
c3dc6f1a 70
762ce218 71 /**
7031a50b
JH
72 * Get size of current buffer in bytes.
73 *
74 * @param this private_generator_t object
75 * @return Size of buffer in bytes
76 */
77 size_t (*get_current_buffer_size) (private_generator_t *this);
78
79 /**
80 * Get free space of current buffer in bytes.
81 *
82 * @param this private_generator_t object
83 * @return space in buffer in bytes
84 */
85 size_t (*get_current_buffer_space) (private_generator_t *this);
86
87 /**
88 * Get length of data in buffer (in bytes).
89 *
90 * @param this private_generator_t object
91 * @return length of data in bytes
92 */
93 size_t (*get_current_data_length) (private_generator_t *this);
94
95 /**
96 * Get current offset in buffer (in bytes).
97 *
98 * @param this private_generator_t object
99 * @return offset in bytes
100 */
101 u_int32_t (*get_current_buffer_offset) (private_generator_t *this);
102
103 /**
104 * Generates a RESERVED BIT field or a RESERVED BYTE field and writes
105 * it to the buffer.
1e8bb886
JH
106 *
107 * @param this private_generator_t object
108 * @param generator_contexts generator_contexts_t object where the context is written or read from
109 * @param bits number of bits to generate
110 * @return - SUCCESS if succeeded
111 * - OUT_OF_RES if out of ressources
112 * - FAILED if bit count not supported
762ce218 113 */
1e8bb886
JH
114 status_t (*generate_reserved_field) (private_generator_t *this,int bits);
115
762ce218 116 /**
1e8bb886
JH
117 * Generates a FLAG field
118 *
119 * @param this private_generator_t object
120 * @param generator_contexts generator_contexts_t object where the context is written or read from
121 * @param offset offset of flag value in data struct
122 * @return - SUCCESS if succeeded
123 * - OUT_OF_RES if out of ressources
762ce218 124 */
1e8bb886
JH
125 status_t (*generate_flag) (private_generator_t *this,u_int32_t offset);
126
762ce218 127 /**
110dc83a
JH
128 * Writes the current buffer content into a chunk_t
129 *
130 * Memory of specific chunk_t gets allocated.
c3dc6f1a 131 *
1e8bb886 132 * @param this calling private_generator_t object
110dc83a
JH
133 * @param data pointer of chunk_t to write to
134 * @return
135 * - SUCCESSFUL if succeeded
136 * - OUT_OF_RES otherwise
762ce218 137 */
1e8bb886 138 status_t (*write_chunk) (private_generator_t *this,chunk_t *data);
110dc83a 139
f561c205
JH
140 /**
141 * Generates a bytestream from a chunk_t
142 *
143 * @param this private_generator_t object
144 * @param offset offset of chunk_t value in data struct
145 * @return - SUCCESS if succeeded
146 * - OUT_OF_RES if out of ressources
147 */
148 status_t (*generate_from_chunk) (private_generator_t *this,u_int32_t offset);
c3dc6f1a 149
762ce218 150 /**
c08ffafe
JH
151 * Makes sure enough space is available in buffer to store amount of bits.
152 *
153 * If buffer is to small to hold the specific amount of bits it
154 * is increased using reallocation function of allocator.
c3dc6f1a 155 *
1e8bb886 156 * @param this calling private_generator_t object
c08ffafe
JH
157 * @param bits number of bits to make available in buffer
158 * @return
159 * - SUCCESSFUL if succeeded
160 * - OUT_OF_RES otherwise
762ce218 161 */
1e8bb886 162 status_t (*make_space_available) (private_generator_t *this,size_t bits);
c3dc6f1a 163
c08ffafe
JH
164 /**
165 * Writes a specific amount of byte into the buffer.
166 *
167 * If buffer is to small to hold the specific amount of bytes it
168 * is increased.
169 *
1e8bb886 170 * @param this calling private_generator_t object
c08ffafe
JH
171 * @param bytes pointer to bytes to write
172 * @param number_of_bytes number of bytes to write into buffer
173 * @return
174 * - SUCCESSFUL if succeeded
175 * - OUT_OF_RES otherwise
176 */
1e8bb886
JH
177 status_t (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes);
178
110dc83a 179
f3c01a28
JH
180 /**
181 * Writes a specific amount of byte into the buffer at a specific offset.
182 *
183 * @warning buffer size is not check to hold the data if offset is to large.
184 *
185 * @param this calling private_generator_t object
186 * @param bytes pointer to bytes to write
187 * @param number_of_bytes number of bytes to write into buffer
188 * @param offset offset to write the data into
189 * @return
190 * - SUCCESSFUL if succeeded
191 * - OUT_OF_RES otherwise
192 */
193 status_t (*write_bytes_to_buffer_at_offset) (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset);
194
b82c0cab 195 /**
1e8bb886 196 * Buffer used to generate the data into.
b82c0cab 197 */
1e8bb886 198 u_int8_t *buffer;
79538669 199
5f08382c 200 /**
1e8bb886 201 * Current write position in buffer (one byte aligned).
5f08382c 202 */
1e8bb886 203 u_int8_t *out_position;
79538669 204
5f08382c 205 /**
1e8bb886 206 * Position of last byte in buffer.
5f08382c 207 */
1e8bb886 208 u_int8_t *roof_position;
79538669 209
7330c172 210 /**
1e8bb886 211 * Current bit writing to in current byte (between 0 and 7).
7330c172 212 */
1e8bb886
JH
213 size_t current_bit;
214
7330c172 215 /**
1e8bb886 216 * Associated data struct to read informations from.
7330c172 217 */
1e8bb886
JH
218 void * data_struct;
219
f3c01a28
JH
220 /*
221 * Last payload length position offset in the buffer
222 */
223 u_int32_t last_payload_length_position_offset;
224
2b9dd467
JH
225 /**
226 * Offset of the header length field in the buffer
227 */
228 u_int32_t header_length_position_offset;
229
bcf0c3af
JH
230 /**
231 * Last SPI size
232 */
233 u_int8_t last_spi_size;
234
f561c205
JH
235 /*
236 * Attribute format of the last generated transform attribute
237 *
238 * Used to check if a variable value field is used or not for
239 * the transform attribute value.
240 */
241 bool attribute_format;
242
243 /*
244 * Depending on the value of attribute_format this field is used
245 * to hold the length of the transform attribute in bytes
246 */
f561c205
JH
247 u_int16_t attribute_length;
248
5f08382c 249 /**
1e8bb886 250 * Associated Logger
5f08382c 251 */
1e8bb886 252 logger_t *logger;
b82c0cab
JH
253};
254
7031a50b
JH
255/**
256 * Implements private_generator_t's get_current_buffer_size function.
257 * See #private_generator_s.get_current_buffer_size.
258 */
259static size_t get_current_buffer_size (private_generator_t *this)
260{
261 return ((this->roof_position) - (this->buffer));
262}
263
264/**
265 * Implements private_generator_t's get_current_buffer_space function.
266 * See #private_generator_s.get_current_buffer_space.
267 */
268static size_t get_current_buffer_space (private_generator_t *this)
269{
270 /* we know, one byte more */
271 size_t space = (this->roof_position) - (this->out_position);
7031a50b
JH
272 return (space);
273}
274
275/**
276 * Implements private_generator_t's get_current_buffer_space function.
277 * See #private_generator_s.get_current_buffer_space.
278 */
279static size_t get_current_data_length (private_generator_t *this)
280{
281 return (this->out_position - this->buffer);
282}
283
284/**
285 * Implements private_generator_t's get_current_buffer_offset function.
286 * See #private_generator_s.get_current_buffer_offset.
287 */
288static u_int32_t get_current_buffer_offset (private_generator_t *this)
289{
290 return (this->out_position - this->buffer);
291}
292
293
5f08382c 294/**
c08ffafe
JH
295 * Implements private_generator_t's generate_u_int_type function.
296 * See #private_generator_s.generate_u_int_type.
5f08382c 297 */
1e8bb886 298static status_t generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset)
5f08382c 299{
79538669 300 size_t number_of_bits = 0;
762ce218 301 status_t status;
c3dc6f1a 302
7031a50b
JH
303 /* find out number of bits of each U_INT type to check for enough space
304 in buffer */
5f08382c
JH
305 switch (int_type)
306 {
307 case U_INT_4:
308 number_of_bits = 4;
309 break;
310 case U_INT_8:
311 number_of_bits = 8;
312 break;
313 case U_INT_16:
314 number_of_bits = 16;
315 break;
316 case U_INT_32:
317 number_of_bits = 32;
318 break;
319 case U_INT_64:
320 number_of_bits = 64;
321 break;
f561c205
JH
322 case ATTRIBUTE_TYPE:
323 number_of_bits = 15;
324 break;
fb71af18
JH
325 case IKE_SPI:
326 number_of_bits = 64;
327 break;
328
5f08382c
JH
329 default:
330 return FAILED;
331 }
7031a50b 332 /* U_INT Types of multiple then 8 bits must be aligned */
1e8bb886 333 if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
74683cbd 334 {
75ab0668
MW
335 this->logger->log(this->logger, ERROR, "U_INT Type %s is not 8 Bit aligned",
336 mapping_find(encoding_type_m,int_type));
f561c205 337 /* current bit has to be zero for values multiple of 8 bits */
74683cbd
JH
338 return FAILED;
339 }
7031a50b
JH
340
341 /* make sure enough space is available in buffer */
1e8bb886 342 status = this->make_space_available(this,number_of_bits);
762ce218
JH
343 if (status != SUCCESS)
344 {
345 return status;
346 }
7031a50b 347 /* now handle each u int type differently */
74683cbd 348 switch (int_type)
762ce218 349 {
74683cbd
JH
350 case U_INT_4:
351 {
1e8bb886 352 if (this->current_bit == 0)
c3dc6f1a 353 {
7031a50b 354 /* highval of current byte in buffer has to be set to the new value*/
1e8bb886 355 u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4;
7031a50b 356 /* lowval in buffer is not changed */
1e8bb886 357 u_int8_t low_val = *(this->out_position) & 0x0F;
7031a50b 358 /* highval is set, low_val is not changed */
1e8bb886 359 *(this->out_position) = high_val | low_val;
75ab0668 360 this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position));
74683cbd 361 /* write position is not changed, just bit position is moved */
1e8bb886 362 this->current_bit = 4;
74683cbd 363 }
1e8bb886 364 else if (this->current_bit == 4)
74683cbd 365 {
7031a50b 366 /* highval in buffer is not changed */
1e8bb886 367 u_int high_val = *(this->out_position) & 0xF0;
7031a50b 368 /* lowval of current byte in buffer has to be set to the new value*/
1e8bb886
JH
369 u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
370 *(this->out_position) = high_val | low_val;
75ab0668 371 this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position));
1e8bb886
JH
372 this->out_position++;
373 this->current_bit = 0;
c3dc6f1a 374
74683cbd
JH
375 }
376 else
377 {
75ab0668 378 this->logger->log(this->logger, ERROR, "U_INT_4 Type is not 4 Bit aligned");
74683cbd
JH
379 /* 4 Bit integers must have a 4 bit alignment */
380 return FAILED;
381 };
382 break;
383 }
74683cbd
JH
384 case U_INT_8:
385 {
7031a50b 386 /* 8 bit values are written as they are */
1e8bb886 387 *this->out_position = *((u_int8_t *)(this->data_struct + offset));
75ab0668 388 this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position));
1e8bb886 389 this->out_position++;
74683cbd 390 break;
c3dc6f1a 391
74683cbd 392 }
f561c205
JH
393 case ATTRIBUTE_TYPE:
394 {
7031a50b 395 /* attribute type must not change first bit uf current byte ! */
f561c205
JH
396 if (this->current_bit != 1)
397 {
75ab0668 398 this->logger->log(this->logger, ERROR, "ATTRIBUTE FORMAT flag is not set");
7031a50b 399 /* first bit has to be set! */
f561c205
JH
400 return FAILED;
401 }
7031a50b 402 /* get value of attribute format flag */
f561c205 403 u_int8_t attribute_format_flag = *(this->out_position) & 0x80;
7031a50b 404 /* get attribute type value as 16 bit integer*/
f561c205 405 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
7031a50b 406 /* last bit must be unset */
f561c205
JH
407 int16_val = int16_val & 0xFF7F;
408
409 int16_val = int16_val | attribute_format_flag;
75ab0668 410 this->logger->log(this->logger, RAW|MOST, " => 0x%x", int16_val);
7031a50b 411 /* write bytes to buffer (set bit is overwritten)*/
f561c205
JH
412 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
413 this->current_bit = 0;
414 break;
415
416 }
74683cbd
JH
417 case U_INT_16:
418 {
1e8bb886 419 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
75ab0668 420 this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)&int16_val, sizeof(int16_val));
1e8bb886 421 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
74683cbd
JH
422 break;
423 }
424 case U_INT_32:
425 {
1e8bb886 426 u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset)));
75ab0668 427 this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)&int32_val, sizeof(int32_val));
1e8bb886 428 this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t));
74683cbd
JH
429 break;
430 }
431 case U_INT_64:
432 {
7031a50b 433 /* 64 bit integers are written as two 32 bit integers */
1e8bb886
JH
434 u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset)));
435 u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1));
75ab0668
MW
436 this->logger->log_bytes(this->logger, RAW|MOST, " => (low)", (void*)&int32_val_low, sizeof(int32_val_low));
437 this->logger->log_bytes(this->logger, RAW|MOST, " => (high)", (void*)&int32_val_high, sizeof(int32_val_high));
7031a50b 438 /* TODO add support for big endian machines */
1e8bb886
JH
439 this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t));
440 this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t));
74683cbd
JH
441 break;
442 }
fb71af18
JH
443
444 case IKE_SPI:
445 {
446 /* 64 bit are written as they come :-) */
447 this->write_bytes_to_buffer(this,(this->data_struct + offset),sizeof(u_int64_t));
448 this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)(this->data_struct + offset), sizeof(u_int64_t));
449 break;
450 }
c3dc6f1a 451
74683cbd 452 default:
75ab0668 453 this->logger->log(this->logger, ERROR, "U_INT Type %s is not supported", mapping_find(encoding_type_m,int_type));
762ce218 454 return FAILED;
762ce218 455 }
5f08382c
JH
456 return SUCCESS;
457}
458
1e8bb886
JH
459/**
460 * Implements private_generator_t's generate_reserved_field function.
461 * See #private_generator_s.generate_reserved_field.
462 */
75ab0668 463static status_t generate_reserved_field(private_generator_t *this,int bits)
7330c172
JH
464{
465 status_t status;
466
7031a50b 467 /* only one bit or 8 bit fields are supported */
7330c172
JH
468 if ((bits != 1) && (bits != 8))
469 {
75ab0668 470 this->logger->log(this->logger, ERROR, "Reserved field of %d bits cannot be generated", bits);
7330c172
JH
471 return FAILED;
472 }
7031a50b 473 /* make sure enough space is available in buffer */
1e8bb886 474 status = this->make_space_available(this,bits);
7330c172
JH
475 if (status != SUCCESS)
476 {
477 return status;
478 }
479
480 if (bits == 1)
481 {
7031a50b 482 /* one bit processing */
1e8bb886 483 u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
1e8bb886 484 *(this->out_position) = *(this->out_position) & reserved_bit;
de257bc0
JH
485 if (this->current_bit == 0)
486 {
487 /* memory must be zero */
488 *(this->out_position) = 0x00;
489 }
490
491
1e8bb886
JH
492 this->current_bit++;
493 if (this->current_bit >= 8)
7330c172 494 {
1e8bb886
JH
495 this->current_bit = this->current_bit % 8;
496 this->out_position++;
7330c172
JH
497 }
498 }
499 else
500 {
7031a50b 501 /* one byte processing*/
1e8bb886 502 if (this->current_bit > 0)
7330c172 503 {
75ab0668
MW
504 this->logger->log(this->logger, ERROR,
505 "Reserved field cannot be written cause allignement of current bit is %d",
506 this->current_bit);
7330c172
JH
507 return FAILED;
508 }
1e8bb886
JH
509 *(this->out_position) = 0x00;
510 this->out_position++;
7330c172
JH
511 }
512
513 return SUCCESS;
514
515
516}
517
1e8bb886
JH
518/**
519 * Implements private_generator_t's generate_flag function.
520 * See #private_generator_s.generate_flag.
521 */
522static status_t generate_flag (private_generator_t *this,u_int32_t offset)
7330c172
JH
523{
524 status_t status;
7031a50b
JH
525 /* value of current flag */
526 u_int8_t flag_value;
527 /* position of flag in current byte */
528 u_int8_t flag;
7330c172 529
7031a50b
JH
530 /* if the value in the data_struct is TRUE, flag_value is set to 1, 0 otherwise */
531 flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
532 /* get flag position */
533 flag = (flag_value << (7 - this->current_bit));
534
535 /* make sure one bit is available in buffer */
1e8bb886 536 status = this->make_space_available(this,1);
7330c172
JH
537 if (status != SUCCESS)
538 {
539 return status;
540 }
de257bc0
JH
541 if (this->current_bit == 0)
542 {
543 /* memory must be zero */
544 *(this->out_position) = 0x00;
545 }
7330c172 546
1e8bb886 547 *(this->out_position) = *(this->out_position) | flag;
75ab0668
MW
548
549
550 this->logger->log(this->logger, RAW|MOST, " => 0x0%x", *(this->out_position));
7330c172 551
1e8bb886
JH
552 this->current_bit++;
553 if (this->current_bit >= 8)
554 {
555 this->current_bit = this->current_bit % 8;
556 this->out_position++;
557 }
558 return SUCCESS;
559}
560
f561c205
JH
561/**
562 * Implements private_generator_t's generate_from_chunk function.
563 * See #private_generator_s.generate_from_chunk.
564 */
565static status_t generate_from_chunk (private_generator_t *this,u_int32_t offset)
566{
567 if (this->current_bit != 0)
568 {
75ab0668 569 this->logger->log(this->logger, ERROR, "can not generate a chunk at Bitpos %d", this->current_bit);
f561c205
JH
570 return FAILED;
571 }
75ab0668 572
7031a50b 573 /* position in buffer */
f561c205
JH
574 chunk_t *attribute_value = (chunk_t *)(this->data_struct + offset);
575
75ab0668
MW
576 this->logger->log_chunk(this->logger, RAW|MOST, " =>", attribute_value);
577
7031a50b
JH
578 /* use write_bytes_to_buffer function to do the job */
579 return this->write_bytes_to_buffer(this,attribute_value->ptr,attribute_value->len);
f561c205
JH
580
581}
582
1e8bb886
JH
583/**
584 * Implements private_generator_t's generator_context_make_space_available function.
585 * See #private_generator_s.generator_context_make_space_available.
586 */
587static status_t make_space_available (private_generator_t *this, size_t bits)
588{
7031a50b 589 while (((this->get_current_buffer_space(this) * 8) - this->current_bit) < bits)
7330c172 590 {
7031a50b
JH
591 /* must increase buffer */
592 u_int8_t *new_buffer;
593 size_t old_buffer_size = this->get_current_buffer_size(this);
1e8bb886
JH
594 size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
595 size_t out_position_offset = ((this->out_position) - (this->buffer));
1e8bb886 596
75ab0668
MW
597 this->logger->log(this->logger, CONTROL|MOST, "increased gen buffer from %d to %d byte",
598 old_buffer_size, new_buffer_size);
7031a50b
JH
599
600 /* Reallocate space for new buffer */
1e8bb886
JH
601 new_buffer = allocator_realloc(this->buffer,new_buffer_size);
602 if (new_buffer == NULL)
603 {
75ab0668 604 this->logger->log(this->logger, ERROR, "reallocation of gen buffer failed!!!");
1e8bb886
JH
605 return OUT_OF_RES;
606 }
607
608 this->buffer = new_buffer;
609
610 this->out_position = (this->buffer + out_position_offset);
611 this->roof_position = (this->buffer + new_buffer_size);
7330c172
JH
612 }
613 return SUCCESS;
614}
615
5f08382c 616/**
1e8bb886
JH
617 * Implements private_generator_t's write_bytes_to_buffer function.
618 * See #private_generator_s.write_bytes_to_buffer.
5f08382c 619 */
75ab0668 620static status_t write_bytes_to_buffer (private_generator_t *this,void * bytes, size_t number_of_bytes)
5f08382c 621{
5f08382c 622 int i;
762ce218 623 status_t status;
7031a50b
JH
624 u_int8_t *read_position = (u_int8_t *) bytes;
625
1e8bb886 626 status = this->make_space_available(this,number_of_bytes * 8);
1e8bb886
JH
627 if (status != SUCCESS)
628 {
629 return status;
630 }
631
632 for (i = 0; i < number_of_bytes; i++)
5f08382c 633 {
1e8bb886
JH
634 *(this->out_position) = *(read_position);
635 read_position++;
636 this->out_position++;
637 }
638 return status;
639}
640
f3c01a28
JH
641/**
642 * Implements private_generator_t's write_bytes_to_buffer_at_offset function.
643 * See #private_generator_s.write_bytes_to_buffer_at_offset.
f3c01a28
JH
644 */
645static status_t write_bytes_to_buffer_at_offset (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset)
646{
f3c01a28 647 int i;
7031a50b
JH
648 status_t status;
649 u_int8_t *read_position = (u_int8_t *) bytes;
650 u_int8_t *write_position;
651 u_int32_t free_space_after_offset = (this->get_current_buffer_size(this) - offset);
652
653 /* check first if enough space for new data is available */
654 if (number_of_bytes > free_space_after_offset)
655 {
656 status = this->make_space_available(this,(number_of_bytes - free_space_after_offset) * 8);
657 }
f3c01a28 658
7031a50b 659 write_position = this->buffer + offset;
f3c01a28
JH
660 for (i = 0; i < number_of_bytes; i++)
661 {
662 *(write_position) = *(read_position);
663 read_position++;
664 write_position++;
665 }
666 return SUCCESS;
667}
668
1e8bb886
JH
669/**
670 * Implements generator_t's write_chunk function.
671 * See #generator_s.write_chunk.
672 */
673static status_t write_to_chunk (private_generator_t *this,chunk_t *data)
674{
7031a50b 675 size_t data_length = this->get_current_data_length(this);
2b9dd467
JH
676 u_int32_t header_length_field = data_length;
677
678 /* write length into header length field */
679 if (this->header_length_position_offset > 0)
680 {
681 u_int32_t int32_val = htonl(header_length_field);
682 this->write_bytes_to_buffer_at_offset(this,&int32_val,sizeof(u_int32_t),this->header_length_position_offset);
683 }
1e8bb886
JH
684
685 if (this->current_bit > 0)
686 data_length++;
687 data->ptr = allocator_alloc(data_length);
688 if (data->ptr == NULL)
689 {
690 data->len = 0;
75ab0668 691 this->logger->log(this->logger, ERROR, "not enougth ressources to allocate chunk");
5f08382c
JH
692 return OUT_OF_RES;
693 }
1e8bb886
JH
694 memcpy(data->ptr,this->buffer,data_length);
695 data->len = data_length;
75ab0668
MW
696
697 this->logger->log_chunk(this->logger, RAW, "generated data of this parser", data);
698
1e8bb886
JH
699 return SUCCESS;
700}
701
1e8bb886
JH
702/**
703 * Implements generator_t's generate_payload function.
704 * See #generator_s.generate_payload.
705 */
706static status_t generate_payload (private_generator_t *this,payload_t *payload)
707{
708 int i;
709 status_t status;
710 this->data_struct = payload;
711 size_t rule_count;
712 encoding_rule_t *rules;
7031a50b 713 payload_type_t payload_type;
75ab0668 714 u_int8_t *payload_start;
1e8bb886 715
7031a50b
JH
716 /* get payload type */
717 payload_type = payload->get_type(payload);
8166bcec
JH
718 /* spi size has to get reseted */
719 this->last_spi_size = 0;
1e8bb886 720
75ab0668
MW
721 payload_start = this->out_position;
722
723 this->logger->log(this->logger, CONTROL, "generating payload of type %s",
724 mapping_find(payload_type_m,payload_type));
1e8bb886 725
7031a50b 726 /* each payload has its own encoding rules */
1e8bb886
JH
727 payload->get_encoding_rules(payload,&rules,&rule_count);
728
729 for (i = 0; i < rule_count;i++)
5f08382c 730 {
762ce218 731 status = SUCCESS;
75ab0668
MW
732 this->logger->log(this->logger, CONTROL|MORE, " generating rule %d %s",
733 i, mapping_find(encoding_type_m,rules[i].type));
1e8bb886 734 switch (rules[i].type)
5f08382c 735 {
fb71af18 736 /* all u int values, IKE_SPI and ATTRIBUTE_TYPE are generated in generate_u_int_type */
5f08382c
JH
737 case U_INT_4:
738 case U_INT_8:
739 case U_INT_16:
740 case U_INT_32:
741 case U_INT_64:
fb71af18 742 case IKE_SPI:
7031a50b
JH
743 case ATTRIBUTE_TYPE:
744 {
1e8bb886 745 status = this->generate_u_int_type(this,rules[i].type,rules[i].offset);
5f08382c 746 break;
7031a50b 747 }
5f08382c 748 case RESERVED_BIT:
e6fbf1d2 749 {
1e8bb886 750 status = this->generate_reserved_field(this,1);
e6fbf1d2
JH
751 break;
752 }
5f08382c 753 case RESERVED_BYTE:
e6fbf1d2 754 {
1e8bb886 755 status = this->generate_reserved_field(this,8);
e6fbf1d2 756 break;
7330c172 757 }
5f08382c 758 case FLAG:
e6fbf1d2 759 {
1e8bb886 760 status = this->generate_flag(this,rules[i].offset);
e6fbf1d2
JH
761 break;
762 }
1b89ef11 763 case PAYLOAD_LENGTH:
7031a50b
JH
764 {
765 /* position of payload lenght field is temporary stored */
766 this->last_payload_length_position_offset = this->get_current_buffer_offset(this);
1b89ef11
JH
767 /* payload length is generated like an U_INT_16 */
768 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
769 break;
7031a50b 770 }
1b89ef11 771 case HEADER_LENGTH:
7031a50b
JH
772 {
773 /* position of header length field is temporary stored */
774 this->header_length_position_offset = this->get_current_buffer_offset(this);
1b89ef11 775 /* header length is generated like an U_INT_32 */
1e8bb886 776 status = this->generate_u_int_type(this,U_INT_32,rules[i].offset);
7330c172 777 break;
7031a50b 778 }
5f08382c 779 case SPI_SIZE:
bcf0c3af
JH
780 /* spi size is handled as 8 bit unsigned integer */
781 status = this->generate_u_int_type(this,U_INT_8,rules[i].offset);
7031a50b 782 /* last spi size is temporary stored */
bcf0c3af 783 this->last_spi_size = *((u_int8_t *)(this->data_struct + rules[i].offset));
f3c01a28 784 break;
bcf0c3af
JH
785 case SPI:
786 {
7031a50b 787 /* the SPI value is generated from chunk */
bcf0c3af
JH
788 status = this->generate_from_chunk(this,rules[i].offset);
789 break;
790 }
113f461e
JH
791 case KEY_EXCHANGE_DATA:
792 {
793 /* the Key Exchange Data value is generated from chunk */
794 status = this->generate_from_chunk(this,rules[i].offset);
795 if (status != SUCCESS)
796 {
75ab0668 797 this->logger->log(this->logger, ERROR, "could no write key exchange data from chunk");
113f461e
JH
798 return status;
799 }
800
113f461e
JH
801 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
802 /* Length of KE_PAYLOAD is calculated */
803 u_int16_t length_of_ke_payload = KE_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len;
804
805 u_int16_t int16_val = htons(length_of_ke_payload);
806 status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
807 if (status != SUCCESS)
808 {
75ab0668 809 this->logger->log(this->logger, ERROR, "could not write payload length into buffer");
113f461e
JH
810 return status;
811 }
812 break;
8166bcec
JH
813 }
814 case NOTIFICATION_DATA:
815 {
816 /* the Notification Data value is generated from chunk */
817 status = this->generate_from_chunk(this,rules[i].offset);
818 if (status != SUCCESS)
819 {
75ab0668 820 this->logger->log(this->logger, ERROR, "Could not generate notification data from chunk");
8166bcec
JH
821 return status;
822 }
823
824 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
825 /* Length of Notification PAYLOAD is calculated */
826 u_int16_t length_of_notify_payload = NOTIFY_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len;
827 length_of_notify_payload += this->last_spi_size;
828 u_int16_t int16_val = htons(length_of_notify_payload);
829
830 status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
831 if (status != SUCCESS)
832 {
75ab0668 833 this->logger->log(this->logger, ERROR, "could not write payload length into buffer");
8166bcec
JH
834 return status;
835 }
836 break;
837 }
2a489f33
JH
838 case NONCE_DATA:
839 {
840 /* the Nonce Data value is generated from chunk */
75ab0668
MW
841 status = this->generate_from_chunk(this, rules[i].offset);
842
2a489f33
JH
843 if (status != SUCCESS)
844 {
75ab0668 845 this->logger->log(this->logger, ERROR, "could not write nonce data from chunk");
2a489f33
JH
846 return status;
847 }
848
849 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
850 /* Length of nonce PAYLOAD is calculated */
851 u_int16_t length_of_nonce_payload = NONCE_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len;
852 u_int16_t int16_val = htons(length_of_nonce_payload);
853
854 status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
855 if (status != SUCCESS)
856 {
75ab0668 857 this->logger->log(this->logger, ERROR, "could not write payload length into buffer");
2a489f33
JH
858 return status;
859 }
860 break;
861 }
7f613a4b
JH
862 case PROPOSALS:
863 {
8bf27ddf 864 /* before iterative generate the transforms, store the current payload length position */
7f613a4b 865 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
8bf27ddf 866 /* Length of SA_PAYLOAD is calculated */
7f613a4b
JH
867 u_int16_t length_of_sa_payload = SA_PAYLOAD_HEADER_LENGTH;
868 u_int16_t int16_val;
8bf27ddf 869 /* proposals are stored in a linked list and so accessed */
7f613a4b
JH
870 linked_list_t *proposals = *((linked_list_t **)(this->data_struct + rules[i].offset));
871
872 linked_list_iterator_t *iterator;
873 /* create forward iterator */
874 status = proposals->create_iterator(proposals,&iterator,TRUE);
875 if (status != SUCCESS)
876 {
75ab0668 877 this->logger->log(this->logger, ERROR, "could not create iterator for proposals");
7f613a4b
JH
878 return status;
879 }
8bf27ddf 880 /* every proposal is processed (iterative call )*/
7f613a4b
JH
881 while (iterator->has_next(iterator))
882 {
883 payload_t *current_proposal;
884 u_int32_t before_generate_position_offset;
885 u_int32_t after_generate_position_offset;
886
887 status = iterator->current(iterator,(void **)&current_proposal);
888 if (status != SUCCESS)
889 {
890 iterator->destroy(iterator);
891 return status;
892 }
8bf27ddf 893 before_generate_position_offset = this->get_current_buffer_offset(this);
7f613a4b 894 status = this->public.generate_payload(&(this->public),current_proposal);
8bf27ddf 895 after_generate_position_offset = this->get_current_buffer_offset(this);
7f613a4b
JH
896 if (status != SUCCESS)
897 {
8bf27ddf 898 iterator->destroy(iterator);
7f613a4b
JH
899 return status;
900 }
901
902 /* increase size of transform */
903 length_of_sa_payload += (after_generate_position_offset - before_generate_position_offset);
904 }
7f613a4b 905 iterator->destroy(iterator);
7f613a4b
JH
906
907 int16_val = htons(length_of_sa_payload);
8bf27ddf
JH
908 status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
909 if (status != SUCCESS)
910 {
75ab0668 911 this->logger->log(this->logger, ERROR, "could not write payload length into buffer");
8bf27ddf
JH
912 return status;
913 }
7f613a4b
JH
914 break;
915 }
916
bcf0c3af 917 case TRANSFORMS:
8bf27ddf 918 {
bcf0c3af
JH
919 /* before iterative generate the transforms, store the current length position */
920 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
bcf0c3af
JH
921 u_int16_t length_of_proposal = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->last_spi_size;
922 u_int16_t int16_val;
923 linked_list_t *transforms = *((linked_list_t **)(this->data_struct + rules[i].offset));
bcf0c3af 924 linked_list_iterator_t *iterator;
75ab0668 925
bcf0c3af
JH
926 /* create forward iterator */
927 status = transforms->create_iterator(transforms,&iterator,TRUE);
928 if (status != SUCCESS)
929 {
930 return status;
931 }
932 while (iterator->has_next(iterator))
933 {
934 payload_t *current_transform;
935 u_int32_t before_generate_position_offset;
936 u_int32_t after_generate_position_offset;
937
938 status = iterator->current(iterator,(void **)&current_transform);
939 if (status != SUCCESS)
940 {
941 iterator->destroy(iterator);
942 return status;
943 }
944
8bf27ddf 945 before_generate_position_offset = this->get_current_buffer_offset(this);
7f613a4b 946 status = this->public.generate_payload(&(this->public),current_transform);
8bf27ddf 947 after_generate_position_offset = this->get_current_buffer_offset(this);
7f613a4b
JH
948 if (status != SUCCESS)
949 {
8bf27ddf 950 iterator->destroy(iterator);
7f613a4b
JH
951 return status;
952 }
bcf0c3af
JH
953
954 /* increase size of transform */
955 length_of_proposal += (after_generate_position_offset - before_generate_position_offset);
956 }
957
958 iterator->destroy(iterator);
75ab0668 959
bcf0c3af
JH
960 int16_val = htons(length_of_proposal);
961 this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
962
963 break;
964 }
f3c01a28
JH
965 case TRANSFORM_ATTRIBUTES:
966 {
bcf0c3af 967 /* before iterative generate the transform attributes, store the current length position */
f3c01a28
JH
968 u_int32_t transform_length_position_offset = this->last_payload_length_position_offset;
969
970 u_int16_t length_of_transform = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
971 u_int16_t int16_val;
972 linked_list_t *transform_attributes =*((linked_list_t **)(this->data_struct + rules[i].offset));
973
974 linked_list_iterator_t *iterator;
975 /* create forward iterator */
976 status = transform_attributes->create_iterator(transform_attributes,&iterator,TRUE);
977 if (status != SUCCESS)
978 {
979 return status;
980 }
981 while (iterator->has_next(iterator))
982 {
983 payload_t *current_attribute;
984 u_int32_t before_generate_position_offset;
985 u_int32_t after_generate_position_offset;
bcf0c3af 986
f3c01a28
JH
987 status = iterator->current(iterator,(void **)&current_attribute);
988 if (status != SUCCESS)
989 {
990 iterator->destroy(iterator);
991 return status;
992 }
993
8bf27ddf 994 before_generate_position_offset = this->get_current_buffer_offset(this);
f3c01a28 995 this->public.generate_payload(&(this->public),current_attribute);
8bf27ddf 996 after_generate_position_offset = this->get_current_buffer_offset(this);
f3c01a28
JH
997
998 /* increase size of transform */
999 length_of_transform += (after_generate_position_offset - before_generate_position_offset);
1000 }
1001
1002 iterator->destroy(iterator);
f561c205 1003
f3c01a28
JH
1004 int16_val = htons(length_of_transform);
1005 this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),transform_length_position_offset);
1006
1007 break;
1008 }
f561c205
JH
1009 case ATTRIBUTE_FORMAT:
1010 {
f561c205 1011 status = this->generate_flag(this,rules[i].offset);
8bf27ddf 1012 /* Attribute format is a flag which is stored in context*/
f561c205
JH
1013 this->attribute_format = *((bool *) (this->data_struct + rules[i].offset));
1014 break;
1015 }
7031a50b 1016
f561c205
JH
1017 case ATTRIBUTE_LENGTH_OR_VALUE:
1018 {
f561c205
JH
1019 if (this->attribute_format == FALSE)
1020 {
1021 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
1022 /* this field hold the length of the attribute */
1023 this->attribute_length = *((u_int16_t *)(this->data_struct + rules[i].offset));
1024 }
1025 else
1026 {
daa1c00e
MW
1027 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
1028// status = this->write_bytes_to_buffer(this,(this->data_struct + rules[i].offset),2);
f561c205 1029 }
5f08382c 1030 break;
f561c205
JH
1031 }
1032 case ATTRIBUTE_VALUE:
1033 {
1034 if (this->attribute_format == FALSE)
1035 {
75ab0668 1036 this->logger->log(this->logger, CONTROL|MOST, "attribute value has not fixed size");
f561c205
JH
1037 /* the attribute value is generated */
1038 status = this->generate_from_chunk(this,rules[i].offset);
1039 }
1040 break;
1041 }
1042 default:
75ab0668
MW
1043 this->logger->log(this->logger, ERROR, "field type %s is not supported",
1044 mapping_find(encoding_type_m,rules[i].type));
f561c205 1045 return NOT_SUPPORTED;
5f08382c 1046 }
5f08382c 1047 }
75ab0668
MW
1048 this->logger->log_bytes(this->logger, RAW|MORE, "generated data for this payload",
1049 payload_start, this->out_position-payload_start);
79538669 1050
762ce218 1051 return status;
b82c0cab
JH
1052}
1053
1054/**
c08ffafe
JH
1055 * Implements generator_t's destroy function.
1056 * See #generator_s.destroy.
b82c0cab
JH
1057 */
1058static status_t destroy(private_generator_t *this)
1059{
1e8bb886
JH
1060 allocator_free(this->buffer);
1061 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
79538669 1062 allocator_free(this);
b82c0cab
JH
1063 return SUCCESS;
1064}
1065
5f08382c
JH
1066/*
1067 * Described in header
1068 */
1e8bb886 1069generator_t * generator_create()
b82c0cab 1070{
5f08382c 1071 private_generator_t *this;
79538669 1072
6c4b815f 1073 this = allocator_alloc_thing(private_generator_t);
5f08382c
JH
1074 if (this == NULL)
1075 {
1076 return NULL;
1077 }
79538669 1078
762ce218 1079 /* initiate public functions */
1e8bb886 1080 this->public.generate_payload = (status_t(*)(generator_t*, payload_t *)) generate_payload;
b82c0cab 1081 this->public.destroy = (status_t(*)(generator_t*)) destroy;
1e8bb886
JH
1082 this->public.write_to_chunk = (status_t (*) (generator_t *,chunk_t *)) write_to_chunk;
1083
1084
762ce218 1085 /* initiate private functions */
7031a50b
JH
1086 this->get_current_buffer_size = get_current_buffer_size;
1087 this->get_current_buffer_space = get_current_buffer_space;
1088 this->get_current_data_length = get_current_data_length;
1089 this->get_current_buffer_offset = get_current_buffer_offset;
5f08382c 1090 this->generate_u_int_type = generate_u_int_type;
7330c172
JH
1091 this->generate_reserved_field = generate_reserved_field;
1092 this->generate_flag = generate_flag;
f561c205 1093 this->generate_from_chunk = generate_from_chunk;
1e8bb886
JH
1094 this->make_space_available = make_space_available;
1095 this->write_bytes_to_buffer = write_bytes_to_buffer;
f3c01a28 1096 this->write_bytes_to_buffer_at_offset = write_bytes_to_buffer_at_offset;
79538669 1097
79538669 1098
1e8bb886
JH
1099 /* allocate memory for buffer */
1100 this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE);
1101 if (this->buffer == NULL)
1102 {
1103 allocator_free(this);
1104 return NULL;
1105 }
1106
1107 /* initiate private variables */
1108 this->out_position = this->buffer;
1109 this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
1110 this->data_struct = NULL;
1111 this->current_bit = 0;
f3c01a28 1112 this->last_payload_length_position_offset = 0;
2b9dd467 1113 this->header_length_position_offset = 0;
1e8bb886 1114 this->logger = global_logger_manager->create_logger(global_logger_manager,GENERATOR,NULL);
75ab0668
MW
1115 this->logger->disable_level(this->logger, FULL);
1116 this->logger->enable_level(this->logger, CONTROL);
8bf27ddf
JH
1117
1118 if (this->logger == NULL)
1119 {
1120 allocator_free(this->buffer);
1121 allocator_free(this);
1122 return NULL;
1123 }
b82c0cab
JH
1124 return &(this->public);
1125}