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>
28 #include "allocator.h"
30 #include "generator.h"
34 * Used for generator operations internaly to store a generator context.
36 typedef struct generator_infos_s generator_infos_t
;
38 struct generator_infos_s
{
41 * Buffer used to generate the data into.
46 * Current write position in buffer (one byte aligned).
48 u_int8_t
*out_position
;
51 * Position of last byte in buffer.
53 u_int8_t
*roof_position
;
56 * Current bit writing to in current byte (between 0 and 7).
61 * Associated data struct to read informations from.
66 * @brief Destroys a generator_infos_t object and its containing buffer
68 * @param generator_infos_t generator_infos_t object
69 * @return always SUCCESSFUL
71 status_t (*destroy
) (generator_infos_t
*this);
74 * Makes sure enough space is available in buffer to store amount of bits.
76 * If buffer is to small to hold the specific amount of bits it
77 * is increased using reallocation function of allocator.
79 * @param generator_infos_t calling generator_infos_t object
80 * @param bits number of bits to make available in buffer
82 * - SUCCESSFUL if succeeded
83 * - OUT_OF_RES otherwise
85 status_t (*make_space_available
) (generator_infos_t
*this,size_t bits
);
88 * Writes a specific amount of byte into the buffer.
90 * If buffer is to small to hold the specific amount of bytes it
93 * @param generator_infos_t calling generator_infos_t object
94 * @param bytes pointer to bytes to write
95 * @param number_of_bytes number of bytes to write into buffer
97 * - SUCCESSFUL if succeeded
98 * - OUT_OF_RES otherwise
100 status_t (*write_bytes_to_buffer
) (generator_infos_t
*this,void * bytes
,size_t number_of_bytes
);
103 * Writes the current buffer content into a chunk_t
105 * Memory of specific chunk_t gets allocated.
107 * @param generator_infos_t calling generator_infos_t object
108 * @param data pointer of chunk_t to write to
110 * - SUCCESSFUL if succeeded
111 * - OUT_OF_RES otherwise
113 status_t (*write_chunk
) (generator_infos_t
*this,chunk_t
*data
);
117 * Implements generator_infos_t's increase_buffer function.
118 * See #generator_infos_s.increase_buffer.
120 static status_t
generator_info_make_space_available (generator_infos_t
*this, size_t bits
)
122 while ((((this->roof_position
- this->out_position
) * 8) - this->current_bit
) < bits
)
124 size_t old_buffer_size
= ((this->roof_position
) - ( this->buffer
));
125 size_t new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
126 size_t out_position_offset
= ((this->out_position
) - (this->buffer
));
127 u_int8_t
*new_buffer
;
129 new_buffer
= allocator_realloc(this->buffer
,new_buffer_size
);
130 if (new_buffer
== NULL
)
135 this->buffer
= new_buffer
;
137 this->out_position
= (this->buffer
+ out_position_offset
);
138 this->roof_position
= (this->buffer
+ new_buffer_size
);
146 * Implements generator_infos_t's write_bytes_to_buffer function.
147 * See #generator_infos_s.write_bytes_to_buffer.
149 static status_t
generator_info_write_bytes_to_buffer (generator_infos_t
*this,void * bytes
,size_t number_of_bytes
)
151 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
155 status
= this->make_space_available(this,number_of_bytes
* 8);
157 if (status
!= SUCCESS
)
162 for (i
= 0; i
< number_of_bytes
; i
++)
164 *(this->out_position
) = *(read_position
);
166 this->out_position
++;
172 * Implements generator_infos_t's write_chunk function.
173 * See #generator_infos_s.write_chunk.
175 static status_t
generator_infos_write_chunk (generator_infos_t
*this,chunk_t
*data
)
177 size_t data_length
= this->out_position
- this->buffer
;
178 if (this->current_bit
> 0)
180 data
->ptr
= allocator_alloc(data_length
);
181 if (data
->ptr
== NULL
)
186 memcpy(data
->ptr
,this->buffer
,data_length
);
187 data
->len
= data_length
;
193 * Implements generator_infos_t's destroy function.
194 * See #generator_infos_s.destroy.
196 static status_t
generator_infos_destroy (generator_infos_t
*this)
198 allocator_free(this->buffer
);
199 allocator_free(this);
204 * Creates a generator_infos_t object holding necessary informations
205 * for generating (buffer, data_struct, etc).
207 * @param data_struct data struct where the specific payload informations are stored
209 * - pointer to created generator_infos_t object
210 * - NULL if memory allocation failed
212 generator_infos_t
* generator_infos_create(void *data_struct
)
214 generator_infos_t
*this = allocator_alloc_thing(generator_infos_t
);
222 this->destroy
= generator_infos_destroy
;
223 this->make_space_available
= generator_info_make_space_available
;
224 this->write_chunk
= generator_infos_write_chunk
;
225 this->write_bytes_to_buffer
= generator_info_write_bytes_to_buffer
;
227 /* allocate memory for buffer */
228 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
229 if (this->buffer
== NULL
)
231 allocator_free(this);
235 /* set private data */
236 this->out_position
= this->buffer
;
237 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
238 this->data_struct
= data_struct
;
239 this->current_bit
= 0;
246 * Private part of a generator_t object
248 typedef struct private_generator_s private_generator_t
;
250 struct private_generator_s
{
252 * Public part of a generator_t object
256 /* private functions and fields */
259 * Generates a chunk_t with specific encoding rules.
261 * Iems are bytewhise written.
263 * @param this private_generator_t object
264 * @param data_struct data_struct to read data from
265 * @param encoding_rules pointer to first encoding_rule
266 * of encoding rules array
267 * @param encoding_rules_count number of encoding rules
268 * in encoding rules array
269 * @param data pointer to chunk_t where to write the data in
271 * @return - SUCCESS if succeeded
272 * - OUT_OF_RES if out of ressources
274 status_t (*generate
) (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, chunk_t
*data
);
277 * Generates a U_INT-Field type
279 * @param this private_generator_t object
280 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
281 * @param offset offset of value in data struct
282 * @param generator_infos generator_infos_t object where the context is written or read from
283 * @return - SUCCESS if succeeded
284 * - OUT_OF_RES if out of ressources
286 status_t (*generate_u_int_type
) (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
, generator_infos_t
*generator_infos
);
289 * Generates a RESERVED BIT field or a RESERVED BYTE field
291 * @param this private_generator_t object
292 * @param generator_infos generator_infos_t object where the context is written or read from
293 * @param bits number of bits to generate
294 * @return - SUCCESS if succeeded
295 * - OUT_OF_RES if out of ressources
296 * - FAILED if bit count not supported
298 status_t (*generate_reserved_field
) (private_generator_t
*this,generator_infos_t
*generator_infos
,int bits
);
301 * Generates a FLAG field
303 * @param this private_generator_t object
304 * @param generator_infos generator_infos_t object where the context is written or read from
305 * @param offset offset of flag value in data struct
306 * @return - SUCCESS if succeeded
307 * - OUT_OF_RES if out of ressources
309 status_t (*generate_flag
) (private_generator_t
*this,generator_infos_t
*generator_infos
,u_int32_t offset
);
312 * Pointer to the payload informations needed to automatic
313 * generate a specific payload type
315 payload_info_t
**payload_infos
;
319 * Implements private_generator_t's generate_u_int_type function.
320 * See #private_generator_s.generate_u_int_type.
322 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
)
324 size_t number_of_bits
= 0;
348 if (((number_of_bits
% 8) == 0) && (generator_infos
->current_bit
!= 0))
350 /* current bit has to be zero for values greater then 4 bits */
354 status
= generator_infos
->make_space_available(generator_infos
,number_of_bits
);
356 if (status
!= SUCCESS
)
365 if (generator_infos
->current_bit
== 0)
367 u_int8_t high_val
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
)) << 4;
368 u_int8_t low_val
= *(generator_infos
->out_position
) & 0x0F;
370 *(generator_infos
->out_position
) = high_val
| low_val
;
371 /* write position is not changed, just bit position is moved */
372 generator_infos
->current_bit
= 4;
374 else if (generator_infos
->current_bit
== 4)
376 u_int high_val
= *(generator_infos
->out_position
) & 0xF0;
377 u_int low_val
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
)) & 0x0F;
378 *(generator_infos
->out_position
) = high_val
| low_val
;
379 generator_infos
->out_position
++;
380 generator_infos
->current_bit
= 0;
385 /* 4 Bit integers must have a 4 bit alignment */
393 *generator_infos
->out_position
= *((u_int8_t
*)(generator_infos
->data_struct
+ offset
));
394 generator_infos
->out_position
++;
400 u_int16_t int16_val
= htons(*((u_int16_t
*)(generator_infos
->data_struct
+ offset
)));
401 generator_infos
->write_bytes_to_buffer(generator_infos
,&int16_val
,sizeof(u_int16_t
));
407 u_int32_t int32_val
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
)));
408 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val
,sizeof(u_int32_t
));
413 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
)));
414 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(generator_infos
->data_struct
+ offset
) + 1));
415 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val_high
,sizeof(u_int32_t
));
416 generator_infos
->write_bytes_to_buffer(generator_infos
,&int32_val_low
,sizeof(u_int32_t
));
428 static status_t
generate_reserved_field (private_generator_t
*this,generator_infos_t
*generator_infos
,int bits
)
432 if ((bits
!= 1) && (bits
!= 8))
436 status
= generator_infos
->make_space_available(generator_infos
,bits
);
437 if (status
!= SUCCESS
)
444 u_int8_t reserved_bit
= ~(1 << (7 - generator_infos
->current_bit
));
446 *(generator_infos
->out_position
) = *(generator_infos
->out_position
) & reserved_bit
;
447 generator_infos
->current_bit
++;
448 if (generator_infos
->current_bit
>= 8)
450 generator_infos
->current_bit
= generator_infos
->current_bit
% 8;
451 generator_infos
->out_position
++;
457 if (generator_infos
->current_bit
> 0)
461 *(generator_infos
->out_position
) = 0x00;
462 generator_infos
->out_position
++;
470 static status_t
generate_flag (private_generator_t
*this,generator_infos_t
*generator_infos
,u_int32_t offset
)
473 u_int8_t flag_value
= (*((bool *) (generator_infos
->data_struct
+ offset
))) ?
1 : 0;
474 u_int8_t flag
= (flag_value
<< (7 - generator_infos
->current_bit
));
476 status
= generator_infos
->make_space_available(generator_infos
,1);
477 if (status
!= SUCCESS
)
482 *(generator_infos
->out_position
) = *(generator_infos
->out_position
) | flag
;
484 generator_infos
->current_bit
++;
485 if (generator_infos
->current_bit
>= 8)
487 generator_infos
->current_bit
= generator_infos
->current_bit
% 8;
488 generator_infos
->out_position
++;
494 * Implements private_generator_t's generate function.
495 * See #private_generator_s.generate.
497 static status_t
generate (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, chunk_t
*data
)
502 generator_infos_t
*infos
= generator_infos_create(data_struct
);
509 for (i
= 0; i
< encoding_rules_count
;i
++)
512 switch (encoding_rules
[i
].type
)
514 /* all u int values are generated in generate_u_int_type */
520 status
= this->generate_u_int_type(this,encoding_rules
[i
].type
,encoding_rules
[i
].offset
,infos
);
524 status
= this->generate_reserved_field(this,infos
,1);
530 status
= this->generate_reserved_field(this,infos
,8);
535 status
= this->generate_flag(this,infos
,encoding_rules
[i
].offset
);
539 /* length is generated like an U_INT_32 */
540 status
= this->generate_u_int_type(this,U_INT_32
,encoding_rules
[i
].offset
,infos
);
543 /* currently not implemented */
547 if (status
!= SUCCESS
)
549 infos
->destroy(infos
);
554 status
= infos
->write_chunk(infos
,data
);
555 infos
->destroy(infos
);
560 * Implements generator_t's generate_payload function.
561 * See #generator_s.generate_payload.
563 static status_t
generate_payload (private_generator_t
*this,payload_type_t payload_type
,void * data_struct
, chunk_t
*data
)
567 /* check every payload info for specific type */
568 for (i
= 0; this->payload_infos
[i
] != NULL
; i
++)
570 if (this->payload_infos
[i
]->payload_type
== payload_type
)
572 /* found payload informations, generating is done in private function generate() */
573 return (this->generate(this, data_struct
,this->payload_infos
[i
]->ecoding_rules
,this->payload_infos
[i
]->encoding_rules_count
,data
));
576 return NOT_SUPPORTED
;
580 * Implements generator_t's destroy function.
581 * See #generator_s.destroy.
583 static status_t
destroy(private_generator_t
*this)
585 allocator_free(this);
590 * Described in header
592 generator_t
* generator_create(payload_info_t
** payload_infos
)
594 private_generator_t
*this;
596 if (payload_infos
== NULL
)
601 this = allocator_alloc_thing(private_generator_t
);
607 /* initiate public functions */
608 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_type_t
, void *, chunk_t
*)) generate_payload
;
609 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
611 /* initiate private functions */
612 this->generate
= generate
;
613 this->generate_u_int_type
= generate_u_int_type
;
614 this->generate_reserved_field
= generate_reserved_field
;
615 this->generate_flag
= generate_flag
;
617 /* initiate private variables */
618 this->payload_infos
= payload_infos
;
620 return &(this->public);