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>
46 typedef struct private_generator_t private_generator_t
;
49 * Private part of a generator_t object.
51 struct private_generator_t
{
53 * Public part of a generator_t object.
58 * Buffer used to generate the data into.
63 * Current write position in buffer (one byte aligned).
65 u_int8_t
*out_position
;
68 * Position of last byte in buffer.
70 u_int8_t
*roof_position
;
73 * Current bit writing to in current byte (between 0 and 7).
78 * Associated data struct to read informations from.
83 * Last payload length position offset in the buffer.
85 u_int32_t last_payload_length_position_offset
;
88 * Offset of the header length field in the buffer.
90 u_int32_t header_length_position_offset
;
95 u_int8_t last_spi_size
;
98 * Attribute format of the last generated transform attribute.
100 * Used to check if a variable value field is used or not for
101 * the transform attribute value.
103 bool attribute_format
;
106 * Depending on the value of attribute_format this field is used
107 * to hold the length of the transform attribute in bytes.
109 u_int16_t attribute_length
;
113 * Get size of current buffer in bytes.
115 static size_t get_size(private_generator_t
*this)
117 return this->roof_position
- this->buffer
;
121 * Get free space of current buffer in bytes.
123 static size_t get_space(private_generator_t
*this)
125 return this->roof_position
- this->out_position
;
129 * Get length of data in buffer (in bytes).
131 static size_t get_length(private_generator_t
*this)
133 return this->out_position
- this->buffer
;
137 * Get current offset in buffer (in bytes).
139 static u_int32_t
get_offset(private_generator_t
*this)
141 return this->out_position
- this->buffer
;
145 * Makes sure enough space is available in buffer to store amount of bits.
147 static void make_space_available(private_generator_t
*this, size_t bits
)
149 while ((get_space(this) * 8 - this->current_bit
) < bits
)
151 size_t old_buffer_size
, new_buffer_size
, out_position_offset
;
153 old_buffer_size
= get_size(this);
154 new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
155 out_position_offset
= this->out_position
- this->buffer
;
157 DBG2(DBG_ENC
, "increasing gen buffer from %d to %d byte",
158 old_buffer_size
, new_buffer_size
);
160 this->buffer
= realloc(this->buffer
,new_buffer_size
);
161 this->out_position
= (this->buffer
+ out_position_offset
);
162 this->roof_position
= (this->buffer
+ new_buffer_size
);
167 * Writes a specific amount of byte into the buffer.
169 static void write_bytes_to_buffer(private_generator_t
*this, void *bytes
,
170 size_t number_of_bytes
)
173 u_int8_t
*read_position
= (u_int8_t
*)bytes
;
175 make_space_available(this, number_of_bytes
* 8);
177 for (i
= 0; i
< number_of_bytes
; i
++)
179 *(this->out_position
) = *(read_position
);
181 this->out_position
++;
186 * Writes a specific amount of byte into the buffer at a specific offset.
188 static void write_bytes_to_buffer_at_offset (private_generator_t
*this,
189 void *bytes
, size_t number_of_bytes
, u_int32_t offset
)
192 u_int8_t
*read_position
= (u_int8_t
*)bytes
;
193 u_int8_t
*write_position
;
194 u_int32_t free_space_after_offset
= get_size(this) - offset
;
196 /* check first if enough space for new data is available */
197 if (number_of_bytes
> free_space_after_offset
)
199 make_space_available(this,
200 (number_of_bytes
- free_space_after_offset
) * 8);
203 write_position
= this->buffer
+ offset
;
204 for (i
= 0; i
< number_of_bytes
; i
++)
206 *write_position
= *read_position
;
213 * Generates a U_INT-Field type and writes it to buffer.
215 static void generate_u_int_type(private_generator_t
*this,
216 encoding_type_t int_type
,u_int32_t offset
)
218 size_t number_of_bits
= 0;
220 /* find out number of bits of each U_INT type to check for enough space */
231 case CONFIGURATION_ATTRIBUTE_LENGTH
:
244 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
245 encoding_type_names
, int_type
);
248 if ((number_of_bits
% 8) == 0 && this->current_bit
!= 0)
250 DBG1(DBG_ENC
, "U_INT Type %N is not 8 Bit aligned",
251 encoding_type_names
, int_type
);
255 make_space_available(this, number_of_bits
);
262 if (this->current_bit
== 0)
264 /* high of current byte in buffer has to be set to the new value*/
265 high
= *((u_int8_t
*)(this->data_struct
+ offset
)) << 4;
266 /* low in buffer is not changed */
267 low
= *(this->out_position
) & 0x0F;
268 /* high is set, low_val is not changed */
269 *(this->out_position
) = high
| low
;
270 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
271 /* write position is not changed, just bit position is moved */
272 this->current_bit
= 4;
274 else if (this->current_bit
== 4)
276 /* high in buffer is not changed */
277 high
= *(this->out_position
) & 0xF0;
278 /* low of current byte in buffer has to be set to the new value*/
279 low
= *((u_int8_t
*)(this->data_struct
+ offset
)) & 0x0F;
280 *(this->out_position
) = high
| low
;
281 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
282 this->out_position
++;
283 this->current_bit
= 0;
287 DBG1(DBG_ENC
, "U_INT_4 Type is not 4 Bit aligned");
288 /* 4 Bit integers must have a 4 bit alignment */
296 /* 8 bit values are written as they are */
297 *this->out_position
= *((u_int8_t
*)(this->data_struct
+ offset
));
298 DBG3(DBG_ENC
, " => %d", *(this->out_position
));
299 this->out_position
++;
304 u_int8_t attribute_format_flag
;
307 /* attribute type must not change first bit of current byte */
308 if (this->current_bit
!= 1)
310 DBG1(DBG_ENC
, "ATTRIBUTE FORMAT flag is not set");
313 attribute_format_flag
= *(this->out_position
) & 0x80;
314 /* get attribute type value as 16 bit integer*/
315 val
= *((u_int16_t
*)(this->data_struct
+ offset
));
316 /* unset most significant bit */
318 if (attribute_format_flag
)
323 DBG3(DBG_ENC
, " => %d", val
);
324 /* write bytes to buffer (set bit is overwritten) */
325 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
326 this->current_bit
= 0;
331 case CONFIGURATION_ATTRIBUTE_LENGTH
:
333 u_int16_t val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
334 DBG3(DBG_ENC
, " => %b", &val
, sizeof(u_int16_t
));
335 write_bytes_to_buffer(this, &val
, sizeof(u_int16_t
));
340 u_int32_t val
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
341 DBG3(DBG_ENC
, " => %b", &val
, sizeof(u_int32_t
));
342 write_bytes_to_buffer(this, &val
, sizeof(u_int32_t
));
347 /* 64 bit are written as-is, no host order conversion */
348 write_bytes_to_buffer(this, this->data_struct
+ offset
,
350 DBG3(DBG_ENC
, " => %b", this->data_struct
+ offset
,
356 DBG1(DBG_ENC
, "U_INT Type %N is not supported",
357 encoding_type_names
, int_type
);
364 * Generate a reserved bit or byte
366 static void generate_reserved_field(private_generator_t
*this, int bits
)
368 /* only one bit or 8 bit fields are supported */
369 if (bits
!= 1 && bits
!= 8)
371 DBG1(DBG_ENC
, "reserved field of %d bits cannot be generated", bits
);
374 make_space_available(this, bits
);
378 u_int8_t reserved_bit
= ~(1 << (7 - this->current_bit
));
380 *(this->out_position
) = *(this->out_position
) & reserved_bit
;
381 if (this->current_bit
== 0)
383 /* memory must be zero */
384 *(this->out_position
) = 0x00;
387 if (this->current_bit
>= 8)
389 this->current_bit
= this->current_bit
% 8;
390 this->out_position
++;
395 if (this->current_bit
> 0)
397 DBG1(DBG_ENC
, "reserved field cannot be written cause "
398 "alignement of current bit is %d", this->current_bit
);
401 *(this->out_position
) = 0x00;
402 this->out_position
++;
407 * Generate a FLAG filed
409 static void generate_flag(private_generator_t
*this, u_int32_t offset
)
414 flag_value
= (*((bool *) (this->data_struct
+ offset
))) ?
1 : 0;
415 /* get flag position */
416 flag
= (flag_value
<< (7 - this->current_bit
));
418 /* make sure one bit is available in buffer */
419 make_space_available(this, 1);
420 if (this->current_bit
== 0)
422 /* memory must be zero */
423 *(this->out_position
) = 0x00;
426 *(this->out_position
) = *(this->out_position
) | flag
;
427 DBG3(DBG_ENC
, " => %d", *this->out_position
);
430 if (this->current_bit
>= 8)
432 this->current_bit
= this->current_bit
% 8;
433 this->out_position
++;
438 * Generates a bytestream from a chunk_t.
440 static void generate_from_chunk(private_generator_t
*this, u_int32_t offset
)
444 if (this->current_bit
!= 0)
446 DBG1(DBG_ENC
, "can not generate a chunk at Bitpos %d", this->current_bit
);
450 value
= (chunk_t
*)(this->data_struct
+ offset
);
451 DBG3(DBG_ENC
, " => %B", value
);
453 write_bytes_to_buffer(this, value
->ptr
, value
->len
);
457 * Implementation of private_generator_t.write_to_chunk.
459 static void write_to_chunk(private_generator_t
*this,chunk_t
*data
)
461 size_t data_length
= get_length(this);
462 u_int32_t header_length_field
= data_length
;
464 /* write length into header length field */
465 if (this->header_length_position_offset
> 0)
467 u_int32_t val
= htonl(header_length_field
);
468 write_bytes_to_buffer_at_offset(this, &val
, sizeof(u_int32_t
),
469 this->header_length_position_offset
);
472 if (this->current_bit
> 0)
476 *data
= chunk_alloc(data_length
);
477 memcpy(data
->ptr
, this->buffer
, data_length
);
479 DBG3(DBG_ENC
, "generated data of this generator %B", data
);
483 * Implementation of private_generator_t.generate_payload.
485 static void generate_payload (private_generator_t
*this,payload_t
*payload
)
488 this->data_struct
= payload
;
489 size_t rule_count
, offset_start
;
490 encoding_rule_t
*rules
;
491 payload_type_t payload_type
;
493 payload_type
= payload
->get_type(payload
);
494 /* spi size has to get reseted */
495 this->last_spi_size
= 0;
497 offset_start
= this->out_position
- this->buffer
;
499 DBG2(DBG_ENC
, "generating payload of type %N",
500 payload_type_names
, payload_type
);
502 /* each payload has its own encoding rules */
503 payload
->get_encoding_rules(payload
,&rules
,&rule_count
);
505 for (i
= 0; i
< rule_count
;i
++)
507 DBG2(DBG_ENC
, " generating rule %d %N",
508 i
, encoding_type_names
, rules
[i
].type
);
509 switch (rules
[i
].type
)
518 case CONFIGURATION_ATTRIBUTE_LENGTH
:
520 generate_u_int_type(this, rules
[i
].type
,rules
[i
].offset
);
525 generate_reserved_field(this, 1);
530 generate_reserved_field(this, 8);
535 generate_flag(this, rules
[i
].offset
);
540 this->last_payload_length_position_offset
= get_offset(this);
541 generate_u_int_type(this, U_INT_16
,rules
[i
].offset
);
546 this->header_length_position_offset
= get_offset(this);
547 generate_u_int_type(this ,U_INT_32
, rules
[i
].offset
);
551 generate_u_int_type(this, U_INT_8
, rules
[i
].offset
);
552 this->last_spi_size
= *((u_int8_t
*)(this->data_struct
+
557 generate_from_chunk(this, rules
[i
].offset
);
562 generate_from_chunk(this, rules
[i
].offset
);
565 case KEY_EXCHANGE_DATA
:
566 case NOTIFICATION_DATA
:
573 case CONFIGURATION_ATTRIBUTE_VALUE
:
577 u_int32_t payload_length_position_offset
;
578 u_int16_t length_of_payload
;
579 u_int16_t header_length
= 0;
580 u_int16_t length_in_network_order
;
582 switch(rules
[i
].type
)
584 case KEY_EXCHANGE_DATA
:
585 header_length
= KE_PAYLOAD_HEADER_LENGTH
;
587 case NOTIFICATION_DATA
:
588 header_length
= NOTIFY_PAYLOAD_HEADER_LENGTH
+
592 header_length
= NONCE_PAYLOAD_HEADER_LENGTH
;
595 header_length
= ID_PAYLOAD_HEADER_LENGTH
;
598 header_length
= AUTH_PAYLOAD_HEADER_LENGTH
;
601 header_length
= CERT_PAYLOAD_HEADER_LENGTH
;
604 header_length
= CERTREQ_PAYLOAD_HEADER_LENGTH
;
607 header_length
= DELETE_PAYLOAD_HEADER_LENGTH
;
610 header_length
= VENDOR_ID_PAYLOAD_HEADER_LENGTH
;
612 case CONFIGURATION_ATTRIBUTE_VALUE
:
613 header_length
= CONFIGURATION_ATTRIBUTE_HEADER_LENGTH
;
616 header_length
= EAP_PAYLOAD_HEADER_LENGTH
;
621 generate_from_chunk(this, rules
[i
].offset
);
623 payload_length_position_offset
=
624 this->last_payload_length_position_offset
;
626 length_of_payload
= header_length
+
627 ((chunk_t
*)(this->data_struct
+ rules
[i
].offset
))->len
;
629 length_in_network_order
= htons(length_of_payload
);
630 write_bytes_to_buffer_at_offset(this, &length_in_network_order
,
631 sizeof(u_int16_t
), payload_length_position_offset
);
636 u_int32_t payload_length_position_offset
=
637 this->last_payload_length_position_offset
;
638 /* Length of SA_PAYLOAD is calculated */
639 u_int16_t length_of_sa_payload
= SA_PAYLOAD_HEADER_LENGTH
;
641 linked_list_t
*proposals
= *((linked_list_t
**)
642 (this->data_struct
+ rules
[i
].offset
));
643 iterator_t
*iterator
;
644 payload_t
*current_proposal
;
646 iterator
= proposals
->create_iterator(proposals
,TRUE
);
647 while (iterator
->iterate(iterator
, (void**)¤t_proposal
))
649 u_int32_t before_generate_position_offset
;
650 u_int32_t after_generate_position_offset
;
652 before_generate_position_offset
= get_offset(this);
653 generate_payload(this, current_proposal
);
654 after_generate_position_offset
= get_offset(this);
655 length_of_sa_payload
+= (after_generate_position_offset
-
656 before_generate_position_offset
);
658 iterator
->destroy(iterator
);
660 int16_val
= htons(length_of_sa_payload
);
661 write_bytes_to_buffer_at_offset(this, &int16_val
,
662 sizeof(u_int16_t
),payload_length_position_offset
);
667 u_int32_t payload_length_position_offset
=
668 this->last_payload_length_position_offset
;
669 u_int16_t length_of_proposal
=
670 PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
+ this->last_spi_size
;
672 linked_list_t
*transforms
= *((linked_list_t
**)
673 (this->data_struct
+ rules
[i
].offset
));
674 iterator_t
*iterator
;
675 payload_t
*current_transform
;
677 iterator
= transforms
->create_iterator(transforms
,TRUE
);
678 while (iterator
->iterate(iterator
, (void**)¤t_transform
))
680 u_int32_t before_generate_position_offset
;
681 u_int32_t after_generate_position_offset
;
683 before_generate_position_offset
= get_offset(this);
684 generate_payload(this, current_transform
);
685 after_generate_position_offset
= get_offset(this);
687 length_of_proposal
+= (after_generate_position_offset
-
688 before_generate_position_offset
);
690 iterator
->destroy(iterator
);
692 int16_val
= htons(length_of_proposal
);
693 write_bytes_to_buffer_at_offset(this, &int16_val
,
694 sizeof(u_int16_t
), payload_length_position_offset
);
697 case TRANSFORM_ATTRIBUTES
:
699 u_int32_t transform_length_position_offset
=
700 this->last_payload_length_position_offset
;
701 u_int16_t length_of_transform
=
702 TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
704 linked_list_t
*transform_attributes
=*((linked_list_t
**)
705 (this->data_struct
+ rules
[i
].offset
));
706 iterator_t
*iterator
;
707 payload_t
*current_attribute
;
709 iterator
= transform_attributes
->create_iterator(
710 transform_attributes
, TRUE
);
711 while (iterator
->iterate(iterator
, (void**)¤t_attribute
))
713 u_int32_t before_generate_position_offset
;
714 u_int32_t after_generate_position_offset
;
716 before_generate_position_offset
= get_offset(this);
717 generate_payload(this, current_attribute
);
718 after_generate_position_offset
= get_offset(this);
720 length_of_transform
+= (after_generate_position_offset
-
721 before_generate_position_offset
);
724 iterator
->destroy(iterator
);
726 int16_val
= htons(length_of_transform
);
727 write_bytes_to_buffer_at_offset(this, &int16_val
,
728 sizeof(u_int16_t
),transform_length_position_offset
);
731 case CONFIGURATION_ATTRIBUTES
:
733 u_int32_t configurations_length_position_offset
=
734 this->last_payload_length_position_offset
;
735 u_int16_t length_of_configurations
= CP_PAYLOAD_HEADER_LENGTH
;
737 linked_list_t
*configuration_attributes
= *((linked_list_t
**)
738 (this->data_struct
+ rules
[i
].offset
));
739 iterator_t
*iterator
;
740 payload_t
*current_attribute
;
742 iterator
= configuration_attributes
->create_iterator(
743 configuration_attributes
,TRUE
);
744 while (iterator
->iterate(iterator
, (void**)¤t_attribute
))
746 u_int32_t before_generate_position_offset
;
747 u_int32_t after_generate_position_offset
;
749 before_generate_position_offset
= get_offset(this);
750 generate_payload(this, current_attribute
);
751 after_generate_position_offset
= get_offset(this);
753 length_of_configurations
+= after_generate_position_offset
-
754 before_generate_position_offset
;
757 iterator
->destroy(iterator
);
759 int16_val
= htons(length_of_configurations
);
760 write_bytes_to_buffer_at_offset(this, &int16_val
,
761 sizeof(u_int16_t
),configurations_length_position_offset
);
764 case ATTRIBUTE_FORMAT
:
766 generate_flag(this, rules
[i
].offset
);
767 /* Attribute format is a flag which is stored in context*/
768 this->attribute_format
=
769 *((bool *)(this->data_struct
+ rules
[i
].offset
));
773 case ATTRIBUTE_LENGTH_OR_VALUE
:
775 if (this->attribute_format
== FALSE
)
777 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
778 /* this field hold the length of the attribute */
779 this->attribute_length
=
780 *((u_int16_t
*)(this->data_struct
+ rules
[i
].offset
));
784 generate_u_int_type(this, U_INT_16
, rules
[i
].offset
);
788 case ATTRIBUTE_VALUE
:
790 if (this->attribute_format
== FALSE
)
792 DBG2(DBG_ENC
, "attribute value has not fixed size");
793 /* the attribute value is generated */
794 generate_from_chunk(this, rules
[i
].offset
);
798 case TRAFFIC_SELECTORS
:
800 u_int32_t payload_length_position_offset
=
801 this->last_payload_length_position_offset
;
802 u_int16_t length_of_ts_payload
= TS_PAYLOAD_HEADER_LENGTH
;
804 linked_list_t
*traffic_selectors
= *((linked_list_t
**)
805 (this->data_struct
+ rules
[i
].offset
));
806 iterator_t
*iterator
;
807 payload_t
*current_tss
;
809 iterator
= traffic_selectors
->create_iterator(
810 traffic_selectors
,TRUE
);
811 while (iterator
->iterate(iterator
, (void **)¤t_tss
))
813 u_int32_t before_generate_position_offset
;
814 u_int32_t after_generate_position_offset
;
816 before_generate_position_offset
= get_offset(this);
817 generate_payload(this, current_tss
);
818 after_generate_position_offset
= get_offset(this);
820 length_of_ts_payload
+= (after_generate_position_offset
-
821 before_generate_position_offset
);
823 iterator
->destroy(iterator
);
825 int16_val
= htons(length_of_ts_payload
);
826 write_bytes_to_buffer_at_offset(this, &int16_val
,
827 sizeof(u_int16_t
),payload_length_position_offset
);
833 generate_from_chunk(this, rules
[i
].offset
);
837 DBG1(DBG_ENC
, "field type %N is not supported",
838 encoding_type_names
, rules
[i
].type
);
842 DBG2(DBG_ENC
, "generating %N payload finished",
843 payload_type_names
, payload_type
);
844 DBG3(DBG_ENC
, "generated data for this payload %b",
845 this->buffer
+ offset_start
,
846 this->out_position
- this->buffer
- offset_start
);
850 * Implementation of generator_t.destroy.
852 static status_t
destroy(private_generator_t
*this)
860 * Described in header
862 generator_t
*generator_create()
864 private_generator_t
*this;
866 this = malloc_thing(private_generator_t
);
868 /* initiate public functions */
869 this->public.generate_payload
= (void(*)(generator_t
*, payload_t
*))generate_payload
;
870 this->public.destroy
= (void(*)(generator_t
*)) destroy
;
871 this->public.write_to_chunk
= (void (*) (generator_t
*,chunk_t
*))write_to_chunk
;
873 /* allocate memory for buffer */
874 this->buffer
= malloc(GENERATOR_DATA_BUFFER_SIZE
);
876 /* initiate private variables */
877 this->out_position
= this->buffer
;
878 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
879 this->data_struct
= NULL
;
880 this->current_bit
= 0;
881 this->last_payload_length_position_offset
= 0;
882 this->header_length_position_offset
= 0;
884 return &(this->public);