Annotation of embedaddon/strongswan/src/libcharon/encoding/generator.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2011 Tobias Brunner
! 3: * Copyright (C) 2005-2009 Martin Willi
! 4: * Copyright (C) 2005 Jan Hutter
! 5: * HSR Hochschule fuer Technik Rapperswil
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include <stdlib.h>
! 19: #include <string.h>
! 20: #include <stdio.h>
! 21:
! 22: #include "generator.h"
! 23:
! 24: #include <library.h>
! 25: #include <daemon.h>
! 26: #include <collections/linked_list.h>
! 27: #include <encoding/payloads/payload.h>
! 28: #include <encoding/payloads/proposal_substructure.h>
! 29: #include <encoding/payloads/transform_substructure.h>
! 30: #include <encoding/payloads/sa_payload.h>
! 31: #include <encoding/payloads/ke_payload.h>
! 32: #include <encoding/payloads/notify_payload.h>
! 33: #include <encoding/payloads/nonce_payload.h>
! 34: #include <encoding/payloads/id_payload.h>
! 35: #include <encoding/payloads/auth_payload.h>
! 36: #include <encoding/payloads/cert_payload.h>
! 37: #include <encoding/payloads/certreq_payload.h>
! 38: #include <encoding/payloads/ts_payload.h>
! 39: #include <encoding/payloads/delete_payload.h>
! 40: #include <encoding/payloads/vendor_id_payload.h>
! 41: #include <encoding/payloads/cp_payload.h>
! 42: #include <encoding/payloads/configuration_attribute.h>
! 43: #include <encoding/payloads/eap_payload.h>
! 44: #include <encoding/payloads/unknown_payload.h>
! 45:
! 46: /**
! 47: * Generating is done in a data buffer.
! 48: * This is the start size of this buffer in bytes.
! 49: */
! 50: #define GENERATOR_DATA_BUFFER_SIZE 500
! 51:
! 52: /**
! 53: * Number of bytes to increase the buffer, if it is too small.
! 54: */
! 55: #define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500
! 56:
! 57: typedef struct private_generator_t private_generator_t;
! 58:
! 59: /**
! 60: * Private part of a generator_t object.
! 61: */
! 62: struct private_generator_t {
! 63: /**
! 64: * Public part of a generator_t object.
! 65: */
! 66: generator_t public;
! 67:
! 68: /**
! 69: * Buffer used to generate the data into.
! 70: */
! 71: uint8_t *buffer;
! 72:
! 73: /**
! 74: * Current write position in buffer (one byte aligned).
! 75: */
! 76: uint8_t *out_position;
! 77:
! 78: /**
! 79: * Position of last byte in buffer.
! 80: */
! 81: uint8_t *roof_position;
! 82:
! 83: /**
! 84: * Current bit writing to in current byte (between 0 and 7).
! 85: */
! 86: uint8_t current_bit;
! 87:
! 88: /**
! 89: * Associated data struct to read information from.
! 90: */
! 91: void *data_struct;
! 92:
! 93: /**
! 94: * Offset of the header length field in the buffer.
! 95: */
! 96: uint32_t header_length_offset;
! 97:
! 98: /**
! 99: * Attribute format of the last generated transform attribute.
! 100: *
! 101: * Used to check if a variable value field is used or not for
! 102: * the transform attribute value.
! 103: */
! 104: bool attribute_format;
! 105:
! 106: /**
! 107: * Depending on the value of attribute_format this field is used
! 108: * to hold the length of the transform attribute in bytes.
! 109: */
! 110: uint16_t attribute_length;
! 111:
! 112: /**
! 113: * TRUE, if debug messages should be logged during generation.
! 114: */
! 115: bool debug;
! 116: };
! 117:
! 118: /**
! 119: * Get size of current buffer in bytes.
! 120: */
! 121: static int get_size(private_generator_t *this)
! 122: {
! 123: return this->roof_position - this->buffer;
! 124: }
! 125:
! 126: /**
! 127: * Get free space of current buffer in bytes.
! 128: */
! 129: static int get_space(private_generator_t *this)
! 130: {
! 131: return this->roof_position - this->out_position;
! 132: }
! 133:
! 134: /**
! 135: * Get length of data in buffer (in bytes).
! 136: */
! 137: static int get_length(private_generator_t *this)
! 138: {
! 139: return this->out_position - this->buffer;
! 140: }
! 141:
! 142: /**
! 143: * Get current offset in buffer (in bytes).
! 144: */
! 145: static uint32_t get_offset(private_generator_t *this)
! 146: {
! 147: return this->out_position - this->buffer;
! 148: }
! 149:
! 150: /**
! 151: * Makes sure enough space is available in buffer to store amount of bits.
! 152: */
! 153: static void make_space_available(private_generator_t *this, int bits)
! 154: {
! 155: while ((get_space(this) * 8 - this->current_bit) < bits)
! 156: {
! 157: int old_buffer_size, new_buffer_size, out_position_offset;
! 158:
! 159: old_buffer_size = get_size(this);
! 160: new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
! 161: out_position_offset = this->out_position - this->buffer;
! 162:
! 163: if (this->debug)
! 164: {
! 165: DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte",
! 166: old_buffer_size, new_buffer_size);
! 167: }
! 168:
! 169: this->buffer = realloc(this->buffer,new_buffer_size);
! 170: this->out_position = (this->buffer + out_position_offset);
! 171: this->roof_position = (this->buffer + new_buffer_size);
! 172: }
! 173: }
! 174:
! 175: /**
! 176: * Writes a specific amount of byte into the buffer.
! 177: */
! 178: static void write_bytes_to_buffer(private_generator_t *this, void *bytes,
! 179: int number_of_bytes)
! 180: {
! 181: int i;
! 182: uint8_t *read_position = (uint8_t *)bytes;
! 183:
! 184: make_space_available(this, number_of_bytes * 8);
! 185:
! 186: for (i = 0; i < number_of_bytes; i++)
! 187: {
! 188: *(this->out_position) = *(read_position);
! 189: read_position++;
! 190: this->out_position++;
! 191: }
! 192: }
! 193:
! 194: /**
! 195: * Generates a U_INT-Field type and writes it to buffer.
! 196: */
! 197: static void generate_u_int_type(private_generator_t *this,
! 198: encoding_type_t int_type,uint32_t offset)
! 199: {
! 200: int number_of_bits = 0;
! 201:
! 202: /* find out number of bits of each U_INT type to check for enough space */
! 203: switch (int_type)
! 204: {
! 205: case U_INT_4:
! 206: number_of_bits = 4;
! 207: break;
! 208: case TS_TYPE:
! 209: case RESERVED_BYTE:
! 210: case SPI_SIZE:
! 211: case U_INT_8:
! 212: number_of_bits = 8;
! 213: break;
! 214: case U_INT_16:
! 215: case PAYLOAD_LENGTH:
! 216: case ATTRIBUTE_LENGTH:
! 217: number_of_bits = 16;
! 218: break;
! 219: case U_INT_32:
! 220: number_of_bits = 32;
! 221: break;
! 222: case ATTRIBUTE_TYPE:
! 223: number_of_bits = 15;
! 224: break;
! 225: case IKE_SPI:
! 226: number_of_bits = 64;
! 227: break;
! 228: default:
! 229: DBG1(DBG_ENC, "U_INT Type %N is not supported",
! 230: encoding_type_names, int_type);
! 231: return;
! 232: }
! 233: if ((number_of_bits % 8) == 0 && this->current_bit != 0)
! 234: {
! 235: DBG1(DBG_ENC, "U_INT Type %N is not 8 Bit aligned",
! 236: encoding_type_names, int_type);
! 237: return;
! 238: }
! 239:
! 240: make_space_available(this, number_of_bits);
! 241: switch (int_type)
! 242: {
! 243: case U_INT_4:
! 244: {
! 245: uint8_t high, low;
! 246:
! 247: if (this->current_bit == 0)
! 248: {
! 249: /* high of current byte in buffer has to be set to the new value*/
! 250: high = *((uint8_t *)(this->data_struct + offset)) << 4;
! 251: /* low in buffer is not changed */
! 252: low = *(this->out_position) & 0x0F;
! 253: /* high is set, low_val is not changed */
! 254: *(this->out_position) = high | low;
! 255: if (this->debug)
! 256: {
! 257: DBG3(DBG_ENC, " => %hhu", *(this->out_position) >> 4);
! 258: }
! 259: /* write position is not changed, just bit position is moved */
! 260: this->current_bit = 4;
! 261: }
! 262: else if (this->current_bit == 4)
! 263: {
! 264: /* high in buffer is not changed */
! 265: high = *(this->out_position) & 0xF0;
! 266: /* low of current byte in buffer has to be set to the new value*/
! 267: low = *((uint8_t *)(this->data_struct + offset)) & 0x0F;
! 268: *(this->out_position) = high | low;
! 269: if (this->debug)
! 270: {
! 271: DBG3(DBG_ENC, " => %hhu", *(this->out_position) & 0x0F);
! 272: }
! 273: this->out_position++;
! 274: this->current_bit = 0;
! 275: }
! 276: else
! 277: {
! 278: DBG1(DBG_ENC, "U_INT_4 Type is not 4 Bit aligned");
! 279: /* 4 Bit integers must have a 4 bit alignment */
! 280: return;
! 281: }
! 282: break;
! 283: }
! 284: case TS_TYPE:
! 285: case RESERVED_BYTE:
! 286: case SPI_SIZE:
! 287: case U_INT_8:
! 288: {
! 289: /* 8 bit values are written as they are */
! 290: *this->out_position = *((uint8_t *)(this->data_struct + offset));
! 291: if (this->debug)
! 292: {
! 293: DBG3(DBG_ENC, " => %hhu", *(this->out_position));
! 294: }
! 295: this->out_position++;
! 296: break;
! 297: }
! 298: case ATTRIBUTE_TYPE:
! 299: {
! 300: uint8_t attribute_format_flag;
! 301: uint16_t val;
! 302:
! 303: /* attribute type must not change first bit of current byte */
! 304: if (this->current_bit != 1)
! 305: {
! 306: DBG1(DBG_ENC, "ATTRIBUTE FORMAT flag is not set");
! 307: return;
! 308: }
! 309: attribute_format_flag = *(this->out_position) & 0x80;
! 310: /* get attribute type value as 16 bit integer*/
! 311: val = *((uint16_t*)(this->data_struct + offset));
! 312: /* unset most significant bit */
! 313: val &= 0x7FFF;
! 314: if (attribute_format_flag)
! 315: {
! 316: val |= 0x8000;
! 317: }
! 318: val = htons(val);
! 319: if (this->debug)
! 320: {
! 321: DBG3(DBG_ENC, " => %hu", val);
! 322: }
! 323: /* write bytes to buffer (set bit is overwritten) */
! 324: write_bytes_to_buffer(this, &val, sizeof(uint16_t));
! 325: this->current_bit = 0;
! 326: break;
! 327:
! 328: }
! 329: case U_INT_16:
! 330: case PAYLOAD_LENGTH:
! 331: case ATTRIBUTE_LENGTH:
! 332: {
! 333: uint16_t val = htons(*((uint16_t*)(this->data_struct + offset)));
! 334: if (this->debug)
! 335: {
! 336: DBG3(DBG_ENC, " %b", &val, sizeof(uint16_t));
! 337: }
! 338: write_bytes_to_buffer(this, &val, sizeof(uint16_t));
! 339: break;
! 340: }
! 341: case U_INT_32:
! 342: {
! 343: uint32_t val = htonl(*((uint32_t*)(this->data_struct + offset)));
! 344: if (this->debug)
! 345: {
! 346: DBG3(DBG_ENC, " %b", &val, sizeof(uint32_t));
! 347: }
! 348: write_bytes_to_buffer(this, &val, sizeof(uint32_t));
! 349: break;
! 350: }
! 351: case IKE_SPI:
! 352: {
! 353: /* 64 bit are written as-is, no host order conversion */
! 354: write_bytes_to_buffer(this, this->data_struct + offset,
! 355: sizeof(uint64_t));
! 356: if (this->debug)
! 357: {
! 358: DBG3(DBG_ENC, " %b", this->data_struct + offset,
! 359: sizeof(uint64_t));
! 360: }
! 361: break;
! 362: }
! 363: default:
! 364: {
! 365: DBG1(DBG_ENC, "U_INT Type %N is not supported",
! 366: encoding_type_names, int_type);
! 367: return;
! 368: }
! 369: }
! 370: }
! 371:
! 372: /**
! 373: * Generate a FLAG filed
! 374: */
! 375: static void generate_flag(private_generator_t *this, uint32_t offset)
! 376: {
! 377: uint8_t flag_value;
! 378: uint8_t flag;
! 379:
! 380: flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
! 381: /* get flag position */
! 382: flag = (flag_value << (7 - this->current_bit));
! 383:
! 384: /* make sure one bit is available in buffer */
! 385: make_space_available(this, 1);
! 386: if (this->current_bit == 0)
! 387: {
! 388: /* memory must be zero */
! 389: *(this->out_position) = 0x00;
! 390: }
! 391:
! 392: *(this->out_position) = *(this->out_position) | flag;
! 393: if (this->debug)
! 394: {
! 395: DBG3(DBG_ENC, " => %hhu", *this->out_position);
! 396: }
! 397:
! 398: this->current_bit++;
! 399: if (this->current_bit >= 8)
! 400: {
! 401: this->current_bit = this->current_bit % 8;
! 402: this->out_position++;
! 403: }
! 404: }
! 405:
! 406: /**
! 407: * Generates a bytestream from a chunk_t.
! 408: */
! 409: static void generate_from_chunk(private_generator_t *this, uint32_t offset)
! 410: {
! 411: chunk_t *value;
! 412:
! 413: if (this->current_bit != 0)
! 414: {
! 415: DBG1(DBG_ENC, "can not generate a chunk at bitpos %hhu",
! 416: this->current_bit);
! 417: return ;
! 418: }
! 419:
! 420: value = (chunk_t *)(this->data_struct + offset);
! 421: if (this->debug)
! 422: {
! 423: DBG3(DBG_ENC, " %B", value);
! 424: }
! 425:
! 426: write_bytes_to_buffer(this, value->ptr, value->len);
! 427: }
! 428:
! 429: METHOD(generator_t, get_chunk, chunk_t,
! 430: private_generator_t *this, uint32_t **lenpos)
! 431: {
! 432: chunk_t data;
! 433:
! 434: *lenpos = (uint32_t*)(this->buffer + this->header_length_offset);
! 435: data = chunk_create(this->buffer, get_length(this));
! 436: if (this->debug)
! 437: {
! 438: DBG3(DBG_ENC, "generated data of this generator %B", &data);
! 439: }
! 440: return data;
! 441: }
! 442:
! 443: METHOD(generator_t, generate_payload, void,
! 444: private_generator_t *this, payload_t *payload)
! 445: {
! 446: int i, offset_start, rule_count;
! 447: encoding_rule_t *rules;
! 448: payload_type_t payload_type;
! 449:
! 450: this->data_struct = payload;
! 451: payload_type = payload->get_type(payload);
! 452:
! 453: offset_start = this->out_position - this->buffer;
! 454:
! 455: if (this->debug)
! 456: {
! 457: DBG2(DBG_ENC, "generating payload of type %N",
! 458: payload_type_names, payload_type);
! 459: }
! 460:
! 461: /* each payload has its own encoding rules */
! 462: rule_count = payload->get_encoding_rules(payload, &rules);
! 463:
! 464: for (i = 0; i < rule_count;i++)
! 465: {
! 466: if (this->debug)
! 467: {
! 468: DBG2(DBG_ENC, " generating rule %d %N",
! 469: i, encoding_type_names, rules[i].type);
! 470: }
! 471: switch ((int)rules[i].type)
! 472: {
! 473: case U_INT_4:
! 474: case U_INT_8:
! 475: case U_INT_16:
! 476: case U_INT_32:
! 477: case PAYLOAD_LENGTH:
! 478: case IKE_SPI:
! 479: case RESERVED_BYTE:
! 480: case SPI_SIZE:
! 481: case TS_TYPE:
! 482: case ATTRIBUTE_TYPE:
! 483: case ATTRIBUTE_LENGTH:
! 484: generate_u_int_type(this, rules[i].type, rules[i].offset);
! 485: break;
! 486: case RESERVED_BIT:
! 487: case FLAG:
! 488: generate_flag(this, rules[i].offset);
! 489: break;
! 490: case HEADER_LENGTH:
! 491: this->header_length_offset = get_offset(this);
! 492: generate_u_int_type(this, U_INT_32, rules[i].offset);
! 493: break;
! 494: case ADDRESS:
! 495: case SPI:
! 496: case CHUNK_DATA:
! 497: case ENCRYPTED_DATA:
! 498: generate_from_chunk(this, rules[i].offset);
! 499: break;
! 500: case PAYLOAD_LIST + PLV2_PROPOSAL_SUBSTRUCTURE:
! 501: case PAYLOAD_LIST + PLV1_PROPOSAL_SUBSTRUCTURE:
! 502: case PAYLOAD_LIST + PLV2_TRANSFORM_SUBSTRUCTURE:
! 503: case PAYLOAD_LIST + PLV1_TRANSFORM_SUBSTRUCTURE:
! 504: case PAYLOAD_LIST + PLV2_TRANSFORM_ATTRIBUTE:
! 505: case PAYLOAD_LIST + PLV1_TRANSFORM_ATTRIBUTE:
! 506: case PAYLOAD_LIST + PLV2_CONFIGURATION_ATTRIBUTE:
! 507: case PAYLOAD_LIST + PLV1_CONFIGURATION_ATTRIBUTE:
! 508: case PAYLOAD_LIST + PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE:
! 509: {
! 510: linked_list_t *proposals;
! 511: enumerator_t *enumerator;
! 512: payload_t *proposal;
! 513:
! 514: proposals = *((linked_list_t **)
! 515: (this->data_struct + rules[i].offset));
! 516: enumerator = proposals->create_enumerator(proposals);
! 517: while (enumerator->enumerate(enumerator, &proposal))
! 518: {
! 519: generate_payload(this, proposal);
! 520: }
! 521: enumerator->destroy(enumerator);
! 522: break;
! 523: }
! 524: case ATTRIBUTE_FORMAT:
! 525: generate_flag(this, rules[i].offset);
! 526: /* Attribute format is a flag which is stored in context*/
! 527: this->attribute_format =
! 528: *((bool *)(this->data_struct + rules[i].offset));
! 529: break;
! 530: case ATTRIBUTE_LENGTH_OR_VALUE:
! 531: if (this->attribute_format)
! 532: {
! 533: generate_u_int_type(this, U_INT_16, rules[i].offset);
! 534: }
! 535: else
! 536: {
! 537: generate_u_int_type(this, U_INT_16, rules[i].offset);
! 538: /* this field hold the length of the attribute */
! 539: this->attribute_length =
! 540: *((uint16_t *)(this->data_struct + rules[i].offset));
! 541: }
! 542: break;
! 543: case ATTRIBUTE_VALUE:
! 544: {
! 545: if (!this->attribute_format)
! 546: {
! 547: if (this->debug)
! 548: {
! 549: DBG2(DBG_ENC, "attribute value has not fixed size");
! 550: }
! 551: /* the attribute value is generated */
! 552: generate_from_chunk(this, rules[i].offset);
! 553: }
! 554: break;
! 555: }
! 556: default:
! 557: DBG1(DBG_ENC, "field type %N is not supported",
! 558: encoding_type_names, rules[i].type);
! 559: return;
! 560: }
! 561: }
! 562: if (this->debug)
! 563: {
! 564: DBG2(DBG_ENC, "generating %N payload finished",
! 565: payload_type_names, payload_type);
! 566: DBG3(DBG_ENC, "generated data for this payload %b",
! 567: this->buffer + offset_start,
! 568: (u_int)(this->out_position - this->buffer - offset_start));
! 569: }
! 570: }
! 571:
! 572: METHOD(generator_t, destroy, void,
! 573: private_generator_t *this)
! 574: {
! 575: free(this->buffer);
! 576: free(this);
! 577: }
! 578:
! 579: /*
! 580: * Described in header
! 581: */
! 582: generator_t *generator_create()
! 583: {
! 584: private_generator_t *this;
! 585:
! 586: INIT(this,
! 587: .public = {
! 588: .get_chunk = _get_chunk,
! 589: .generate_payload = _generate_payload,
! 590: .destroy = _destroy,
! 591: },
! 592: .buffer = malloc(GENERATOR_DATA_BUFFER_SIZE),
! 593: .debug = TRUE,
! 594: );
! 595:
! 596: this->out_position = this->buffer;
! 597: this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
! 598:
! 599: return &this->public;
! 600: }
! 601:
! 602: /*
! 603: * Described in header
! 604: */
! 605: generator_t *generator_create_no_dbg()
! 606: {
! 607: private_generator_t *this = (private_generator_t*)generator_create();
! 608:
! 609: this->debug = FALSE;
! 610:
! 611: return &this->public;
! 612: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>