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>
27 #include "allocator.h"
29 #include "generator.h"
33 * Used for generator operations internaly to store a generator context.
35 typedef struct generator_infos_s generator_infos_t
;
37 struct generator_infos_s
{
40 * Buffer used to generate the data into.
45 * Current write position in buffer (one byte aligned).
47 u_int8_t
*out_position
;
50 * Position of last byte in buffer.
52 u_int8_t
*roof_position
;
55 * Current bit writing to in current byte (between 0 and 7).
60 * Associated data struct to read informations from.
65 * @brief Destroys a generator_infos_t object and its containing buffer
67 * @param generator_infos_t generator_infos_t object
68 * @return always SUCCESSFUL
70 status_t (*destroy
) (generator_infos_t
*this);
73 * Makes sure enough space is available in buffer to store amount of bits.
75 * If buffer is to small to hold the specific amount of bits it
76 * is increased using reallocation function of allocator.
78 * @param generator_infos_t calling generator_infos_t object
79 * @param bits number of bits to make available in buffer
81 * - SUCCESSFUL if succeeded
82 * - OUT_OF_RES otherwise
84 status_t (*make_space_available
) (generator_infos_t
*this,size_t bits
);
87 * Writes a specific amount of byte into the buffer.
89 * If buffer is to small to hold the specific amount of bytes it
92 * @param generator_infos_t calling generator_infos_t object
93 * @param bytes pointer to bytes to write
94 * @param number_of_bytes number of bytes to write into buffer
96 * - SUCCESSFUL if succeeded
97 * - OUT_OF_RES otherwise
99 status_t (*write_bytes_to_buffer
) (generator_infos_t
*this,void * bytes
,size_t number_of_bytes
);
102 * Writes the current buffer content into a chunk_t
104 * Memory of specific chunk_t gets allocated.
106 * @param generator_infos_t calling generator_infos_t object
107 * @param data pointer of chunk_t to write to
109 * - SUCCESSFUL if succeeded
110 * - OUT_OF_RES otherwise
112 status_t (*write_chunk
) (generator_infos_t
*this,chunk_t
*data
);
116 * Implements generator_infos_t's increase_buffer function.
117 * See #generator_infos_s.increase_buffer.
119 static status_t
generator_info_make_space_available (generator_infos_t
*this, size_t bits
)
121 while ((((this->roof_position
- this->out_position
) * 8) - this->current_bit
) < bits
)
123 size_t old_buffer_size
= ((this->roof_position
) - ( this->buffer
));
124 size_t new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
125 size_t out_position_offset
= ((this->out_position
) - (this->buffer
));
126 u_int8_t
*new_buffer
;
128 new_buffer
= allocator_realloc(this->buffer
,new_buffer_size
);
129 if (new_buffer
== NULL
)
134 this->buffer
= new_buffer
;
136 this->out_position
= (this->buffer
+ out_position_offset
);
137 this->roof_position
= (this->buffer
+ new_buffer_size
);
145 * Implements generator_infos_t's write_bytes_to_buffer function.
146 * See #generator_infos_s.write_bytes_to_buffer.
148 static status_t
generator_info_write_bytes_to_buffer (generator_infos_t
*this,void * bytes
,size_t number_of_bytes
)
150 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
154 status
= this->make_space_available(this,number_of_bytes
* 8);
156 if (status
!= SUCCESS
)
161 for (i
= 0; i
< number_of_bytes
; i
++)
163 *(this->out_position
) = *(read_position
);
165 this->out_position
++;
171 * Implements generator_infos_t's write_chunk function.
172 * See #generator_infos_s.write_chunk.
174 static status_t
generator_infos_write_chunk (generator_infos_t
*this,chunk_t
*data
)
176 size_t data_length
= this->out_position
- this->buffer
;
177 if (this->current_bit
> 0)
179 data
->ptr
= allocator_alloc(data_length
);
180 if (data
->ptr
== NULL
)
185 memcpy(data
->ptr
,this->buffer
,data_length
);
186 data
->len
= data_length
;
192 * Implements generator_infos_t's destroy function.
193 * See #generator_infos_s.destroy.
195 static status_t
generator_infos_destroy (generator_infos_t
*this)
197 allocator_free(this->buffer
);
198 allocator_free(this);
203 * Creates a generator_infos_t object holding necessary informations
204 * for generating (buffer, data_struct, etc).
206 * @param data_struct data struct where the specific payload informations are stored
208 * - pointer to created generator_infos_t object
209 * - NULL if memory allocation failed
211 generator_infos_t
* generator_infos_create(void *data_struct
)
213 generator_infos_t
*this = allocator_alloc_thing(generator_infos_t
);
221 this->destroy
= generator_infos_destroy
;
222 this->make_space_available
= generator_info_make_space_available
;
223 this->write_chunk
= generator_infos_write_chunk
;
224 this->write_bytes_to_buffer
= generator_info_write_bytes_to_buffer
;
226 /* allocate memory for buffer */
227 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
228 if (this->buffer
== NULL
)
230 allocator_free(this);
234 /* set private data */
235 this->out_position
= this->buffer
;
236 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
237 this->data_struct
= data_struct
;
238 this->current_bit
= 0;
245 * Private part of a generator_t object
247 typedef struct private_generator_s private_generator_t
;
249 struct private_generator_s
{
251 * Public part of a generator_t object
255 /* private functions and fields */
258 * Generates a chunk_t with specific encoding rules.
260 * Iems are bytewhise written.
262 * @param this private_generator_t object
263 * @param data_struct data_struct to read data from
264 * @param encoding_rules pointer to first encoding_rule
265 * of encoding rules array
266 * @param encoding_rules_count number of encoding rules
267 * in encoding rules array
268 * @param data pointer to chunk_t where to write the data in
270 * @return - SUCCESS if succeeded
271 * - OUT_OF_RES if out of ressources
273 status_t (*generate
) (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, chunk_t
*data
);
276 * Generates a U_INT-Field type
278 * @param this private_generator_t object
279 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
280 * @param offset offset of value in data struct
281 * @param generator_infos generator_infos_t object where the context is written or read from
282 * @return - SUCCESS if succeeded
283 * - OUT_OF_RES if out of ressources
285 status_t (*generate_u_int_type
) (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
, generator_infos_t
*generator_infos
);
288 * Pointer to the payload informations needed to automatic
289 * generate a specific payload type
291 payload_info_t
**payload_infos
;
295 * Implements private_generator_t's generate_u_int_type function.
296 * See #private_generator_s.generate_u_int_type.
298 static status_t
generate_u_int_type (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
,generator_infos_t
*generator_infos
)
300 size_t number_of_bits
= 0;
324 if (((number_of_bits
% 8) == 0) && (generator_infos
->current_bit
!= 0))
326 /* current bit has to be zero for values greater then 4 bits */
330 status
= generator_infos
->make_space_available(generator_infos
,number_of_bits
);
332 if (status
!= SUCCESS
)
341 if (generator_infos
->current_bit
== 0)
343 u_int8_t high_val
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
)) << 4;
344 u_int8_t low_val
= *(generator_infos
->out_position
) & 0x0F;
346 *(generator_infos
->out_position
) = high_val
| low_val
;
347 /* write position is not changed, just bit position is moved */
348 generator_infos
->current_bit
= 4;
350 else if (generator_infos
->current_bit
== 4)
352 u_int high_val
= *(generator_infos
->out_position
) & 0xF0;
353 u_int low_val
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
)) & 0x0F;
354 *(generator_infos
->out_position
) = high_val
| low_val
;
355 generator_infos
->out_position
++;
356 generator_infos
->current_bit
= 0;
361 /* 4 Bit integers must have a 4 bit alignment */
369 *generator_infos
->out_position
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
));
370 generator_infos
->out_position
++;
376 u_int16_t int16_val
= htons(*((u_int16_t
*)(generator_infos
->data_struct
+ offset
)));
377 generator_infos
->write_bytes_to_buffer(generator_infos
,&int16_val
,sizeof(u_int16_t
));
383 u_int32_t int32_val
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
)));
384 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val
,sizeof(u_int32_t
));
389 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
)));
390 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
) + 1));
391 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val_high
,sizeof(u_int32_t
));
392 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val_low
,sizeof(u_int32_t
));
405 * Implements private_generator_t's generate function.
406 * See #private_generator_s.generate.
408 static status_t
generate (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, chunk_t
*data
)
414 generator_infos_t
*infos
= generator_infos_create(data_struct
);
422 for (i
= 0; i
< encoding_rules_count
;i
++)
425 switch (encoding_rules
[i
].type
)
427 /* all u int values are generated in generate_u_int_type */
433 status
= this->generate_u_int_type(this,encoding_rules
[i
].type
,encoding_rules
[i
].offset
,infos
);
437 status
= infos
->make_space_available(infos
,1);
438 u_int8_t reserved_bit
= ~(1 << (7 - infos
->current_bit
));
440 *(infos
->out_position
) = *(infos
->out_position
) & reserved_bit
;
442 infos
->current_bit
++;
443 if (infos
->current_bit
>= 8)
445 infos
->current_bit
= infos
->current_bit
% 8;
446 infos
->out_position
++;
452 status
= infos
->make_space_available(infos
,8);
453 if ((status
!= SUCCESS
) || (infos
->current_bit
> 0))
457 *(infos
->out_position
) = 0x00;
458 infos
->out_position
++;
463 u_int8_t flag_value
= (*((bool *) (infos
->data_struct
+ encoding_rules
[i
].offset
))) ?
1 : 0;
464 u_int8_t flag
= (flag_value
<< (7 - infos
->current_bit
));
466 *(infos
->out_position
) = *(infos
->out_position
) | flag
;
468 infos
->current_bit
++;
469 if (infos
->current_bit
>= 8)
471 infos
->current_bit
= infos
->current_bit
% 8;
472 status
= infos
->make_space_available(infos
,8);
473 infos
->out_position
++;
478 /* length is generated like an U_INT_32 */
479 status
= this->generate_u_int_type(this,U_INT_32
,encoding_rules
[i
].offset
,infos
);
481 /* actually not implemented */
485 if (status
!= SUCCESS
)
487 infos
->destroy(infos
);
493 status
= infos
->write_chunk(infos
,data
);
494 infos
->destroy(infos
);
499 * Implements generator_t's generate_payload function.
500 * See #generator_s.generate_payload.
502 static status_t
generate_payload (private_generator_t
*this,payload_type_t payload_type
,void * data_struct
, chunk_t
*data
)
506 /* check every payload info for specific type */
507 for (i
= 0; this->payload_infos
[i
] != NULL
; i
++)
509 if (this->payload_infos
[i
]->payload_type
== payload_type
)
511 /* found payload informations, generating is done in private function generate() */
512 return (this->generate(this, data_struct
,this->payload_infos
[i
]->ecoding_rules
,this->payload_infos
[i
]->encoding_rules_count
,data
));
515 return NOT_SUPPORTED
;
519 * Implements generator_t's destroy function.
520 * See #generator_s.destroy.
522 static status_t
destroy(private_generator_t
*this)
524 allocator_free(this);
529 * Described in header
531 generator_t
* generator_create(payload_info_t
** payload_infos
)
533 private_generator_t
*this;
535 if (payload_infos
== NULL
)
540 this = allocator_alloc_thing(private_generator_t
);
546 /* initiate public functions */
547 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_type_t
, void *, chunk_t
*)) generate_payload
;
548 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
550 /* initiate private functions */
551 this->generate
= generate
;
552 this->generate_u_int_type
= generate_u_int_type
;
554 /* initiate private variables */
555 this->payload_infos
= payload_infos
;
557 return &(this->public);