4 * @brief Generic generator class used to generate IKEv2-header and payloads.
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
25 #include <arpa/inet.h>
29 #include "generator.h"
32 #include "utils/allocator.h"
33 #include "utils/linked_list.h"
34 #include "utils/logger_manager.h"
35 #include "payloads/payload.h"
36 #include "payloads/proposal_substructure.h"
37 #include "payloads/transform_substructure.h"
40 extern logger_manager_t
*global_logger_manager
;
43 * Private part of a generator_t object
45 typedef struct private_generator_s private_generator_t
;
47 struct private_generator_s
{
49 * Public part of a generator_t object
53 /* private functions and fields */
57 * Generates a U_INT-Field type
59 * @param this private_generator_t object
60 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
61 * @param offset offset of value in data struct
62 * @param generator_contexts generator_contexts_t object where the context is written or read from
63 * @return - SUCCESS if succeeded
64 * - OUT_OF_RES if out of ressources
66 status_t (*generate_u_int_type
) (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
);
69 * Generates a RESERVED BIT field or a RESERVED BYTE field
71 * @param this private_generator_t object
72 * @param generator_contexts generator_contexts_t object where the context is written or read from
73 * @param bits number of bits to generate
74 * @return - SUCCESS if succeeded
75 * - OUT_OF_RES if out of ressources
76 * - FAILED if bit count not supported
78 status_t (*generate_reserved_field
) (private_generator_t
*this,int bits
);
81 * Generates a FLAG field
83 * @param this private_generator_t object
84 * @param generator_contexts generator_contexts_t object where the context is written or read from
85 * @param offset offset of flag value in data struct
86 * @return - SUCCESS if succeeded
87 * - OUT_OF_RES if out of ressources
89 status_t (*generate_flag
) (private_generator_t
*this,u_int32_t offset
);
92 * Writes the current buffer content into a chunk_t
94 * Memory of specific chunk_t gets allocated.
96 * @param this calling private_generator_t object
97 * @param data pointer of chunk_t to write to
99 * - SUCCESSFUL if succeeded
100 * - OUT_OF_RES otherwise
102 status_t (*write_chunk
) (private_generator_t
*this,chunk_t
*data
);
105 * Generates a bytestream from a chunk_t
107 * @param this private_generator_t object
108 * @param offset offset of chunk_t value in data struct
109 * @return - SUCCESS if succeeded
110 * - OUT_OF_RES if out of ressources
112 status_t (*generate_from_chunk
) (private_generator_t
*this,u_int32_t offset
);
115 * Makes sure enough space is available in buffer to store amount of bits.
117 * If buffer is to small to hold the specific amount of bits it
118 * is increased using reallocation function of allocator.
120 * @param this calling private_generator_t object
121 * @param bits number of bits to make available in buffer
123 * - SUCCESSFUL if succeeded
124 * - OUT_OF_RES otherwise
126 status_t (*make_space_available
) (private_generator_t
*this,size_t bits
);
129 * Writes a specific amount of byte into the buffer.
131 * If buffer is to small to hold the specific amount of bytes it
134 * @param this calling private_generator_t object
135 * @param bytes pointer to bytes to write
136 * @param number_of_bytes number of bytes to write into buffer
138 * - SUCCESSFUL if succeeded
139 * - OUT_OF_RES otherwise
141 status_t (*write_bytes_to_buffer
) (private_generator_t
*this,void * bytes
,size_t number_of_bytes
);
145 * Writes a specific amount of byte into the buffer at a specific offset.
147 * @warning buffer size is not check to hold the data if offset is to large.
149 * @param this calling private_generator_t object
150 * @param bytes pointer to bytes to write
151 * @param number_of_bytes number of bytes to write into buffer
152 * @param offset offset to write the data into
154 * - SUCCESSFUL if succeeded
155 * - OUT_OF_RES otherwise
157 status_t (*write_bytes_to_buffer_at_offset
) (private_generator_t
*this,void * bytes
,size_t number_of_bytes
,u_int32_t offset
);
160 * Buffer used to generate the data into.
165 * Current write position in buffer (one byte aligned).
167 u_int8_t
*out_position
;
170 * Position of last byte in buffer.
172 u_int8_t
*roof_position
;
175 * Current bit writing to in current byte (between 0 and 7).
180 * Associated data struct to read informations from.
185 * Last payload length position offset in the buffer
187 u_int32_t last_payload_length_position_offset
;
192 u_int8_t last_spi_size
;
195 * Attribute format of the last generated transform attribute
197 * Used to check if a variable value field is used or not for
198 * the transform attribute value.
200 bool attribute_format
;
203 * Depending on the value of attribute_format this field is used
204 * to hold the length of the transform attribute in bytes
206 u_int16_t attribute_length
;
215 * Implements private_generator_t's generate_u_int_type function.
216 * See #private_generator_s.generate_u_int_type.
218 static status_t
generate_u_int_type (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
)
220 size_t number_of_bits
= 0;
247 if (((number_of_bits
% 8) == 0) && (this->current_bit
!= 0))
249 /* current bit has to be zero for values multiple of 8 bits */
253 status
= this->make_space_available(this,number_of_bits
);
255 if (status
!= SUCCESS
)
264 if (this->current_bit
== 0)
266 u_int8_t high_val
= *((u_int8_t
*)(this->data_struct
+ offset
)) << 4;
267 u_int8_t low_val
= *(this->out_position
) & 0x0F;
269 *(this->out_position
) = high_val
| low_val
;
270 /* write position is not changed, just bit position is moved */
271 this->current_bit
= 4;
273 else if (this->current_bit
== 4)
275 u_int high_val
= *(this->out_position
) & 0xF0;
276 u_int low_val
= *((u_int8_t
*)(this->data_struct
+ offset
)) & 0x0F;
277 *(this->out_position
) = high_val
| low_val
;
278 this->out_position
++;
279 this->current_bit
= 0;
284 /* 4 Bit integers must have a 4 bit alignment */
292 *this->out_position
= *((u_int8_t
*)(this->data_struct
+ offset
));
293 this->out_position
++;
299 if (this->current_bit
!= 1)
303 u_int8_t attribute_format_flag
= *(this->out_position
) & 0x80;
305 u_int16_t int16_val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
307 int16_val
= int16_val
& 0xFF7F;
309 int16_val
= int16_val
| attribute_format_flag
;
311 this->write_bytes_to_buffer(this,&int16_val
,sizeof(u_int16_t
));
312 this->current_bit
= 0;
319 u_int16_t int16_val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
320 this->write_bytes_to_buffer(this,&int16_val
,sizeof(u_int16_t
));
326 u_int32_t int32_val
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
327 this->write_bytes_to_buffer(this,&int32_val
,sizeof(u_int32_t
));
332 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
333 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
) + 1));
334 this->write_bytes_to_buffer(this,&int32_val_high
,sizeof(u_int32_t
));
335 this->write_bytes_to_buffer(this,&int32_val_low
,sizeof(u_int32_t
));
348 * Implements private_generator_t's generate_reserved_field function.
349 * See #private_generator_s.generate_reserved_field.
351 static status_t
generate_reserved_field (private_generator_t
*this,int bits
)
355 if ((bits
!= 1) && (bits
!= 8))
359 status
= this->make_space_available(this,bits
);
360 if (status
!= SUCCESS
)
367 u_int8_t reserved_bit
= ~(1 << (7 - this->current_bit
));
369 *(this->out_position
) = *(this->out_position
) & reserved_bit
;
371 if (this->current_bit
>= 8)
373 this->current_bit
= this->current_bit
% 8;
374 this->out_position
++;
380 if (this->current_bit
> 0)
384 *(this->out_position
) = 0x00;
385 this->out_position
++;
394 * Implements private_generator_t's generate_flag function.
395 * See #private_generator_s.generate_flag.
397 static status_t
generate_flag (private_generator_t
*this,u_int32_t offset
)
400 u_int8_t flag_value
= (*((bool *) (this->data_struct
+ offset
))) ?
1 : 0;
401 u_int8_t flag
= (flag_value
<< (7 - this->current_bit
));
403 status
= this->make_space_available(this,1);
404 if (status
!= SUCCESS
)
409 *(this->out_position
) = *(this->out_position
) | flag
;
412 if (this->current_bit
>= 8)
414 this->current_bit
= this->current_bit
% 8;
415 this->out_position
++;
421 * Implements private_generator_t's generate_from_chunk function.
422 * See #private_generator_s.generate_from_chunk.
424 static status_t
generate_from_chunk (private_generator_t
*this,u_int32_t offset
)
426 if (this->current_bit
!= 0)
430 chunk_t
*attribute_value
= (chunk_t
*)(this->data_struct
+ offset
);
432 return this->write_bytes_to_buffer (this,attribute_value
->ptr
,attribute_value
->len
);
437 * Implements private_generator_t's generator_context_make_space_available function.
438 * See #private_generator_s.generator_context_make_space_available.
440 static status_t
make_space_available (private_generator_t
*this, size_t bits
)
442 while ((((this->roof_position
- this->out_position
) * 8) - this->current_bit
) < bits
)
444 size_t old_buffer_size
= ((this->roof_position
) - ( this->buffer
));
445 size_t new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
446 size_t out_position_offset
= ((this->out_position
) - (this->buffer
));
447 u_int8_t
*new_buffer
;
449 new_buffer
= allocator_realloc(this->buffer
,new_buffer_size
);
450 if (new_buffer
== NULL
)
455 this->buffer
= new_buffer
;
457 this->out_position
= (this->buffer
+ out_position_offset
);
458 this->roof_position
= (this->buffer
+ new_buffer_size
);
466 * Implements private_generator_t's write_bytes_to_buffer function.
467 * See #private_generator_s.write_bytes_to_buffer.
469 static status_t
write_bytes_to_buffer (private_generator_t
*this,void * bytes
,size_t number_of_bytes
)
471 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
475 status
= this->make_space_available(this,number_of_bytes
* 8);
477 if (status
!= SUCCESS
)
482 for (i
= 0; i
< number_of_bytes
; i
++)
484 *(this->out_position
) = *(read_position
);
486 this->out_position
++;
492 * Implements private_generator_t's write_bytes_to_buffer_at_offset function.
493 * See #private_generator_s.write_bytes_to_buffer_at_offset.
494 * TODO automatic buffer increasing!
496 static status_t
write_bytes_to_buffer_at_offset (private_generator_t
*this,void * bytes
,size_t number_of_bytes
,u_int32_t offset
)
498 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
500 u_int8_t
*write_position
= this->buffer
+ offset
;
502 for (i
= 0; i
< number_of_bytes
; i
++)
504 *(write_position
) = *(read_position
);
512 * Implements generator_t's write_chunk function.
513 * See #generator_s.write_chunk.
515 static status_t
write_to_chunk (private_generator_t
*this,chunk_t
*data
)
517 size_t data_length
= this->out_position
- this->buffer
;
519 if (this->current_bit
> 0)
521 data
->ptr
= allocator_alloc(data_length
);
522 if (data
->ptr
== NULL
)
527 memcpy(data
->ptr
,this->buffer
,data_length
);
528 data
->len
= data_length
;
535 * Implements generator_t's generate_payload function.
536 * See #generator_s.generate_payload.
538 static status_t
generate_payload (private_generator_t
*this,payload_t
*payload
)
542 this->data_struct
= payload
;
544 encoding_rule_t
*rules
;
547 payload_type_t payload_type
= payload
->get_type(payload
);
549 this->logger
->log(this->logger
,CONTROL
,"Start generating payload of type %s",mapping_find(payload_type_t_mappings
,payload_type
));
551 payload
->get_encoding_rules(payload
,&rules
,&rule_count
);
553 for (i
= 0; i
< rule_count
;i
++)
556 switch (rules
[i
].type
)
558 /* all u int values are generated in generate_u_int_type */
564 status
= this->generate_u_int_type(this,rules
[i
].type
,rules
[i
].offset
);
568 status
= this->generate_reserved_field(this,1);
574 status
= this->generate_reserved_field(this,8);
579 status
= this->generate_flag(this,rules
[i
].offset
);
583 /* payload length is generated like an U_INT_16 */
584 this->last_payload_length_position_offset
= (this->out_position
- this->buffer
);
585 status
= this->generate_u_int_type(this,U_INT_16
,rules
[i
].offset
);
589 /* header length is generated like an U_INT_32 */
590 status
= this->generate_u_int_type(this,U_INT_32
,rules
[i
].offset
);
593 /* spi size is handled as 8 bit unsigned integer */
594 status
= this->generate_u_int_type(this,U_INT_8
,rules
[i
].offset
);
595 this->last_spi_size
= *((u_int8_t
*)(this->data_struct
+ rules
[i
].offset
));
599 this->logger
->log(this->logger
,CONTROL_MORE
,"SPI value");
600 /* the attribute value is generated */
601 status
= this->generate_from_chunk(this,rules
[i
].offset
);
606 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Transforms");
607 /* before iterative generate the transforms, store the current length position */
608 u_int32_t payload_length_position_offset
= this->last_payload_length_position_offset
;
610 u_int16_t length_of_proposal
= PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
+ this->last_spi_size
;
612 linked_list_t
*transforms
= *((linked_list_t
**)(this->data_struct
+ rules
[i
].offset
));
614 linked_list_iterator_t
*iterator
;
615 /* create forward iterator */
616 status
= transforms
->create_iterator(transforms
,&iterator
,TRUE
);
617 if (status
!= SUCCESS
)
621 while (iterator
->has_next(iterator
))
623 payload_t
*current_transform
;
624 u_int32_t before_generate_position_offset
;
625 u_int32_t after_generate_position_offset
;
627 status
= iterator
->current(iterator
,(void **)¤t_transform
);
628 if (status
!= SUCCESS
)
630 iterator
->destroy(iterator
);
634 before_generate_position_offset
= (this->out_position
- this->buffer
);
635 this->public.generate_payload(&(this->public),current_transform
);
636 after_generate_position_offset
= (this->out_position
- this->buffer
);
638 /* increase size of transform */
639 length_of_proposal
+= (after_generate_position_offset
- before_generate_position_offset
);
642 iterator
->destroy(iterator
);
644 this->logger
->log(this->logger
,CONTROL_MORE
,"Length of Transform is %d, offset is %d",length_of_proposal
,payload_length_position_offset
);
646 int16_val
= htons(length_of_proposal
);
647 this->write_bytes_to_buffer_at_offset(this,&int16_val
,sizeof(u_int16_t
),payload_length_position_offset
);
651 case TRANSFORM_ATTRIBUTES
:
653 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Transform attributes");
654 /* before iterative generate the transform attributes, store the current length position */
655 u_int32_t transform_length_position_offset
= this->last_payload_length_position_offset
;
657 u_int16_t length_of_transform
= TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
659 linked_list_t
*transform_attributes
=*((linked_list_t
**)(this->data_struct
+ rules
[i
].offset
));
661 linked_list_iterator_t
*iterator
;
662 /* create forward iterator */
663 status
= transform_attributes
->create_iterator(transform_attributes
,&iterator
,TRUE
);
664 if (status
!= SUCCESS
)
668 while (iterator
->has_next(iterator
))
670 payload_t
*current_attribute
;
671 u_int32_t before_generate_position_offset
;
672 u_int32_t after_generate_position_offset
;
674 status
= iterator
->current(iterator
,(void **)¤t_attribute
);
675 if (status
!= SUCCESS
)
677 iterator
->destroy(iterator
);
681 before_generate_position_offset
= (this->out_position
- this->buffer
);
682 this->public.generate_payload(&(this->public),current_attribute
);
683 after_generate_position_offset
= (this->out_position
- this->buffer
);
685 /* increase size of transform */
686 length_of_transform
+= (after_generate_position_offset
- before_generate_position_offset
);
689 iterator
->destroy(iterator
);
691 this->logger
->log(this->logger
,CONTROL_MORE
,"Length of Transform is %d, offset is %d",length_of_transform
,transform_length_position_offset
);
693 int16_val
= htons(length_of_transform
);
694 this->write_bytes_to_buffer_at_offset(this,&int16_val
,sizeof(u_int16_t
),transform_length_position_offset
);
698 case ATTRIBUTE_FORMAT
:
700 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Format flag");
701 /* Attribute format is a flag which is stored in context*/
703 status
= this->generate_flag(this,rules
[i
].offset
);
704 this->attribute_format
= *((bool *) (this->data_struct
+ rules
[i
].offset
));
709 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Type field");
710 // the attribute type is a 15 bit integer so it has to be generated special
711 status
= this->generate_u_int_type(this,ATTRIBUTE_TYPE
,rules
[i
].offset
);
714 case ATTRIBUTE_LENGTH_OR_VALUE
:
716 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Length or Value field");
717 if (this->attribute_format
== FALSE
)
719 status
= this->generate_u_int_type(this,U_INT_16
,rules
[i
].offset
);
720 /* this field hold the length of the attribute */
721 this->attribute_length
= *((u_int16_t
*)(this->data_struct
+ rules
[i
].offset
));
725 status
= this->write_bytes_to_buffer(this,(this->data_struct
+ rules
[i
].offset
),2);
729 case ATTRIBUTE_VALUE
:
731 if (this->attribute_format
== FALSE
)
733 this->logger
->log(this->logger
,CONTROL_MORE
,"Attribute value has not fixed size");
734 /* the attribute value is generated */
735 status
= this->generate_from_chunk(this,rules
[i
].offset
);
740 return NOT_SUPPORTED
;
748 * Implements generator_t's destroy function.
749 * See #generator_s.destroy.
751 static status_t
destroy(private_generator_t
*this)
753 allocator_free(this->buffer
);
754 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
755 allocator_free(this);
760 * Described in header
762 generator_t
* generator_create()
764 private_generator_t
*this;
766 this = allocator_alloc_thing(private_generator_t
);
772 /* initiate public functions */
773 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_t
*)) generate_payload
;
774 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
775 this->public.write_to_chunk
= (status_t (*) (generator_t
*,chunk_t
*)) write_to_chunk
;
778 /* initiate private functions */
779 // this->generate = generate;
780 this->generate_u_int_type
= generate_u_int_type
;
781 this->generate_reserved_field
= generate_reserved_field
;
782 this->generate_flag
= generate_flag
;
783 this->generate_from_chunk
= generate_from_chunk
;
784 this->make_space_available
= make_space_available
;
785 this->write_bytes_to_buffer
= write_bytes_to_buffer
;
786 this->write_bytes_to_buffer_at_offset
= write_bytes_to_buffer_at_offset
;
789 /* allocate memory for buffer */
790 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
791 if (this->buffer
== NULL
)
793 allocator_free(this);
797 /* initiate private variables */
798 this->out_position
= this->buffer
;
799 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
800 this->data_struct
= NULL
;
801 this->current_bit
= 0;
802 this->last_payload_length_position_offset
= 0;
803 this->logger
= global_logger_manager
->create_logger(global_logger_manager
,GENERATOR
,NULL
);
804 return &(this->public);