2 * Copyright (C) 2005-2009 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
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>.
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
19 #include <arpa/inet.h>
22 #include "generator.h"
26 #include <utils/linked_list.h>
27 #include <encoding/payloads/payload.h>
28 #include <encoding/payloads/proposal_substructure.h>
29 #include <encoding/payloads/transform_substructure.h>
30 #include <encoding/payloads/sa_payload.h>
31 #include <encoding/payloads/ke_payload.h>
32 #include <encoding/payloads/notify_payload.h>
33 #include <encoding/payloads/nonce_payload.h>
34 #include <encoding/payloads/id_payload.h>
35 #include <encoding/payloads/auth_payload.h>
36 #include <encoding/payloads/cert_payload.h>
37 #include <encoding/payloads/certreq_payload.h>
38 #include <encoding/payloads/ts_payload.h>
39 #include <encoding/payloads/delete_payload.h>
40 #include <encoding/payloads/vendor_id_payload.h>
41 #include <encoding/payloads/cp_payload.h>
42 #include <encoding/payloads/configuration_attribute.h>
43 #include <encoding/payloads/eap_payload.h>
44 #include <encoding/payloads/unknown_payload.h>
47 * Generating is done in a data buffer.
48 * This is the start size of this buffer in bytes.
50 #define GENERATOR_DATA_BUFFER_SIZE 500
53 * Number of bytes to increase the buffer, if it is too small.
55 #define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500
57 typedef struct private_generator_t private_generator_t
;
60 * Private part of a generator_t object.
62 struct private_generator_t
{
64 * Public part of a generator_t object.
69 * Buffer used to generate the data into.
74 * Current write position in buffer (one byte aligned).
76 u_int8_t
*out_position
;
79 * Position of last byte in buffer.
81 u_int8_t
*roof_position
;
84 * Current bit writing to in current byte (between 0 and 7).
89 * Associated data struct to read informations from.
94 * Offset of the header length field in the buffer.
96 u_int32_t header_length_offset
;
99 * Attribute format of the last generated transform attribute.
101 * Used to check if a variable value field is used or not for
102 * the transform attribute value.
104 bool attribute_format
;
107 * Depending on the value of attribute_format this field is used
108 * to hold the length of the transform attribute in bytes.
110 u_int16_t attribute_length
;
114 * Get size of current buffer in bytes.
116 static int get_size(private_generator_t
*this)
118 return this->roof_position
- this->buffer
;
122 * Get free space of current buffer in bytes.
124 static int get_space(private_generator_t
*this)
126 return this->roof_position
- this->out_position
;
130 * Get length of data in buffer (in bytes).
132 static int get_length(private_generator_t
*this)
134 return this->out_position
- this->buffer
;
138 * Get current offset in buffer (in bytes).
140 static u_int32_t
get_offset(private_generator_t
*this)
142 return this->out_position
- this->buffer
;
146 * Makes sure enough space is available in buffer to store amount of bits.
148 static void make_space_available(private_generator_t
*this, int bits
)
150 while ((get_space(this) * 8 - this->current_bit
) < bits
)
152 int old_buffer_size
, new_buffer_size
, out_position_offset
;
154 old_buffer_size
= get_size(this);
155 new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
156 out_position_offset
= this->out_position
- this->buffer
;
158 DBG2(DBG_ENC
, "increasing gen buffer from %d to %d byte",
159 old_buffer_size
, new_buffer_size
);
161 this->buffer
= realloc(this->buffer
,new_buffer_size
);
162 this->out_position
= (this->buffer
+ out_position_offset
);
163 this->roof_position
= (this->buffer
+ new_buffer_size
);
168 * Writes a specific amount of byte into the buffer.
170 static void write_bytes_to_buffer(private_generator_t
*this, void *bytes
,
174 u_int8_t
*read_position
= (u_int8_t
*)bytes
;
176 make_space_available(this, number_of_bytes
* 8);
178 for (i
= 0; i
< number_of_bytes
; i
++)
180 *(this->out_position
) = *(read_position
);
182 this->out_position
++;
187 * Generates a U_INT-Field type and writes it to buffer.
189 static void generate_u_int_type(private_generator_t
*this,
190 encoding_type_t int_type
,u_int32_t offset
)
192 int number_of_bits
= 0;
194 /* find out number of bits of each U_INT type to check for enough space */
208 case CONFIGURATION_ATTRIBUTE_LENGTH
:
221 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
222 encoding_type_names
, int_type
);
225 if ((number_of_bits
% 8) == 0 && this->current_bit
!= 0)
227 DBG1(DBG_ENC
, "U_INT Type %N is not 8 Bit aligned",
228 encoding_type_names
, int_type
);
232 make_space_available(this, number_of_bits
);
239 if (this->current_bit
== 0)
241 /* high of current byte in buffer has to be set to the new value*/
242 high
= *((u_int8_t
*)(this->data_struct
+ offset
)) << 4;
243 /* low in buffer is not changed */
244 low
= *(this->out_position
) & 0x0F;
245 /* high is set, low_val is not changed */
246 *(this->out_position
) = high
| low
;
247 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
248 /* write position is not changed, just bit position is moved */
249 this->current_bit
= 4;
251 else if (this->current_bit
== 4)
253 /* high in buffer is not changed */
254 high
= *(this->out_position
) & 0xF0;
255 /* low of current byte in buffer has to be set to the new value*/
256 low
= *((u_int8_t
*)(this->data_struct
+ offset
)) & 0x0F;
257 *(this->out_position
) = high
| low
;
258 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
259 this->out_position
++;
260 this->current_bit
= 0;
264 DBG1(DBG_ENC
, "U_INT_4 Type is not 4 Bit aligned");
265 /* 4 Bit integers must have a 4 bit alignment */
275 /* 8 bit values are written as they are */
276 *this->out_position
= *((u_int8_t
*)(this->data_struct
+ offset
));
277 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
278 this->out_position
++;
283 u_int8_t attribute_format_flag
;
286 /* attribute type must not change first bit of current byte */
287 if (this->current_bit
!= 1)
289 DBG1(DBG_ENC
, "ATTRIBUTE FORMAT flag is not set");
292 attribute_format_flag
= *(this->out_position
) & 0x80;
293 /* get attribute type value as 16 bit integer*/
294 val
= *((u_int16_t
*)(this->data_struct
+ offset
));
295 /* unset most significant bit */
297 if (attribute_format_flag
)
302 DBG3(DBG_ENC
, " => %d", val
);
303 /* write bytes to buffer (set bit is overwritten) */
304 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
305 this->current_bit
= 0;
311 case CONFIGURATION_ATTRIBUTE_LENGTH
:
313 u_int16_t val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
314 DBG3(DBG_ENC
, " => %b", &val
, sizeof(u_int16_t
));
315 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
320 u_int32_t val
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
321 DBG3(DBG_ENC
, " => %b", &val
, sizeof(u_int32_t
));
322 write_bytes_to_buffer(this, &val
, sizeof(u_int32_t
));
327 /* 64 bit are written as-is, no host order conversion */
328 write_bytes_to_buffer(this, this->data_struct
+ offset
,
330 DBG3(DBG_ENC
, " => %b", this->data_struct
+ offset
,
336 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
337 encoding_type_names
, int_type
);
344 * Generate a FLAG filed
346 static void generate_flag(private_generator_t
*this, u_int32_t offset
)
351 flag_value
= (*((bool *) (this->data_struct
+ offset
))) ?
1 : 0;
352 /* get flag position */
353 flag
= (flag_value
<< (7 - this->current_bit
));
355 /* make sure one bit is available in buffer */
356 make_space_available(this, 1);
357 if (this->current_bit
== 0)
359 /* memory must be zero */
360 *(this->out_position
) = 0x00;
363 *(this->out_position
) = *(this->out_position
) | flag
;
364 DBG3(DBG_ENC
, " => %d", *this->out_position
);
367 if (this->current_bit
>= 8)
369 this->current_bit
= this->current_bit
% 8;
370 this->out_position
++;
375 * Generates a bytestream from a chunk_t.
377 static void generate_from_chunk(private_generator_t
*this, u_int32_t offset
)
381 if (this->current_bit
!= 0)
383 DBG1(DBG_ENC
, "can not generate a chunk at Bitpos %d", this->current_bit
);
387 value
= (chunk_t
*)(this->data_struct
+ offset
);
388 DBG3(DBG_ENC
, " => %B", value
);
390 write_bytes_to_buffer(this, value
->ptr
, value
->len
);
393 METHOD(generator_t
, get_chunk
, chunk_t
,
394 private_generator_t
*this, u_int32_t
**lenpos
)
398 *lenpos
= (u_int32_t
*)(this->buffer
+ this->header_length_offset
);
399 data
= chunk_create(this->buffer
, get_length(this));
400 DBG3(DBG_ENC
, "generated data of this generator %B", &data
);
404 METHOD(generator_t
, generate_payload
, void,
405 private_generator_t
*this,payload_t
*payload
)
407 int i
, offset_start
, rule_count
;
408 encoding_rule_t
*rules
;
409 payload_type_t payload_type
;
411 this->data_struct
= payload
;
412 payload_type
= payload
->get_type(payload
);
414 offset_start
= this->out_position
- this->buffer
;
416 DBG2(DBG_ENC
, "generating payload of type %N",
417 payload_type_names
, payload_type
);
419 /* each payload has its own encoding rules */
420 rule_count
= payload
->get_encoding_rules(payload
, &rules
);
422 for (i
= 0; i
< rule_count
;i
++)
424 DBG2(DBG_ENC
, " generating rule %d %N",
425 i
, encoding_type_names
, rules
[i
].type
);
426 switch (rules
[i
].type
)
438 case CONFIGURATION_ATTRIBUTE_LENGTH
:
439 generate_u_int_type(this, rules
[i
].type
, rules
[i
].offset
);
443 generate_flag(this, rules
[i
].offset
);
446 this->header_length_offset
= get_offset(this);
447 generate_u_int_type(this, U_INT_32
, rules
[i
].offset
);
451 case KEY_EXCHANGE_DATA
:
452 case KEY_EXCHANGE_DATA_V1
:
453 case NOTIFICATION_DATA
:
460 case CONFIGURATION_ATTRIBUTE_VALUE
:
465 generate_from_chunk(this, rules
[i
].offset
);
471 case TRANSFORM_ATTRIBUTES
:
472 case TRANSFORM_ATTRIBUTES_V1
:
473 case CONFIGURATION_ATTRIBUTES
:
474 case TRAFFIC_SELECTORS
:
476 linked_list_t
*proposals
;
477 enumerator_t
*enumerator
;
480 proposals
= *((linked_list_t
**)
481 (this->data_struct
+ rules
[i
].offset
));
482 enumerator
= proposals
->create_enumerator(proposals
);
483 while (enumerator
->enumerate(enumerator
, &proposal
))
485 generate_payload(this, proposal
);
487 enumerator
->destroy(enumerator
);
490 case ATTRIBUTE_FORMAT
:
491 generate_flag(this, rules
[i
].offset
);
492 /* Attribute format is a flag which is stored in context*/
493 this->attribute_format
=
494 *((bool *)(this->data_struct
+ rules
[i
].offset
));
496 case ATTRIBUTE_LENGTH_OR_VALUE
:
497 if (this->attribute_format
)
499 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
503 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
504 /* this field hold the length of the attribute */
505 this->attribute_length
=
506 *((u_int16_t
*)(this->data_struct
+ rules
[i
].offset
));
509 case ATTRIBUTE_VALUE
:
511 if (!this->attribute_format
)
513 DBG2(DBG_ENC
, "attribute value has not fixed size");
514 /* the attribute value is generated */
515 generate_from_chunk(this, rules
[i
].offset
);
520 DBG1(DBG_ENC
, "field type %N is not supported",
521 encoding_type_names
, rules
[i
].type
);
525 DBG2(DBG_ENC
, "generating %N payload finished",
526 payload_type_names
, payload_type
);
527 DBG3(DBG_ENC
, "generated data for this payload %b",
528 this->buffer
+ offset_start
,
529 this->out_position
- this->buffer
- offset_start
);
532 METHOD(generator_t
, destroy
, void,
533 private_generator_t
*this)
540 * Described in header
542 generator_t
*generator_create()
544 private_generator_t
*this;
548 .get_chunk
= _get_chunk
,
549 .generate_payload
= _generate_payload
,
552 .buffer
= malloc(GENERATOR_DATA_BUFFER_SIZE
),
555 this->out_position
= this->buffer
;
556 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
558 return &this->public;