LENGTH is not anymore available
[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/logger_manager.h"
34 #include "payloads/payload.h"
35
36
37 extern logger_manager_t *global_logger_manager;
38
39 /**
40 * Private part of a generator_t object
41 */
42 typedef struct private_generator_s private_generator_t;
43
44 struct private_generator_s {
45 /**
46 * Public part of a generator_t object
47 */
48 generator_t public;
49
50 /* private functions and fields */
51
52
53 /**
54 * Generates a U_INT-Field type
55 *
56 * @param this private_generator_t object
57 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
58 * @param offset offset of value in data struct
59 * @param generator_contexts generator_contexts_t object where the context is written or read from
60 * @return - SUCCESS if succeeded
61 * - OUT_OF_RES if out of ressources
62 */
63 status_t (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset);
64
65 /**
66 * Generates a RESERVED BIT field or a RESERVED BYTE field
67 *
68 * @param this private_generator_t object
69 * @param generator_contexts generator_contexts_t object where the context is written or read from
70 * @param bits number of bits to generate
71 * @return - SUCCESS if succeeded
72 * - OUT_OF_RES if out of ressources
73 * - FAILED if bit count not supported
74 */
75 status_t (*generate_reserved_field) (private_generator_t *this,int bits);
76
77 /**
78 * Generates a FLAG field
79 *
80 * @param this private_generator_t object
81 * @param generator_contexts generator_contexts_t object where the context is written or read from
82 * @param offset offset of flag value in data struct
83 * @return - SUCCESS if succeeded
84 * - OUT_OF_RES if out of ressources
85 */
86 status_t (*generate_flag) (private_generator_t *this,u_int32_t offset);
87
88 /**
89 * Writes the current buffer content into a chunk_t
90 *
91 * Memory of specific chunk_t gets allocated.
92 *
93 * @param this calling private_generator_t object
94 * @param data pointer of chunk_t to write to
95 * @return
96 * - SUCCESSFUL if succeeded
97 * - OUT_OF_RES otherwise
98 */
99 status_t (*write_chunk) (private_generator_t *this,chunk_t *data);
100
101
102 /**
103 * Makes sure enough space is available in buffer to store amount of bits.
104 *
105 * If buffer is to small to hold the specific amount of bits it
106 * is increased using reallocation function of allocator.
107 *
108 * @param this calling private_generator_t object
109 * @param bits number of bits to make available in buffer
110 * @return
111 * - SUCCESSFUL if succeeded
112 * - OUT_OF_RES otherwise
113 */
114 status_t (*make_space_available) (private_generator_t *this,size_t bits);
115
116 /**
117 * Writes a specific amount of byte into the buffer.
118 *
119 * If buffer is to small to hold the specific amount of bytes it
120 * is increased.
121 *
122 * @param this calling private_generator_t object
123 * @param bytes pointer to bytes to write
124 * @param number_of_bytes number of bytes to write into buffer
125 * @return
126 * - SUCCESSFUL if succeeded
127 * - OUT_OF_RES otherwise
128 */
129 status_t (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes);
130
131
132 /**
133 * Buffer used to generate the data into.
134 */
135 u_int8_t *buffer;
136
137 /**
138 * Current write position in buffer (one byte aligned).
139 */
140 u_int8_t *out_position;
141
142 /**
143 * Position of last byte in buffer.
144 */
145 u_int8_t *roof_position;
146
147 /**
148 * Current bit writing to in current byte (between 0 and 7).
149 */
150 size_t current_bit;
151
152 /**
153 * Associated data struct to read informations from.
154 */
155 void * data_struct;
156
157 /**
158 * Associated Logger
159 */
160 logger_t *logger;
161 };
162
163 /**
164 * Implements private_generator_t's generate_u_int_type function.
165 * See #private_generator_s.generate_u_int_type.
166 */
167 static status_t generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset)
168 {
169 size_t number_of_bits = 0;
170 status_t status;
171
172
173 switch (int_type)
174 {
175 case U_INT_4:
176 number_of_bits = 4;
177 break;
178 case U_INT_8:
179 number_of_bits = 8;
180 break;
181 case U_INT_16:
182 number_of_bits = 16;
183 break;
184 case U_INT_32:
185 number_of_bits = 32;
186 break;
187 case U_INT_64:
188 number_of_bits = 64;
189 break;
190 default:
191 return FAILED;
192 }
193 if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
194 {
195 /* current bit has to be zero for values greater then 4 bits */
196 return FAILED;
197 }
198
199 status = this->make_space_available(this,number_of_bits);
200
201 if (status != SUCCESS)
202 {
203 return status;
204 }
205
206 switch (int_type)
207 {
208 case U_INT_4:
209 {
210 if (this->current_bit == 0)
211 {
212 u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4;
213 u_int8_t low_val = *(this->out_position) & 0x0F;
214
215 *(this->out_position) = high_val | low_val;
216 /* write position is not changed, just bit position is moved */
217 this->current_bit = 4;
218 }
219 else if (this->current_bit == 4)
220 {
221 u_int high_val = *(this->out_position) & 0xF0;
222 u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
223 *(this->out_position) = high_val | low_val;
224 this->out_position++;
225 this->current_bit = 0;
226
227 }
228 else
229 {
230 /* 4 Bit integers must have a 4 bit alignment */
231 return FAILED;
232 };
233 break;
234 }
235
236 case U_INT_8:
237 {
238 *this->out_position = *((u_int8_t *)(this->data_struct + offset));
239 this->out_position++;
240 break;
241
242 }
243 case U_INT_16:
244 {
245 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
246 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
247
248 break;
249 }
250 case U_INT_32:
251 {
252 u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset)));
253 this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t));
254 break;
255 }
256 case U_INT_64:
257 {
258 u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset)));
259 u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1));
260 this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t));
261 this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t));
262 break;
263 }
264
265 default:
266 return FAILED;
267
268 }
269
270 return SUCCESS;
271 }
272
273 /**
274 * Implements private_generator_t's generate_reserved_field function.
275 * See #private_generator_s.generate_reserved_field.
276 */
277 static status_t generate_reserved_field (private_generator_t *this,int bits)
278 {
279 status_t status;
280
281 if ((bits != 1) && (bits != 8))
282 {
283 return FAILED;
284 }
285 status = this->make_space_available(this,bits);
286 if (status != SUCCESS)
287 {
288 return status;
289 }
290
291 if (bits == 1)
292 {
293 u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
294
295 *(this->out_position) = *(this->out_position) & reserved_bit;
296 this->current_bit++;
297 if (this->current_bit >= 8)
298 {
299 this->current_bit = this->current_bit % 8;
300 this->out_position++;
301 }
302 }
303 else
304 {
305 /* one byte */
306 if (this->current_bit > 0)
307 {
308 return FAILED;
309 }
310 *(this->out_position) = 0x00;
311 this->out_position++;
312 }
313
314 return SUCCESS;
315
316
317 }
318
319 /**
320 * Implements private_generator_t's generate_flag function.
321 * See #private_generator_s.generate_flag.
322 */
323 static status_t generate_flag (private_generator_t *this,u_int32_t offset)
324 {
325 status_t status;
326 u_int8_t flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
327 u_int8_t flag = (flag_value << (7 - this->current_bit));
328
329 status = this->make_space_available(this,1);
330 if (status != SUCCESS)
331 {
332 return status;
333 }
334
335 *(this->out_position) = *(this->out_position) | flag;
336
337 this->current_bit++;
338 if (this->current_bit >= 8)
339 {
340 this->current_bit = this->current_bit % 8;
341 this->out_position++;
342 }
343 return SUCCESS;
344 }
345
346 /**
347 * Implements private_generator_t's generator_context_make_space_available function.
348 * See #private_generator_s.generator_context_make_space_available.
349 */
350 static status_t make_space_available (private_generator_t *this, size_t bits)
351 {
352 while ((((this->roof_position - this->out_position) * 8) - this->current_bit) < bits)
353 {
354 size_t old_buffer_size = ((this->roof_position) - ( this->buffer));
355 size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
356 size_t out_position_offset = ((this->out_position) - (this->buffer));
357 u_int8_t *new_buffer;
358
359 new_buffer = allocator_realloc(this->buffer,new_buffer_size);
360 if (new_buffer == NULL)
361 {
362 return OUT_OF_RES;
363 }
364
365 this->buffer = new_buffer;
366
367 this->out_position = (this->buffer + out_position_offset);
368 this->roof_position = (this->buffer + new_buffer_size);
369
370 }
371
372 return SUCCESS;
373 }
374
375 /**
376 * Implements private_generator_t's write_bytes_to_buffer function.
377 * See #private_generator_s.write_bytes_to_buffer.
378 */
379 static status_t write_bytes_to_buffer (private_generator_t *this,void * bytes,size_t number_of_bytes)
380 {
381 u_int8_t *read_position = (u_int8_t *) bytes;
382 int i;
383 status_t status;
384
385 status = this->make_space_available(this,number_of_bytes * 8);
386
387 if (status != SUCCESS)
388 {
389 return status;
390 }
391
392 for (i = 0; i < number_of_bytes; i++)
393 {
394 *(this->out_position) = *(read_position);
395 read_position++;
396 this->out_position++;
397 }
398 return status;
399 }
400
401 /**
402 * Implements generator_t's write_chunk function.
403 * See #generator_s.write_chunk.
404 */
405 static status_t write_to_chunk (private_generator_t *this,chunk_t *data)
406 {
407 size_t data_length = this->out_position - this->buffer;
408
409 if (this->current_bit > 0)
410 data_length++;
411 data->ptr = allocator_alloc(data_length);
412 if (data->ptr == NULL)
413 {
414 data->len = 0;
415 return OUT_OF_RES;
416 }
417 memcpy(data->ptr,this->buffer,data_length);
418 data->len = data_length;
419 return SUCCESS;
420 }
421
422
423
424 /**
425 * Implements generator_t's generate_payload function.
426 * See #generator_s.generate_payload.
427 */
428 static status_t generate_payload (private_generator_t *this,payload_t *payload)
429 {
430 int i;
431 status_t status;
432 this->data_struct = payload;
433 size_t rule_count;
434 encoding_rule_t *rules;
435
436
437 payload_type_t payload_type = payload->get_type(payload);
438
439 this->logger->log(this->logger,CONTROL,"Start generating payload of type %s",mapping_find(payload_type_t_mappings,payload_type));
440
441 payload->get_encoding_rules(payload,&rules,&rule_count);
442
443 for (i = 0; i < rule_count;i++)
444 {
445 status = SUCCESS;
446 switch (rules[i].type)
447 {
448 /* all u int values are generated in generate_u_int_type */
449 case U_INT_4:
450 case U_INT_8:
451 case U_INT_16:
452 case U_INT_32:
453 case U_INT_64:
454 status = this->generate_u_int_type(this,rules[i].type,rules[i].offset);
455 break;
456 case RESERVED_BIT:
457 {
458 status = this->generate_reserved_field(this,1);
459
460 break;
461 }
462 case RESERVED_BYTE:
463 {
464 status = this->generate_reserved_field(this,8);
465 break;
466 }
467 case FLAG:
468 {
469 status = this->generate_flag(this,rules[i].offset);
470 break;
471 }
472 case PAYLOAD_LENGTH:
473 /* payload length is generated like an U_INT_16 */
474 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
475 break;
476
477 case HEADER_LENGTH:
478 /* header length is generated like an U_INT_32 */
479 status = this->generate_u_int_type(this,U_INT_32,rules[i].offset);
480 break;
481 case SPI_SIZE:
482 /* currently not implemented */
483 default:
484 break;
485 }
486 }
487
488 return status;
489
490 return NOT_SUPPORTED;
491 }
492
493 /**
494 * Implements generator_t's destroy function.
495 * See #generator_s.destroy.
496 */
497 static status_t destroy(private_generator_t *this)
498 {
499 allocator_free(this->buffer);
500 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
501 allocator_free(this);
502 return SUCCESS;
503 }
504
505 /*
506 * Described in header
507 */
508 generator_t * generator_create()
509 {
510 private_generator_t *this;
511
512 this = allocator_alloc_thing(private_generator_t);
513 if (this == NULL)
514 {
515 return NULL;
516 }
517
518 /* initiate public functions */
519 this->public.generate_payload = (status_t(*)(generator_t*, payload_t *)) generate_payload;
520 this->public.destroy = (status_t(*)(generator_t*)) destroy;
521 this->public.write_to_chunk = (status_t (*) (generator_t *,chunk_t *)) write_to_chunk;
522
523
524 /* initiate private functions */
525 // this->generate = generate;
526 this->generate_u_int_type = generate_u_int_type;
527 this->generate_reserved_field = generate_reserved_field;
528 this->generate_flag = generate_flag;
529 this->make_space_available = make_space_available;
530 this->write_bytes_to_buffer = write_bytes_to_buffer;
531
532
533 /* allocate memory for buffer */
534 this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE);
535 if (this->buffer == NULL)
536 {
537 allocator_free(this);
538 return NULL;
539 }
540
541 /* initiate private variables */
542 this->out_position = this->buffer;
543 this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
544 this->data_struct = NULL;
545 this->current_bit = 0;
546 this->logger = global_logger_manager->create_logger(global_logger_manager,GENERATOR,NULL);
547 return &(this->public);
548 }