message: Fragment and reassemble IKEv2 messages
authorTobias Brunner <tobias@strongswan.org>
Mon, 16 Jun 2014 13:46:33 +0000 (15:46 +0200)
committerTobias Brunner <tobias@strongswan.org>
Fri, 10 Oct 2014 07:32:41 +0000 (09:32 +0200)
src/libcharon/encoding/message.c
src/libcharon/encoding/message.h

index 262f105..43f7423 100644 (file)
@@ -33,6 +33,7 @@
 #include <encoding/payloads/payload.h>
 #include <encoding/payloads/hash_payload.h>
 #include <encoding/payloads/encrypted_payload.h>
+#include <encoding/payloads/encrypted_fragment_payload.h>
 #include <encoding/payloads/unknown_payload.h>
 #include <encoding/payloads/cp_payload.h>
 #include <encoding/payloads/fragment_payload.h>
@@ -819,8 +820,9 @@ typedef struct {
         * For IKEv1 the number of the last fragment (in case we receive them out
         * of order), since the first one starts with 1 this defines the number of
         * fragments we expect.
+        * For IKEv2 we store the total number of fragment we received last.
         */
-       u_int8_t last;
+       u_int16_t last;
 
        /**
         * Length of all currently received fragments.
@@ -908,7 +910,7 @@ struct private_message_t {
 
        /**
         * Array of generated fragments (if any), as packet_t*.
-        * If defragmenting (frag != NULL) this contains fragment_t*
+        * If defragmenting (i.e. frag != NULL) this contains fragment_t*
         */
        array_t *fragments;
 
@@ -952,11 +954,10 @@ static void fragment_destroy(fragment_t *this)
        free(this);
 }
 
-static void reset_defrag(private_message_t *this, u_int16_t id)
+static void reset_defrag(private_message_t *this)
 {
        array_destroy_function(this->fragments, (void*)fragment_destroy, NULL);
        this->fragments = NULL;
-       this->message_id = id;
        this->frag->last = 0;
        this->frag->len = 0;
 }
@@ -1822,35 +1823,64 @@ static message_t *clone_message(private_message_t *this)
        message->set_source(message, src->clone(src));
        message->set_destination(message, dst->clone(dst));
        message->set_exchange_type(message, this->exchange_type);
+       memcpy(((private_message_t*)message)->reserved, this->reserved,
+                  sizeof(this->reserved));
        return message;
 }
 
 /**
  * Create a single fragment with the given data
  */
