vpnengine/ikev2lib/src/ikev2message.cpp
changeset 0 33413c0669b9
child 1 c9c2ad51f972
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev2lib/src/ikev2message.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1293 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include <es_sock.h>
+#include <badesca.h>
+#include <random.h>
+
+#include "ikev2message.h"
+#include "ikev2const.h"
+#include "ikecalist.h"
+#include "ikecaelem.h"
+#include "ikev2trafficselector.h"
+#include "ikecrypto.h"
+#include "ikev2identity.h"
+#include "ikemsgheader.h"
+#include "ikedebug.h"
+
+static const TUint8 KMessageIdFieldOffset = 20; 
+
+static const TUint KIkePayloadGenericHeaderLength = 4;
+static const TUint8 KLengthFieldOffset = 2;
+
+static const TUint32 KSha1Length = 20;
+static const TUint32 KCertReqHeaderLength = 5;
+static const TUint32 KCertHeaderLength = 5;
+static const TUint32 KSaHeaderLength = 4;
+static const TUint32 KKeHeaderLength = 8;
+static const TUint32 KNonceHeaderLength = 4;
+static const TUint32 KAuthHeaderLength = 8;
+static const TUint32 KNotifyHeaderLength = 8;
+static const TUint32 KConfigurationHeaderLength = 8;
+static const TUint32 KVendorIdHeaderLength = 4;
+static const TUint32 KDeleteHeaderLength = 8;
+static const TUint32 KEapHeaderLength = 4;
+static const TUint32 KTsHeaderLength = 8;
+static const TUint32 KEncryptedHeaderLength = 4;
+
+_LIT8(KNonEspMarker, "\0\0\0\0");
+
+CIkeV2Payload::CIkeV2Payload(TUint8 aPayloadType)
+:iPayloadType(aPayloadType)
+    {    
+    }
+
+
+CIkeV2Payload::~CIkeV2Payload()
+    {
+    delete iPayloadData;
+    }
+
+TUint8 CIkeV2Payload::PayloadType() const
+    {
+    return iPayloadType;
+    }
+
+
+TUint8 CIkeV2Payload::NextPayload() const
+    {
+    __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength,
+                   User::Invariant());
+    
+    return (*iPayloadData)[0];
+    }
+
+
+void CIkeV2Payload::SetNextPayload(TUint8 aNextPayload)
+    {
+    __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength,
+                   User::Invariant());
+    
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr[0] = aNextPayload;
+    }
+
+
+TUint16 CIkeV2Payload::PayloadLength() const
+    {
+    __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength,
+                   User::Invariant());
+    
+    return BigEndian::Get16(iPayloadData->Ptr() + KLengthFieldOffset);
+    }
+
+
+void CIkeV2Payload::SetPayloadLength(TUint16 aLength)
+    {
+    __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength,
+                   User::Invariant());
+    const TUint KLengthPosition = 2; 
+    
+    BigEndian::Put16(reinterpret_cast<TUint8*>(&aLength), aLength);
+    TPtrC8 length(reinterpret_cast<TUint8*>(&aLength), sizeof(aLength));
+    
+    TPtr8 lengthPtr(iPayloadData->Des().MidTPtr(KLengthPosition, 
+                                                length.Length()));    
+    lengthPtr = length; 
+    }
+
+TPtrC8 CIkeV2Payload::PayloadData() const
+    {
+    return TPtrC8(*iPayloadData);
+    }
+
+
+CIkevV2CertReqPayload* CIkevV2CertReqPayload::NewL(const CIkeCaList& aCaList)
+    {
+    CIkevV2CertReqPayload* self = new (ELeave) CIkevV2CertReqPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aCaList);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+
+CIkevV2CertReqPayload::CIkevV2CertReqPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_CR)
+    {
+    }
+
+
+void CIkevV2CertReqPayload::ConstructL(const CIkeCaList& aCaList)
+    {
+    __ASSERT_DEBUG(aCaList.Count() > 0, User::Invariant());
+    TUint16 length = (aCaList.Count() * KSha1Length) + KCertReqHeaderLength;
+    
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    TUint8 encoding = X509_CERTIFICATE_SIGN;       
+    TPtrC8 encodingPtr(&encoding, sizeof(encoding));
+    payloadDataPtr.Append(encodingPtr);
+    
+    for (TUint i = 0; i < aCaList.Count(); ++i)
+        {
+        payloadDataPtr.Append(aCaList[i]->KeyHash());
+        }
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2CertPayload* CIkevV2CertPayload::NewL(const TDesC8& aCertData)
+    {
+    CIkevV2CertPayload* self = new (ELeave) CIkevV2CertPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aCertData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkevV2CertPayload::CIkevV2CertPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_CERT)
+    {
+    
+    }
+
+
+void CIkevV2CertPayload::ConstructL(const TDesC8& aCertData)
+    {
+    TUint16 length = aCertData.Length() + KCertHeaderLength;
+    
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);  
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    TUint8 encoding = X509_CERTIFICATE_SIGN;     
+    TPtrC8 encodingPtr(&encoding, sizeof(encoding));
+    payloadDataPtr.Append(encodingPtr);       
+    payloadDataPtr.Append(aCertData);   
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2SaPayload* CIkevV2SaPayload::NewL(const TDesC8& aSaData)
+    {
+    CIkevV2SaPayload* self = new (ELeave) CIkevV2SaPayload; 
+    CleanupStack::PushL(self);
+    self->ConstructL(aSaData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkevV2SaPayload::CIkevV2SaPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_SA)
+    {    
+    }
+
+
+void CIkevV2SaPayload::ConstructL(const TDesC8& aSaData)
+    {
+    TUint16 length = aSaData.Length() + KSaHeaderLength;
+    
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    payloadDataPtr.Append(aSaData);
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2KePayload* CIkevV2KePayload::NewL(TUint16 aDHGroup, const TDesC8& aKeData)
+    {    
+    CIkevV2KePayload* self = new (ELeave) CIkevV2KePayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aDHGroup, aKeData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkevV2KePayload::CIkevV2KePayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_KE)
+    {
+    }
+
+void CIkevV2KePayload::ConstructL(TUint16 aDHGroup, const TDesC8& aKeData)
+    {
+    static const TUint8 KReservedFieldLength = 2;
+    
+    TUint16 length = aKeData.Length() + KKeHeaderLength;
+    
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    BigEndian::Put16(reinterpret_cast<TUint8*>(&aDHGroup), aDHGroup);
+    TPtrC8 dhGroupPtr(reinterpret_cast<TUint8*>(&aDHGroup), sizeof(aDHGroup));
+    payloadDataPtr.Append(dhGroupPtr);
+    
+    //Leave reserved bytes zero
+    payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength);
+    TPtr8 reservedBytes = payloadDataPtr.RightTPtr(KReservedFieldLength);
+    reservedBytes.FillZ();
+    
+    payloadDataPtr.Append(aKeData);  
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2NoncePayload* CIkevV2NoncePayload::NewL(const TDesC8& aNonceData)
+    {
+    CIkevV2NoncePayload* self = new (ELeave) CIkevV2NoncePayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aNonceData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkevV2NoncePayload::CIkevV2NoncePayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_NONCE)
+    {
+    }
+
+
+void CIkevV2NoncePayload::ConstructL(const TDesC8& aNonceData)
+    {
+    TUint16 length = aNonceData.Length() + KNonceHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);  
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    payloadDataPtr.Append(aNonceData);
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2IdPayload::CIkevV2IdPayload(TUint8 aPayloadType)
+:CIkeV2Payload(aPayloadType)
+    {    
+    }
+
+void CIkevV2IdPayload::ConstructL(const CIkeV2Identity& aIdentity)
+    {        
+    TPtrC8 idPayloadData = aIdentity.PayloadData();
+    TUint32 length = idPayloadData.Length() + KIkePayloadGenericHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);    
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    payloadDataPtr.Append(idPayloadData);
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkevV2IdiPayload* CIkevV2IdiPayload::NewL(const CIkeV2Identity& aIdentity)
+    {    
+    CIkevV2IdiPayload* self = new (ELeave) CIkevV2IdiPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aIdentity);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+
+CIkevV2IdiPayload::CIkevV2IdiPayload()
+:CIkevV2IdPayload(IKEV2_PAYLOAD_ID_I)
+    {  
+    }
+
+
+CIkevV2IdrPayload* CIkevV2IdrPayload::NewL(const CIkeV2Identity& aIdentity)
+    {    
+    CIkevV2IdrPayload* self = new (ELeave) CIkevV2IdrPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aIdentity);
+    CleanupStack::Pop(self);
+    return self;    
+    }
+
+
+CIkevV2IdrPayload::CIkevV2IdrPayload()
+:CIkevV2IdPayload(IKEV2_PAYLOAD_ID_R)
+    {    
+    }
+
+
+CIkeV2AuthPayload* CIkeV2AuthPayload::NewL(TUint8 aAuthMethod, const TDesC8& aAuthData)
+    {
+    CIkeV2AuthPayload* self = new (ELeave) CIkeV2AuthPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aAuthMethod, aAuthData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2AuthPayload::CIkeV2AuthPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_AUTH)
+    {
+    }
+
+
+void CIkeV2AuthPayload::ConstructL(TUint8 aAuthMethod, const TDesC8& aAuthData)
+    {
+    static const TUint8 KReservedFieldLength = 3;
+    
+    TUint32 length = aAuthData.Length() + KAuthHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);    
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    TPtrC8 authTypePtr(&aAuthMethod, sizeof(aAuthMethod));
+    payloadDataPtr.Append(authTypePtr);
+    //Leave reserved bytes zero
+    payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength);    
+    TPtr8 reservedField = payloadDataPtr.RightTPtr(KReservedFieldLength);
+    reservedField.FillZ();
+    
+    payloadDataPtr.Append(aAuthData);   
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2NotifyPayload* CIkeV2NotifyPayload::NewL(TUint8 aProtocolId,
+                                               const TDesC8& aSpi,
+                                               TUint16 aNotifyType,
+                                               const TDesC8& aNotifyData)
+    {    
+    CIkeV2NotifyPayload* self = new (ELeave) CIkeV2NotifyPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aProtocolId, aSpi, aNotifyType, aNotifyData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2NotifyPayload::CIkeV2NotifyPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_NOTIF)
+    {
+    }
+
+
+void CIkeV2NotifyPayload::ConstructL(TUint8 aProtocolId,
+                                     const TDesC8& aSpi,
+                                     TUint16 aNotifyType,
+                                     const TDesC8& aNotifyData)
+    {    
+    TUint32 length = aSpi.Length() + aNotifyData.Length() + KNotifyHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);    
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    TPtrC8 protocolIdPtr(&aProtocolId, sizeof(aProtocolId));
+    TUint8 spiSize = aSpi.Length();
+    TPtrC8 spiSizePtr(&spiSize, sizeof(spiSize));
+    
+    BigEndian::Put16(reinterpret_cast<TUint8*>(&aNotifyType), aNotifyType);
+    TPtrC8 notifyTypePtr(reinterpret_cast<TUint8*>(&aNotifyType), sizeof(aNotifyType));
+    
+    
+    payloadDataPtr.Append(protocolIdPtr);
+    payloadDataPtr.Append(spiSizePtr);
+    payloadDataPtr.Append(notifyTypePtr);
+    payloadDataPtr.Append(aSpi);
+    payloadDataPtr.Append(aNotifyData);  
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2ConfigurationPayload* CIkeV2ConfigurationPayload::NewL(TUint8 aCfgType, 
+                                                             const TDesC8& aConfigurationData)
+    {
+    CIkeV2ConfigurationPayload* self = new (ELeave) CIkeV2ConfigurationPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aCfgType, aConfigurationData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2ConfigurationPayload::CIkeV2ConfigurationPayload()
+: CIkeV2Payload(IKEV2_PAYLOAD_CONFIG)
+    {    
+    }
+
+
+void CIkeV2ConfigurationPayload::ConstructL(TUint8 aCfgType, 
+                                            const TDesC8& aConfigurationData)
+    {
+    static const TUint8 KReservedFieldLength = 3;
+    
+    TUint32 length = aConfigurationData.Length() + KConfigurationHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);    
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    TPtrC8 cfgTypePtr(reinterpret_cast<TUint8*>(&aCfgType), sizeof(aCfgType));
+    payloadDataPtr.Append(cfgTypePtr);
+    
+    //Leave reserved bytes zero
+    payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength);    
+    TPtr8 reservedField = payloadDataPtr.RightTPtr(KReservedFieldLength);
+    reservedField.FillZ();
+    
+    payloadDataPtr.Append(aConfigurationData);  
+
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2VendorIdPayload* CIkeV2VendorIdPayload::NewL(const TDesC8& aVendorIdData)
+    {
+    CIkeV2VendorIdPayload* self = new (ELeave) CIkeV2VendorIdPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aVendorIdData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2VendorIdPayload::CIkeV2VendorIdPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_VID)
+    {    
+    }
+
+
+void CIkeV2VendorIdPayload::ConstructL(const TDesC8& aVendorIdData)
+    {        
+    TUint32 length = aVendorIdData.Length() + KVendorIdHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    payloadDataPtr.Append(aVendorIdData);    
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2DeletePayload* CIkeV2DeletePayload::NewL(TUint8 aProtocolId, 
+                                              const CDesC8Array& aSpiList)
+    {
+    CIkeV2DeletePayload* self = new (ELeave) CIkeV2DeletePayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aProtocolId, aSpiList);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2DeletePayload::CIkeV2DeletePayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_DELETE)
+    {    
+    }
+
+
+void CIkeV2DeletePayload::ConstructL(TUint8 aProtocolId, const CDesC8Array& aSpiList)
+    {
+    TUint16 spiCount = aSpiList.Count();
+    TUint8 spiLength = (spiCount > 0) ? aSpiList[0].Length() : 0; 
+    TUint32 length = KDeleteHeaderLength + (spiCount * spiLength);
+    
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);  
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+
+    TPtrC8 protocolIdPtr(&aProtocolId, sizeof(aProtocolId));
+    TPtrC8 spiLengthPtr(&spiLength, sizeof(spiLength));
+    
+    BigEndian::Put16(reinterpret_cast<TUint8*>(&spiCount), spiCount);    
+    TPtrC8 spiCountPtr(reinterpret_cast<TUint8*>(&spiCount), sizeof(spiCount));
+    
+    payloadDataPtr.Append(protocolIdPtr);
+    payloadDataPtr.Append(spiLengthPtr);
+    payloadDataPtr.Append(spiCountPtr);
+    
+    for (TInt i = 0; i < aSpiList.Count(); ++i)
+        {
+        const TDesC8& spi = aSpiList[i];
+        __ASSERT_DEBUG(spi.Length() == spiLength, User::Invariant());
+        payloadDataPtr.Append(spi);
+        }
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2EapPayload* CIkeV2EapPayload::NewL(const TDesC8& aEapData)
+    {
+    CIkeV2EapPayload* self = new (ELeave) CIkeV2EapPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aEapData);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2EapPayload::CIkeV2EapPayload()
+:CIkeV2Payload(IKEV2_PAYLOAD_EAP)
+    {    
+    }
+
+
+void CIkeV2EapPayload::ConstructL(const TDesC8& aEapData)
+    {       
+    TUint32 length = aEapData.Length() + KEapHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());    
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);
+    payloadDataPtr.FillZ();
+    SetPayloadLength(length);
+
+    payloadDataPtr.Append(aEapData);
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+
+CIkeV2TsPayload::CIkeV2TsPayload(TUint aPayloadType)
+:CIkeV2Payload(aPayloadType)
+    {    
+    }
+
+
+void CIkeV2TsPayload::ConstructL(const CArrayFix<TIkeV2TrafficSelector>& aTsList)
+    {       
+    //selector format: 
+    //                       1                   2                   3
+    //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //   !   TS Type     !IP Protocol ID*|       Selector Length         |
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //   |           Start Port*         |           End Port*           |
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //   !                                                               !
+    //   ~                         Starting Address*                     ~
+    //   !                                                               !
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    //   !                                                               !
+    //   ~                         Ending Address*                       ~
+    //   !                                                               !
+    //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+        
+    const TUint16 KIpv4SelectorLength = 2*4 + 2*4; //fixed selector header + 2*IPv4 address length
+    const TUint16 KIpv6SelectorLength = 2*4 + 2*16;//fixed selector header + 2*IPv6 address length   
+    
+    TUint8 tsCount = aTsList.Count();
+    __ASSERT_DEBUG(tsCount > 0, User::Invariant());
+
+    
+    TUint32 length = KTsHeaderLength;
+    
+    TUint i;
+    for (i = 0; i < aTsList.Count(); ++i)
+        {
+        if (aTsList[i].Type() == TS_IPV4_ADDR_RANGE)          
+            {
+            length += KIpv4SelectorLength; //fixed selector header + 2*IPv4 address length
+            }
+        else
+            {
+            __ASSERT_DEBUG(aTsList[i].Type() == TS_IPV6_ADDR_RANGE, User::Invariant());
+            length += KIpv6SelectorLength; //fixed selector header + 2*IPv6 address length       
+            }
+        }
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);  
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    
+    const TPtrC8 tsCountPtr(&tsCount, sizeof(tsCount));
+    payloadDataPtr.Append(tsCountPtr);
+    
+    _LIT(KReservedField, "\0\0\0");
+    payloadDataPtr.Append(KReservedField);
+    
+    for (i = 0; i < aTsList.Count(); ++i)
+        {
+        TBuf8<KIpv6SelectorLength> selector;
+        selector.Zero();
+        const TIkeV2TrafficSelector& selectorData = aTsList[i]; 
+        TUint8 type = selectorData.Type();
+        selector.Append(&type, sizeof(type));
+        
+        TUint8 protocol = selectorData.ProtocolId();
+        selector.Append(&protocol, sizeof(protocol));
+        
+        TUint16 selectorLength = 0;
+        if (selectorData.Type() == TS_IPV4_ADDR_RANGE)          
+             {
+             BigEndian::Put16(reinterpret_cast<TUint8*>(&selectorLength), KIpv4SelectorLength);
+             }
+         else
+             {
+             BigEndian::Put16(reinterpret_cast<TUint8*>(&selectorLength), KIpv6SelectorLength);
+             }  
+        selector.Append(reinterpret_cast<TUint8*>(&selectorLength), sizeof(selectorLength));
+        
+        TInetAddr startAddress = selectorData.StartingAddress();
+        TInetAddr endAddress = selectorData.EndingAddress();
+        
+        TUint16 startPort = startAddress.Port(); 
+        TUint16 endPort = endAddress.Port();
+        
+        BigEndian::Put16(reinterpret_cast<TUint8*>(&startPort), startPort);
+        BigEndian::Put16(reinterpret_cast<TUint8*>(&endPort), endPort);
+        
+        selector.Append(reinterpret_cast<TUint8*>(&startPort), sizeof(startPort));
+        selector.Append(reinterpret_cast<TUint8*>(&endPort), sizeof(endPort));
+        
+        if (selectorData.Type() == TS_IPV4_ADDR_RANGE)          
+             {
+             TUint32 start = 0;
+             TUint32 end = 0;
+             BigEndian::Put32(reinterpret_cast<TUint8*>(&start), startAddress.Address());
+             BigEndian::Put32(reinterpret_cast<TUint8*>(&end), endAddress.Address());
+             
+             selector.Append(reinterpret_cast<TUint8*>(&start), sizeof(start));
+             selector.Append(reinterpret_cast<TUint8*>(&end), sizeof(end));
+             }
+         else
+             {
+             TPtrC8 start(&startAddress.Ip6Address().u.iAddr8[0], 16);
+             TPtrC8 end(&endAddress.Ip6Address().u.iAddr8[0], 16);
+             selector.Append(start);
+             selector.Append(end);             
+             }   
+        payloadDataPtr.Append(selector);
+        }    
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+
+CIkeV2TsiPayload* CIkeV2TsiPayload::NewL(const CArrayFix<TIkeV2TrafficSelector>& aTsList)
+    {
+    CIkeV2TsiPayload* self = new (ELeave) CIkeV2TsiPayload();
+    CleanupStack::PushL(self);
+    self->ConstructL(aTsList);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2TsiPayload::CIkeV2TsiPayload()
+:CIkeV2TsPayload(IKEV2_PAYLOAD_TS_I)
+    {
+    
+    }
+
+
+CIkeV2TsrPayload* CIkeV2TsrPayload::NewL(const CArrayFix<TIkeV2TrafficSelector>& aTsList)
+    {
+    CIkeV2TsrPayload* self = new (ELeave) CIkeV2TsrPayload();
+    CleanupStack::PushL(self);
+    self->ConstructL(aTsList);
+    CleanupStack::Pop(self);
+    
+    return self;    
+    }
+
+
+CIkeV2TsrPayload::CIkeV2TsrPayload()
+:CIkeV2TsPayload(IKEV2_PAYLOAD_TS_R)
+    {    
+    }
+
+
+CIkeV2EncryptedPayload* CIkeV2EncryptedPayload::NewL(TUint aBlockSize)
+    {
+    CIkeV2EncryptedPayload* self = new (ELeave) CIkeV2EncryptedPayload;
+    CleanupStack::PushL(self);
+    self->ConstructL(aBlockSize);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2EncryptedPayload::CIkeV2EncryptedPayload()
+:CIkeV2TsPayload(IKEV2_PAYLOAD_ENCR)
+    {    
+    }
+
+
+void CIkeV2EncryptedPayload::ConstructL(TUint aBlockSize)
+    {
+    TUint32 length = aBlockSize + KEncryptedHeaderLength;
+
+    iPayloadData = HBufC8::NewL(length);
+    TPtr8 payloadDataPtr(iPayloadData->Des());
+    payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength);    
+    payloadDataPtr.FillZ();
+    
+    SetPayloadLength(length);
+    payloadDataPtr.SetLength(length);
+    
+    TPtr8 Iv = payloadDataPtr.MidTPtr(KEncryptedHeaderLength);
+    Iv.SetLength(aBlockSize);
+    TRandom::RandomL(Iv);        
+    
+    iBlockSize = aBlockSize;
+    
+    __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant());
+    }
+
+TUint CIkeV2EncryptedPayload::BlockSize() const
+    {
+    return iBlockSize;
+    }
+
+TPtrC8 CIkeV2EncryptedPayload::InitializationVector() const
+    {
+    return iPayloadData->Right(iBlockSize);
+    }
+
+void CIkeV2EncryptedPayload::SetContentLength(TUint16 aLength)
+    {
+    //Set the payload length to be: header + Iv + content
+    SetPayloadLength(aLength + iPayloadData->Length());
+    }
+
+static const TUint   KDefaultMessageSize = 4096;
+static const TUint32 KIkeV2MsgHeaderLength = 28;
+static const TUint8  KIkeV2Version = 2 << 4;
+
+CIkeV2Message* CIkeV2Message::NewL(const TDesC8& aInitiatorSpi,
+                                   const TDesC8& aResponderSpi,
+                                   TUint8 aExchangeType,
+                                   TBool aIntiator,
+                                   TBool aResponse,
+                                   TUint32 aMessageId,
+                                   MIkeDebug& aDebug)
+    {
+    CIkeV2Message* self = new (ELeave)CIkeV2Message(aDebug);
+    CleanupStack::PushL(self);
+    self->ConstructL(aInitiatorSpi,
+                     aResponderSpi,
+                     aExchangeType,
+                     aIntiator,
+                     aResponse,
+                     aMessageId);
+    CleanupStack::Pop(self);
+    
+    return self;
+    }
+
+
+CIkeV2Message::CIkeV2Message(MIkeDebug& aDebug)
+:iDebug(aDebug), iModified(ETrue)
+    {    
+    }
+
+
+void CIkeV2Message::ConstructL(const TDesC8& aInitiatorSpi,
+                               const TDesC8& aResponderSpi,
+                               TUint8 aExchangeType,   
+                               TBool aIntiator,
+                               TBool aResponse,
+                               TUint32 aMessageId)
+    {
+    __ASSERT_DEBUG(aInitiatorSpi.Length() == 8, User::Invariant());
+    __ASSERT_DEBUG(aResponderSpi.Length() == 8, User::Invariant());
+    
+    iIkeV2MessageHeader = HBufC8::NewL(KDefaultMessageSize);    
+    TPtr8 messageDataPtr = iIkeV2MessageHeader->Des();
+    
+   
+    const TPtrC8 versionPtr(&KIkeV2Version, sizeof(TUint8));    
+    const TPtrC8 exchangeTypePtr(&aExchangeType, sizeof(TUint8));
+    
+    TUint8 flags = (aIntiator) ? IKEV2_INITIATOR : 0;
+    flags |= (aResponse) ? IKEV2_RESPONSE_MSG : 0; 
+    
+    
+    const TPtrC8 flagsPtr(&flags, sizeof(flags));
+    BigEndian::Put32(reinterpret_cast<TUint8*>(&aMessageId), aMessageId);
+    const TPtrC8 messageIdPtr(reinterpret_cast<TUint8*>(&aMessageId), sizeof(TUint32));
+    
+    TUint32 length;
+    BigEndian::Put32(reinterpret_cast<TUint8*>(&length), KIkeV2MsgHeaderLength);
+    const TPtrC8 lengthPtr(reinterpret_cast<TUint8*>(&length), sizeof(TUint32));
+    
+    //Add SPIs
+    messageDataPtr.Append(aInitiatorSpi);
+    messageDataPtr.Append(aResponderSpi);
+    
+    //Left next payload as zero
+    TUint8 nextPayload = 0;
+    TPtrC8 nextPayloadPtr(&nextPayload, sizeof(nextPayload));
+    messageDataPtr.Append(nextPayloadPtr);
+    
+    messageDataPtr.Append(versionPtr);
+    messageDataPtr.Append(exchangeTypePtr);
+    messageDataPtr.Append(flagsPtr);
+    messageDataPtr.Append(messageIdPtr);
+    messageDataPtr.Append(lengthPtr);
+    
+    __ASSERT_DEBUG(iIkeV2MessageHeader->Length() == KIkeV2MsgHeaderLength, User::Invariant());
+    }
+
+
+CIkeV2Message::~CIkeV2Message()
+    {
+    delete iIkeV2Datagram;
+    delete iIkeV2MessageHeader;
+    iPayloads.ResetAndDestroy();
+    iPayloads.Close();
+    }
+
+
+TPtrC8 CIkeV2Message::InitiatorSpi()const
+    {
+    TUint KInitiatorSpiPosition = 0;
+    TUint KSpiLength = 8;
+    
+    return iIkeV2MessageHeader->Mid(KInitiatorSpiPosition, KSpiLength);
+    }
+
+
+TPtrC8 CIkeV2Message::ResponderSpi() const
+    {
+    TUint KResponderSpiPosition = 8;
+    TUint KSpiLength = 8;
+    
+    return iIkeV2MessageHeader->Mid(KResponderSpiPosition, KSpiLength);
+    }
+
+
+TUint8 CIkeV2Message::Flags() const
+    {
+    TUint KFlagsPosition = 19;
+    return (*iIkeV2MessageHeader)[KFlagsPosition];
+    }
+
+
+TUint32 CIkeV2Message::MessageId() const
+    {
+    __ASSERT_DEBUG(iIkeV2MessageHeader->Length() >= KIkeV2MsgHeaderLength, User::Invariant());
+    const TUint8* messageIdPtr = iIkeV2MessageHeader->Ptr() + KMessageIdFieldOffset; 
+    return BigEndian::Get32(messageIdPtr);
+    
+    }
+
+
+void CIkeV2Message::AppendCertReqPayloadL(const CIkeCaList& aCaList)
+    {
+    __ASSERT_DEBUG(aCaList.Count() > 0, User::Invariant());
+
+    CIkevV2CertReqPayload* certReqPayload = CIkevV2CertReqPayload::NewL(aCaList);
+    AppendPayloadL(certReqPayload);
+    }
+
+
+void CIkeV2Message::AppendCertPayloadL(const TDesC8& aCertificateData)
+    {
+    CIkevV2CertPayload* certPayload = CIkevV2CertPayload::NewL(aCertificateData);
+    AppendPayloadL(certPayload);
+    }
+
+
+void CIkeV2Message::AppendSaPayloadL(const TDesC8& aSaData)
+    {
+    CIkevV2SaPayload* saPayload = CIkevV2SaPayload::NewL(aSaData);
+    AppendPayloadL(saPayload);
+    }
+
+
+void CIkeV2Message::AppendKePayloadL(TUint16 aDHGroup, const TDesC8& aKeData)
+    {
+    CIkevV2KePayload* kePayload = CIkevV2KePayload::NewL(aDHGroup, aKeData);
+    AppendPayloadL(kePayload);
+    }
+
+
+void CIkeV2Message::AppendNoncePayloadL(const TDesC8& aNonceData)
+    {
+    CIkevV2NoncePayload* noncePayload = CIkevV2NoncePayload::NewL(aNonceData);
+    AppendPayloadL(noncePayload);
+    }
+
+
+void CIkeV2Message::AppendIdiPayloadL(const CIkeV2Identity& aIdentity)
+    {
+    CIkevV2IdiPayload* idiPayload = CIkevV2IdiPayload::NewL(aIdentity);  
+    AppendPayloadL(idiPayload);
+    }
+
+
+void CIkeV2Message::AppendIdrPayloadL(const CIkeV2Identity& aIdentity)
+    {
+    CIkevV2IdrPayload* idrPayload = CIkevV2IdrPayload::NewL(aIdentity);  
+    AppendPayloadL(idrPayload);    
+    }
+
+void CIkeV2Message::AppendAuthPayloadL(TUint8 aAuthMethod, const TDesC8& aAuthData)
+    {
+    CIkeV2AuthPayload* authPayload = CIkeV2AuthPayload::NewL(aAuthMethod, aAuthData);
+    AppendPayloadL(authPayload);
+    }
+
+
+void CIkeV2Message::AppendNotifyPayloadL(TUint8 aProtocolId,
+                                         const TDesC8& aSpi,
+                                         TUint16 aNotifyType,
+                                         const TDesC8& aNotifyData)
+    {
+    CIkeV2NotifyPayload* notifyPayload = CIkeV2NotifyPayload::NewL(aProtocolId, aSpi,
+                                                                   aNotifyType, aNotifyData);
+    AppendPayloadL(notifyPayload);
+    }
+
+void CIkeV2Message::PrependCookieNotifyPayloadL(const TDesC8& aCookieData)
+    {
+    _LIT8(KZeroDesc, "");
+    CIkeV2NotifyPayload* notifyPayload = CIkeV2NotifyPayload::NewL(0, KZeroDesc,
+                                                                   COOKIE, aCookieData);
+    
+    delete iIkeV2Datagram;
+    iIkeV2Datagram = NULL;    
+    iModified = ETrue;
+
+    if (iPayloads.Count() > 0)
+        {
+        notifyPayload->SetNextPayload(iPayloads[0]->PayloadType());
+        }
+    
+    TInt err = iPayloads.Insert(notifyPayload, 0);
+    if (err != KErrNone)
+        {
+        delete notifyPayload;
+        User::Leave(err);
+        }
+    
+    SetNextPayload(notifyPayload->PayloadType());    
+    }
+
+
+void CIkeV2Message::AppendConfigurationPayloadL(TUint8 aCfgType, 
+                                               const TDesC8& aConfigurationData)
+    {
+    CIkeV2ConfigurationPayload* configPayload = 
+                        CIkeV2ConfigurationPayload::NewL(aCfgType, aConfigurationData);
+    AppendPayloadL(configPayload);
+    }
+
+
+void CIkeV2Message::AppendVendorIdPayloadL(const TDesC8& aVendorIdData)
+    {
+    CIkeV2VendorIdPayload* vendorIdPayload = CIkeV2VendorIdPayload::NewL(aVendorIdData);
+    AppendPayloadL(vendorIdPayload);
+    }
+
+void CIkeV2Message::AppendDeletePayloadL(TUint8 aProtocolId, const CDesC8Array& aSpiList)
+    {
+    CIkeV2DeletePayload* deletePayload = CIkeV2DeletePayload::NewL(aProtocolId, aSpiList);
+    AppendPayloadL(deletePayload);
+    }
+
+
+void CIkeV2Message::AppendEapPayloadL(const TDesC8& aEapData)
+    {
+    CIkeV2EapPayload* eapPayload = CIkeV2EapPayload::NewL(aEapData);
+    AppendPayloadL(eapPayload);
+    }
+
+
+void CIkeV2Message::AppendTsiPayloadL(const CArrayFix<TIkeV2TrafficSelector>& aTsList)
+    {
+    CIkeV2TsiPayload* tsPayload = CIkeV2TsiPayload::NewL(aTsList);
+    AppendPayloadL(tsPayload);
+    }
+
+
+void CIkeV2Message::AppendTsrPayloadL(const CArrayFix<TIkeV2TrafficSelector>& aTsList)
+    {
+    CIkeV2TsrPayload* tsPayload = CIkeV2TsrPayload::NewL(aTsList);
+    AppendPayloadL(tsPayload);    
+    }
+
+
+void CIkeV2Message::AppendEncryptedPayloadL(TUint aBlockSize)
+    {
+    __ASSERT_DEBUG(iPayloads.Count() == 0, User::Invariant());
+    CIkeV2EncryptedPayload* encryptedPayload = CIkeV2EncryptedPayload::NewL(aBlockSize);
+    AppendPayloadL(encryptedPayload);
+    }
+
+void CIkeV2Message::PrepareIkeMessageDatagramL(TUint16 aEncryptionAlgorith, 
+                                               const TDesC8& aEncryptionKey,
+                                               TUint16 aIntegrityAlgorithm,
+                                               const TDesC8& aIntegrityKey,
+#ifdef _DEBUG                                               
+                                               const TInetAddr& aSourceAddress,
+#else
+                                               const TInetAddr& /*aSourceAddress*/,
+#endif                                               
+                                               const TInetAddr& aDestinationAddress)
+    {    
+    __ASSERT_DEBUG(iPayloads.Count() > 0, User::Invariant());
+    
+    if (iModified)
+        {        
+        __ASSERT_DEBUG(iIkeV2Datagram == NULL, User::Invariant());
+        
+        if (iPayloads[0]->PayloadType() == IKEV2_PAYLOAD_ENCR)
+            {
+            //Datagram is should be encrypted
+            //Calculate the length of the padding
+            CIkeV2EncryptedPayload* encryptedPayload = static_cast<CIkeV2EncryptedPayload*>(iPayloads[0]);
+            TUint encryptedDataLength = 0;
+            for(TInt i = 1; i < iPayloads.Count(); ++i)
+                {
+                encryptedDataLength += iPayloads[i]->PayloadLength();
+                }
+            
+            //If the data length is multiple of the blocksize, we add full block length
+            //of padding. Otherwise we just add padding enough to fill the block.
+            TUint8 paddingLength = encryptedPayload->BlockSize() -
+                                   encryptedDataLength % encryptedPayload->BlockSize();
+            //The last octet of the padding tells the length of the padding.
+            //we just use that value to fill the entire padding.
+            TInt integrityCheckSumLength = 0;
+            IkeCrypto::AlgorithmInfo(IKEV2_INTEG, aIntegrityAlgorithm, &integrityCheckSumLength);
+            
+            
+            //The length of the whole datagram:
+            TUint32 datagramLength = iIkeV2MessageHeader->Length() +
+                                     encryptedPayload->PayloadLength() +
+                                     encryptedDataLength + 
+                                     paddingLength +
+                                     integrityCheckSumLength;
+    
+            //Update header fields
+            SetLength(datagramLength);
+            encryptedPayload->SetContentLength((TUint16)(encryptedDataLength + 
+                                                         paddingLength + 
+                                                         integrityCheckSumLength));
+    
+            //Allocate buffer, which has space for the whole datagram. (+ Non ESP marker)
+            HBufC8* datagram = HBufC8::NewLC(datagramLength + KNonEspMarker().Length());
+            TPtr8 datagramPtr = datagram->Des();
+            
+            datagramPtr = *iIkeV2MessageHeader;
+            datagramPtr.Append(encryptedPayload->PayloadData());
+            
+            //buffer for data, which is encrypted
+            HBufC8* encryptionSource = HBufC8::NewLC(encryptedDataLength + 
+                                                     paddingLength);
+            TPtr8 encryptionSourcePtr = encryptionSource->Des();
+            
+            for (TInt i = 1; i < iPayloads.Count(); ++i)
+                {
+                const CIkeV2Payload* pl = iPayloads[i];                 
+                __ASSERT_DEBUG(pl->PayloadData().Length() == pl->PayloadLength(), User::Invariant());
+                
+                encryptionSourcePtr.Append(pl->PayloadData());                
+                datagramPtr.Append(pl->PayloadData()); //This is because we want to trace the datagram              
+                }
+             
+            
+            //Last byte of the padding has to be the length of the padding.
+            //We fillup the whole padding with this same number
+            TUint8 paddingValue = paddingLength - 1;
+            for (TInt i = 0; i < paddingLength; ++i)
+                {
+                encryptionSourcePtr.Append(&paddingValue, 1);                
+                datagramPtr.Append(&paddingValue, 1);
+                }
+            
+            
+            datagramPtr.SetLength(datagram->Length() + integrityCheckSumLength);
+            TRACE_MSG(*datagram, aSourceAddress, aDestinationAddress, 
+                      (CIkePcapTrace::TEncryptionType)aEncryptionAlgorith);
+            datagramPtr.SetLength(datagram->Length() - integrityCheckSumLength);
+            
+            //Extracts the data, which is encrypted. 
+            //(Excludes IKE hdr, Encrypted payload hdr and Iv)
+            TPtr8 encryptionBuffer = datagramPtr.MidTPtr(iIkeV2MessageHeader->Length() + 
+                                                         KEncryptedHeaderLength + 
+                                                         encryptedPayload->BlockSize());
+            __ASSERT_DEBUG(encryptionBuffer.Length() == encryptionSource->Length(), User::Invariant());
+            encryptionBuffer.SetLength(0);
+            IkeCrypto::EncryptL(*encryptionSource, encryptionBuffer, 
+                                encryptedPayload->InitializationVector(), 
+                                aEncryptionKey, aEncryptionAlgorith);
+            
+            CleanupStack::PopAndDestroy(encryptionSource);
+            
+            //Extracts the space for the checksum from the end of the buffer
+            TUint lengthWithoutItegrityCheckSum = datagramPtr.Length();
+            datagramPtr.SetLength(lengthWithoutItegrityCheckSum + integrityCheckSumLength);
+            TPtr8 checksum = datagramPtr.MidTPtr(lengthWithoutItegrityCheckSum);           
+            
+            //Extracts the source for the integrity checksum calculation
+            TPtrC8 integrityCheckSumSource = datagram->Left(lengthWithoutItegrityCheckSum);            
+            IkeCrypto::IntegHMACL(integrityCheckSumSource, checksum, aIntegrityKey, aIntegrityAlgorithm);
+                        
+            CleanupStack::Pop(datagram);
+            iIkeV2Datagram = datagram;             
+            }    
+        else
+            {
+            //calculate the length of unencrypted datagram
+            TUint datagramLength = iIkeV2MessageHeader->Length();
+            for (TInt i = 0; i < iPayloads.Count(); ++i)
+                {
+                datagramLength += iPayloads[i]->PayloadLength();         
+                }
+            SetLength(datagramLength);
+            
+            iIkeV2Datagram = HBufC8::NewL(datagramLength + KNonEspMarker().Length());
+            TPtr8 ikeV2DatargramPtr = iIkeV2Datagram->Des();
+            ikeV2DatargramPtr.Append(*iIkeV2MessageHeader);
+            
+            for (TInt i = 0; i < iPayloads.Count(); ++i)
+                {
+                ikeV2DatargramPtr.Append(iPayloads[i]->PayloadData());
+                }
+            TRACE_MSG(*iIkeV2Datagram, aSourceAddress, aDestinationAddress, 
+                      (CIkePcapTrace::TEncryptionType)aEncryptionAlgorith);
+
+            }  
+        
+        if (aDestinationAddress.Port() == FLOATED_IKE_PORT)
+            {
+            //insert non esp marker
+            iIkeV2Datagram->Des().Insert(0, KNonEspMarker);
+            }
+        iModified = EFalse;
+        }
+   
+    __ASSERT_DEBUG(!iModified && iIkeV2Datagram != NULL, User::Invariant());
+    }
+
+
+TPtrC8 CIkeV2Message::IkeMessageDatagram() const
+    {
+    __ASSERT_DEBUG(!iModified && iIkeV2Datagram != NULL, User::Invariant());
+    return *iIkeV2Datagram;
+    }
+
+
+void CIkeV2Message::AppendPayloadL(CIkeV2Payload* aPayload)
+    {
+    TInt err = iPayloads.Append(aPayload);    
+    if (err != KErrNone)
+        {
+        delete aPayload;
+        User::Leave(err);
+        }
+    
+    if (iPayloads.Count() > 1)
+        {
+        iPayloads[iPayloads.Count() - 2]->SetNextPayload(aPayload->PayloadType());
+        }
+    else
+        {
+        SetNextPayload(aPayload->PayloadType());
+        }    
+    
+    delete iIkeV2Datagram;
+    iIkeV2Datagram = NULL;    
+    iModified = ETrue;
+    }
+
+void CIkeV2Message::SetLength(TUint32 aDatagramLength)
+    {
+    static const TUint KLengthFieldPosition = 6*4;
+    BigEndian::Put32(reinterpret_cast<TUint8*>(&aDatagramLength), aDatagramLength);
+    TPtr8 lengthField = iIkeV2MessageHeader->Des().MidTPtr(KLengthFieldPosition, sizeof(aDatagramLength));
+    lengthField = TPtrC8(reinterpret_cast<TUint8*>(&aDatagramLength), sizeof(aDatagramLength));
+    }
+
+
+void CIkeV2Message::SetNextPayload(TUint8 aNextPayload)
+    {
+    const TUint KNextPayloadPosition =  16;
+    TPtr8 ikeHeaderPtr = iIkeV2MessageHeader->Des();
+    ikeHeaderPtr[KNextPayloadPosition] = aNextPayload;
+    }