2 * Copyright (C) 2011 Tobias Brunner
3 * Copyright (C) 2005-2009 Martin Willi
4 * Copyright (C) 2005 Jan Hutter
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 #include "generator.h"
26 #include <collections/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
;
113 * TRUE, if debug messages should be logged during generation.
119 * Get size of current buffer in bytes.
121 static int get_size(private_generator_t
*this)
123 return this->roof_position
- this->buffer
;
127 * Get free space of current buffer in bytes.
129 static int get_space(private_generator_t
*this)
131 return this->roof_position
- this->out_position
;
135 * Get length of data in buffer (in bytes).
137 static int get_length(private_generator_t
*this)
139 return this->out_position
- this->buffer
;
143 * Get current offset in buffer (in bytes).
145 static u_int32_t
get_offset(private_generator_t
*this)
147 return this->out_position
- this->buffer
;
151 * Makes sure enough space is available in buffer to store amount of bits.
153 static void make_space_available(private_generator_t
*this, int bits
)
155 while ((get_space(this) * 8 - this->current_bit
) < bits
)
157 int old_buffer_size
, new_buffer_size
, out_position_offset
;
159 old_buffer_size
= get_size(this);
160 new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
161 out_position_offset
= this->out_position
- this->buffer
;
165 DBG2(DBG_ENC
, "increasing gen buffer from %d to %d byte",
166 old_buffer_size
, new_buffer_size
);
169 this->buffer
= realloc(this->buffer
,new_buffer_size
);
170 this->out_position
= (this->buffer
+ out_position_offset
);
171 this->roof_position
= (this->buffer
+ new_buffer_size
);
176 * Writes a specific amount of byte into the buffer.
178 static void write_bytes_to_buffer(private_generator_t
*this, void *bytes
,
182 u_int8_t
*read_position
= (u_int8_t
*)bytes
;
184 make_space_available(this, number_of_bytes
* 8);
186 for (i
= 0; i
< number_of_bytes
; i
++)
188 *(this->out_position
) = *(read_position
);
190 this->out_position
++;
195 * Generates a U_INT-Field type and writes it to buffer.
197 static void generate_u_int_type(private_generator_t
*this,
198 encoding_type_t int_type
,u_int32_t offset
)
200 int number_of_bits
= 0;
202 /* find out number of bits of each U_INT type to check for enough space */
216 case ATTRIBUTE_LENGTH
:
229 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
230 encoding_type_names
, int_type
);
233 if ((number_of_bits
% 8) == 0 && this->current_bit
!= 0)
235 DBG1(DBG_ENC
, "U_INT Type %N is not 8 Bit aligned",
236 encoding_type_names
, int_type
);
240 make_space_available(this, number_of_bits
);
247 if (this->current_bit
== 0)
249 /* high of current byte in buffer has to be set to the new value*/
250 high
= *((u_int8_t
*)(this->data_struct
+ offset
)) << 4;
251 /* low in buffer is not changed */
252 low
= *(this->out_position
) & 0x0F;
253 /* high is set, low_val is not changed */
254 *(this->out_position
) = high
| low
;
257 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
259 /* write position is not changed, just bit position is moved */
260 this->current_bit
= 4;
262 else if (this->current_bit
== 4)
264 /* high in buffer is not changed */
265 high
= *(this->out_position
) & 0xF0;
266 /* low of current byte in buffer has to be set to the new value*/
267 low
= *((u_int8_t
*)(this->data_struct
+ offset
)) & 0x0F;
268 *(this->out_position
) = high
| low
;
271 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
273 this->out_position
++;
274 this->current_bit
= 0;
278 DBG1(DBG_ENC
, "U_INT_4 Type is not 4 Bit aligned");
279 /* 4 Bit integers must have a 4 bit alignment */
289 /* 8 bit values are written as they are */
290 *this->out_position
= *((u_int8_t
*)(this->data_struct
+ offset
));
293 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
295 this->out_position
++;
300 u_int8_t attribute_format_flag
;
303 /* attribute type must not change first bit of current byte */
304 if (this->current_bit
!= 1)
306 DBG1(DBG_ENC
, "ATTRIBUTE FORMAT flag is not set");
309 attribute_format_flag
= *(this->out_position
) & 0x80;
310 /* get attribute type value as 16 bit integer*/
311 val
= *((u_int16_t
*)(this->data_struct
+ offset
));
312 /* unset most significant bit */
314 if (attribute_format_flag
)
321 DBG3(DBG_ENC
, " => %d", val
);
323 /* write bytes to buffer (set bit is overwritten) */
324 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
325 this->current_bit
= 0;
331 case ATTRIBUTE_LENGTH
:
333 u_int16_t val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
336 DBG3(DBG_ENC
, " %b", &val
, sizeof(u_int16_t
));
338 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
343 u_int32_t val
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
346 DBG3(DBG_ENC
, " %b", &val
, sizeof(u_int32_t
));
348 write_bytes_to_buffer(this, &val
, sizeof(u_int32_t
));
353 /* 64 bit are written as-is, no host order conversion */
354 write_bytes_to_buffer(this, this->data_struct
+ offset
,
358 DBG3(DBG_ENC
, " %b", this->data_struct
+ offset
,
365 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
366 encoding_type_names
, int_type
);
373 * Generate a FLAG filed
375 static void generate_flag(private_generator_t
*this, u_int32_t offset
)
380 flag_value
= (*((bool *) (this->data_struct
+ offset
))) ?
1 : 0;
381 /* get flag position */
382 flag
= (flag_value
<< (7 - this->current_bit
));
384 /* make sure one bit is available in buffer */
385 make_space_available(this, 1);
386 if (this->current_bit
== 0)
388 /* memory must be zero */
389 *(this->out_position
) = 0x00;
392 *(this->out_position
) = *(this->out_position
) | flag
;
395 DBG3(DBG_ENC
, " => %d", *this->out_position
);
399 if (this->current_bit
>= 8)
401 this->current_bit
= this->current_bit
% 8;
402 this->out_position
++;
407 * Generates a bytestream from a chunk_t.
409 static void generate_from_chunk(private_generator_t
*this, u_int32_t offset
)
413 if (this->current_bit
!= 0)
415 DBG1(DBG_ENC
, "can not generate a chunk at bitpos %d",
420 value
= (chunk_t
*)(this->data_struct
+ offset
);
423 DBG3(DBG_ENC
, " %B", value
);
426 write_bytes_to_buffer(this, value
->ptr
, value
->len
);
429 METHOD(generator_t
, get_chunk
, chunk_t
,
430 private_generator_t
*this, u_int32_t
**lenpos
)
434 *lenpos
= (u_int32_t
*)(this->buffer
+ this->header_length_offset
);
435 data
= chunk_create(this->buffer
, get_length(this));
438 DBG3(DBG_ENC
, "generated data of this generator %B", &data
);
443 METHOD(generator_t
, generate_payload
, void,
444 private_generator_t
*this, payload_t
*payload
)
446 int i
, offset_start
, rule_count
;
447 encoding_rule_t
*rules
;
448 payload_type_t payload_type
;
450 this->data_struct
= payload
;
451 payload_type
= payload
->get_type(payload
);
453 offset_start
= this->out_position
- this->buffer
;
457 DBG2(DBG_ENC
, "generating payload of type %N",
458 payload_type_names
, payload_type
);
461 /* each payload has its own encoding rules */
462 rule_count
= payload
->get_encoding_rules(payload
, &rules
);
464 for (i
= 0; i
< rule_count
;i
++)
468 DBG2(DBG_ENC
, " generating rule %d %N",
469 i
, encoding_type_names
, rules
[i
].type
);
471 switch ((int)rules
[i
].type
)
483 case ATTRIBUTE_LENGTH
:
484 generate_u_int_type(this, rules
[i
].type
, rules
[i
].offset
);
488 generate_flag(this, rules
[i
].offset
);
491 this->header_length_offset
= get_offset(this);
492 generate_u_int_type(this, U_INT_32
, rules
[i
].offset
);
498 generate_from_chunk(this, rules
[i
].offset
);
500 case PAYLOAD_LIST
+ PLV2_PROPOSAL_SUBSTRUCTURE
:
501 case PAYLOAD_LIST
+ PLV1_PROPOSAL_SUBSTRUCTURE
:
502 case PAYLOAD_LIST
+ PLV2_TRANSFORM_SUBSTRUCTURE
:
503 case PAYLOAD_LIST
+ PLV1_TRANSFORM_SUBSTRUCTURE
:
504 case PAYLOAD_LIST
+ PLV2_TRANSFORM_ATTRIBUTE
:
505 case PAYLOAD_LIST
+ PLV1_TRANSFORM_ATTRIBUTE
:
506 case PAYLOAD_LIST
+ PLV2_CONFIGURATION_ATTRIBUTE
:
507 case PAYLOAD_LIST
+ PLV1_CONFIGURATION_ATTRIBUTE
:
508 case PAYLOAD_LIST
+ PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE
:
510 linked_list_t
*proposals
;
511 enumerator_t
*enumerator
;
514 proposals
= *((linked_list_t
**)
515 (this->data_struct
+ rules
[i
].offset
));
516 enumerator
= proposals
->create_enumerator(proposals
);
517 while (enumerator
->enumerate(enumerator
, &proposal
))
519 generate_payload(this, proposal
);
521 enumerator
->destroy(enumerator
);
524 case ATTRIBUTE_FORMAT
:
525 generate_flag(this, rules
[i
].offset
);
526 /* Attribute format is a flag which is stored in context*/
527 this->attribute_format
=
528 *((bool *)(this->data_struct
+ rules
[i
].offset
));
530 case ATTRIBUTE_LENGTH_OR_VALUE
:
531 if (this->attribute_format
)
533 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
537 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
538 /* this field hold the length of the attribute */
539 this->attribute_length
=
540 *((u_int16_t
*)(this->data_struct
+ rules
[i
].offset
));
543 case ATTRIBUTE_VALUE
:
545 if (!this->attribute_format
)
549 DBG2(DBG_ENC
, "attribute value has not fixed size");
551 /* the attribute value is generated */
552 generate_from_chunk(this, rules
[i
].offset
);
557 DBG1(DBG_ENC
, "field type %N is not supported",
558 encoding_type_names
, rules
[i
].type
);
564 DBG2(DBG_ENC
, "generating %N payload finished",
565 payload_type_names
, payload_type
);
566 DBG3(DBG_ENC
, "generated data for this payload %b",
567 this->buffer
+ offset_start
,
568 (u_int
)(this->out_position
- this->buffer
- offset_start
));
572 METHOD(generator_t
, destroy
, void,
573 private_generator_t
*this)
580 * Described in header
582 generator_t
*generator_create()
584 private_generator_t
*this;
588 .get_chunk
= _get_chunk
,
589 .generate_payload
= _generate_payload
,
592 .buffer
= malloc(GENERATOR_DATA_BUFFER_SIZE
),
596 this->out_position
= this->buffer
;
597 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
599 return &this->public;
603 * Described in header
605 generator_t
*generator_create_no_dbg()
607 private_generator_t
*this = (private_generator_t
*)generator_create();
611 return &this->public;