-static message_t *create_fragment(private_message_t *this, u_int8_t num,
-                                                                 bool last, chunk_t data)
+static message_t *create_fragment(private_message_t *this, payload_type_t next,
+                                                                 u_int16_t num, u_int16_t count, chunk_t data)
 {
-       fragment_payload_t *fragment;
+       enumerator_t *enumerator;
+       payload_t *fragment, *payload;
        message_t *message;
        peer_cfg_t *peer_cfg;
        ike_sa_t *ike_sa;
 
-       fragment = fragment_payload_create_from_data(num, last, data);
        message = clone_message(this);
-       /* other implementations seem to just use 0 as message ID, so here we go */
-       message->set_message_id(message, 0);
-       /* always use the initial message type for fragments, even for quick mode
-        * or transaction messages. */
-       ike_sa = charon->bus->get_sa(charon->bus);
-       if (ike_sa && (peer_cfg = ike_sa->get_peer_cfg(ike_sa)) &&
-               peer_cfg->use_aggressive(peer_cfg))
-       {
-               message->set_exchange_type(message, AGGRESSIVE);
+       if (this->major_version == IKEV1_MAJOR_VERSION)
+       {
+               /* other implementations seem to just use 0 as message ID, so here we go */
+               message->set_message_id(message, 0);
+               /* always use the initial message type for fragments, even for quick mode
+                * or transaction messages. */
+               ike_sa = charon->bus->get_sa(charon->bus);
+               if (ike_sa && (peer_cfg = ike_sa->get_peer_cfg(ike_sa)) &&
+                       peer_cfg->use_aggressive(peer_cfg))
+               {
+                       message->set_exchange_type(message, AGGRESSIVE);
+               }
+               else
+               {
+                       message->set_exchange_type(message, ID_PROT);
+               }
+               fragment = (payload_t*)fragment_payload_create_from_data(
+                                                                                                       num, num == count, data);
        }
        else
        {
-               message->set_exchange_type(message, ID_PROT);
+               fragment = (payload_t*)encrypted_fragment_payload_create_from_data(
+                                                                                                       num, count, data);
+               if (num == 1)
+               {
+                       /* only in the first fragment is this set to the type of the first
+                        * payload in the encrypted payload */
+                       fragment->set_next_type(fragment, next);
+                       /* move unencrypted payloads to the first fragment */
+                       enumerator = this->payloads->create_enumerator(this->payloads);
+                       while (enumerator->enumerate(enumerator, &payload))
+                       {
+                               if (payload->get_type(payload) != PLV2_ENCRYPTED)
+                               {
+                                       this->payloads->remove_at(this->payloads, enumerator);
+                                       message->add_payload(message, payload);
+                               }
+                       }
+                       enumerator->destroy(enumerator);
+               }
        }
        message->add_payload(message, (payload_t*)fragment);
        return message;
@@ -1869,29 +1899,18 @@ METHOD(message_t, fragment, status_t,
        private_message_t *this, keymat_t *keymat, size_t frag_len,
        enumerator_t **fragments)
 {
+       encrypted_payload_t *encrypted = NULL;
+       generator_t *generator = NULL;
        message_t *fragment;
        packet_t *packet;
-       u_int8_t num, count;
+       payload_type_t next = PL_NONE;
+       u_int16_t num, count;
        host_t *src, *dst;
        chunk_t data;
        status_t status;
+       u_int32_t *lenpos;
        size_t len;
 
-       if (this->major_version == IKEV2_MAJOR_VERSION)
-       {
-               return INVALID_STATE;
-       }
-       clear_fragments(this);
-
-       if (!is_encoded(this))
-       {
-               status = generate(this, keymat, NULL);
-               if (status != SUCCESS)
-               {
-                       return status;
-               }
-       }
-
        src = this->packet->get_source(this->packet);
        dst = this->packet->get_destination(this->packet);
        if (!frag_len)
@@ -1901,31 +1920,112 @@ METHOD(message_t, fragment, status_t,
        /* frag_len is the complete IP datagram length, account for overhead (we
         * assume no IP options/extension headers are used) */
        frag_len -= (src->get_family(src) == AF_INET) ? 20 : 40;
-       /* 8 (UDP header) + 28 (IKE header) */
-       frag_len -= 36;
+       /* 8 (UDP header) */
+       frag_len -= 8;
        if (dst->get_port(dst) != IKEV2_UDP_PORT &&
                src->get_port(src) != IKEV2_UDP_PORT)
        {       /* reduce length due to non-ESP marker */
                frag_len -= 4;
        }
 
-       data = this->packet->get_data(this->packet);
-       if (data.len <= frag_len)
+       if (is_encoded(this))
        {
+               if (this->major_version == IKEV2_MAJOR_VERSION)
+               {
+                       encrypted = (encrypted_payload_t*)get_payload(this, PLV2_ENCRYPTED);
+               }
+               data = this->packet->get_data(this->packet);
+               len = data.len;
+       }
+       else
+       {
+               status = generate_message(this, keymat, &generator, &encrypted);
+               if (status != SUCCESS)
+               {
+                       DESTROY_IF(generator);
+                       return status;
+               }
+               data = generator->get_chunk(generator, &lenpos);
+               len = data.len + (encrypted ? encrypted->get_length(encrypted) : 0);
+       }
+
+       /* check if we actually need to fragment the message and if we have an
+        * encrypted payload for IKEv2 */
+       if (len <= frag_len ||
+          (this->major_version == IKEV2_MAJOR_VERSION && !encrypted))
+       {
+               if (generator)
+               {
+                       status = finalize_message(this, keymat, generator, encrypted);
+                       if (status != SUCCESS)
+                       {
+                               return status;
+                       }
+               }
                *fragments = enumerator_create_single(this->packet, NULL);
                return SUCCESS;
        }
-       /* overhead for the fragmentation payload header */
-       frag_len -= 8;
+
+       /* frag_len denoted the maximum IKE message size so far, later on it will
+        * denote the maximum content size of a fragment payload, therefore,
+        * account for IKE header */
+       frag_len -= 28;
+
+       if (this->major_version == IKEV1_MAJOR_VERSION)
+       {
+               if (generator)
+               {
+                       status = finalize_message(this, keymat, generator, encrypted);
+                       if (status != SUCCESS)
+                       {
+                               return status;
+                       }
+                       data = this->packet->get_data(this->packet);
+                       generator = NULL;
+               }
+               /* overhead for the fragmentation payload header */
+               frag_len -= 8;
+       }
+       else
+       {
+               aead_t *aead;
+
+               if (generator)
+               {
+                       generator->destroy(generator);
+                       generator = generator_create();
+               }
+               else
+               {       /* do not log again if it was generated previously */
+                       generator = generator_create_no_dbg();
+               }
+               next = encrypted->payload_interface.get_next_type((payload_t*)encrypted);
+               encrypted->generate_payloads(encrypted, generator);
+               data = generator->get_chunk(generator, &lenpos);
+               if (!is_encoded(this))
+               {
+                       encrypted->destroy(encrypted);
+               }
+               aead = keymat->get_aead(keymat, FALSE);
+               /* overhead for the encrypted fragment payload */
+               frag_len -= aead->get_iv_size(aead) + aead->get_icv_size(aead);
+               frag_len -= 8 /* header */;
+               /* padding and padding length */
+               frag_len = round_down(frag_len, aead->get_block_size(aead)) - 1;
+               /* TODO-FRAG: if there are unencrypted payloads, should we account for
+                * their length in the first fragment? we still would have to add
+                * an encrypted fragment payload (albeit empty), even so we couldn't
+                * prevent IP fragmentation in every case */
+       }
 
        count = data.len / frag_len + (data.len % frag_len ? 1 : 0);
        this->fragments = array_create(0, count);
-       DBG2(DBG_ENC, "splitting IKE message with length of %zu bytes into "
-                "%hhu fragments", data.len, count);
+       DBG1(DBG_ENC, "splitting IKE message with length of %zu bytes into "
+                "%hu fragments", len, count);
        for (num = 1; num <= count; num++)
        {
                len = min(data.len, frag_len);
-               fragment = create_fragment(this, num, num == count,
+               fragment = create_fragment(this, next, num, count,
                                                                   chunk_create(data.ptr, len));
                status = fragment->generate(fragment, keymat, &packet);
                fragment->destroy(fragment);
@@ -1933,12 +2033,14 @@ METHOD(message_t, fragment, status_t,
                {
                        DBG1(DBG_ENC, "failed to generate IKE fragment");
                        clear_fragments(this);
+                       DESTROY_IF(generator);
                        return FAILED;
                }
                array_insert(this->fragments, ARRAY_TAIL, packet);
                data = chunk_skip(data, len);
        }
        *fragments = array_create_enumerator(this->fragments);
+       DESTROY_IF(generator);
        return SUCCESS;
 }
 
@@ -1970,6 +2072,10 @@ METHOD(message_t, parse_header, status_t,
 
        DBG2(DBG_ENC, "parsing header of message");
 
+       if (!this->parser)
+       {       /* reassembled IKEv2 message, header is inherited from fragments */
+               return SUCCESS;
+       }
        this->parser->reset_context(this->parser);
        status = this->parser->parse_payload(this->parser, PL_HEADER,
                                                                                 (payload_t**)&ike_header);
@@ -2149,43 +2255,52 @@ static status_t decrypt_and_extract(private_message_t *this, keymat_t *keymat,
                DBG1(DBG_ENC, "found encrypted payload, but no transform set");
                return INVALID_ARG;
        }
-       bs = aead->get_block_size(aead);
-       encryption->set_transform(encryption, aead);
-       chunk = this->packet->get_data(this->packet);
-       if (chunk.len < encryption->get_length(encryption) ||
-               chunk.len < bs)
+       if (!this->parser)
        {
-               DBG1(DBG_ENC, "invalid payload length");
-               return VERIFY_ERROR;
+               /* reassembled IKEv2 messages are already decrypted, we still call
+                * decrypt() to parse the contained payloads */
+               status = encryption->decrypt(encryption, chunk_empty);
        }
-       if (keymat->get_version(keymat) == IKEV1)
-       {       /* instead of associated data we provide the IV, we also update
-                * the IV with the last encrypted block */
-               keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat;
-               chunk_t iv;
-
-               if (keymat_v1->get_iv(keymat_v1, this->message_id, &iv))
+       else
+       {
+               bs = aead->get_block_size(aead);
+               encryption->set_transform(encryption, aead);
+               chunk = this->packet->get_data(this->packet);
+               if (chunk.len < encryption->get_length(encryption) ||
+                       chunk.len < bs)
                {
-                       status = encryption->decrypt(encryption, iv);
-                       if (status == SUCCESS)
+                       DBG1(DBG_ENC, "invalid payload length");
+                       return VERIFY_ERROR;
+               }
+               if (keymat->get_version(keymat) == IKEV1)
+               {       /* instead of associated data we provide the IV, we also update
+                        * the IV with the last encrypted block */
+                       keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat;
+                       chunk_t iv;
+
+                       if (keymat_v1->get_iv(keymat_v1, this->message_id, &iv))
                        {
-                               if (!keymat_v1->update_iv(keymat_v1, this->message_id,
-                                               chunk_create(chunk.ptr + chunk.len - bs, bs)))
+                               status = encryption->decrypt(encryption, iv);
+                               if (status == SUCCESS)
                                {
-                                       status = FAILED;
+                                       if (!keymat_v1->update_iv(keymat_v1, this->message_id,
+                                                       chunk_create(chunk.ptr + chunk.len - bs, bs)))
+                                       {
+                                               status = FAILED;
+                                       }
                                }
                        }
+                       else
+                       {
+                               status = FAILED;
+                       }
                }
                else
                {
-                       status = FAILED;
+                       chunk.len -= encryption->get_length(encryption);
+                       status = encryption->decrypt(encryption, chunk);
                }
        }
-       else
-       {
-               chunk.len -= encryption->get_length(encryption);
-               status = encryption->decrypt(encryption, chunk);
-       }
        if (status != SUCCESS)
        {
                return status;
@@ -2432,10 +2547,15 @@ METHOD(message_t, parse_body, status_t,
                return NOT_SUPPORTED;
        }
 
-       status = parse_payloads(this);
-       if (status != SUCCESS)
-       {       /* error is already logged */
-               return status;
+       /* reassembled IKEv2 messages are already parsed (except for the payloads
+        * contained in the encrypted payload, which are handled below) */
+       if (this->parser)
+       {
+               status = parse_payloads(this);
+               if (status != SUCCESS)
+               {       /* error is already logged */
+                       return status;
+               }
        }
 
        status = decrypt_payloads(this, keymat);
@@ -2500,46 +2620,22 @@ METHOD(message_t, parse_body, status_t,
        return SUCCESS;
 }
 
-METHOD(message_t, add_fragment, status_t,
-       private_message_t *this, message_t *message)
+/**
+ * Store the fragment data for the fragment with the given fragment number.
+ */
+static status_t add_fragment(private_message_t *this, u_int16_t num,
+                                                        chunk_t data)
 {
-       fragment_payload_t *payload;
        fragment_t *fragment;
-       bio_writer_t *writer;
-       host_t *src, *dst;
-       chunk_t data;
-       u_int8_t num;
        int i, insert_at = -1;
 
-       if (!this->frag)
-       {
-               return INVALID_STATE;
-       }
-       payload = (fragment_payload_t*)message->get_payload(message, PLV1_FRAGMENT);
-       if (!payload)
-       {
-               return INVALID_ARG;
-       }
-       if (!this->fragments || this->message_id != payload->get_id(payload))
-       {
-               reset_defrag(this, payload->get_id(payload));
-               /* we don't know the total number of fragments */
-               this->fragments = array_create(0, 0);
-       }
-
-       num = payload->get_number(payload);
-       if (!this->frag->last && payload->is_last(payload))
-       {
-               this->frag->last = num;
-       }
-
        for (i = 0; i < array_count(this->fragments); i++)
        {
                array_get(this->fragments, i, &fragment);
                if (fragment->num == num)
                {
                        /* ignore a duplicate fragment */
-                       DBG1(DBG_ENC, "received duplicate fragment #%hhu", num);
+                       DBG1(DBG_ENC, "received duplicate fragment #%hu", num);
                        return NEED_MORE;
                }
                if (fragment->num > num)
@@ -2548,12 +2644,11 @@ METHOD(message_t, add_fragment, status_t,
                        break;
                }
        }
-       data = payload->get_data(payload);
        this->frag->len += data.len;
        if (this->frag->len > this->frag->max_packet)
        {
                DBG1(DBG_ENC, "fragmented IKE message is too large");
-               reset_defrag(this, 0);
+               reset_defrag(this);
                return FAILED;
        }
        INIT(fragment,
@@ -2561,35 +2656,93 @@ METHOD(message_t, add_fragment, status_t,
                .data = chunk_clone(data),
        );
        array_insert(this->fragments, insert_at, fragment);
+       return SUCCESS;
+}
 
-       if (this->frag->last < array_count(this->fragments))
-       {
-               /* there are some fragments missing */
-               DBG1(DBG_ENC, "received fragment #%hhu, waiting for complete IKE "
-                        "message", num);
-               return NEED_MORE;
-       }
+/**
+ * Merge the cached fragment data and resets the defragmentation state.
+ * Also updates the IP addresses to those of the last received fragment.
+ */
+static chunk_t merge_fragments(private_message_t *this, message_t *last)
+{
+       fragment_t *fragment;
+       bio_writer_t *writer;
+       host_t *src, *dst;
+       chunk_t data;
+       int i;
 
        writer = bio_writer_create(this->frag->len);
-       DBG1(DBG_ENC, "received fragment #%hhu, reassembling fragmented IKE "
-                "message", num);
-
        for (i = 0; i < array_count(this->fragments); i++)
        {
                array_get(this->fragments, i, &fragment);
                writer->write_data(writer, fragment->data);
        }
-       src = message->get_source(message);
-       dst = message->get_destination(message);
+       data = writer->extract_buf(writer);
+       writer->destroy(writer);
+
+       /* set addresses to those of the last fragment we received */
+       src = last->get_source(last);
+       dst = last->get_destination(last);
        this->packet->set_source(this->packet, src->clone(src));
        this->packet->set_destination(this->packet, dst->clone(dst));
-       this->packet->set_data(this->packet, writer->extract_buf(writer));
-       writer->destroy(writer);
-       this->parser->destroy(this->parser);
-       this->parser = parser_create(this->packet->get_data(this->packet));
-       reset_defrag(this, 0);
+
+       reset_defrag(this);
        free(this->frag);
        this->frag = NULL;
+       return data;
+}
+
+METHOD(message_t, add_fragment_v1, status_t,
+       private_message_t *this, message_t *message)
+{
+       fragment_payload_t *payload;
+       chunk_t data;
+       u_int8_t num;
+       status_t status;
+
+       if (!this->frag)
+       {
+               return INVALID_STATE;
+       }
+       payload = (fragment_payload_t*)message->get_payload(message, PLV1_FRAGMENT);
+       if (!payload)
+       {
+               return INVALID_ARG;
+       }
+       if (!this->fragments || this->message_id != payload->get_id(payload))
+       {
+               reset_defrag(this);
+               this->message_id = payload->get_id(payload);
+               /* we don't know the total number of fragments, assume something */
+               this->fragments = array_create(0, 4);
+       }
+
+       num = payload->get_number(payload);
+       data = payload->get_data(payload);
+       if (!this->frag->last && payload->is_last(payload))
+       {
+               this->frag->last = num;
+       }
+       status = add_fragment(this, num, data);
+       if (status != SUCCESS)
+       {
+               return status;
+       }
+
+       if (array_count(this->fragments) != this->frag->last)
+       {
+               /* there are some fragments missing */
+               DBG1(DBG_ENC, "received fragment #%hhu, waiting for complete IKE "
+                        "message", num);
+               return NEED_MORE;
+       }
+
+       DBG1(DBG_ENC, "received fragment #%hhu, reassembling fragmented IKE "
+                "message", num);
+
+       data = merge_fragments(this, message);
+       this->packet->set_data(this->packet, data);
+       this->parser = parser_create(data);
 
        if (parse_header(this) != SUCCESS)
        {
@@ -2599,16 +2752,91 @@ METHOD(message_t, add_fragment, status_t,
        return SUCCESS;
 }
 
+METHOD(message_t, add_fragment_v2, status_t,
+       private_message_t *this, message_t *message)
+{
+       encrypted_fragment_payload_t *encrypted_fragment;
+       encrypted_payload_t *encrypted;
+       payload_t *payload;
+       enumerator_t *enumerator;
+       chunk_t data;
+       u_int16_t total, num;
+       status_t status;
+
+       if (!this->frag)
+       {
+               return INVALID_STATE;
+       }
+       payload = message->get_payload(message, PLV2_FRAGMENT);
+       if (!payload || this->message_id != message->get_message_id(message))
+       {
+               return INVALID_ARG;
+       }
+       encrypted_fragment = (encrypted_fragment_payload_t*)payload;
+       total = encrypted_fragment->get_total_fragments(encrypted_fragment);
+
+       if (!this->fragments || total > this->frag->last)
+       {
+               reset_defrag(this);
+               this->frag->last = total;
+               this->fragments = array_create(0, total);
+       }
+       num = encrypted_fragment->get_fragment_number(encrypted_fragment);
+       data = encrypted_fragment->get_content(encrypted_fragment);
+       status = add_fragment(this, num, data);
+       if (status != SUCCESS)
+       {
+               return status;
+       }
+
+       if (num == 1)
+       {
+               /* the first fragment denotes the payload type of the first payload in
+                * the original encrypted payload, cache that */
+               this->first_payload = payload->get_next_type(payload);
+               /* move all unencrypted payloads contained in the first fragment */
+               enumerator = message->create_payload_enumerator(message);
+               while (enumerator->enumerate(enumerator, &payload))
+               {
+                       if (payload->get_type(payload) != PLV2_FRAGMENT)
+                       {
+                               message->remove_payload_at(message, enumerator);
+                               this->payloads->insert_last(this->payloads, payload);
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+
+       if (array_count(this->fragments) != total)
+       {
+               /* there are some fragments missing */
+               DBG1(DBG_ENC, "received fragment #%hu of %hu, waiting for complete IKE "
+                        "message", num, total);
+               return NEED_MORE;
+       }
+
+       DBG1(DBG_ENC, "received fragment #%hu of %hu, reassembling fragmented IKE "
+                "message", num, total);
+
+       data = merge_fragments(this, message);
+       encrypted = encrypted_payload_create_from_plain(this->first_payload, data);
+       this->payloads->insert_last(this->payloads, encrypted);
+       /* update next payload type (could be an unencrypted payload) */
+       this->payloads->get_first(this->payloads, (void**)&payload);
+       this->first_payload = payload->get_type(payload);
+       return SUCCESS;
+}
+
 METHOD(message_t, destroy, void,
        private_message_t *this)
 {
        DESTROY_IF(this->ike_sa_id);
+       DESTROY_IF(this->parser);
        this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy));
        this->packet->destroy(this->packet);
-       this->parser->destroy(this->parser);
        if (this->frag)
        {
-               reset_defrag(this, 0);
+               reset_defrag(this);
                free(this->frag);
        }
        else
@@ -2652,7 +2880,7 @@ message_t *message_create_from_packet(packet_t *packet)
                        .is_encoded = _is_encoded,
                        .is_fragmented = _is_fragmented,
                        .fragment = _fragment,
-                       .add_fragment = _add_fragment,
+                       .add_fragment = _add_fragment_v2,
                        .set_source = _set_source,
                        .get_source = _get_source,
                        .set_destination = _set_destination,
@@ -2699,13 +2927,23 @@ message_t *message_create_defrag(message_t *fragment)
 {
        private_message_t *this;
 
-       if (!fragment->get_payload(fragment, PLV1_FRAGMENT))
+       if (!fragment->get_payload(fragment, PLV1_FRAGMENT) &&
+               !fragment->get_payload(fragment, PLV2_FRAGMENT))
        {
                return NULL;
        }
-       this = (private_message_t*)message_create(
-                                                                               fragment->get_major_version(fragment),
-                                                                               fragment->get_minor_version(fragment));
+       this = (private_message_t*)clone_message((private_message_t*)fragment);
+       /* we don't need a parser for IKEv2, the one for IKEv1 is created after
+        * reassembling the original message */
+       this->parser->destroy(this->parser);
+       this->parser = NULL;
+       if (fragment->get_major_version(fragment) == IKEV1_MAJOR_VERSION)
+       {
+               /* we store the fragment ID in the message ID field, which should be
+                * zero for fragments, but make sure */
+               this->message_id = 0;
+               this->public.add_fragment = _add_fragment_v1;
+       }
        INIT(this->frag,
                .max_packet = lib->settings->get_int(lib->settings,
                                                                                "%s.max_packet", MAX_PACKET, lib->ns),
index 69a8e93..a03aa8e 100644 (file)
@@ -268,8 +268,6 @@ struct message_t {
         * Generates the message split into fragments of the given size (total IP
         * datagram length).
         *
-        * @note Only supported for IKEv1 at the moment.
-        *
         * @param keymat        keymat to encrypt/sign message(s)
         * @param frag_len      fragment length (maximum total IP datagram length), 0
         *                                      for default value depending on address family
@@ -277,7 +275,6 @@ struct message_t {
         *                                      which are owned by the enumerator
         * @return
         *                                      - SUCCESS if message could be fragmented
-        *                                      - INVALID_STATE if message is IKEv2
         *                                      - FAILED if fragmentation failed
         *                                      - and the possible return values of generate()
         */
@@ -303,8 +300,6 @@ struct message_t {
         * Once the message is completed it should be processed like any other
         * inbound message.
         *
-        * @note Only supported for IKEv1 at the moment.
-        *
         * @param fragment      fragment to add
         * @return
         *                                      - SUCCESS if message was reassembled