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"
33 typedef struct private_generator_context_s private_generator_context_t
;
35 struct private_generator_context_s
{
37 * Public part of the context
39 generator_context_t
public;
42 * Buffer used to generate the data into.
47 * Current write position in buffer (one byte aligned).
49 u_int8_t
*out_position
;
52 * Position of last byte in buffer.
54 u_int8_t
*roof_position
;
57 * Current bit writing to in current byte (between 0 and 7).
62 * Associated data struct to read informations from.
67 * Writes the current buffer content into a chunk_t
69 * Memory of specific chunk_t gets allocated.
71 * @param generator_infos_t calling generator_infos_t object
72 * @param data pointer of chunk_t to write to
74 * - SUCCESSFUL if succeeded
75 * - OUT_OF_RES otherwise
77 status_t (*write_chunk
) (private_generator_context_t
*this,chunk_t
*data
);
81 * Makes sure enough space is available in buffer to store amount of bits.
83 * If buffer is to small to hold the specific amount of bits it
84 * is increased using reallocation function of allocator.
86 * @param generator_infos_t calling generator_infos_t object
87 * @param bits number of bits to make available in buffer
89 * - SUCCESSFUL if succeeded
90 * - OUT_OF_RES otherwise
92 status_t (*make_space_available
) (private_generator_context_t
*this,size_t bits
);
95 * Writes a specific amount of byte into the buffer.
97 * If buffer is to small to hold the specific amount of bytes it
100 * @param generator_infos_t calling generator_infos_t object
101 * @param bytes pointer to bytes to write
102 * @param number_of_bytes number of bytes to write into buffer
104 * - SUCCESSFUL if succeeded
105 * - OUT_OF_RES otherwise
107 status_t (*write_bytes_to_buffer
) (private_generator_context_t
*this,void * bytes
,size_t number_of_bytes
);
113 * Implements generator_infos_t's increase_buffer function.
114 * See #generator_infos_s.increase_buffer.
116 static status_t
generator_context_make_space_available (private_generator_context_t
*this, size_t bits
)
118 while ((((this->roof_position
- this->out_position
) * 8) - this->current_bit
) < bits
)
120 size_t old_buffer_size
= ((this->roof_position
) - ( this->buffer
));
121 size_t new_buffer_size
= old_buffer_size
+ GENERATOR_DATA_BUFFER_INCREASE_VALUE
;
122 size_t out_position_offset
= ((this->out_position
) - (this->buffer
));
123 u_int8_t
*new_buffer
;
125 new_buffer
= allocator_realloc(this->buffer
,new_buffer_size
);
126 if (new_buffer
== NULL
)
131 this->buffer
= new_buffer
;
133 this->out_position
= (this->buffer
+ out_position_offset
);
134 this->roof_position
= (this->buffer
+ new_buffer_size
);
142 * Implements generator_infos_t's write_bytes_to_buffer function.
143 * See #generator_infos_s.write_bytes_to_buffer.
145 static status_t
generator_context_write_bytes_to_buffer (private_generator_context_t
*this,void * bytes
,size_t number_of_bytes
)
147 u_int8_t
*read_position
= (u_int8_t
*) bytes
;
151 status
= this->make_space_available(this,number_of_bytes
* 8);
153 if (status
!= SUCCESS
)
158 for (i
= 0; i
< number_of_bytes
; i
++)
160 *(this->out_position
) = *(read_position
);
162 this->out_position
++;
168 * Implements generator_infos_t's write_chunk function.
169 * See #generator_infos_s.write_chunk.
171 static status_t
generator_context_write_chunk (private_generator_context_t
*this,chunk_t
*data
)
173 size_t data_length
= this->out_position
- this->buffer
;
175 if (this->current_bit
> 0)
177 data
->ptr
= allocator_alloc(data_length
);
178 if (data
->ptr
== NULL
)
183 memcpy(data
->ptr
,this->buffer
,data_length
);
184 data
->len
= data_length
;
190 * Implements generator_infos_t's destroy function.
191 * See #generator_infos_s.destroy.
193 static status_t
generator_context_destroy (private_generator_context_t
*this)
195 allocator_free(this->buffer
);
196 allocator_free(this);
201 * Described in header
203 static generator_context_t
* generator_context_create(generator_t
*generator
)
205 private_generator_context_t
*this = allocator_alloc_thing(private_generator_context_t
);
213 this->public.destroy
= (status_t (*) (generator_context_t
*this))generator_context_destroy
;
214 this->make_space_available
= generator_context_make_space_available
;
215 this->write_chunk
= generator_context_write_chunk
;
216 this->write_bytes_to_buffer
= generator_context_write_bytes_to_buffer
;
218 /* allocate memory for buffer */
219 this->buffer
= allocator_alloc(GENERATOR_DATA_BUFFER_SIZE
);
220 if (this->buffer
== NULL
)
222 allocator_free(this);
226 /* set private data */
227 this->out_position
= this->buffer
;
228 this->roof_position
= this->buffer
+ GENERATOR_DATA_BUFFER_SIZE
;
229 this->data_struct
= NULL
;
230 this->current_bit
= 0;
231 return &(this->public);
236 * Private part of a generator_t object
238 typedef struct private_generator_s private_generator_t
;
240 struct private_generator_s
{
242 * Public part of a generator_t object
246 /* private functions and fields */
249 * Generates a chunk_t with specific encoding rules.
251 * Iems are bytewhise written.
253 * @param this private_generator_t object
254 * @param data_struct data_struct to read data from
255 * @param encoding_rules pointer to first encoding_rule
256 * of encoding rules array
257 * @param encoding_rules_count number of encoding rules
258 * in encoding rules array
259 * @param data pointer to chunk_t where to write the data in
261 * @return - SUCCESS if succeeded
262 * - OUT_OF_RES if out of ressources
264 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
);
267 * Generates a U_INT-Field type
269 * @param this private_generator_t object
270 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
271 * @param offset offset of value in data struct
272 * @param generator_contexts generator_contexts_t object where the context is written or read from
273 * @return - SUCCESS if succeeded
274 * - OUT_OF_RES if out of ressources
276 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
);
279 * Generates a RESERVED BIT field or a RESERVED BYTE field
281 * @param this private_generator_t object
282 * @param generator_contexts generator_contexts_t object where the context is written or read from
283 * @param bits number of bits to generate
284 * @return - SUCCESS if succeeded
285 * - OUT_OF_RES if out of ressources
286 * - FAILED if bit count not supported
288 status_t (*generate_reserved_field
) (private_generator_t
*this,private_generator_context_t
*generator_context
,int bits
);
291 * Generates a FLAG field
293 * @param this private_generator_t object
294 * @param generator_contexts generator_contexts_t object where the context is written or read from
295 * @param offset offset of flag value in data struct
296 * @return - SUCCESS if succeeded
297 * - OUT_OF_RES if out of ressources
299 status_t (*generate_flag
) (private_generator_t
*this,private_generator_context_t
*generator_context
,u_int32_t offset
);
302 * Pointer to the payload informations needed to automatic
303 * generate a specific payload type
305 payload_info_t
**payload_infos
;
309 * Implements private_generator_t's generate_u_int_type function.
310 * See #private_generator_s.generate_u_int_type.
312 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
)
314 size_t number_of_bits
= 0;
338 if (((number_of_bits
% 8) == 0) && (generator_context
->current_bit
!= 0))
340 /* current bit has to be zero for values greater then 4 bits */
344 status
= generator_context
->make_space_available(generator_context
,number_of_bits
);
346 if (status
!= SUCCESS
)
355 if (generator_context
->current_bit
== 0)
357 u_int8_t high_val
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
)) << 4;
358 u_int8_t low_val
= *(generator_context
->out_position
) & 0x0F;
360 *(generator_context
->out_position
) = high_val
| low_val
;
361 /* write position is not changed, just bit position is moved */
362 generator_context
->current_bit
= 4;
364 else if (generator_context
->current_bit
== 4)
366 u_int high_val
= *(generator_context
->out_position
) & 0xF0;
367 u_int low_val
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
)) & 0x0F;
368 *(generator_context
->out_position
) = high_val
| low_val
;
369 generator_context
->out_position
++;
370 generator_context
->current_bit
= 0;
375 /* 4 Bit integers must have a 4 bit alignment */
383 *generator_context
->out_position
= *((u_int8_t
*)(generator_context
->data_struct
+ offset
));
384 generator_context
->out_position
++;
390 u_int16_t int16_val
= htons(*((u_int16_t
*)(generator_context
->data_struct
+ offset
)));
391 generator_context
->write_bytes_to_buffer(generator_context
,&int16_val
,sizeof(u_int16_t
));
397 u_int32_t int32_val
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
)));
398 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val
,sizeof(u_int32_t
));
403 u_int32_t int32_val_low
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
)));
404 u_int32_t int32_val_high
= htonl(*((u_int32_t
*)(generator_context
->data_struct
+ offset
) + 1));
405 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val_high
,sizeof(u_int32_t
));
406 generator_context
->write_bytes_to_buffer(generator_context
,&int32_val_low
,sizeof(u_int32_t
));
418 static status_t
generate_reserved_field (private_generator_t
*this,private_generator_context_t
*generator_context
,int bits
)
422 if ((bits
!= 1) && (bits
!= 8))
426 status
= generator_context
->make_space_available(generator_context
,bits
);
427 if (status
!= SUCCESS
)
434 u_int8_t reserved_bit
= ~(1 << (7 - generator_context
->current_bit
));
436 *(generator_context
->out_position
) = *(generator_context
->out_position
) & reserved_bit
;
437 generator_context
->current_bit
++;
438 if (generator_context
->current_bit
>= 8)
440 generator_context
->current_bit
= generator_context
->current_bit
% 8;
441 generator_context
->out_position
++;
447 if (generator_context
->current_bit
> 0)
451 *(generator_context
->out_position
) = 0x00;
452 generator_context
->out_position
++;
460 static status_t
generate_flag (private_generator_t
*this,private_generator_context_t
*generator_context
,u_int32_t offset
)
463 u_int8_t flag_value
= (*((bool *) (generator_context
->data_struct
+ offset
))) ?
1 : 0;
464 u_int8_t flag
= (flag_value
<< (7 - generator_context
->current_bit
));
466 status
= generator_context
->make_space_available(generator_context
,1);
467 if (status
!= SUCCESS
)
472 *(generator_context
->out_position
) = *(generator_context
->out_position
) | flag
;
474 generator_context
->current_bit
++;
475 if (generator_context
->current_bit
>= 8)
477 generator_context
->current_bit
= generator_context
->current_bit
% 8;
478 generator_context
->out_position
++;
484 * Implements private_generator_t's generate function.
485 * See #private_generator_s.generate.
487 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
)
492 if (generator_context
== NULL
)
497 for (i
= 0; i
< encoding_rules_count
;i
++)
500 switch (encoding_rules
[i
].type
)
502 /* all u int values are generated in generate_u_int_type */
508 status
= this->generate_u_int_type(this,encoding_rules
[i
].type
,encoding_rules
[i
].offset
,generator_context
);
512 status
= this->generate_reserved_field(this,generator_context
,1);
518 status
= this->generate_reserved_field(this,generator_context
,8);
523 status
= this->generate_flag(this,generator_context
,encoding_rules
[i
].offset
);
527 /* length is generated like an U_INT_32 */
528 status
= this->generate_u_int_type(this,U_INT_32
,encoding_rules
[i
].offset
,generator_context
);
531 /* currently not implemented */
535 if (status
!= SUCCESS
)
537 generator_context
->public.destroy(&(generator_context
->public));
542 // infos->destroy(infos);
547 * Implements generator_t's generate_payload function.
548 * See #generator_s.generate_payload.
550 static status_t
generate_payload (private_generator_t
*this,payload_type_t payload_type
,void * data_struct
, generator_context_t
*generator_context
)
554 private_generator_context_t
*private_generator_context
= (private_generator_context_t
*) generator_context
;
556 private_generator_context
->data_struct
= data_struct
;
558 /* check every payload info for specific type */
559 for (i
= 0; this->payload_infos
[i
] != NULL
; i
++)
561 if (this->payload_infos
[i
]->payload_type
== payload_type
)
563 /* found payload informations, generating is done in private function generate() */
564 return (this->generate(this, data_struct
,this->payload_infos
[i
]->ecoding_rules
,this->payload_infos
[i
]->encoding_rules_count
,private_generator_context
));
567 return NOT_SUPPORTED
;
570 status_t
write_to_chunk (private_generator_t
*this,private_generator_context_t
*generator_context
, chunk_t
*data
)
572 return generator_context
->write_chunk(generator_context
,data
);
576 * Implements generator_t's destroy function.
577 * See #generator_s.destroy.
579 static status_t
destroy(private_generator_t
*this)
581 allocator_free(this);
586 * Described in header
588 generator_t
* generator_create(payload_info_t
** payload_infos
)
590 private_generator_t
*this;
592 if (payload_infos
== NULL
)
597 this = allocator_alloc_thing(private_generator_t
);
603 /* initiate public functions */
604 this->public.create_context
= (generator_context_t
* (*) (generator_t
*)) generator_context_create
;
605 this->public.generate_payload
= (status_t(*)(generator_t
*, payload_type_t
, void *, generator_context_t
*)) generate_payload
;
606 this->public.destroy
= (status_t(*)(generator_t
*)) destroy
;
607 this->public.write_to_chunk
= (status_t (*) (generator_t
*,generator_context_t
*, chunk_t
*)) write_to_chunk
;
608 /* initiate private functions */
609 this->generate
= generate
;
610 this->generate_u_int_type
= generate_u_int_type
;
611 this->generate_reserved_field
= generate_reserved_field
;
612 this->generate_flag
= generate_flag
;
614 /* initiate private variables */
615 this->payload_infos
= payload_infos
;
617 return &(this->public);