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/transform_substructure.h"
39 extern logger_manager_t
*global_logger_manager
;
42 * Private part of a generator_t object
44 typedef struct private_generator_s private_generator_t
;
46 struct private_generator_s
{
48 * Public part of a generator_t object
52 /* private functions and fields */
56 * Generates a U_INT-Field type
58 * @param this private_generator_t object
59 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
60 * @param offset offset of value in data struct
61 * @param generator_contexts generator_contexts_t object where the context is written or read from
62 * @return - SUCCESS if succeeded
63 * - OUT_OF_RES if out of ressources
65 status_t (*generate_u_int_type
) (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
);
68 * Generates a RESERVED BIT field or a RESERVED BYTE field
70 * @param this private_generator_t object
71 * @param generator_contexts generator_contexts_t object where the context is written or read from
72 * @param bits number of bits to generate
73 * @return - SUCCESS if succeeded
74 * - OUT_OF_RES if out of ressources
75 * - FAILED if bit count not supported
77 status_t (*generate_reserved_field
) (private_generator_t
*this,int bits
);
80 * Generates a FLAG field
82 * @param this private_generator_t object
83 * @param generator_contexts generator_contexts_t object where the context is written or read from
84 * @param offset offset of flag value in data struct
85 * @return - SUCCESS if succeeded
86 * - OUT_OF_RES if out of ressources
88 status_t (*generate_flag
) (private_generator_t
*this,u_int32_t offset
);
91 * Writes the current buffer content into a chunk_t
93 * Memory of specific chunk_t gets allocated.
95 * @param this calling private_generator_t object
96 * @param data pointer of chunk_t to write to
98 * - SUCCESSFUL if succeeded
99 * - OUT_OF_RES otherwise
101 status_t (*write_chunk
) (private_generator_t
*this,chunk_t
*data
);
104 * Generates a bytestream from a chunk_t
106 * @param this private_generator_t object
107 * @param offset offset of chunk_t value in data struct
108 * @return - SUCCESS if succeeded
109 * - OUT_OF_RES if out of ressources
111 status_t (*generate_from_chunk
) (private_generator_t
*this,u_int32_t offset
);
114 * Makes sure enough space is available in buffer to store amount of bits.
116 * If buffer is to small to hold the specific amount of bits it
117 * is increased using reallocation function of allocator.
119 * @param this calling private_generator_t object
120 * @param bits number of bits to make available in buffer
122 * - SUCCESSFUL if succeeded
123 * - OUT_OF_RES otherwise
125 status_t (*make_space_available
) (private_generator_t
*this,size_t bits
);
128 * Writes a specific amount of byte into the buffer.
130 * If buffer is to small to hold the specific amount of bytes it
133 * @param this calling private_generator_t object
134 * @param bytes pointer to bytes to write
135 * @param number_of_bytes number of bytes to write into buffer
137 * - SUCCESSFUL if succeeded
138 * - OUT_OF_RES otherwise
140 status_t (*write_bytes_to_buffer
) (private_generator_t
*this,void * bytes
,size_t number_of_bytes
);
144 * Writes a specific amount of byte into the buffer at a specific offset.
146 * @warning buffer size is not check to hold the data if offset is to large.
148 * @param this calling private_generator_t object
149 * @param bytes pointer to bytes to write
150 * @param number_of_bytes number of bytes to write into buffer
151 * @param offset offset to write the data into
153 * - SUCCESSFUL if succeeded
154 * - OUT_OF_RES otherwise
156 status_t (*write_bytes_to_buffer_at_offset
) (private_generator_t
*this,void * bytes
,size_t number_of_bytes
,u_int32_t offset
);
159 * Buffer used to generate the data into.
164 * Current write position in buffer (one byte aligned).
166 u_int8_t
*out_position
;
169 * Position of last byte in buffer.
171 u_int8_t
*roof_position
;
174 * Current bit writing to in current byte (between 0 and 7).
179 * Associated data struct to read informations from.
184 * Last payload length position offset in the buffer
186 u_int32_t last_payload_length_position_offset
;
189 * Attribute format of the last generated transform attribute
191 * Used to check if a variable value field is used or not for
192 * the transform attribute value.
194 bool attribute_format
;
197 * Depending on the value of attribute_format this field is used
198 * to hold the length of the transform attribute in bytes
201 u_int16_t attribute_length
;
210 * Implements private_generator_t's generate_u_int_type function.
211 * See #private_generator_s.generate_u_int_type.
213 static status_t
generate_u_int_type (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
)
215 size_t number_of_bits
= 0;
242 if (((number_of_bits
% 8) == 0) && (this->current_bit
!= 0))
244 /* current bit has to be zero for values multiple of 8 bits */
248 status
= this->make_space_available(this,number_of_bits
);
250 if (status
!= SUCCESS
)
259 if (this->current_bit
== 0)
261 u_int8_t high_val
= *((u_int8_t
*)(this->data_struct
+ offset
)) << 4;
262 u_int8_t low_val
= *(this->out_position
) & 0x0F;
264 *(this->out_position
) = high_val
| low_val
;
265 /* write position is not changed, just bit position is moved */
266 this->current_bit
= 4;
268 else if (this->current_bit
== 4)
270 u_int high_val
= *(this->out_position
) & 0xF0;
271 u_int low_val
= *((u_int8_t
*)(this->data_struct
+ offset
)) & 0x0F;
272 *(this->out_position
) = high_val
| low_val
;
273 this->out_position
++;
274 this->current_bit
= 0;
279 /* 4 Bit integers must have a 4 bit alignment */
287 *this->out_position
= *((u_int8_t
*)(this->data_struct
+ offset
));
288 this->out_position
++;
294 if (this->current_bit
!= 1)
298 u_int8_t attribute_format_flag
= *(this->out_position
) & 0x80;
300 u_int16_t int16_val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
302 int16_val
= int16_val
& 0xFF7F;
304 int16_val
= int16_val
| attribute_format_flag
;
306 this->write_bytes_to_buffer(this,&int16_val
,sizeof(u_int16_t
));
307 this->current_bit
= 0;
314 u_int16_t int16_val
= htons(*((u_int16_t
*)(this->data_struct
+ offset
)));
315 this->write_bytes_to_buffer(this,&int16_val
,sizeof(u_int16_t
));
321 u_int32_t int32_val
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
322 this->write_bytes_to_buffer(this,&int32_val
,sizeof(u_int32_t
));
327 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
)));
328 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(this->data_struct
+ offset
) + 1));
329 this->write_bytes_to_buffer(this,&int32_val_high
,sizeof(u_int32_t
));
330 this->write_bytes_to_buffer(this,&int32_val_low
,sizeof(u_int32_t
));
343 * Implements private_generator_t's generate_reserved_field function.
344 * See #private_generator_s.generate_reserved_field.
346 static status_t
generate_reserved_field (private_generator_t
*this,int bits
)
350 if ((bits
!= 1) && (bits
!= 8))
354 status
= this->make_space_available(this,bits
);
355 if (status
!= SUCCESS
)
362 u_int8_t reserved_bit
= ~(1 << (7 - this->current_bit
));
364 *(this->out_position
) = *(this->out_position
) & reserved_bit
;
366 if (this->current_bit
>= 8)
368 this->current_bit
= this->current_bit
% 8;
369 this->out_position
++;
375 if (this->current_bit
> 0)
379 *(this->out_position
) = 0x00;
380 this->out_position
++;
389 * Implements private_generator_t's generate_flag function.
390 * See #private_generator_s.generate_flag.
392 static status_t
generate_flag (private_generator_t
*this,u_int32_t offset
)
395 u_int8_t flag_value
= (*((bool *) (this->data_struct
+ offset
))) ?
1 : 0;
396 u_int8_t flag
= (flag_value
<< (7 - this->current_bit
));
398 status
= this->make_space_available(this,1);
399 if (status
!= SUCCESS
)
404 *(this->out_position
) = *(this->out_position
) | flag
;
407 if (this->current_bit
>= 8)
409 this->current_bit
= this->current_bit
% 8;
410 this->out_position
++;
416 * Implements private_generator_t's generate_from_chunk function.
417 * See #private_generator_s.generate_from_chunk.
419 static status_t
generate_from_chunk (private_generator_t
*this,u_int32_t offset
)
421 if (this->current_bit
!= 0)
425 chunk_t
*attribute_value
= (chunk_t
*)(this->data_struct
+ offset
);
427 return this->write_bytes_to_buffer (this,attribute_value
->ptr
,attribute_value
->len
);
432 * Implements private_generator_t's generator_context_make_space_available function.
433 * See #private_generator_s.generator_context_make_space_available.
435 static status_t
make_space_available (private_generator_t
*this, size_t bits
)
437 while ((((this->roof_position
- this->out_position
) * 8) - this->current_bit
) < bits
)
439 size_t old_buffer_size
= ((this->roof_position
) - ( this->buffer
));
440 size_t new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
441 size_t out_position_offset
= ((this->out_position
) - (this->buffer
));
442 u_int8_t
*new_buffer
;
444 new_buffer
= allocator_realloc(this->buffer
,new_buffer_size
);
445 if (new_buffer
== NULL
)
450 this->buffer
= new_buffer
;
452 this->out_position
= (this->buffer
+ out_position_offset
);
453 this->roof_position
= (this->buffer
+ new_buffer_size
);
461 * Implements private_generator_t's write_bytes_to_buffer function.
462 * See #private_generator_s.write_bytes_to_buffer.
464 static status_t
write_bytes_to_buffer (private_generator_t
*this,void * bytes
,size_t number_of_bytes
)
466 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
470 status
= this->make_space_available(this,number_of_bytes
* 8);
472 if (status
!= SUCCESS
)
477 for (i
= 0; i
< number_of_bytes
; i
++)
479 *(this->out_position
) = *(read_position
);
481 this->out_position
++;
487 * Implements private_generator_t's write_bytes_to_buffer_at_offset function.
488 * See #private_generator_s.write_bytes_to_buffer_at_offset.
489 * TODO automatic buffer increasing!
491 static status_t
write_bytes_to_buffer_at_offset (private_generator_t
*this,void * bytes
,size_t number_of_bytes
,u_int32_t offset
)
493 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
495 u_int8_t
*write_position
= this->buffer
+ offset
;
497 for (i
= 0; i
< number_of_bytes
; i
++)
499 *(write_position
) = *(read_position
);
507 * Implements generator_t's write_chunk function.
508 * See #generator_s.write_chunk.
510 static status_t
write_to_chunk (private_generator_t
*this,chunk_t
*data
)
512 size_t data_length
= this->out_position
- this->buffer
;
514 if (this->current_bit
> 0)
516 data
->ptr
= allocator_alloc(data_length
);
517 if (data
->ptr
== NULL
)
522 memcpy(data
->ptr
,this->buffer
,data_length
);
523 data
->len
= data_length
;
530 * Implements generator_t's generate_payload function.
531 * See #generator_s.generate_payload.
533 static status_t
generate_payload (private_generator_t
*this,payload_t
*payload
)
537 this->data_struct
= payload
;
539 encoding_rule_t
*rules
;
542 payload_type_t payload_type
= payload
->get_type(payload
);
544 this->logger
->log(this->logger
,CONTROL
,"Start generating payload of type %s",mapping_find(payload_type_t_mappings
,payload_type
));
546 payload
->get_encoding_rules(payload
,&rules
,&rule_count
);
548 for (i
= 0; i
< rule_count
;i
++)
551 switch (rules
[i
].type
)
553 /* all u int values are generated in generate_u_int_type */
559 status
= this->generate_u_int_type(this,rules
[i
].type
,rules
[i
].offset
);
563 status
= this->generate_reserved_field(this,1);
569 status
= this->generate_reserved_field(this,8);
574 status
= this->generate_flag(this,rules
[i
].offset
);
578 /* payload length is generated like an U_INT_16 */
579 this->last_payload_length_position_offset
= (this->out_position
- this->buffer
);
580 status
= this->generate_u_int_type(this,U_INT_16
,rules
[i
].offset
);
584 /* header length is generated like an U_INT_32 */
585 status
= this->generate_u_int_type(this,U_INT_32
,rules
[i
].offset
);
588 /* currently not implemented */
590 case TRANSFORM_ATTRIBUTES
:
592 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Transform attributes");
593 /* before iterative generate the transforms, store the current length position */
594 u_int32_t transform_length_position_offset
= this->last_payload_length_position_offset
;
596 u_int16_t length_of_transform
= TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
598 linked_list_t
*transform_attributes
=*((linked_list_t
**)(this->data_struct
+ rules
[i
].offset
));
600 linked_list_iterator_t
*iterator
;
601 /* create forward iterator */
602 status
= transform_attributes
->create_iterator(transform_attributes
,&iterator
,TRUE
);
603 if (status
!= SUCCESS
)
607 while (iterator
->has_next(iterator
))
609 payload_t
*current_attribute
;
610 u_int32_t before_generate_position_offset
;
611 u_int32_t after_generate_position_offset
;
612 status
= iterator
->current(iterator
,(void **)¤t_attribute
);
613 if (status
!= SUCCESS
)
615 iterator
->destroy(iterator
);
619 before_generate_position_offset
= (this->out_position
- this->buffer
);
620 this->public.generate_payload(&(this->public),current_attribute
);
621 after_generate_position_offset
= (this->out_position
- this->buffer
);
623 /* increase size of transform */
624 length_of_transform
+= (after_generate_position_offset
- before_generate_position_offset
);
627 iterator
->destroy(iterator
);
629 this->logger
->log(this->logger
,CONTROL_MORE
,"Length of Transform is %d, offset is %d",length_of_transform
,transform_length_position_offset
);
631 int16_val
= htons(length_of_transform
);
632 this->write_bytes_to_buffer_at_offset(this,&int16_val
,sizeof(u_int16_t
),transform_length_position_offset
);
636 case ATTRIBUTE_FORMAT
:
638 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Format flag");
639 /* Attribute format is a flag which is stored in context*/
641 status
= this->generate_flag(this,rules
[i
].offset
);
642 this->attribute_format
= *((bool *) (this->data_struct
+ rules
[i
].offset
));
647 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Type field");
648 // the attribute type is a 15 bit integer so it has to be generated special
649 status
= this->generate_u_int_type(this,ATTRIBUTE_TYPE
,rules
[i
].offset
);
652 case ATTRIBUTE_LENGTH_OR_VALUE
:
654 this->logger
->log(this->logger
,CONTROL_MORE
,"Generate Attribute Length or Value field");
655 if (this->attribute_format
== FALSE
)
657 status
= this->generate_u_int_type(this,U_INT_16
,rules
[i
].offset
);
658 /* this field hold the length of the attribute */
659 this->attribute_length
= *((u_int16_t
*)(this->data_struct
+ rules
[i
].offset
));
663 status
= this->write_bytes_to_buffer(this,(this->data_struct
+ rules
[i
].offset
),2);
667 case ATTRIBUTE_VALUE
:
669 if (this->attribute_format
== FALSE
)
671 this->logger
->log(this->logger
,CONTROL_MORE
,"Attribute value has not fixed size");
672 /* the attribute value is generated */
673 status
= this->generate_from_chunk(this,rules
[i
].offset
);
678 return NOT_SUPPORTED
;
686 * Implements generator_t's destroy function.
687 * See #generator_s.destroy.
689 static status_t
destroy(private_generator_t
*this)
691 allocator_free(this->buffer
);
692 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
693 allocator_free(this);
698 * Described in header
700 generator_t
* generator_create()
702 private_generator_t
*this;
704 this = allocator_alloc_thing(private_generator_t
);
710 /* initiate public functions */
711 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_t
*)) generate_payload
;
712 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
713 this->public.write_to_chunk
= (status_t (*) (generator_t
*,chunk_t
*)) write_to_chunk
;
716 /* initiate private functions */
717 // this->generate = generate;
718 this->generate_u_int_type
= generate_u_int_type
;
719 this->generate_reserved_field
= generate_reserved_field
;
720 this->generate_flag
= generate_flag
;
721 this->generate_from_chunk
= generate_from_chunk
;
722 this->make_space_available
= make_space_available
;
723 this->write_bytes_to_buffer
= write_bytes_to_buffer
;
724 this->write_bytes_to_buffer_at_offset
= write_bytes_to_buffer_at_offset
;
727 /* allocate memory for buffer */
728 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
729 if (this->buffer
== NULL
)
731 allocator_free(this);
735 /* initiate private variables */
736 this->out_position
= this->buffer
;
737 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
738 this->data_struct
= NULL
;
739 this->current_bit
= 0;
740 this->last_payload_length_position_offset
= 0;
741 this->logger
= global_logger_manager
->create_logger(global_logger_manager
,GENERATOR
,NULL
);
742 return &(this->public);