9fb304787432a9b2060b2c77e671fc29ab5d9aab
[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
29 #include "generator.h"
30
31 #include "types.h"
32 #include "utils/allocator.h"
33 #include "utils/linked_list.h"
34 #include "utils/logger_manager.h"
35 #include "payloads/payload.h"
36 #include "payloads/proposal_substructure.h"
37 #include "payloads/transform_substructure.h"
38 #include "payloads/sa_payload.h"
39
40
41 extern logger_manager_t *global_logger_manager;
42
43 /**
44 * Private part of a generator_t object
45 */
46 typedef struct private_generator_s private_generator_t;
47
48 struct private_generator_s {
49 /**
50 * Public part of a generator_t object
51 */
52 generator_t public;
53
54 /* private functions and fields */
55
56
57 /**
58 * Generates a U_INT-Field type and writes it to buffer.
59 *
60 * @param this private_generator_t object
61 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
62 * ATTRIBUTE_TYPE is also generated in this function
63 * @param offset offset of value in data struct
64 * @param generator_contexts generator_contexts_t object where the context is written or read from
65 * @return - SUCCESS if succeeded
66 * - OUT_OF_RES if out of ressources
67 */
68 status_t (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset);
69
70 /**
71 * Get size of current buffer in bytes.
72 *
73 * @param this private_generator_t object
74 * @return Size of buffer in bytes
75 */
76 size_t (*get_current_buffer_size) (private_generator_t *this);
77
78 /**
79 * Get free space of current buffer in bytes.
80 *
81 * @param this private_generator_t object
82 * @return space in buffer in bytes
83 */
84 size_t (*get_current_buffer_space) (private_generator_t *this);
85
86 /**
87 * Get length of data in buffer (in bytes).
88 *
89 * @param this private_generator_t object
90 * @return length of data in bytes
91 */
92 size_t (*get_current_data_length) (private_generator_t *this);
93
94 /**
95 * Get current offset in buffer (in bytes).
96 *
97 * @param this private_generator_t object
98 * @return offset in bytes
99 */
100 u_int32_t (*get_current_buffer_offset) (private_generator_t *this);
101
102 /**
103 * Generates a RESERVED BIT field or a RESERVED BYTE field and writes
104 * it to the buffer.
105 *
106 * @param this private_generator_t object
107 * @param generator_contexts generator_contexts_t object where the context is written or read from
108 * @param bits number of bits to generate
109 * @return - SUCCESS if succeeded
110 * - OUT_OF_RES if out of ressources
111 * - FAILED if bit count not supported
112 */
113 status_t (*generate_reserved_field) (private_generator_t *this,int bits);
114
115 /**
116 * Generates a FLAG field
117 *
118 * @param this private_generator_t object
119 * @param generator_contexts generator_contexts_t object where the context is written or read from
120 * @param offset offset of flag value in data struct
121 * @return - SUCCESS if succeeded
122 * - OUT_OF_RES if out of ressources
123 */
124 status_t (*generate_flag) (private_generator_t *this,u_int32_t offset);
125
126 /**
127 * Writes the current buffer content into a chunk_t
128 *
129 * Memory of specific chunk_t gets allocated.
130 *
131 * @param this calling private_generator_t object
132 * @param data pointer of chunk_t to write to
133 * @return
134 * - SUCCESSFUL if succeeded
135 * - OUT_OF_RES otherwise
136 */
137 status_t (*write_chunk) (private_generator_t *this,chunk_t *data);
138
139 /**
140 * Generates a bytestream from a chunk_t
141 *
142 * @param this private_generator_t object
143 * @param offset offset of chunk_t value in data struct
144 * @return - SUCCESS if succeeded
145 * - OUT_OF_RES if out of ressources
146 */
147 status_t (*generate_from_chunk) (private_generator_t *this,u_int32_t offset);
148
149 /**
150 * Makes sure enough space is available in buffer to store amount of bits.
151 *
152 * If buffer is to small to hold the specific amount of bits it
153 * is increased using reallocation function of allocator.
154 *
155 * @param this calling private_generator_t object
156 * @param bits number of bits to make available in buffer
157 * @return
158 * - SUCCESSFUL if succeeded
159 * - OUT_OF_RES otherwise
160 */
161 status_t (*make_space_available) (private_generator_t *this,size_t bits);
162
163 /**
164 * Writes a specific amount of byte into the buffer.
165 *
166 * If buffer is to small to hold the specific amount of bytes it
167 * is increased.
168 *
169 * @param this calling private_generator_t object
170 * @param bytes pointer to bytes to write
171 * @param number_of_bytes number of bytes to write into buffer
172 * @return
173 * - SUCCESSFUL if succeeded
174 * - OUT_OF_RES otherwise
175 */
176 status_t (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes);
177
178
179 /**
180 * Writes a specific amount of byte into the buffer at a specific offset.
181 *
182 * @warning buffer size is not check to hold the data if offset is to large.
183 *
184 * @param this calling private_generator_t object
185 * @param bytes pointer to bytes to write
186 * @param number_of_bytes number of bytes to write into buffer
187 * @param offset offset to write the data into
188 * @return
189 * - SUCCESSFUL if succeeded
190 * - OUT_OF_RES otherwise
191 */
192 status_t (*write_bytes_to_buffer_at_offset) (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset);
193
194 /**
195 * Buffer used to generate the data into.
196 */
197 u_int8_t *buffer;
198
199 /**
200 * Current write position in buffer (one byte aligned).
201 */
202 u_int8_t *out_position;
203
204 /**
205 * Position of last byte in buffer.
206 */
207 u_int8_t *roof_position;
208
209 /**
210 * Current bit writing to in current byte (between 0 and 7).
211 */
212 size_t current_bit;
213
214 /**
215 * Associated data struct to read informations from.
216 */
217 void * data_struct;
218
219 /*
220 * Last payload length position offset in the buffer
221 */
222 u_int32_t last_payload_length_position_offset;
223
224 /**
225 * Offset of the header length field in the buffer
226 */
227 u_int32_t header_length_position_offset;
228
229 /**
230 * Last SPI size
231 */
232 u_int8_t last_spi_size;
233
234 /*
235 * Attribute format of the last generated transform attribute
236 *
237 * Used to check if a variable value field is used or not for
238 * the transform attribute value.
239 */
240 bool attribute_format;
241
242 /*
243 * Depending on the value of attribute_format this field is used
244 * to hold the length of the transform attribute in bytes
245 */
246 u_int16_t attribute_length;
247
248 /**
249 * Associated Logger
250 */
251 logger_t *logger;
252 };
253
254 /**
255 * Implements private_generator_t's get_current_buffer_size function.
256 * See #private_generator_s.get_current_buffer_size.
257 */
258 static size_t get_current_buffer_size (private_generator_t *this)
259 {
260 return ((this->roof_position) - (this->buffer));
261 }
262
263 /**
264 * Implements private_generator_t's get_current_buffer_space function.
265 * See #private_generator_s.get_current_buffer_space.
266 */
267 static size_t get_current_buffer_space (private_generator_t *this)
268 {
269 /* we know, one byte more */
270 size_t space = (this->roof_position) - (this->out_position);
271 if (this->current_bit == 0)
272 {
273 space++;
274 }
275 return (space);
276 }
277
278 /**
279 * Implements private_generator_t's get_current_buffer_space function.
280 * See #private_generator_s.get_current_buffer_space.
281 */
282 static size_t get_current_data_length (private_generator_t *this)
283 {
284 return (this->out_position - this->buffer);
285 }
286
287 /**
288 * Implements private_generator_t's get_current_buffer_offset function.
289 * See #private_generator_s.get_current_buffer_offset.
290 */
291 static u_int32_t get_current_buffer_offset (private_generator_t *this)
292 {
293 return (this->out_position - this->buffer);
294 }
295
296
297 /**
298 * Implements private_generator_t's generate_u_int_type function.
299 * See #private_generator_s.generate_u_int_type.
300 */
301 static status_t generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset)
302 {
303 size_t number_of_bits = 0;
304 status_t status;
305
306 /* find out number of bits of each U_INT type to check for enough space
307 in buffer */
308 switch (int_type)
309 {
310 case U_INT_4:
311 number_of_bits = 4;
312 break;
313 case U_INT_8:
314 number_of_bits = 8;
315 break;
316 case U_INT_16:
317 number_of_bits = 16;
318 break;
319 case U_INT_32:
320 number_of_bits = 32;
321 break;
322 case U_INT_64:
323 number_of_bits = 64;
324 break;
325 case ATTRIBUTE_TYPE:
326 number_of_bits = 15;
327 break;
328 default:
329 return FAILED;
330 }
331 /* U_INT Types of multiple then 8 bits must be aligned */
332 if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
333 {
334 this->logger->log(this->logger,CONTROL_MORE,"U_INT Type %s is not 8 Bit aligned", mapping_find(encoding_type_t_mappings,int_type));
335 /* current bit has to be zero for values multiple of 8 bits */
336 return FAILED;
337 }
338
339 /* make sure enough space is available in buffer */
340 status = this->make_space_available(this,number_of_bits);
341 if (status != SUCCESS)
342 {
343 return status;
344 }
345 /* now handle each u int type differently */
346 switch (int_type)
347 {
348 case U_INT_4:
349 {
350 if (this->current_bit == 0)
351 {
352 /* highval of current byte in buffer has to be set to the new value*/
353 u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4;
354 /* lowval in buffer is not changed */
355 u_int8_t low_val = *(this->out_position) & 0x0F;
356 /* highval is set, low_val is not changed */
357 *(this->out_position) = high_val | low_val;
358 /* write position is not changed, just bit position is moved */
359 this->current_bit = 4;
360 }
361 else if (this->current_bit == 4)
362 {
363 /* highval in buffer is not changed */
364 u_int high_val = *(this->out_position) & 0xF0;
365 /* lowval of current byte in buffer has to be set to the new value*/
366 u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
367 *(this->out_position) = high_val | low_val;
368 this->out_position++;
369 this->current_bit = 0;
370
371 }
372 else
373 {
374 this->logger->log(this->logger,CONTROL_MORE,"U_INT_4 Type is not 4 Bit aligned");
375 /* 4 Bit integers must have a 4 bit alignment */
376 return FAILED;
377 };
378 break;
379 }
380 case U_INT_8:
381 {
382 /* 8 bit values are written as they are */
383 *this->out_position = *((u_int8_t *)(this->data_struct + offset));
384 this->out_position++;
385 break;
386
387 }
388 case ATTRIBUTE_TYPE:
389 {
390 /* attribute type must not change first bit uf current byte ! */
391 if (this->current_bit != 1)
392 {
393 this->logger->log(this->logger,CONTROL_MORE,"ATTRIBUTE FORMAT flag is not set");
394 /* first bit has to be set! */
395 return FAILED;
396 }
397 /* get value of attribute format flag */
398 u_int8_t attribute_format_flag = *(this->out_position) & 0x80;
399 /* get attribute type value as 16 bit integer*/
400 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
401 /* last bit must be unset */
402 int16_val = int16_val & 0xFF7F;
403
404 int16_val = int16_val | attribute_format_flag;
405 /* write bytes to buffer (set bit is overwritten)*/
406 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
407 this->current_bit = 0;
408 break;
409
410 }
411 case U_INT_16:
412 {
413 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
414 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
415 break;
416 }
417 case U_INT_32:
418 {
419 u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset)));
420 this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t));
421 break;
422 }
423 case U_INT_64:
424 {
425 /* 64 bit integers are written as two 32 bit integers */
426 u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset)));
427 u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1));
428 /* TODO add support for big endian machines */
429 this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t));
430 this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t));
431 break;
432 }
433
434 default:
435 this->logger->log(this->logger,CONTROL_MORE,"U_INT Type %s is not supported", mapping_find(encoding_type_t_mappings,int_type));
436 return FAILED;
437 }
438 return SUCCESS;
439 }
440
441 /**
442 * Implements private_generator_t's generate_reserved_field function.
443 * See #private_generator_s.generate_reserved_field.
444 */
445 static status_t generate_reserved_field (private_generator_t *this,int bits)
446 {
447 status_t status;
448
449 /* only one bit or 8 bit fields are supported */
450 if ((bits != 1) && (bits != 8))
451 {
452 this->logger->log(this->logger,CONTROL_MORE,"Reserved field of %d bits cannot be generated",bits);
453 return FAILED;
454 }
455 /* make sure enough space is available in buffer */
456 status = this->make_space_available(this,bits);
457 if (status != SUCCESS)
458 {
459 return status;
460 }
461
462 if (bits == 1)
463 {
464 /* one bit processing */
465 u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
466 *(this->out_position) = *(this->out_position) & reserved_bit;
467 this->current_bit++;
468 if (this->current_bit >= 8)
469 {
470 this->current_bit = this->current_bit % 8;
471 this->out_position++;
472 }
473 }
474 else
475 {
476 /* one byte processing*/
477 if (this->current_bit > 0)
478 {
479 this->logger->log(this->logger,CONTROL_MORE,"Reserved field cannot be written cause allignement of current bit is %d",this->current_bit);
480 return FAILED;
481 }
482 *(this->out_position) = 0x00;
483 this->out_position++;
484 }
485
486 return SUCCESS;
487
488
489 }
490
491 /**
492 * Implements private_generator_t's generate_flag function.
493 * See #private_generator_s.generate_flag.
494 */
495 static status_t generate_flag (private_generator_t *this,u_int32_t offset)
496 {
497 status_t status;
498 /* value of current flag */
499 u_int8_t flag_value;
500 /* position of flag in current byte */
501 u_int8_t flag;
502
503 /* if the value in the data_struct is TRUE, flag_value is set to 1, 0 otherwise */
504 flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
505 /* get flag position */
506 flag = (flag_value << (7 - this->current_bit));
507
508 /* make sure one bit is available in buffer */
509 status = this->make_space_available(this,1);
510 if (status != SUCCESS)
511 {
512 return status;
513 }
514
515 *(this->out_position) = *(this->out_position) | flag;
516
517 this->current_bit++;
518 if (this->current_bit >= 8)
519 {
520 this->current_bit = this->current_bit % 8;
521 this->out_position++;
522 }
523 return SUCCESS;
524 }
525
526 /**
527 * Implements private_generator_t's generate_from_chunk function.
528 * See #private_generator_s.generate_from_chunk.
529 */
530 static status_t generate_from_chunk (private_generator_t *this,u_int32_t offset)
531 {
532 if (this->current_bit != 0)
533 {
534 this->logger->log(this->logger,CONTROL_MORE,"Chunks can only be taken if bits are alligned in buffer");
535 return FAILED;
536 }
537 /* position in buffer */
538 chunk_t *attribute_value = (chunk_t *)(this->data_struct + offset);
539
540 /* use write_bytes_to_buffer function to do the job */
541 return this->write_bytes_to_buffer(this,attribute_value->ptr,attribute_value->len);
542
543 }
544
545 /**
546 * Implements private_generator_t's generator_context_make_space_available function.
547 * See #private_generator_s.generator_context_make_space_available.
548 */
549 static status_t make_space_available (private_generator_t *this, size_t bits)
550 {
551 while (((this->get_current_buffer_space(this) * 8) - this->current_bit) < bits)
552 {
553 /* must increase buffer */
554 u_int8_t *new_buffer;
555 size_t old_buffer_size = this->get_current_buffer_size(this);
556 size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
557 size_t out_position_offset = ((this->out_position) - (this->buffer));
558
559 this->logger->log(this->logger,CONTROL_MORE,"Gen-Buffer is increased from %d to %d byte",old_buffer_size,new_buffer_size);
560
561 /* Reallocate space for new buffer */
562 new_buffer = allocator_realloc(this->buffer,new_buffer_size);
563 if (new_buffer == NULL)
564 {
565 return OUT_OF_RES;
566 }
567
568 this->buffer = new_buffer;
569
570 this->out_position = (this->buffer + out_position_offset);
571 this->roof_position = (this->buffer + new_buffer_size);
572 }
573 return SUCCESS;
574 }
575
576 /**
577 * Implements private_generator_t's write_bytes_to_buffer function.
578 * See #private_generator_s.write_bytes_to_buffer.
579 */
580 static status_t write_bytes_to_buffer (private_generator_t *this,void * bytes,size_t number_of_bytes)
581 {
582 int i;
583 status_t status;
584 u_int8_t *read_position = (u_int8_t *) bytes;
585
586 status = this->make_space_available(this,number_of_bytes * 8);
587 if (status != SUCCESS)
588 {
589 return status;
590 }
591
592 for (i = 0; i < number_of_bytes; i++)
593 {
594 *(this->out_position) = *(read_position);
595 read_position++;
596 this->out_position++;
597 }
598 return status;
599 }
600
601 /**
602 * Implements private_generator_t's write_bytes_to_buffer_at_offset function.
603 * See #private_generator_s.write_bytes_to_buffer_at_offset.
604 */
605 static status_t write_bytes_to_buffer_at_offset (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset)
606 {
607 int i;
608 status_t status;
609 u_int8_t *read_position = (u_int8_t *) bytes;
610 u_int8_t *write_position;
611 u_int32_t free_space_after_offset = (this->get_current_buffer_size(this) - offset);
612
613 /* check first if enough space for new data is available */
614 if (number_of_bytes > free_space_after_offset)
615 {
616 status = this->make_space_available(this,(number_of_bytes - free_space_after_offset) * 8);
617 }
618
619 write_position = this->buffer + offset;
620 for (i = 0; i < number_of_bytes; i++)
621 {
622 *(write_position) = *(read_position);
623 read_position++;
624 write_position++;
625 }
626 return SUCCESS;
627 }
628
629 /**
630 * Implements generator_t's write_chunk function.
631 * See #generator_s.write_chunk.
632 */
633 static status_t write_to_chunk (private_generator_t *this,chunk_t *data)
634 {
635 size_t data_length = this->get_current_data_length(this);
636 u_int32_t header_length_field = data_length;
637
638 /* write length into header length field */
639 if (this->header_length_position_offset > 0)
640 {
641 u_int32_t int32_val = htonl(header_length_field);
642 this->write_bytes_to_buffer_at_offset(this,&int32_val,sizeof(u_int32_t),this->header_length_position_offset);
643 }
644
645 if (this->current_bit > 0)
646 data_length++;
647 data->ptr = allocator_alloc(data_length);
648 if (data->ptr == NULL)
649 {
650 data->len = 0;
651 this->logger->log(this->logger,CONTROL_MORE,"OUT OF Ressources to wrote data to chunk!!!!!");
652 return OUT_OF_RES;
653 }
654 memcpy(data->ptr,this->buffer,data_length);
655 data->len = data_length;
656 return SUCCESS;
657 }
658
659 /**
660 * Implements generator_t's generate_payload function.
661 * See #generator_s.generate_payload.
662 */
663 static status_t generate_payload (private_generator_t *this,payload_t *payload)
664 {
665 int i;
666 status_t status;
667 this->data_struct = payload;
668 size_t rule_count;
669 encoding_rule_t *rules;
670 payload_type_t payload_type;
671
672 /* get payload type */
673 payload_type = payload->get_type(payload);
674
675 this->logger->log(this->logger,CONTROL,"Start generating payload of type %s",mapping_find(payload_type_t_mappings,payload_type));
676
677 /* each payload has its own encoding rules */
678 payload->get_encoding_rules(payload,&rules,&rule_count);
679
680 for (i = 0; i < rule_count;i++)
681 {
682 status = SUCCESS;
683 switch (rules[i].type)
684 {
685 /* all u int values and ATTRIBUTE_TYPE are generated in generate_u_int_type */
686 case U_INT_4:
687 case U_INT_8:
688 case U_INT_16:
689 case U_INT_32:
690 case U_INT_64:
691 case ATTRIBUTE_TYPE:
692 {
693 status = this->generate_u_int_type(this,rules[i].type,rules[i].offset);
694 break;
695 }
696 case RESERVED_BIT:
697 {
698 status = this->generate_reserved_field(this,1);
699 break;
700 }
701 case RESERVED_BYTE:
702 {
703 status = this->generate_reserved_field(this,8);
704 break;
705 }
706 case FLAG:
707 {
708 status = this->generate_flag(this,rules[i].offset);
709 break;
710 }
711 case PAYLOAD_LENGTH:
712 {
713 /* position of payload lenght field is temporary stored */
714 this->last_payload_length_position_offset = this->get_current_buffer_offset(this);
715 /* payload length is generated like an U_INT_16 */
716 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
717 break;
718 }
719 case HEADER_LENGTH:
720 {
721 /* position of header length field is temporary stored */
722 this->header_length_position_offset = this->get_current_buffer_offset(this);
723 /* header length is generated like an U_INT_32 */
724 status = this->generate_u_int_type(this,U_INT_32,rules[i].offset);
725 break;
726 }
727 case SPI_SIZE:
728 /* spi size is handled as 8 bit unsigned integer */
729 status = this->generate_u_int_type(this,U_INT_8,rules[i].offset);
730 /* last spi size is temporary stored */
731 this->last_spi_size = *((u_int8_t *)(this->data_struct + rules[i].offset));
732 break;
733 case SPI:
734 {
735 /* the SPI value is generated from chunk */
736 status = this->generate_from_chunk(this,rules[i].offset);
737 break;
738 }
739 case PROPOSALS:
740 {
741 /* before iterative generate the transforms, store the current payload length position */
742 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
743 /* Length of SA_PAYLOAD is calculated */
744 u_int16_t length_of_sa_payload = SA_PAYLOAD_HEADER_LENGTH;
745 u_int16_t int16_val;
746 /* proposals are stored in a linked list and so accessed */
747 linked_list_t *proposals = *((linked_list_t **)(this->data_struct + rules[i].offset));
748
749 this->logger->log(this->logger,CONTROL_MORE,"Generate Proposals");
750
751 linked_list_iterator_t *iterator;
752 /* create forward iterator */
753 status = proposals->create_iterator(proposals,&iterator,TRUE);
754 if (status != SUCCESS)
755 {
756 this->logger->log(this->logger,CONTROL_MORE,"Could not iterator of proposals");
757 return status;
758 }
759 /* every proposal is processed (iterative call )*/
760 while (iterator->has_next(iterator))
761 {
762 payload_t *current_proposal;
763 u_int32_t before_generate_position_offset;
764 u_int32_t after_generate_position_offset;
765
766 status = iterator->current(iterator,(void **)&current_proposal);
767 if (status != SUCCESS)
768 {
769 iterator->destroy(iterator);
770 return status;
771 }
772 before_generate_position_offset = this->get_current_buffer_offset(this);
773 status = this->public.generate_payload(&(this->public),current_proposal);
774 after_generate_position_offset = this->get_current_buffer_offset(this);
775 if (status != SUCCESS)
776 {
777 iterator->destroy(iterator);
778 return status;
779 }
780
781 /* increase size of transform */
782 length_of_sa_payload += (after_generate_position_offset - before_generate_position_offset);
783 }
784 iterator->destroy(iterator);
785 this->logger->log(this->logger,CONTROL_MORE,"Length of Payload is %d, offset is %d",length_of_sa_payload,payload_length_position_offset);
786
787 int16_val = htons(length_of_sa_payload);
788 status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
789 if (status != SUCCESS)
790 {
791 this->logger->log(this->logger,CONTROL_MORE,"Could no write payload length into buffer");
792 return status;
793 }
794 break;
795 }
796
797 case TRANSFORMS:
798 {
799 /* before iterative generate the transforms, store the current length position */
800 u_int32_t payload_length_position_offset = this->last_payload_length_position_offset;
801 u_int16_t length_of_proposal = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->last_spi_size;
802 u_int16_t int16_val;
803 linked_list_t *transforms = *((linked_list_t **)(this->data_struct + rules[i].offset));
804 linked_list_iterator_t *iterator;
805
806 this->logger->log(this->logger,CONTROL_MORE,"Generate Transforms");
807
808 /* create forward iterator */
809 status = transforms->create_iterator(transforms,&iterator,TRUE);
810 if (status != SUCCESS)
811 {
812 return status;
813 }
814 while (iterator->has_next(iterator))
815 {
816 payload_t *current_transform;
817 u_int32_t before_generate_position_offset;
818 u_int32_t after_generate_position_offset;
819
820 status = iterator->current(iterator,(void **)&current_transform);
821 if (status != SUCCESS)
822 {
823 iterator->destroy(iterator);
824 return status;
825 }
826
827 before_generate_position_offset = this->get_current_buffer_offset(this);
828 status = this->public.generate_payload(&(this->public),current_transform);
829 after_generate_position_offset = this->get_current_buffer_offset(this);
830 if (status != SUCCESS)
831 {
832 iterator->destroy(iterator);
833 return status;
834 }
835
836 /* increase size of transform */
837 length_of_proposal += (after_generate_position_offset - before_generate_position_offset);
838 }
839
840 iterator->destroy(iterator);
841
842 this->logger->log(this->logger,CONTROL_MORE,"Length of Transform is %d, offset is %d",length_of_proposal,payload_length_position_offset);
843
844 int16_val = htons(length_of_proposal);
845 this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset);
846
847 break;
848 }
849 case TRANSFORM_ATTRIBUTES:
850 {
851 this->logger->log(this->logger,CONTROL_MORE,"Generate Transform attributes");
852 /* before iterative generate the transform attributes, store the current length position */
853 u_int32_t transform_length_position_offset = this->last_payload_length_position_offset;
854
855 u_int16_t length_of_transform = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
856 u_int16_t int16_val;
857 linked_list_t *transform_attributes =*((linked_list_t **)(this->data_struct + rules[i].offset));
858
859 linked_list_iterator_t *iterator;
860 /* create forward iterator */
861 status = transform_attributes->create_iterator(transform_attributes,&iterator,TRUE);
862 if (status != SUCCESS)
863 {
864 return status;
865 }
866 while (iterator->has_next(iterator))
867 {
868 payload_t *current_attribute;
869 u_int32_t before_generate_position_offset;
870 u_int32_t after_generate_position_offset;
871
872 status = iterator->current(iterator,(void **)&current_attribute);
873 if (status != SUCCESS)
874 {
875 iterator->destroy(iterator);
876 return status;
877 }
878
879 before_generate_position_offset = this->get_current_buffer_offset(this);
880 this->public.generate_payload(&(this->public),current_attribute);
881 after_generate_position_offset = this->get_current_buffer_offset(this);
882
883 /* increase size of transform */
884 length_of_transform += (after_generate_position_offset - before_generate_position_offset);
885 }
886
887 iterator->destroy(iterator);
888
889 this->logger->log(this->logger,CONTROL_MORE,"Length of Transform is %d, offset is %d",length_of_transform,transform_length_position_offset);
890
891 int16_val = htons(length_of_transform);
892 this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),transform_length_position_offset);
893
894 break;
895 }
896 case ATTRIBUTE_FORMAT:
897 {
898 status = this->generate_flag(this,rules[i].offset);
899 /* Attribute format is a flag which is stored in context*/
900 this->attribute_format = *((bool *) (this->data_struct + rules[i].offset));
901 break;
902 }
903
904 case ATTRIBUTE_LENGTH_OR_VALUE:
905 {
906 this->logger->log(this->logger,CONTROL_MORE,"Generate Attribute Length or Value field");
907 if (this->attribute_format == FALSE)
908 {
909 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
910 /* this field hold the length of the attribute */
911 this->attribute_length = *((u_int16_t *)(this->data_struct + rules[i].offset));
912 }
913 else
914 {
915 status = this->write_bytes_to_buffer(this,(this->data_struct + rules[i].offset),2);
916 }
917 break;
918 }
919 case ATTRIBUTE_VALUE:
920 {
921 if (this->attribute_format == FALSE)
922 {
923 this->logger->log(this->logger,CONTROL_MORE,"Attribute value has not fixed size");
924 /* the attribute value is generated */
925 status = this->generate_from_chunk(this,rules[i].offset);
926 }
927 break;
928 }
929 default:
930 this->logger->log(this->logger,CONTROL_MORE,"Field Type %s is not supported",mapping_find(encoding_type_t_mappings,rules[i].type));
931 return NOT_SUPPORTED;
932 }
933 }
934
935 return status;
936 }
937
938 /**
939 * Implements generator_t's destroy function.
940 * See #generator_s.destroy.
941 */
942 static status_t destroy(private_generator_t *this)
943 {
944 allocator_free(this->buffer);
945 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
946 allocator_free(this);
947 return SUCCESS;
948 }
949
950 /*
951 * Described in header
952 */
953 generator_t * generator_create()
954 {
955 private_generator_t *this;
956
957 this = allocator_alloc_thing(private_generator_t);
958 if (this == NULL)
959 {
960 return NULL;
961 }
962
963 /* initiate public functions */
964 this->public.generate_payload = (status_t(*)(generator_t*, payload_t *)) generate_payload;
965 this->public.destroy = (status_t(*)(generator_t*)) destroy;
966 this->public.write_to_chunk = (status_t (*) (generator_t *,chunk_t *)) write_to_chunk;
967
968
969 /* initiate private functions */
970 this->get_current_buffer_size = get_current_buffer_size;
971 this->get_current_buffer_space = get_current_buffer_space;
972 this->get_current_data_length = get_current_data_length;
973 this->get_current_buffer_offset = get_current_buffer_offset;
974 this->generate_u_int_type = generate_u_int_type;
975 this->generate_reserved_field = generate_reserved_field;
976 this->generate_flag = generate_flag;
977 this->generate_from_chunk = generate_from_chunk;
978 this->make_space_available = make_space_available;
979 this->write_bytes_to_buffer = write_bytes_to_buffer;
980 this->write_bytes_to_buffer_at_offset = write_bytes_to_buffer_at_offset;
981
982
983 /* allocate memory for buffer */
984 this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE);
985 if (this->buffer == NULL)
986 {
987 allocator_free(this);
988 return NULL;
989 }
990
991 /* initiate private variables */
992 this->out_position = this->buffer;
993 this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
994 this->data_struct = NULL;
995 this->current_bit = 0;
996 this->last_payload_length_position_offset = 0;
997 this->header_length_position_offset = 0;
998 this->logger = global_logger_manager->create_logger(global_logger_manager,GENERATOR,NULL);
999
1000 if (this->logger == NULL)
1001 {
1002 allocator_free(this->buffer);
1003 allocator_free(this);
1004 return NULL;
1005 }
1006 return &(this->public);
1007 }