- private function for every field type
[strongswan.git] / Source / charon / generator.c
1 /**
2 * @file generator.c
3 *
4 * @brief Generic generator class used to generate IKEv2-header and payloads.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <arpa/inet.h>
26 #include <stdio.h>
27
28 #include "allocator.h"
29 #include "types.h"
30 #include "generator.h"
31
32
33 /**
34 * Used for generator operations internaly to store a generator context.
35 */
36 typedef struct generator_infos_s generator_infos_t;
37
38 struct generator_infos_s {
39
40 /**
41 * Buffer used to generate the data into.
42 */
43 u_int8_t *buffer;
44
45 /**
46 * Current write position in buffer (one byte aligned).
47 */
48 u_int8_t *out_position;
49
50 /**
51 * Position of last byte in buffer.
52 */
53 u_int8_t *roof_position;
54
55 /**
56 * Current bit writing to in current byte (between 0 and 7).
57 */
58 size_t current_bit;
59
60 /**
61 * Associated data struct to read informations from.
62 */
63 void * data_struct;
64
65 /**
66 * @brief Destroys a generator_infos_t object and its containing buffer
67 *
68 * @param generator_infos_t generator_infos_t object
69 * @return always SUCCESSFUL
70 */
71 status_t (*destroy) (generator_infos_t *this);
72
73 /**
74 * Makes sure enough space is available in buffer to store amount of bits.
75 *
76 * If buffer is to small to hold the specific amount of bits it
77 * is increased using reallocation function of allocator.
78 *
79 * @param generator_infos_t calling generator_infos_t object
80 * @param bits number of bits to make available in buffer
81 * @return
82 * - SUCCESSFUL if succeeded
83 * - OUT_OF_RES otherwise
84 */
85 status_t (*make_space_available) (generator_infos_t *this,size_t bits);
86
87 /**
88 * Writes a specific amount of byte into the buffer.
89 *
90 * If buffer is to small to hold the specific amount of bytes it
91 * is increased.
92 *
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
96 * @return
97 * - SUCCESSFUL if succeeded
98 * - OUT_OF_RES otherwise
99 */
100 status_t (*write_bytes_to_buffer) (generator_infos_t *this,void * bytes,size_t number_of_bytes);
101
102 /**
103 * Writes the current buffer content into a chunk_t
104 *
105 * Memory of specific chunk_t gets allocated.
106 *
107 * @param generator_infos_t calling generator_infos_t object
108 * @param data pointer of chunk_t to write to
109 * @return
110 * - SUCCESSFUL if succeeded
111 * - OUT_OF_RES otherwise
112 */
113 status_t (*write_chunk) (generator_infos_t *this,chunk_t *data);
114 };
115
116 /**
117 * Implements generator_infos_t's increase_buffer function.
118 * See #generator_infos_s.increase_buffer.
119 */
120 static status_t generator_info_make_space_available (generator_infos_t *this, size_t bits)
121 {
122 while ((((this->roof_position - this->out_position) * 8) - this->current_bit) < bits)
123 {
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;
128
129 new_buffer = allocator_realloc(this->buffer,new_buffer_size);
130 if (new_buffer == NULL)
131 {
132 return OUT_OF_RES;
133 }
134
135 this->buffer = new_buffer;
136
137 this->out_position = (this->buffer + out_position_offset);
138 this->roof_position = (this->buffer + new_buffer_size);
139
140 }
141
142 return SUCCESS;
143 }
144
145 /**
146 * Implements generator_infos_t's write_bytes_to_buffer function.
147 * See #generator_infos_s.write_bytes_to_buffer.
148 */
149 static status_t generator_info_write_bytes_to_buffer (generator_infos_t *this,void * bytes,size_t number_of_bytes)
150 {
151 u_int8_t *read_position = (u_int8_t *) bytes;
152 int i;
153 status_t status;
154
155 status = this->make_space_available(this,number_of_bytes * 8);
156
157 if (status != SUCCESS)
158 {
159 return status;
160 }
161
162 for (i = 0; i < number_of_bytes; i++)
163 {
164 *(this->out_position) = *(read_position);
165 read_position++;
166 this->out_position++;
167 }
168 return status;
169 }
170
171 /**
172 * Implements generator_infos_t's write_chunk function.
173 * See #generator_infos_s.write_chunk.
174 */
175 static status_t generator_infos_write_chunk (generator_infos_t *this,chunk_t *data)
176 {
177 size_t data_length = this->out_position - this->buffer;
178 if (this->current_bit > 0)
179 data_length++;
180 data->ptr = allocator_alloc(data_length);
181 if (data->ptr == NULL)
182 {
183 data->len = 0;
184 return OUT_OF_RES;
185 }
186 memcpy(data->ptr,this->buffer,data_length);
187 data->len = data_length;
188 return SUCCESS;
189 }
190
191
192 /**
193 * Implements generator_infos_t's destroy function.
194 * See #generator_infos_s.destroy.
195 */
196 static status_t generator_infos_destroy (generator_infos_t *this)
197 {
198 allocator_free(this->buffer);
199 allocator_free(this);
200 return SUCCESS;
201 }
202
203 /**
204 * Creates a generator_infos_t object holding necessary informations
205 * for generating (buffer, data_struct, etc).
206 *
207 * @param data_struct data struct where the specific payload informations are stored
208 * @return
209 * - pointer to created generator_infos_t object
210 * - NULL if memory allocation failed
211 */
212 generator_infos_t * generator_infos_create(void *data_struct)
213 {
214 generator_infos_t *this = allocator_alloc_thing(generator_infos_t);
215
216 if (this == NULL)
217 {
218 return NULL;
219 }
220
221 /* object methods */
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;
226
227 /* allocate memory for buffer */
228 this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE);
229 if (this->buffer == NULL)
230 {
231 allocator_free(this);
232 return NULL;
233 }
234
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;
240 return (this);
241 }
242
243
244
245 /**
246 * Private part of a generator_t object
247 */
248 typedef struct private_generator_s private_generator_t;
249
250 struct private_generator_s {
251 /**
252 * Public part of a generator_t object
253 */
254 generator_t public;
255
256 /* private functions and fields */
257
258 /**
259 * Generates a chunk_t with specific encoding rules.
260 *
261 * Iems are bytewhise written.
262 *
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
270 *
271 * @return - SUCCESS if succeeded
272 * - OUT_OF_RES if out of ressources
273 */
274 status_t (*generate) (private_generator_t *this,void * data_struct,encoding_rule_t *encoding_rules, size_t encoding_rules_count, chunk_t *data);
275
276 /**
277 * Generates a U_INT-Field type
278 *
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
285 */
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);
287
288 /**
289 * Generates a RESERVED BIT field or a RESERVED BYTE field
290 *
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
297 */
298 status_t (*generate_reserved_field) (private_generator_t *this,generator_infos_t *generator_infos,int bits);
299
300 /**
301 * Generates a FLAG field
302 *
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
308 */
309 status_t (*generate_flag) (private_generator_t *this,generator_infos_t *generator_infos,u_int32_t offset);
310
311 /**
312 * Pointer to the payload informations needed to automatic
313 * generate a specific payload type
314 */
315 payload_info_t **payload_infos;
316 };
317
318 /**
319 * Implements private_generator_t's generate_u_int_type function.
320 * See #private_generator_s.generate_u_int_type.
321 */
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)
323 {
324 size_t number_of_bits = 0;
325 status_t status;
326
327
328 switch (int_type)
329 {
330 case U_INT_4:
331 number_of_bits = 4;
332 break;
333 case U_INT_8:
334 number_of_bits = 8;
335 break;
336 case U_INT_16:
337 number_of_bits = 16;
338 break;
339 case U_INT_32:
340 number_of_bits = 32;
341 break;
342 case U_INT_64:
343 number_of_bits = 64;
344 break;
345 default:
346 return FAILED;
347 }
348 if (((number_of_bits % 8) == 0) && (generator_infos->current_bit != 0))
349 {
350 /* current bit has to be zero for values greater then 4 bits */
351 return FAILED;
352 }
353
354 status = generator_infos->make_space_available(generator_infos,number_of_bits);
355
356 if (status != SUCCESS)
357 {
358 return status;
359 }
360
361 switch (int_type)
362 {
363 case U_INT_4:
364 {
365 if (generator_infos->current_bit == 0)
366 {
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;
369
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;
373 }
374 else if (generator_infos->current_bit == 4)
375 {
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;
381
382 }
383 else
384 {
385 /* 4 Bit integers must have a 4 bit alignment */
386 return FAILED;
387 };
388 break;
389 }
390
391 case U_INT_8:
392 {
393 *generator_infos->out_position = *((u_int8_t *)(generator_infos->data_struct + offset));
394 generator_infos->out_position++;
395 break;
396
397 }
398 case U_INT_16:
399 {
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));
402
403 break;
404 }
405 case U_INT_32:
406 {
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));
409 break;
410 }
411 case U_INT_64:
412 {
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));
417 break;
418 }
419
420 default:
421 return FAILED;
422
423 }
424
425 return SUCCESS;
426 }
427
428 static status_t generate_reserved_field (private_generator_t *this,generator_infos_t *generator_infos,int bits)
429 {
430 status_t status;
431
432 if ((bits != 1) && (bits != 8))
433 {
434 return FAILED;
435 }
436 status = generator_infos->make_space_available(generator_infos,bits);
437 if (status != SUCCESS)
438 {
439 return status;
440 }
441
442 if (bits == 1)
443 {
444 u_int8_t reserved_bit = ~(1 << (7 - generator_infos->current_bit));
445
446 *(generator_infos->out_position) = *(generator_infos->out_position) & reserved_bit;
447 generator_infos->current_bit++;
448 if (generator_infos->current_bit >= 8)
449 {
450 generator_infos->current_bit = generator_infos->current_bit % 8;
451 generator_infos->out_position++;
452 }
453 }
454 else
455 {
456 /* one byte */
457 if (generator_infos->current_bit > 0)
458 {
459 return FAILED;
460 }
461 *(generator_infos->out_position) = 0x00;
462 generator_infos->out_position++;
463 }
464
465 return SUCCESS;
466
467
468 }
469
470 static status_t generate_flag (private_generator_t *this,generator_infos_t *generator_infos,u_int32_t offset)
471 {
472 status_t status;
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));
475
476 status = generator_infos->make_space_available(generator_infos,1);
477 if (status != SUCCESS)
478 {
479 return status;
480 }
481
482 *(generator_infos->out_position) = *(generator_infos->out_position) | flag;
483
484 generator_infos->current_bit++;
485 if (generator_infos->current_bit >= 8)
486 {
487 generator_infos->current_bit = generator_infos->current_bit % 8;
488 generator_infos->out_position++;
489 }
490 return SUCCESS;
491 }
492
493 /**
494 * Implements private_generator_t's generate function.
495 * See #private_generator_s.generate.
496 */
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)
498 {
499 int i;
500 status_t status;
501
502 generator_infos_t *infos = generator_infos_create(data_struct);
503
504 if (infos == NULL)
505 {
506 return OUT_OF_RES;
507 }
508
509 for (i = 0; i < encoding_rules_count;i++)
510 {
511 status = SUCCESS;
512 switch (encoding_rules[i].type)
513 {
514 /* all u int values are generated in generate_u_int_type */
515 case U_INT_4:
516 case U_INT_8:
517 case U_INT_16:
518 case U_INT_32:
519 case U_INT_64:
520 status = this->generate_u_int_type(this,encoding_rules[i].type,encoding_rules[i].offset,infos);
521 break;
522 case RESERVED_BIT:
523 {
524 status = this->generate_reserved_field(this,infos,1);
525
526 break;
527 }
528 case RESERVED_BYTE:
529 {
530 status = this->generate_reserved_field(this,infos,8);
531 break;
532 }
533 case FLAG:
534 {
535 status = this->generate_flag(this,infos,encoding_rules[i].offset);
536 break;
537 }
538 case LENGTH:
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);
541 break;
542 case SPI_SIZE:
543 /* currently not implemented */
544 default:
545 break;
546 }
547 if (status != SUCCESS)
548 {
549 infos->destroy(infos);
550 return status;
551 }
552 }
553
554 status = infos->write_chunk(infos,data);
555 infos->destroy(infos);
556 return status;
557 }
558
559 /**
560 * Implements generator_t's generate_payload function.
561 * See #generator_s.generate_payload.
562 */
563 static status_t generate_payload (private_generator_t *this,payload_type_t payload_type,void * data_struct, chunk_t *data)
564 {
565 int i;
566
567 /* check every payload info for specific type */
568 for (i = 0; this->payload_infos[i] != NULL; i++)
569 {
570 if (this->payload_infos[i]->payload_type == payload_type)
571 {
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));
574 }
575 }
576 return NOT_SUPPORTED;
577 }
578
579 /**
580 * Implements generator_t's destroy function.
581 * See #generator_s.destroy.
582 */
583 static status_t destroy(private_generator_t *this)
584 {
585 allocator_free(this);
586 return SUCCESS;
587 }
588
589 /*
590 * Described in header
591 */
592 generator_t * generator_create(payload_info_t ** payload_infos)
593 {
594 private_generator_t *this;
595
596 if (payload_infos == NULL)
597 {
598 return NULL;
599 }
600
601 this = allocator_alloc_thing(private_generator_t);
602 if (this == NULL)
603 {
604 return NULL;
605 }
606
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;
610
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;
616
617 /* initiate private variables */
618 this->payload_infos = payload_infos;
619
620 return &(this->public);
621 }