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