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 "payloads/payload.h"
36 typedef struct private_generator_context_s private_generator_context_t
;
38 struct private_generator_context_s
{
40 * Public part of the context
42 generator_context_t
public;
45 * Buffer used to generate the data into.
50 * Current write position in buffer (one byte aligned).
52 u_int8_t
*out_position
;
55 * Position of last byte in buffer.
57 u_int8_t
*roof_position
;
60 * Current bit writing to in current byte (between 0 and 7).
65 * Associated data struct to read informations from.
70 * Writes the current buffer content into a chunk_t
72 * Memory of specific chunk_t gets allocated.
74 * @param generator_infos_t calling generator_infos_t object
75 * @param data pointer of chunk_t to write to
77 * - SUCCESSFUL if succeeded
78 * - OUT_OF_RES otherwise
80 status_t (*write_chunk
) (private_generator_context_t
*this,chunk_t
*data
);
84 * Makes sure enough space is available in buffer to store amount of bits.
86 * If buffer is to small to hold the specific amount of bits it
87 * is increased using reallocation function of allocator.
89 * @param generator_infos_t calling generator_infos_t object
90 * @param bits number of bits to make available in buffer
92 * - SUCCESSFUL if succeeded
93 * - OUT_OF_RES otherwise
95 status_t (*make_space_available
) (private_generator_context_t
*this,size_t bits
);
98 * Writes a specific amount of byte into the buffer.
100 * If buffer is to small to hold the specific amount of bytes it
103 * @param generator_infos_t calling generator_infos_t object
104 * @param bytes pointer to bytes to write
105 * @param number_of_bytes number of bytes to write into buffer
107 * - SUCCESSFUL if succeeded
108 * - OUT_OF_RES otherwise
110 status_t (*write_bytes_to_buffer
) (private_generator_context_t
*this,void * bytes
,size_t number_of_bytes
);
116 * Implements generator_infos_t's increase_buffer function.
117 * See #generator_infos_s.increase_buffer.
119 static status_t
generator_context_make_space_available (private_generator_context_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_context_write_bytes_to_buffer (private_generator_context_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_context_write_chunk (private_generator_context_t
*this,chunk_t
*data
)
176 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_context_destroy (private_generator_context_t
*this)
198 allocator_free(this->buffer
);
199 allocator_free(this);
204 * Described in header
206 static generator_context_t
* generator_context_create(generator_t
*generator
)
208 private_generator_context_t
*this = allocator_alloc_thing(private_generator_context_t
);
216 this->public.destroy
= (status_t (*) (generator_context_t
*this))generator_context_destroy
;
217 this->make_space_available
= generator_context_make_space_available
;
218 this->write_chunk
= generator_context_write_chunk
;
219 this->write_bytes_to_buffer
= generator_context_write_bytes_to_buffer
;
221 /* allocate memory for buffer */
222 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
223 if (this->buffer
== NULL
)
225 allocator_free(this);
229 /* set private data */
230 this->out_position
= this->buffer
;
231 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
232 this->data_struct
= NULL
;
233 this->current_bit
= 0;
234 return &(this->public);
239 * Private part of a generator_t object
241 typedef struct private_generator_s private_generator_t
;
243 struct private_generator_s
{
245 * Public part of a generator_t object
249 /* private functions and fields */
252 * Generates a chunk_t with specific encoding rules.
254 * Iems are bytewhise written.
256 * @param this private_generator_t object
257 * @param data_struct data_struct to read data from
258 * @param encoding_rules pointer to first encoding_rule
259 * of encoding rules array
260 * @param encoding_rules_count number of encoding rules
261 * in encoding rules array
262 * @param data pointer to chunk_t where to write the data in
264 * @return - SUCCESS if succeeded
265 * - OUT_OF_RES if out of ressources
267 status_t (*generate
) (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, private_generator_context_t
*generator_context
);
270 * Generates a U_INT-Field type
272 * @param this private_generator_t object
273 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
274 * @param offset offset of value in data struct
275 * @param generator_contexts generator_contexts_t object where the context is written or read from
276 * @return - SUCCESS if succeeded
277 * - OUT_OF_RES if out of ressources
279 status_t (*generate_u_int_type
) (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
, private_generator_context_t
*generator_context
);
282 * Generates a RESERVED BIT field or a RESERVED BYTE field
284 * @param this private_generator_t object
285 * @param generator_contexts generator_contexts_t object where the context is written or read from
286 * @param bits number of bits to generate
287 * @return - SUCCESS if succeeded
288 * - OUT_OF_RES if out of ressources
289 * - FAILED if bit count not supported
291 status_t (*generate_reserved_field
) (private_generator_t
*this,private_generator_context_t
*generator_context
,int bits
);
294 * Generates a FLAG field
296 * @param this private_generator_t object
297 * @param generator_contexts generator_contexts_t object where the context is written or read from
298 * @param offset offset of flag value in data struct
299 * @return - SUCCESS if succeeded
300 * - OUT_OF_RES if out of ressources
302 status_t (*generate_flag
) (private_generator_t
*this,private_generator_context_t
*generator_context
,u_int32_t offset
);
305 * Pointer to the payload informations needed to automatic
306 * generate a specific payload type
308 payload_info_t
**payload_infos
;
312 * Implements private_generator_t's generate_u_int_type function.
313 * See #private_generator_s.generate_u_int_type.
315 static status_t
generate_u_int_type (private_generator_t
*this,encoding_type_t int_type
,u_int32_t offset
,private_generator_context_t
*generator_context
)
317 size_t number_of_bits
= 0;
341 if (((number_of_bits
% 8) == 0) && (generator_context
->current_bit
!= 0))
343 /* current bit has to be zero for values greater then 4 bits */
347 status
= generator_context
->make_space_available(generator_context
,number_of_bits
);
349 if (status
!= SUCCESS
)
358 if (generator_context
->current_bit
== 0)
360 u_int8_t high_val
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
)) << 4;
361 u_int8_t low_val
= *(generator_context
->out_position
) & 0x0F;
363 *(generator_context
->out_position
) = high_val
| low_val
;
364 /* write position is not changed, just bit position is moved */
365 generator_context
->current_bit
= 4;
367 else if (generator_context
->current_bit
== 4)
369 u_int high_val
= *(generator_context
->out_position
) & 0xF0;
370 u_int low_val
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
)) & 0x0F;
371 *(generator_context
->out_position
) = high_val
| low_val
;
372 generator_context
->out_position
++;
373 generator_context
->current_bit
= 0;
378 /* 4 Bit integers must have a 4 bit alignment */
386 *generator_context
->out_position
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
));
387 generator_context
->out_position
++;
393 u_int16_t int16_val
= htons(*((u_int16_t
*)(generator_context
->data_struct
+ offset
)));
394 generator_context
->write_bytes_to_buffer(generator_context
,&int16_val
,sizeof(u_int16_t
));
400 u_int32_t int32_val
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
)));
401 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val
,sizeof(u_int32_t
));
406 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
)));
407 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
) + 1));
408 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val_high
,sizeof(u_int32_t
));
409 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val_low
,sizeof(u_int32_t
));
421 static status_t
generate_reserved_field (private_generator_t
*this,private_generator_context_t
*generator_context
,int bits
)
425 if ((bits
!= 1) && (bits
!= 8))
429 status
= generator_context
->make_space_available(generator_context
,bits
);
430 if (status
!= SUCCESS
)
437 u_int8_t reserved_bit
= ~(1 << (7 - generator_context
->current_bit
));
439 *(generator_context
->out_position
) = *(generator_context
->out_position
) & reserved_bit
;
440 generator_context
->current_bit
++;
441 if (generator_context
->current_bit
>= 8)
443 generator_context
->current_bit
= generator_context
->current_bit
% 8;
444 generator_context
->out_position
++;
450 if (generator_context
->current_bit
> 0)
454 *(generator_context
->out_position
) = 0x00;
455 generator_context
->out_position
++;
463 static status_t
generate_flag (private_generator_t
*this,private_generator_context_t
*generator_context
,u_int32_t offset
)
466 u_int8_t flag_value
= (*((bool *) (generator_context
->data_struct
+ offset
))) ?
1 : 0;
467 u_int8_t flag
= (flag_value
<< (7 - generator_context
->current_bit
));
469 status
= generator_context
->make_space_available(generator_context
,1);
470 if (status
!= SUCCESS
)
475 *(generator_context
->out_position
) = *(generator_context
->out_position
) | flag
;
477 generator_context
->current_bit
++;
478 if (generator_context
->current_bit
>= 8)
480 generator_context
->current_bit
= generator_context
->current_bit
% 8;
481 generator_context
->out_position
++;
487 * Implements private_generator_t's generate function.
488 * See #private_generator_s.generate.
490 static status_t
generate (private_generator_t
*this,void * data_struct
,encoding_rule_t
*encoding_rules
, size_t encoding_rules_count
, private_generator_context_t
*generator_context
)
495 if (generator_context
== NULL
)
500 for (i
= 0; i
< encoding_rules_count
;i
++)
503 switch (encoding_rules
[i
].type
)
505 /* all u int values are generated in generate_u_int_type */
511 status
= this->generate_u_int_type(this,encoding_rules
[i
].type
,encoding_rules
[i
].offset
,generator_context
);
515 status
= this->generate_reserved_field(this,generator_context
,1);
521 status
= this->generate_reserved_field(this,generator_context
,8);
526 status
= this->generate_flag(this,generator_context
,encoding_rules
[i
].offset
);
530 /* length is generated like an U_INT_32 */
531 status
= this->generate_u_int_type(this,U_INT_32
,encoding_rules
[i
].offset
,generator_context
);
534 /* currently not implemented */
538 if (status
!= SUCCESS
)
540 generator_context
->public.destroy(&(generator_context
->public));
545 // infos->destroy(infos);
550 * Implements generator_t's generate_payload function.
551 * See #generator_s.generate_payload.
553 static status_t
generate_payload (private_generator_t
*this,payload_type_t payload_type
,void * data_struct
, generator_context_t
*generator_context
)
557 private_generator_context_t
*private_generator_context
= (private_generator_context_t
*) generator_context
;
559 private_generator_context
->data_struct
= data_struct
;
561 /* check every payload info for specific type */
562 for (i
= 0; this->payload_infos
[i
] != NULL
; i
++)
564 if (this->payload_infos
[i
]->payload_type
== payload_type
)
566 /* found payload informations, generating is done in private function generate() */
567 return (this->generate(this, data_struct
,this->payload_infos
[i
]->ecoding_rules
,this->payload_infos
[i
]->encoding_rules_count
,private_generator_context
));
570 return NOT_SUPPORTED
;
573 status_t
write_to_chunk (private_generator_t
*this,private_generator_context_t
*generator_context
, chunk_t
*data
)
575 return generator_context
->write_chunk(generator_context
,data
);
579 * Implements generator_t's destroy function.
580 * See #generator_s.destroy.
582 static status_t
destroy(private_generator_t
*this)
584 allocator_free(this);
589 * Described in header
591 generator_t
* generator_create(payload_info_t
** payload_infos
)
593 private_generator_t
*this;
595 if (payload_infos
== NULL
)
600 this = allocator_alloc_thing(private_generator_t
);
606 /* initiate public functions */
607 this->public.create_context
= (generator_context_t
* (*) (generator_t
*)) generator_context_create
;
608 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_type_t
, void *, generator_context_t
*)) generate_payload
;
609 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
610 this->public.write_to_chunk
= (status_t (*) (generator_t
*,generator_context_t
*, chunk_t
*)) write_to_chunk
;
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);