vpnengine/ikev1lib/src/ikev1negotiation.cpp
changeset 0 33413c0669b9
child 2 ef893827b4d1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev1lib/src/ikev1negotiation.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,8306 @@
+/*
+* Copyright (c) 2005-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:   IKEv1/IPSEC SA negotiation 
+*
+*/
+
+#include <x509cert.h>
+#include <x500dn.h>
+#include <random.h>
+#include <vpnlogmessages.rsg>
+
+#include "ikev1negotiation.h"
+#include "ikedebug.h"
+#include "ikev1isakmpstream.h"
+#include "ikev1timeout.h"
+#include "ikev1payload.h"
+#include "ikev1plugin.h"
+#include "ikev1crack.h"
+#include "ikev1trans.h"
+#include "ipsecsadata.h"
+#include "ipsecsalifetime.h"
+#include "pfkeymsg.h"
+#include "kmdapi.h"
+#include "ikev1pkiservice.h"
+#include "ikev1crypto.h"
+#include "ikev1natdiscovery.h"
+#include "ikev1private.h"
+#include "vpnapidefs.h"
+#include "ikepkiutils.h"
+#include "vpnclientuids.h"
+#include "ikecalist.h"
+#include "ikecaelem.h"
+#include "ikecert.h"
+#include "ikev1pluginsession.h"
+#include "ikesocketdefs.h"
+#include "kmdeventloggerif.h"
+#include "pfkeyextdatautil.h"
+#include "ipsecsalist.h"
+
+const TInt KSubjectName              = 1;
+
+/////////////////////////////////////////////////////////////////////////////////
+// CIkev1Negotiation related stuff
+/////////////////////////////////////////////////////////////////////////////////
+
+
+//
+//Proto negotiation to send a informational payload and be destroyed
+//
+CIkev1Negotiation* CIkev1Negotiation::NewL( CIkev1PluginSession* aPluginSession,
+                                            CPFKeySocketIf& aPFKeySocketIf,
+                                            MIkeDebug& aDebug,
+                                            const TInetAddr& aRemote,
+                                            const TCookie& aInitiator,
+                                            const TCookie& aResponder )
+    {   	
+	CIkev1Negotiation* self = new ( ELeave ) CIkev1Negotiation( aPluginSession,
+                                                                aPFKeySocketIf,
+                                                                aDebug );
+	CleanupStack::PushL( self );
+	self->iRemoteAddr = aRemote;
+	self->iCookie_I = aInitiator;
+	self->iCookie_R = aResponder;     
+	self->iExchange = ISAKMP_EXCHANGE_INFO;   
+	self->iDOI = IPSEC_DOI;
+	self->iTimer = CIkev1Timeout::NewL( *self );	
+	CleanupStack::Pop( self );	
+	return self;
+    }
+
+CIkev1Negotiation* CIkev1Negotiation::NewL( CIkev1PluginSession* aPluginSession,
+                                            CPFKeySocketIf& aPFKeySocketIf,
+                                            MIkeDebug& aDebug,
+                                            const TInetAddr& aRemote,
+                                            const TCookie& aInitiator,
+                                            TBool aAutoLogin ) 
+    {
+	CIkev1Negotiation* self = new ( ELeave ) CIkev1Negotiation( aPluginSession,
+                                                                aPFKeySocketIf,
+	                                                            aDebug,
+	                                                            aRemote,
+	                                                            aInitiator );
+	CleanupStack::PushL( self );
+    self->ConstructL( aAutoLogin );
+    CleanupStack::Pop( self );
+	return self;
+    }
+
+CIkev1Negotiation* CIkev1Negotiation::NewL( CIkev1PluginSession* aPluginSession,
+                                            CPFKeySocketIf& aPFKeySocketIf,
+                                            MIkeDebug& aDebug,
+                                            TIkev1SAData* aIkev1SAdata,
+                                            TUint aRole,
+                                            const TPfkeyMessage *aReq )
+    {
+    CIkev1Negotiation* self = new ( ELeave ) CIkev1Negotiation( aPluginSession,
+                                                                aPFKeySocketIf,
+                                                                aDebug );
+    CleanupStack::PushL( self );
+    self->ConstructL( aIkev1SAdata, aRole, aReq );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+CIkev1Negotiation* CIkev1Negotiation::NewL( CIkev1PluginSession* aPluginSession,
+                                            CPFKeySocketIf& aPFKeySocketIf,
+                                            MIkeDebug& aDebug,
+                                            const TInetAddr& aRemote,
+                                            TBool aAutoLogin ) 
+    {
+	CIkev1Negotiation* self = new ( ELeave ) CIkev1Negotiation( aPluginSession,
+                                                                aPFKeySocketIf,
+	                                                            aDebug,
+	                                                            aRemote );
+	CleanupStack::PushL( self );
+    self->iCookie_I = self->CreateCookieL();
+    self->ConstructL( aAutoLogin );
+    CleanupStack::Pop( self );
+	return self;
+    }
+
+CIkev1Negotiation* CIkev1Negotiation::NewL( CIkev1PluginSession* aPluginSession,
+                                            CPFKeySocketIf& aPFKeySocketIf,
+                                            MIkeDebug& aDebug,
+                                            const TInetAddr& aRemote,
+                                            const TPfkeyMessage& aReq )
+    {    
+    CIkev1Negotiation* self = new (  ELeave ) CIkev1Negotiation( aPluginSession,
+                                                                 aPFKeySocketIf,
+                                                                 aDebug,
+                                                                 aRemote );
+    CleanupStack::PushL( self );
+    self->iCookie_I = self->CreateCookieL();
+    self->ConstructL( aReq );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+//
+// Destructor
+//
+CIkev1Negotiation::~CIkev1Negotiation()
+    {
+    DEBUG_LOG1( _L("CIkev1Negotiation::~CIkev1Negotiation this=0x%x"), this );
+    
+    
+    if ( iRole == INITIATOR &&
+         iAcquirePending )
+        {
+        // Response with error to pending Acquire.
+        AcquireSAErrorResponse( KKmdIkeNegotFailed );
+        }
+    
+    delete iIpsecSaSpiRetriever;
+    delete iSavedIkeMsgBfr;
+    
+    if( iPluginSession )
+        { 		
+	    iPluginSession->RemoveNegotiation( this );  
+        }
+		
+    iCookie_I.FillZ(ISAKMP_COOKIE_SIZE);
+    
+    if(iTimer)
+        {
+        iTimer->Cancel();
+        delete iTimer;
+        }
+
+    delete iOwnCert;
+    delete iPeerX509Cert;
+    delete iPeerTrustedCA;  // Peer trusted CA name 
+    delete iICA1;
+    delete iICA2;
+
+    delete iPkiService;     // Trusted CA certificate list
+
+    delete iSAPayload;
+    delete iPeerIdentPayload;
+    delete iOwnIdentPayload;
+    
+    //Keys
+    delete iOwnKeys;        //structure containing the public and private keys
+    delete iOwnPublicKey;   //Public Key
+
+    //Phase_I Proposal
+    TAttrib *attr;
+    while ((attr = iProposal_I.iAttrList) != NULL)
+    {
+        iProposal_I.iAttrList = attr->iNext;
+        delete attr;
+    }
+
+    delete iChosenProposal_I.iAttrList; //Only one transformation chosen
+
+    //Phase_II proposals (include transformations)
+    delete iProposal_IIList;
+
+    //Phase_II chosen Proposal
+    delete iChosenProp_IIList;
+    delete iInboundSPIList;
+    delete iCRACKneg;
+    delete iTransactionNeg; // Transaction exchange 
+    delete iInternalAddr;
+    delete iNatDiscovery;
+	delete iSARekeyInfo;
+	delete iLastMsg;
+}
+
+
+//
+// CIkev1Negotiation
+//  Constructor for remote initiated negotiation
+//
+CIkev1Negotiation::CIkev1Negotiation( CIkev1PluginSession* aPluginSession,
+                                      CPFKeySocketIf& aPFKeySocketIf,
+                                      MIkeDebug& aDebug,
+                                      const TInetAddr& aRemote,
+                                      const TCookie& aInitiator )
+ : iCookie_I( aInitiator ),
+   iRemoteAddr( aRemote ),
+   iPluginSession( aPluginSession ),
+   iPFKeySocketIf( aPFKeySocketIf ),
+   iDebug( aDebug )
+{
+
+    DEBUG_LOG1( _L("CIkev1Negotiation::CIkev1Negotiation, RESPONDER this=0x%x"), this );
+    iCookie_R.FillZ(ISAKMP_COOKIE_SIZE);
+    iSAId = iPluginSession->GetSAId();
+    iPluginSession->LinkNegotiation(this);         
+    iRole = RESPONDER;
+    iStage = 1; //next phase for the responder is 2
+}
+
+//
+//  Constructor for local initiated negotiation
+//
+
+CIkev1Negotiation::CIkev1Negotiation( CIkev1PluginSession* aPluginSession,
+                                      CPFKeySocketIf& aPFKeySocketIf,
+                                      MIkeDebug& aDebug,
+                                      const TInetAddr& aRemote )
+ : iRemoteAddr( aRemote ),
+   iPluginSession( aPluginSession ),
+   iPFKeySocketIf( aPFKeySocketIf ),
+   iDebug( aDebug )
+{
+    DEBUG_LOG1( _L("CIkev1Negotiation::CIkev1Negotiation, INITIATOR this=0x%x"), this );
+    iCookie_I.FillZ(ISAKMP_COOKIE_SIZE);
+    iCookie_R.FillZ(ISAKMP_COOKIE_SIZE);
+    iSAId = iPluginSession->GetSAId();
+    iPluginSession->LinkNegotiation(this);     
+    iRole = INITIATOR;
+    iStage = 0;
+}
+
+//
+//  Constructor for Phase II initiated negotiations
+//
+
+CIkev1Negotiation::CIkev1Negotiation( CIkev1PluginSession* aPluginSession,
+                                      CPFKeySocketIf& aPFKeySocketIf,
+                                      MIkeDebug& aDebug )
+ : iPluginSession( aPluginSession ),
+   iPFKeySocketIf( aPFKeySocketIf ),
+   iDebug( aDebug )
+{ 
+    DEBUG_LOG1( _L("CIkev1Negotiation::CIkev1Negotiation, this=0x%x"), this );
+    iCookie_I.FillZ(ISAKMP_COOKIE_SIZE);
+    iCookie_R.FillZ(ISAKMP_COOKIE_SIZE);    
+    iSAId = iPluginSession->GetSAId();
+    iPluginSession->LinkNegotiation(this); 
+}
+
+//Used when creating a negotiation as a RESPONDER!
+//Used also when Initiator (= Phase 1 negotiation stated by the policy activation)
+//Leaves if error detected
+void CIkev1Negotiation::ConstructL(TBool aAutoLogin)
+{
+    iIpsecSaSpiRetriever = CIpsecSaSpiRetriever::NewL( *this,
+                                                       iPFKeySocketIf );
+
+    iAutoLogin = aAutoLogin;
+    CommonConstructL();
+}
+
+
+//Used when an Acquire is received
+//Leaves if error detected
+void CIkev1Negotiation::ConstructL(const TPfkeyMessage &aReq)
+{
+    iIpsecSaSpiRetriever = CIpsecSaSpiRetriever::NewL( *this,
+                                                       iPFKeySocketIf );
+
+    CommonConstructL();     
+    GetAcquireDataL(aReq);
+}
+
+//Used when initiating a new Phase II negotiation from a negotiated ISAKMP SA.
+void CIkev1Negotiation::ConstructL( TIkev1SAData* aSA,
+                                    TUint aRole,
+                                    const TPfkeyMessage *aReq )
+{
+
+    iIpsecSaSpiRetriever = CIpsecSaSpiRetriever::NewL( *this,
+                                                       iPFKeySocketIf );
+
+    iPhase = PHASE_II;
+
+    //Almost like common construct
+    iTimer = CIkev1Timeout::NewL(*this);    
+
+    //Phase II proposal lists
+    iProposal_IIList = new (ELeave) CProposal_IIList(1);
+
+    iRemoteAddr.SetPort(IKE_PORT);
+
+    iSeq = aSA->iSeq;
+    iLocalAddr  = aSA->iLocalAddr;
+    iRemoteAddr = aSA->iRemoteAddr;         // Remote Address from peer
+    iLastRemoteAddr = aSA->iDestinAddr;     // Remote Address last transmitted
+    
+    iLastIKEMsgInfo = aSA->iLastIKEMsgInfo;
+    iLastMsg = HBufC8::NewL(4096);
+    if ( aSA->iLastMsg != NULL )
+        {        
+        *iLastMsg = *aSA->iLastMsg;        
+        }
+    
+    iRole = aRole;          // If we are initiator or responder
+
+    //Header Data
+    iCookie_I = aSA->iCookie_I; // Initiator Cookie (Used with responder to create KEYID)
+    iCookie_R = aSA->iCookie_R; // Responder Cookie
+    iPrevExchange = aSA->iPrevExchange;
+    iExchange = IKE_QUICK_MODE;
+
+    iMessageId = RandomMessageId();
+
+    iFlags = aSA->iFlags;           // Flags in the msg header
+    
+//  iNotifyMessageId = aSA->iHdr.iNotifyMessageId;   // Message Id. for Informational Exchanges
+
+    //SA Data
+    iDOI = IPSEC_DOI;
+    
+    iChosenProposal_I.iProtocol = PROTO_ISAKMP;
+    iChosenProposal_I.iProposalNum = 0;
+//    iChosenProposal_I.iSPI.Copy(aSA->iChosenProposal_I.iSPI);
+    iChosenProposal_I.iNumTransforms = 1;
+    iChosenProposal_I.iAttrList = new (ELeave) TAttrib; //allocated now and deleted when destroying the obj
+//  *iChosenProposal_I.iAttrList = *aSA->iChosenProposal_I.iAttrList;
+    iChosenProposal_I.iAttrList->iEncrAlg = aSA->iEncrAlg;
+    iChosenProposal_I.iAttrList->iHashAlg = aSA->iHashAlg;
+    iChosenProposal_I.iAttrList->iGroupDesc = aSA->iGroupDesc;
+    iChosenProposal_I.iAttrList->iGroupType = aSA->iGroupType;
+    iChosenProposal_I.iAttrList->iKeyLength = aSA->iKeyLength;  
+    if ( aSA->iLifeTimeSecs )
+       iChosenProposal_I.iAttrList->iLifeDurationSecs.Copy((TUint8 *)&aSA->iLifeTimeSecs, sizeof(TUint32)); 
+    if ( aSA->iLifeTimeKB )
+        iChosenProposal_I.iAttrList->iLifeDurationKBytes.Copy((TUint8 *)&aSA->iLifeTimeKB, sizeof(TUint32));    
+
+ 
+    iHostData = aSA->iIkeData;
+    if ( iHostData->iCAList && iHostData->iCAList->Count() )
+    {
+        iPkiService = CIkeV1PkiService::NewL(iHostData, iDebug);                                           
+    }   
+    
+    if (aRole == INITIATOR)
+    {
+        GetAcquireDataL(*aReq); //Data needed from the acquire
+    }
+    else    //RESPONDER 
+    {
+        iAcquireSeq = 1;        //msg Seq. number
+    }
+
+    //
+    //NAT Traversal data
+    //
+    iFamiliarPeer   = aSA->iFamiliarPeer;
+    iNAT_T_Required = aSA->iNAT_T_Required;
+    
+    //
+    //Copy an Internal address object (if exists) to the new negotiation 
+    //
+    if ( aSA->iVirtualIp )
+    {
+       iInternalAddr = CInternalAddress::NewL(*(aSA->iVirtualIp));    
+    }
+
+    iNAT_D_Flags  = aSA->iNAT_D_Flags;  
+    if ( iNAT_D_Flags ) {
+       //
+       // Use IETF specified NAT traversal
+       //
+       iNatDiscovery = CIkev1NatDiscovery::NewL(aSA->iNAT_D_Flags);
+    }
+    
+    //Keys  (DH Generated public value when own)
+    iSKEYID.Copy(aSA->iSKEYID);
+    iSKEYID_d.Copy(aSA->iSKEYID_d);
+    iSKEYID_a.Copy(aSA->iSKEYID_a);
+    iSKEYID_e.Copy(aSA->iSKEYID_e);
+    
+    //IV used by des_cbc and des3_cbc is 8 but digest returns 16 bytes for MDx and 20 for SHS (first 8 used)
+    iIV = aSA->iIV;     //normal IV
+    iIVSize = iIV.Length(); 
+
+    iLastIV = aSA->iLastIV; //Saves the last IV of PHASE_I to compute iNotifIV everytime
+
+    //Nonces
+//    iNONCE_I = aSA->iNONCE_I;
+//    iNONCE_R = aSA->iNONCE_R;
+    //
+    // If the ISAKMP SA (=aSA) has been originally negotiated due the policy activation (iAutoLogin = ETrue)
+    // The iLocalAddr maybe then undefined in aSA.
+    // If local end is acting as an initiator, method GetAcquireDataL updates iLocalAddr in CIkev1Negotiation object.
+    // In that case take iLocalAddr value from there and store it to CIsakmpSa (aSA) object.
+    // If local end is acting as a responder, resolve iLocalAddr value.
+    //
+    if ( aSA->iAutoLogin )
+    {
+        if ( aRole == INITIATOR)    
+             iLocalAddr = aSA->iLocalAddr;
+        else User::LeaveIfError( iPluginSession->GetLocalAddress( iLocalAddr ) );
+    }
+    iDPDSupported = aSA->iDPDSupported;
+    
+    iSAId = aSA->iSAId;    // Reference to existin ISAKMP SA
+    iStage = 1; //if initiator the stage will be set in a subsequent call to InitPhase_IIL()
+}
+
+//Leaves if error detected
+void CIkev1Negotiation::CommonConstructL()
+{
+    iPhase = PHASE_I;
+    iTimer = CIkev1Timeout::NewL(*this);    
+
+    //Phase II proposal lists
+    iProposal_IIList = new (ELeave) CProposal_IIList(1);
+
+    iRemoteAddr.SetPort(IKE_PORT);
+    
+    iHostData = &iPluginSession->IkeData();
+    if (!iHostData)
+    {
+        DEBUG_LOG(_L("The host has no data. Negotiation aborted"));
+        User::Leave(KKmdIkeNoPolicyErr);
+    }   
+
+	if ( iHostData->iCAList && iHostData->iCAList->Count() )
+	{
+		iPkiService = CIkeV1PkiService::NewL(iHostData, iDebug);
+		TInt stat ( EFalse );
+		stat=ReadCAsL(iHostData->iCAList);  // Build trusted CA list
+		if ( !stat )
+		{
+			SetErrorStatus( KVpnErrInvalidCaCertFile );
+			User::Leave(KVpnErrInvalidCaCertFile);
+		}
+	}	
+    iSendCert = iHostData->iAlwaysSendCert; //If true will always be sent, otherwise only with a CR
+
+    //Proposals
+    if (!BuildProposals1L())
+    {
+        SetFinished();
+        User::Leave(KKmdIkePolicyFileErr); //if any error returns
+    }
+
+    iEncoding = X509_CERT_SIG;  //Only type in use
+
+    iChosenProposal_I.iAttrList = new (ELeave) TAttrib; //allocated now and deleted when destroying the obj   
+    User::LeaveIfError( iPluginSession->GetLocalAddress( iLocalAddr ) );
+
+    //PFKEY data (is overwritten if initiator because we use the data given in the acquire
+
+    iAcquireSeq = 1;//msg Seq. number of acquire needed for the UPDATE
+    iSeq = 1;       //Sequence number for pfkey messages
+
+	iLastRemoteAddr = iRemoteAddr;   // Used as destination address when sending data
+#ifdef _DEBUG	
+	TBuf<40> txt_addr;
+    iRemoteAddr.OutputWithScope(txt_addr);
+#endif            
+    
+    iLastMsg = HBufC8::NewL(4096);
+    
+    DEBUG_LOG1( _L("New negotiation with Host %S"),
+            &txt_addr );
+
+    if ( !iHostData->iUseNatProbing && iHostData->iEspUdpPort == 0 )
+	{
+       //
+       // Use IETF specified NAT traversal
+       //
+       iNatDiscovery = CIkev1NatDiscovery::NewL(0);   
+    }
+	
+	if ( iRole == RESPONDER )
+	{
+	   //
+	   // Get base value internal address (=VPN virtual IP)
+	   //
+	   iInternalAddr = iPluginSession->InternalAddressL();
+	}	
+}
+
+
+TBool CIkev1Negotiation::ReadCAsL(CArrayFixFlat<TCertInfo*> *aCAList)
+{
+
+	TBool Status = iPkiService->ImportCACertsL(aCAList);
+
+#ifdef _DEBUG	
+	if ( !Status )
+	    {
+	    DEBUG_LOG( _L("Trusted CA list creation failed!") );
+	    }
+#endif // _DEBUG
+	
+	return Status;
+			   
+}
+
+TBool CIkev1Negotiation::ReadOwnCertL()
+{
+    //
+    // Read own certificate from PKI store using own trusted CA as
+    // specified issuer
+    //
+    TBool Status = EFalse;
+    _LIT(KVpnApplUid, "101F7993");
+    if ( iPkiService && iHostData->iCAList )
+		{
+       TCertInfo* CertInfo;
+	   HBufC8* CAName = HBufC8::NewLC(256);  	   
+       TInt i = 0;
+       if ( iHostData->iCAList->At(0)->iData!=KVpnApplUid )
+          {
+	       while ( i < iHostData->iCAList->Count() )
+			   {
+
+	           CertInfo = iHostData->iCAList->At(i);
+	           CAName->Des().Copy(CertInfo->iData); // Assure that CA name is in ASCII format
+               if ( iPkiService->ReadUserCertWithNameL(CAName->Des(), iHostData, EFalse) == KErrNone )
+				   {
+				   Status = ETrue;			   
+				   delete iOwnCert;  // delete old if exists			   
+				   iOwnCert = iPkiService->GetCertificate();
+				   delete iPeerTrustedCA;  // for sure
+				   iPeerTrustedCA = iPkiService->GetTrustedCA();
+                   CleanupStack::PopAndDestroy(CAName);   //CAName
+                   CAName=NULL;
+				   break;
+				   }
+               i ++;           
+               }
+              if (!Status)
+                  {
+                  CleanupStack::PopAndDestroy(CAName);
+                  CAName=NULL;
+                  }
+           }
+       else
+           {
+           CIkeCaList* trustedCaList = iPkiService->CaList();
+           CleanupStack::PopAndDestroy(CAName);        
+           CAName=NULL;
+           while ( i < trustedCaList->Count() )
+               {
+               
+               CIkeCaElem* CaElem = (*trustedCaList)[i];                     
+               CAName = IkeCert::GetCertificateFieldDERL(CaElem->Certificate(), KSubjectName);
+               if (CAName == NULL)
+                  {
+                   User::Leave(KErrArgument);
+                  }
+               CleanupStack::PushL(CAName);
+               if ( iPkiService->ReadUserCertWithNameL(*CAName, iHostData, ETrue) == KErrNone)
+                   {
+                   Status = ETrue;             
+                   delete iOwnCert;  // delete old if exists               
+                   iOwnCert = iPkiService->GetCertificate();
+                   delete iPeerTrustedCA;
+                   iPeerTrustedCA = iPkiService->GetTrustedCA();
+                   CleanupStack::PopAndDestroy(CAName);        
+                   CAName=NULL;
+                   
+                   
+                   break;
+                   }
+               i ++;
+               
+               CleanupStack::PopAndDestroy(CAName);
+               CAName=NULL;
+               } 
+           }
+       if ( !Status )
+		   {	   
+          DEBUG_LOG( _L("Error loading Own Certificate!") );
+		   }		   
+    }
+    return Status;
+}
+
+
+
+void CIkev1Negotiation::GetAcquireDataL(const TPfkeyMessage &aReq)
+{
+    // ACQUIRE Contains: <Base, Addr(Src & Dest) (Addr(Proxy)), (Ident(S & D)), (Sensitivity), Proposal>
+    
+    iLocalAddr = *aReq.iSrcAddr.iAddr;    //Copies our own address because it's the only way to know it
+
+    //Phase II proposals
+    //Only one combination received so only one transform
+    CProposal_II *prop_II = new (ELeave) CProposal_II();
+    CleanupStack::PushL(prop_II);
+    prop_II->ConstructL();
+    iProposal_IIList->AppendL(prop_II);
+    CleanupStack::Pop();            //prop_II safe in case of leave
+
+    prop_II->iProposalNum   = FIRST_IPSEC_PROPOSAL;
+    prop_II->iNumTransforms = 1;
+    prop_II->iReplayWindowLength = aReq.iProposal.iExt->sadb_prop_replay;
+    TAttrib_II *attr_II = new (ELeave) TAttrib_II();
+    CleanupStack::PushL(attr_II);
+    prop_II->iAttrList->AppendL(attr_II);   //added into the proposal so it's safe if function leaves
+    CleanupStack::Pop();            //attr_II safe in case of leave
+
+    attr_II->iTransformNum = FIRST_IPSEC_TRANSFORM;
+
+    if (aReq.iBase.iMsg->sadb_msg_satype==SADB_SATYPE_AH)
+    {
+        prop_II->iProtocol = PROTO_IPSEC_AH;
+        if (aReq.iProposal.iComb->sadb_comb_auth == SADB_AALG_MD5HMAC)
+        {
+            attr_II->iTransformID = AH_MD5;
+            attr_II->iAuthAlg = DOI_HMAC_MD5;
+        }
+        else if (aReq.iProposal.iComb->sadb_comb_auth == SADB_AALG_SHA1HMAC)
+        {
+            attr_II->iTransformID=AH_SHA;
+            attr_II->iAuthAlg = DOI_HMAC_SHA;
+        }
+        else
+        {
+            DEBUG_LOG(_L("Unsupported Authentication Algorithm in Acquire"));
+			SetFinished();					
+            return;
+        }
+        // No auth with variable encryption
+    }
+    else if (aReq.iBase.iMsg->sadb_msg_satype == SADB_SATYPE_ESP)
+    {
+        prop_II->iProtocol=PROTO_IPSEC_ESP;
+        /* Request ESP from peer host */
+
+        attr_II->iTransformID = aReq.iProposal.iComb->sadb_comb_encrypt;
+		switch ( attr_II->iTransformID )
+		{
+			case ESP_DES_CBC:
+			case ESP_3DES_CBC:
+			case ESP_NULL:
+				break;
+				
+			case ESP_AES_CBC:
+				attr_II->iKeyLength = aReq.iProposal.iComb->sadb_comb_encrypt_maxbits;
+				break;
+
+			default:
+				DEBUG_LOG(_L("IPsec Encryption algorithm is not implemented. Wrong algorithms file"));
+				SetFinished();
+				return;
+				
+		}	
+        if (aReq.iProposal.iComb->sadb_comb_auth != SADB_AALG_NONE)
+        {
+            if (aReq.iProposal.iComb->sadb_comb_auth == SADB_AALG_MD5HMAC)
+                attr_II->iAuthAlg = DOI_HMAC_MD5;
+            else if (aReq.iProposal.iComb->sadb_comb_auth == SADB_AALG_SHA1HMAC)
+                attr_II->iAuthAlg = DOI_HMAC_SHA;
+            else
+            {
+                DEBUG_LOG(_L("Unsupported Authentication Algorithm in Acquire"));
+				SetFinished();
+				return;
+            }
+        }
+    }
+    
+    //Check if PFS in use...
+    if (aReq.iProposal.iComb->sadb_comb_flags & SADB_SAFLAGS_PFS)
+    {
+        iPFS=ETrue;
+        switch (iHostData->iGroupDesc_II)
+        {
+        case IKE_PARSER_MODP_768:
+            attr_II->iGroupDesc = MODP_768;
+            break;
+        case IKE_PARSER_MODP_1024:
+            attr_II->iGroupDesc = MODP_1024;
+            break;
+        case IKE_PARSER_MODP_1536:
+            attr_II->iGroupDesc = MODP_1536;
+            break;
+        case IKE_PARSER_MODP_2048:
+            attr_II->iGroupDesc = MODP_2048;
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Group description)"));
+			SetFinished();
+			return;
+        }
+    }
+    else
+    {
+        iPFS=EFalse;
+        attr_II->iGroupDesc = 0;    //No group assigned because no PFS
+    }
+
+    if (aReq.iProposal.iComb->sadb_comb_flags & SADB_SAFLAGS_TUNNEL)
+    {
+        attr_II->iEncMode = DOI_TUNNEL;
+    }
+    else
+    {
+        attr_II->iEncMode = DOI_TRANSPORT;
+    }
+
+    iIDLocalPort = (TUint16)aReq.iSrcAddr.iAddr->Port();
+    iIDRemotePort = (TUint16)aReq.iDstAddr.iAddr->Port();
+    iIDProtocol = aReq.iDstAddr.iExt->sadb_address_proto;   //May be needed for phase II ID
+
+    //Source Identity
+    if (aReq.iSrcIdent.iExt)
+    {
+        if (aReq.iSrcIdent.iExt->sadb_ident_type == SADB_IDENTTYPE_PREFIX)
+        {
+			if ( !ProcessIdentityData(aReq.iSrcIdent.iData, &iLocalIDType_II,
+								      &iLocalAddr1_ID_II, &iLocalAddr2_ID_II) )
+			{
+				SetFinished();
+				return;
+			}	
+		}
+        else    //Invalid identity type
+        {
+            DEBUG_LOG1(_L("Invalid Local identity type (%d)"), aReq.iSrcIdent.iExt->sadb_ident_type);
+			SetFinished();
+			return;
+        }
+    }
+    else
+    {
+        //We need to assign a default address if other info is to be sent in the same payload
+        if (attr_II->iEncMode == DOI_TUNNEL || iIDLocalPort != 0 || iIDRemotePort != 0 ||
+            iIDProtocol != 0 || aReq.iDstIdent.iExt)
+        {
+            DEBUG_LOG(_L("Local Identity not defined and needed. Using Own address as local identity."));
+            iLocalAddr1_ID_II = iLocalAddr;
+            if ((iLocalAddr.Family() == KAfInet) || iLocalAddr.IsV4Mapped() )
+                iLocalIDType_II = ID_IPV4_ADDR;
+            else
+                iLocalIDType_II = ID_IPV6_ADDR;
+            iDefaultLocalID = ETrue;    //Must be sent but won't be used when updating the SAD
+        }
+    }
+
+    //Destination Identity
+    if (aReq.iDstIdent.iExt)
+    {
+        if (aReq.iDstIdent.iExt->sadb_ident_type == SADB_IDENTTYPE_PREFIX)
+        {
+			if ( !ProcessIdentityData(aReq.iDstIdent.iData, &iRemoteIDType_II,
+									  &iRemoteAddr1_ID_II, &iRemoteAddr2_ID_II) )
+			{
+				SetFinished();
+				return;
+			}
+        }
+        else    //Invalid identity type
+        {
+            
+            DEBUG_LOG1( _L("Invalid Destination identity type (%d)"), aReq.iDstIdent.iExt->sadb_ident_type );
+			SetFinished();
+			return;
+        }
+    }
+    else
+    {
+        //
+        // RemoteID_II is required only if LocalID_II already exists
+		// If transports mode
+        //      Build RemoteID_II for Quick mode negotiation from specified remote IP address
+        // else Use subnet 0/0 as remote id
+		//
+        if ( iLocalIDType_II != 0 )
+        {
+		   if (	attr_II->iEncMode == DOI_TUNNEL ) {
+			  if ( iLocalIDType_II == ID_IPV4_ADDR || iLocalIDType_II == ID_IPV4_ADDR_SUBNET ) {
+				 iRemoteAddr1_ID_II.Init(KAfInet);
+				 iRemoteAddr2_ID_II.Init(KAfInet); 				 
+				 iRemoteIDType_II = ID_IPV4_ADDR_SUBNET;
+			  }	   
+			  else {
+			     iRemoteAddr1_ID_II.Init(KAfInet6);
+				 iRemoteAddr2_ID_II.Init(KAfInet6); 				 				 
+				 iRemoteIDType_II = ID_IPV6_ADDR_SUBNET;
+			  }	 
+		   }
+		   else {
+              iRemoteAddr1_ID_II = *aReq.iDstAddr.iAddr;
+			  if ( iRemoteAddr1_ID_II.Family() == KAfInet6 )			  
+				   iRemoteIDType_II = ID_IPV6_ADDR;
+			  else iRemoteIDType_II = ID_IPV4_ADDR;
+		   }   
+           iDefaultRemoteID = ETrue;  //Must be sent but won't be used when updating the SAD   
+        }  
+    }
+
+    //Only Hard Lifetimes taken into account
+    TInt64 lifetime64 = aReq.iProposal.iComb->sadb_comb_soft_addtime;
+    iHardLifetime = aReq.iProposal.iComb->sadb_comb_hard_addtime;
+    
+    if ( lifetime64 == 0 )
+        {
+        lifetime64 = iHardLifetime;
+        }
+    
+    TUint high = 0;
+    TUint low = 0;
+    if (lifetime64!=0)
+    {
+        high = ByteOrder::Swap32(I64HIGH(lifetime64));
+        if (high > 0)
+            attr_II->iLifeDurationSecs.Copy((TUint8 *)&high, sizeof(high));
+        low = ByteOrder::Swap32(I64LOW(lifetime64));
+        attr_II->iLifeDurationSecs.Append((TUint8 *)&low, sizeof(low));
+    }
+
+    //Bytes lifetime
+    lifetime64 = aReq.iProposal.iComb->sadb_comb_soft_bytes;
+    lifetime64 = (lifetime64/1024); //Bytes to KB
+    if (lifetime64 != 0)
+    {
+        high = ByteOrder::Swap32(I64HIGH(lifetime64));      
+        if (high > 0)
+            attr_II->iLifeDurationKBytes.Copy((TUint8 *)&high, sizeof(high));
+        low = ByteOrder::Swap32(I64LOW(lifetime64));        
+        attr_II->iLifeDurationKBytes.Append((TUint8 *)&low, sizeof(low));
+    }
+
+    //Save some pf_key data to use later in PFKEY_UPDATE msg
+    iAcquireSeq = aReq.iBase.iMsg->sadb_msg_seq;        //msg Seq. number
+    iPfkeyAcquirePID = aReq.iBase.iMsg->sadb_msg_pid;   //msg PID.
+    iAcquirePending = ETrue;
+    DEBUG_LOG2( _L("Acq seq= %d , PID= %d"), iAcquireSeq, iPfkeyAcquirePID );
+    
+}
+
+//
+//  CIkev1Negotiation::ExecuteL()
+//  An ISAKMP message has been received belonging to this negotiation.
+//  Process the message and advance the negotiation session to appropriate
+//  next state/stage.
+//
+TBool CIkev1Negotiation::ExecuteL( const ThdrISAKMP& aHdr,
+                                   const TInetAddr& aRemote,
+                                   TInt aLocalPort )
+{
+    aLocalPort = aLocalPort;
+
+    TBool ret=EFalse;
+    const ThdrISAKMP *hdr;
+    TUint8 *msg = NULL;   //to place the new msg
+    TBuf8<IKEV1_MAX_IV_SIZE> tmp_IV(iIV);   //Temporal IV. Used to update the real one if the msg OK
+    
+    TLastIKEMsg msg_info(aHdr); //For retransmitted IKE msg detection
+    if ( IsRetransmit(msg_info) ) {
+       DEBUG_LOG(_L("Retransmitted IKE message received."));       
+       TBool FloatedPort = EFalse; 
+       if ( iNAT_D_Flags & (REMOTE_END_NAT + LOCAL_END_NAT) )
+           FloatedPort = ETrue;
+       TPtr8 lastMsg(iLastMsg->Des());
+       iPluginSession->SendIkeMsgL(lastMsg, iLastRemoteAddr, FloatedPort);        
+       return EFalse;              
+    }
+
+    if ( iPhase == PHASE_II &&
+         aHdr.GetExchange() != IKE_QUICK_MODE )
+    {
+        DEBUG_LOG(_L("Bad packet (retransmission?)"));
+#ifdef _DEBUG                    
+        const TPtrC8 ikeMsgPtr( (TUint8 *)&aHdr, (TUint16)aHdr.GetLength() );
+        TInetAddr dstAddr;
+        iPluginSession->GetLocalAddress( dstAddr );
+        dstAddr.SetPort( aLocalPort );
+        TRACE_MSG_IKEV1( ikeMsgPtr, iRemoteAddr, dstAddr );
+#endif // _DEBUG                            
+
+        SetFinished();
+        return EFalse;  //Bad packet, is a retransmission
+    }    
+    
+	iLastRemoteAddr = aRemote;  //Save last remote address (used in NAT cases)	
+
+    iLengthLeft = aHdr.GetLength(); //Used to check the size in the payload are OK
+
+    DEBUG_LOG2( _L("---------- Phase %d - Stage %d ----------"), iPhase, iStage );
+
+    if ((iStage==1) && (iPhase==PHASE_I))   //Only saved for the first message
+        iExchange = aHdr.GetExchange();
+
+    DEBUG_LOG1( _L("Exchange %d"), aHdr.GetExchange() );
+
+    if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted
+    {
+        //before anything, prints the packet
+        DEBUG_LOG(_L("Received message (encr)."));
+        DEBUG_LOG(_L("Decrypting..."));
+        msg = new (ELeave)(TUint8[aHdr.GetLength()]);    //to place the new msg
+		CleanupStack::PushL(msg);
+		
+        Mem::Copy(msg,(TUint8 *)&aHdr,sizeof(aHdr));    //The header is not encrypted
+
+        if ((iPhase==PHASE_II) && (iStage == 1))
+        {
+            iMessageId = aHdr.GetMessageId();   //Saves the ID to compute IV
+            DEBUG_LOG(_L("Quick IV:"));
+            ComputeIVL(iIV, iMessageId);
+        }
+
+        DecryptL((TUint8 *)aHdr.Next(),&msg[sizeof(aHdr)], aHdr.GetLength()-sizeof(aHdr),iIV, iSKEYID_e, iChosenProposal_I.iAttrList->iEncrAlg);
+        if ((iStage == 6 && iExchange == ISAKMP_EXCHANGE_ID) || 
+            (iStage == 3 && iExchange == ISAKMP_EXCHANGE_AGGR))
+        {
+            iLastIV.Copy(iIV);  //Saves last IV in Phase 1
+            DEBUG_LOG(_L("Last IV Saved!"));
+        }
+        hdr=(ThdrISAKMP *)msg;  //decrypted msg
+
+    }
+    else if (iFlags & ISAKMP_HDR_EFLAG)  // IKE message SHOULD be encrypted
+    {
+        hdr=&aHdr;  //no encryption    
+        DEBUG_LOG(_L("Received message."));
+#ifdef _DEBUG                    
+        const TPtrC8 ikeMsgPtr( (TUint8 *)hdr, (TUint16)hdr->GetLength() );
+        TInetAddr dstAddr;
+        iPluginSession->GetLocalAddress( dstAddr );
+        dstAddr.SetPort( aLocalPort );
+        TRACE_MSG_IKEV1( ikeMsgPtr, iRemoteAddr, dstAddr );
+#endif // _DEBUG                            
+        DEBUG_LOG(_L("The message is NOT encrypted (ignored)"));
+        return EFalse;
+    }
+    else
+        hdr=&aHdr;  //no encryption
+
+    DEBUG_LOG(_L("Received message."));
+#ifdef _DEBUG                    
+    const TPtrC8 ikeMsgPtr( (TUint8 *)hdr, (TUint16)hdr->GetLength() );
+    TInetAddr dstAddr;
+    iPluginSession->GetLocalAddress( dstAddr );
+    dstAddr.SetPort( aLocalPort );
+    TRACE_MSG_IKEV1( ikeMsgPtr, iRemoteAddr, dstAddr );
+#endif // _DEBUG                            
+
+    if (iPhase==PHASE_I)
+        ret = Phase_IExchangeL(*hdr);//MAIN MODE && AGGRESSIVE MODE
+    else
+    {
+        ret = Phase_IIExchangeL(*hdr);//QUICK MODE 
+    }
+    if (!ret)   //Incorrect packet. Restore the IV
+    {
+        DEBUG_LOG(_L("Restoring previous IV"));
+        iIV.Copy(tmp_IV);
+    }
+    else    //correct packet
+    {
+        SaveRetransmitInfo(msg_info); // store new last received IKE message info        
+    }
+
+    if ( msg )    //If used erase it (when encryption)
+ 	   CleanupStack::PopAndDestroy(); 
+
+    return ret;
+}
+
+TBool CIkev1Negotiation::ExecutePhase2L( const ThdrISAKMP &aHdr,
+                                         const TInetAddr &aRemote,
+                                         TInt aLocalPort )
+{
+    return ExecuteL( aHdr, aRemote, aLocalPort );
+}
+
+//
+// CIkev1Negotiation::ExecuteTransactionL
+// An ISAKMP Transaction exchange message received.
+// Call CTransNegotiation::ExecuteL method and process returned status
+//
+TBool CIkev1Negotiation::ExecuteTransactionL( const ThdrISAKMP& aHdr,
+                                              const TInetAddr& aRemote,
+                                              TInt aLocalPort )
+{
+    TInt  status;
+	TBool ret = ETrue;
+    if ( iTransactionNeg ) {
+       status = iTransactionNeg->ExecuteL( aHdr, aRemote, aLocalPort );
+       if ( status == TRANSACTION_SUCCESS ) {
+          //
+          // XAUTH / CONFIG-MODE completed succesfully
+          //
+          IsakmpPhase1CompletedL(); 
+       }
+       else {
+          if ( status == TRANSACTION_FAILED ) {
+             //
+             // XAUTH / CONFIG-MODE completed succesfully
+             //
+			 LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+			                R_VPN_MSG_VPN_GW_AUTH_FAIL,
+			                KKmdIkeAuthFailedErr,
+			                iPluginSession->VpnIapId(),
+			                &iRemoteAddr );
+			 SendDeleteL(PROTO_ISAKMP);
+             SetFinished(); 
+          }   
+       }       
+    }
+	else ret = EFalse;
+
+    return ret;
+}
+
+
+//
+// CIkev1Negotiation::AuthDialogCompletedL
+// Authentication dialog is completed. Check CAuthDialogInfo object ID
+// and call eithet CIKECRACKNegotiation::ProcessUserResponseL or
+// CTransNegotiation::ProcessUserResponseL to handle dialog data
+//
+void CIkev1Negotiation::AuthDialogCompletedL(CAuthDialogInfo *aUserInfo)
+{
+	if ( !aUserInfo || (!aUserInfo->iUsername && !aUserInfo->iSecret) ) 
+	{
+	   DEBUG_LOG(_L("Legacy authentication cancelled by user!"));		
+	   SendDeleteL(PROTO_ISAKMP);		
+	   LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+	                  R_VPN_MSG_VPN_GW_AUTH_FAIL,
+	                  KErrCancel,
+	                  iPluginSession->VpnIapId(),
+	                  &iRemoteAddr );
+	   SetErrorStatus(KErrCancel);
+	   return;
+	}	
+		
+    TInt status;
+
+    if ( aUserInfo->GetObjId() == XAUTH_DIALOG_ID ) 
+    {
+       if ( iTransactionNeg )
+            status = iTransactionNeg->ProcessUserResponseL(aUserInfo);       
+       else status = TRANSACTION_FAILED;
+       
+       if ( status == TRANSACTION_FAILED ) 
+       {
+         /*--------------------------------------------------------
+          *
+          *  XAUTH negotiation failed. Negotiation shall be deleted
+          *
+          *--------------------------------------------------------*/
+		  LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+		                 R_VPN_MSG_VPN_GW_AUTH_FAIL,
+		                 status,
+		                 iPluginSession->VpnIapId(),
+		                 &iRemoteAddr );
+		  SetErrorStatus(KKmdIkeAuthFailedErr);
+          AcquireSAErrorResponse(KKmdIkeAuthFailedErr);
+       }      
+    }
+    else 
+    {
+       if ( iCRACKneg )
+            status = iCRACKneg->ProcessUserResponseL(aUserInfo);       
+       else status = CRACK_FAILED;
+
+       if ( status == CRACK_FAILED ) 
+       {
+         /*--------------------------------------------------------
+          *
+          *  Crack negotiation failed. Negotiation shall be deleted
+          *
+          *--------------------------------------------------------*/
+		  LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+		                 R_VPN_MSG_VPN_GW_AUTH_FAIL,
+		                 status,
+		                 iPluginSession->VpnIapId(),
+		                 &iRemoteAddr );		   
+		  SetErrorStatus(KKmdIkeAuthFailedErr);		  
+          AcquireSAErrorResponse(KKmdIkeAuthFailedErr);
+       }      
+    }
+}
+
+
+//
+// CIkev1Negotiation::StartCRACKAuthL
+//      Start CRACK authentication phase of IKE phase I negotiation
+//      - Create CIKECRACKNegotiation object and call it`s ConstructL
+//      - Set iStage variable to 7 to indicate that CRACK authentication
+//        is going
+//
+TBool CIkev1Negotiation::StartCRACKAuthL()
+{
+TInt status;    
+
+    iStage = 7;
+    
+    if ( !iCRACKneg ) {
+       iCRACKneg = new(ELeave) CIKECRACKNegotiation( iDebug );
+	   TBuf<2> DummyDomain;
+	   //
+	   // If the IKE Id-type value is configured to value "Opaque
+	   // String" and iFQDN length is larger than zero in the current
+	   // policy ==> iFQDN value contains "Group name" value
+	   // which shall be conveyed to the peer in CRACK "Domain name"
+	   // attribute  
+	   //
+       iFlags |= ISAKMP_HDR_EFLAG; //From now on encryption is used    
+	   
+	   if ( (iHostData->iIdType == ID_KEY_ID) && (iHostData->iFQDN.Length() > 0 ) )
+            status = iCRACKneg->ConstructL(iHostData->iCRACKLAMType, this, iHostData->iFQDN);
+	   else status = iCRACKneg->ConstructL(iHostData->iCRACKLAMType, this, DummyDomain);
+       if ( status == CRACK_FAILED ) {
+          return EFalse;
+       }
+    }
+    
+    return ETrue;
+}
+
+//
+// CIkev1Negotiation::IsakmpPhase1CompletedL
+// This method is called when an ISAKMP phase 1 negotiation is succesfully
+// completed. The following actions are taken:
+// -- If either Extended authentication or/and Config mode required
+//    If iTransactionNeg data member exists it means that XAUTH/CONFIG mode
+//    has been succesfully completed.
+//    If iTransactionNeg data member is NULL, XAUTH/CONFIG mode shall be initiated
+// -- If No XAUTH/CONFIG mode (or if XAUTH/CONFIG mode already completed).
+//    If iAutoLogin is TRUE save ISAKMP SA and deconstruct negotiation.
+//    If iAutoLogin is False, save ISAKMP SA and;
+//       if negotiation role is initiator continue with Quick mode exchange. 
+//       if negotiation role is responder deconstruct negotiation.
+//
+TBool CIkev1Negotiation::IsakmpPhase1CompletedL()
+{
+    TBool Status;
+
+    if ( iTransactionNeg ) {
+       //
+       // Try to get Internal address information and delete iTransactionNeg
+       //
+       delete iInternalAddr;  
+       iInternalAddr = iTransactionNeg->GetInternalAddr();
+       delete iTransactionNeg;
+       iTransactionNeg = NULL;
+    }
+    else {
+       if ( (iRole == INITIATOR) && (iHostData->iUseXauth || iHostData->iUseCfgMode) )
+	   {
+		  TBool useModeCfg;
+		  if ( iSARekeyInfo )
+		       useModeCfg = EFalse;  // Use existing virtual Ip, if any
+		  else 
+		      useModeCfg = iHostData->iUseCfgMode; 
+		  
+          iTransactionNeg = CTransNegotiation::NewL( iHostData->iUseXauth,
+                                                     useModeCfg,
+                                                     iPluginSession,
+                                                     this,
+                                                     iDebug );
+          
+          // If only MODE_CFG is needed a request is sent
+          if(useModeCfg && !iHostData->iUseXauth)
+              iTransactionNeg->BuildConfigRequestL();
+          
+          iStage = 8;                    
+          return ETrue; 
+       }       
+    }   
+
+	SaveISAKMPSAL();
+
+    if ( iAutoLogin ) {
+       //
+       // ISAKMP Phase 1 completed. Quick mode is NOT started because there is no acquire pending
+       // but phase 1 negotiation is started by the policy activation.   
+       //
+       CInternalAddress* internalAddr = NULL;
+       if ( iInternalAddr != NULL )
+           {
+           internalAddr = CInternalAddress::NewL(*iInternalAddr);        
+           }
+       iPluginSession->IkeSaCompleted(KErrNone, internalAddr);
+	   SetFinished(); // Causes negotiation object destruction	   
+	   iAutoLogin = EFalse; 	   
+       Status     = EFalse;
+    }
+    else {
+	   if ( iRole == INITIATOR ) {
+	      TBool internalAddressChanged = EFalse;
+		  if ( iInternalAddr ) {
+		     //
+		     // Report internal IP address changed event
+		     //
+	         internalAddressChanged = iPluginSession->InternalAddressChangedL(*iInternalAddr);
+		  }
+		  if ( (!iSARekeyInfo ||
+		       iPhaseIIAfterIkeSaRekey) &&
+		       !internalAddressChanged )
+		  {	  
+             iPhaseIIAfterIkeSaRekey = EFalse;
+             iPrevExchange = iExchange;  //Needed to know how to begin Phase II (Sending or receiving)
+		     iExchange  = IKE_QUICK_MODE;
+		     iPhase     = PHASE_II;
+		     iStage     = 1;
+ 	         Status     = ETrue;
+             iMessageId = RandomMessageId(); 
+             InitPhase2L();  //Immediately inits PHASE_II. No reply expected.
+		  }
+		  else {
+			  //
+			  // Rekeyed IKE SA or internal address changed. No IKE quick mode started
+		      // Pending acquire will be failed, if internal address has changed.
+			  //
+			  SetFinished(); 
+			  Status    = EFalse;
+		  }	  
+	   }
+	   else {
+	      SetFinished(); // Causes negotiation object destruction
+		  Status    = EFalse;
+	   }	   
+    }
+	
+	LOG_KMD_EVENT( MKmdEventLoggerIf::KLogInfo,
+	               R_VPN_MSG_VPN_GW_AUTH_OK,
+	               KErrNone,
+	               iPluginSession->VpnIapId(),
+	               &iRemoteAddr );
+
+	TInt NatStatus = iNAT_D_Flags;   // Record "IETF" NAT status  
+	if ( NatStatus == 0 )
+	{	
+	   if ( iNAT_T_Required )
+			NatStatus = 4;           // Local end is NAT:ted (discovered via "Nokia" NAT-T)    
+	   else if ( !iHostData->iUseNatProbing )
+		       NatStatus = iHostData->iEspUdpPort; // "Forced" ESP UDP encapsulation ?
+	}
+
+	TInetAddr localAddr;
+	iPluginSession->GetLocalAddress( localAddr );
+    LOG_KMD_EVENT2( MKmdEventLoggerIf::KLogInfo,
+                    R_VPN_MSG_ADDR_INFO_FOR_VPN_AP,
+                    NatStatus, iPluginSession->VpnIapId(),
+                    (iInternalAddr ? &iInternalAddr->iClientIntAddr : NULL),
+                    &localAddr );	
+
+    return Status;
+}   
+
+
+//Sends the initial IKE packets to start the negotiation. PHASE I
+void CIkev1Negotiation::InitNegotiationL()   //Equiv. to stage 1
+{
+    TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );
+	
+    TInt  vendor_id_type;
+
+    //Main mode stage 1
+
+    switch (iHostData->iMode)
+    {
+        case IKE_PARSER_MAIN:
+            iExchange = ISAKMP_EXCHANGE_ID;     // Identity Protection (Main mode in IKE)
+            DEBUG_LOG(_L("IKE: Initiating negotiation (Main Mode)"));
+            break;
+        case IKE_PARSER_AGGRESSIVE:
+            iExchange = ISAKMP_EXCHANGE_AGGR;   // Agressive
+            DEBUG_LOG(_L("IKE: Initiating negotiation (Aggressive Mode)"));
+            break;
+        default:
+            DEBUG_LOG1(_L("Bad Mode used (%d)"), iHostData->iMode);
+            return;
+    }
+    iStage = 1;
+    DEBUG_LOG2(_L("---------- Phase %d - Stage %d ----------"),iPhase, iStage);
+
+    iCookie_R.FillZ(ISAKMP_COOKIE_SIZE);  //Set responder Cookie to 0
+
+    iDOI = IPSEC_DOI;
+    iEncoding = X509_CERT_SIG;  //Only cert Allowed
+    msg->IsakmpInit(this);
+    msg->IsakmpSa();
+
+    const TUint8 *ptr = msg->iBuf.Ptr() + sizeof(ThdrISAKMP);
+    const TSAISAKMP *sa = (TSAISAKMP*)ptr;
+    //Generic payload NOT included
+    iSAPayloadSize = sa->GetLength() - sizeof(TPayloadISAKMP);
+    delete iSAPayload;
+	iSAPayload = NULL;
+    iSAPayload = new (ELeave) TUint8[iSAPayloadSize];   
+    ptr += sizeof(TPayloadISAKMP);  
+    Mem::Copy(iSAPayload, ptr,iSAPayloadSize);
+
+    TBool cert_required = EFalse;   //If any proposal requires a cert to send a CR if needed
+    TBool preshared_key = EFalse;   //Preshared key authentication        
+    TBool crack_used = EFalse;
+    
+    TAttrib *transf = iProposal_I.iAttrList;
+    for (TInt i=0; (i < iProposal_I.iNumTransforms) && (!cert_required); i++)
+    {
+        switch (transf->iAuthMethod)
+        {
+        case RSA_SIG:   //Proposals involving certificates
+        case DSS_SIG:
+            cert_required = ETrue;
+            break;
+        case IKE_A_CRACK:           
+            cert_required = ETrue;
+            crack_used = ETrue;
+            break;
+        default:    // No cert involved
+            preshared_key = ETrue;
+            transf = transf->iNext;
+        }
+    }
+    
+    if (crack_used &&
+        !iHostData->iCRACKLAMUserName && 
+        !iHostData->iCRACKLAMPassword)
+        {
+        TBuf<256> UserName;
+        TBuf<64> Password;
+        CIkev1Dialog* Dialog = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);                     
+        if (KErrNone != Dialog->GetSyncUNPWCacheDialog(UserName, Password))
+            {
+            DEBUG_LOG(_L("Failed to get credentials for crack auth!"));
+            SetFinished();
+            delete Dialog;
+            return;
+            }
+        iHostData->iCRACKLAMUserName = TStringData::NewL(UserName);
+        iHostData->iCRACKLAMPassword = TStringData::NewL(Password);
+        delete Dialog;
+    }
+
+    if (iExchange == ISAKMP_EXCHANGE_AGGR) //Aggressive contains more payloads
+    {
+        if ( preshared_key && !cert_required ) {
+           //
+           // Only pre-shared key authentication proposal(s) exists
+           // Check if is necessary to ask user name/password (= IKE ID/preshared key)
+           // from user
+           //
+           if ( CheckCredentials(iHostData) != KErrNone ) {
+              DEBUG_LOG(_L("Failed to get credentials for Aggressive pre-shared auth!"));
+              SetFinished();
+              return;
+           }
+        }   
+        ComputeNonceL();         //Nonce to be sent
+        if ( cert_required && !iOwnCert ) 
+           ReadOwnCertL();    // For possible DER ASN1 distuingish name Ident
+        msg->IsakmpKeyL();
+        msg->IsakmpNonce();
+        msg->IsakmpOwnIdentL();
+		
+        //For aggressive mode we send a CR if a cert is going to be needed
+        if ((!iPeerX509Cert) && (cert_required))
+        {
+           msg->IsakmpCertificateReqL();   
+        }
+        if ( iHostData->iUseNatProbing )
+             vendor_id_type = EXPANDED_VENDOR_ID;
+        else vendor_id_type = HASH_VENDOR_ID;           
+        msg->IsakmpVendorId(vendor_id_type,
+                            (TUint8*)iCookie_I.Ptr(),
+                            (TUint8*)iCookie_R.Ptr(), iLocalAddr);
+            
+    }
+	
+	if ( iHostData->iDPDHeartBeat != 0 )
+	   BuildDPDVendorId(*msg);
+	
+    if ( iNatDiscovery ) {
+       iNatDiscovery->BuildNatVendorId(*msg);
+       iNatDiscovery->BuildRfcNatVendorId(*msg);
+    }
+	
+    if ( iHostData->iUseXauth || iHostData->iUseCfgMode ) {  
+       CTransNegotiation::BuildXauthVendorId(*msg);  
+    }
+
+    SendL(*msg);
+    iStage = 2;
+}
+
+//Builds the proposal list from the structure in the engine
+TBool CIkev1Negotiation::BuildProposals1L()
+{
+    TProposalData *p_list = iHostData->iPropList;
+
+    if (!p_list)
+    {
+        DEBUG_LOG(_L("ERROR: No proposals in the configuration file. Negotiation Cancelled"));
+        return EFalse;
+    }
+    iProposal_I.iSPI.FillZ(4);  //filled with 0 (not send anyway)
+    iProposal_I.iProposalNum   = FIRST_ISAKMP_PROPOSAL; 
+    iProposal_I.iProtocol      = PROTO_ISAKMP;
+    iProposal_I.iNumTransforms = 0;
+    
+    TUint8 trans_num = FIRST_ISAKMP_TRANSFORM;
+
+    TAttrib *prev=NULL,*attrlist=NULL;
+    
+    while ( p_list )
+    {
+        iProposal_I.iNumTransforms ++;
+        attrlist = new (ELeave) TAttrib;
+        if (!iProposal_I.iAttrList) //First transform
+            iProposal_I.iAttrList=attrlist; //attrlist safe
+        if (prev)
+            prev->iNext = attrlist;
+        prev = attrlist;
+        
+        attrlist->iTransformID  = KEY_IKE; //only one allowed by Protocol ISAKMP (KEY_IKE)
+        attrlist->iTransformNum = trans_num;
+        trans_num++;        
+        switch (p_list->iEncrAlg)
+        {
+        case IKE_PARSER_DES_CBC:
+            attrlist->iEncrAlg=DES_CBC;     //DES_CBC
+            break;
+        case IKE_PARSER_DES3_CBC:
+            attrlist->iEncrAlg=DES3_CBC;    //DES3_CBC
+            break;
+        case IKE_PARSER_AES_CBC:
+            attrlist->iEncrAlg   = AES_CBC;     //AES_CBC
+            attrlist->iKeyLength = (TUint16)p_list->iEncrKeyLth;
+            if (!attrlist->iKeyLength)
+               attrlist->iKeyLength = 128; //default AES key size   
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Encryption algorithm)"));
+            return EFalse;
+        }
+        switch (p_list->iHashAlg)
+        {
+        case IKE_PARSER_MD5:
+            attrlist->iHashAlg=HASH_MD5;    //HASH_MD5
+            break;
+        case IKE_PARSER_SHA1:
+            attrlist->iHashAlg=HASH_SHA1;   //HASH_SHA1
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Hash algorithm)"));
+            return EFalse;
+        }
+        switch (p_list->iAuthMeth)
+        {
+        case IKE_PARSER_RSA_SIG:
+            attrlist->iAuthMethod=RSA_SIG;
+            break;
+        case IKE_PARSER_DSS_SIG:
+            attrlist->iAuthMethod=DSS_SIG;
+            break;
+        case IKE_PARSER_PRE_SHARED:
+            attrlist->iAuthMethod=PRE_SHARED;           
+            break;
+        case IKE_PARSER_CRACK:
+            attrlist->iAuthMethod=IKE_A_CRACK; //CRACK authentication
+            break;
+            
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Authentication Method)"));
+            return EFalse;
+        }
+        
+        switch (p_list->iGroupDesc)
+        {
+        case IKE_PARSER_MODP_768:
+            attrlist->iGroupDesc = MODP_768;
+            break;
+        case IKE_PARSER_MODP_1024:
+            attrlist->iGroupDesc = MODP_1024;
+            break;
+        case IKE_PARSER_MODP_1536:
+            attrlist->iGroupDesc = MODP_1536;
+            break;
+        case IKE_PARSER_MODP_2048:
+            attrlist->iGroupDesc = MODP_2048;
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Group description)"));
+            return EFalse;      
+        }
+
+        switch (p_list->iGroupType)
+        {
+        case IKE_PARSER_MODP:
+            attrlist->iGroupType = MODP;
+            break;
+        case IKE_PARSER_DEFAULT:
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad Group Type)"));
+            return EFalse;
+        }
+
+        switch (p_list->iPRF)
+        {
+        case IKE_PARSER_DES3_CBC_MAC:
+            attrlist->iPRF=OAKLEY_PRF_3DES_CBC_MAC;
+            break;
+        case IKE_PARSER_NONE:
+            break;
+        default:
+            DEBUG_LOG(_L("ISAKMP Proposals error (Bad PRF specified)"));
+            return EFalse;
+        }
+
+        TUint32 lifetime = ByteOrder::Swap32(p_list->iLifetimeSec);
+        if (lifetime)
+            attrlist->iLifeDurationSecs.Copy((TUint8 *)&lifetime, sizeof(lifetime));
+
+        lifetime = ByteOrder::Swap32(p_list->iLifetimeKb);
+        if (lifetime)
+            attrlist->iLifeDurationKBytes.Copy((TUint8 *)&lifetime, sizeof(lifetime));
+
+        //
+        // Store parameters for extended authentication
+        //
+        attrlist->iXauthUsed = iHostData->iUseXauth;
+        attrlist->iRole      = iRole;
+        
+        p_list = p_list->iNext;
+        
+    }
+    attrlist->iNext=NULL;   //Last transform
+
+
+    return ETrue;
+}
+
+//Builds Phase_II proposals from the config. file to when acting as RESPONDER to see if 
+//proposals received are acceptable.
+TInt CIkev1Negotiation::BuildProposals2L()
+{
+    CIpsecSaSpecList* SaList = NULL;
+    TInetAddr empty_addr;  //empty address
+    TInt err = KErrNone;
+    
+    TRAP(err,
+        if ( iLocalIDType_II == 0 )  //Local ID not received (so remote neither) so it's the same as gateway
+            {
+            TInetAddr localSelector(iLocalAddr);
+            localSelector.SetPort(iIDLocalPort);
+            TInetAddr remoteSelector(iRemoteAddr);
+            remoteSelector.SetPort(iIDRemotePort);
+            
+            SaList = iPluginSession->GetIpseSaSpecListLC(localSelector, empty_addr, 
+                                                         remoteSelector, empty_addr,
+                                                         iIDProtocol );
+            }
+        else    // either none or both (RFC 2409 5.5 so we must have both)
+            {
+            TInetAddr localSelector(iLocalAddr1_ID_II);
+            localSelector.SetPort(iIDLocalPort);
+            TInetAddr remoteSelector(iRemoteAddr1_ID_II);
+            remoteSelector.SetPort(iIDRemotePort);
+    
+            
+            SaList = iPluginSession->GetIpseSaSpecListLC(localSelector,
+                                                         iLocalAddr2_ID_II,
+                                                         remoteSelector,
+                                                         iRemoteAddr2_ID_II,
+                                                         iIDProtocol );
+            }
+        
+        CleanupStack::Pop(SaList);
+    );
+    
+    if (err != KErrNone)
+        return err;
+    
+    CleanupStack::PushL(SaList);
+
+    //Phase II proposals
+
+    CProposal_II *prop = NULL;
+    TAttrib_II *attr_II = NULL;
+    const TIpsecSaSpec *spec = NULL;
+    TInt count = SaList->Count();
+    TInt i     = 0;
+
+    while ( i < count ) 
+    {
+        prop = new (ELeave) CProposal_II();
+        CleanupStack::PushL(prop);
+        prop->ConstructL(1);
+        iProposal_IIList->AppendL(prop);
+        CleanupStack::Pop();    //prop safe
+        //
+        // Only 1 proposal which may be AND'd (many prop with same num) if many bundles
+        // Only 1 transform because no OR'ing implemented in IPSEC
+        //
+        prop->iProposalNum   = FIRST_IPSEC_PROPOSAL;
+        prop->iNumTransforms = 1;  
+
+        attr_II = new (ELeave) TAttrib_II();
+        CleanupStack::PushL(attr_II);
+        prop->iAttrList->AppendL(attr_II);
+        CleanupStack::Pop();    //attr_II safe
+        
+        attr_II->iTransformNum = FIRST_IPSEC_TRANSFORM;     
+
+        spec = &(SaList->At(i));
+        
+        if (spec->iType == SADB_SATYPE_AH)
+        {
+            prop->iProtocol=PROTO_IPSEC_AH;
+            if (spec->iAalg == SADB_AALG_MD5HMAC)
+            {
+                attr_II->iTransformID = AH_MD5;
+                attr_II->iAuthAlg = DOI_HMAC_MD5;
+            }
+            else if (spec->iAalg == SADB_AALG_SHA1HMAC)
+            {
+                attr_II->iTransformID=AH_SHA;
+                attr_II->iAuthAlg = DOI_HMAC_SHA;
+            }
+            else
+            {
+                DEBUG_LOG(_L("Unsupported Authentication Algorithm in IPsec Policy"));
+                err = KKmdIkeNoProposalErr;
+                break;
+            }
+            // No auth with variable encryption
+        }
+        else if (spec->iType == SADB_SATYPE_ESP)
+        {
+            prop->iProtocol = PROTO_IPSEC_ESP;
+            // Request ESP from peer host
+
+            attr_II->iTransformID = spec->iEalg;
+			switch ( attr_II->iTransformID )
+			{
+				case ESP_DES_CBC:
+				case ESP_3DES_CBC:
+				case ESP_NULL:
+					break;
+
+				case ESP_AES_CBC:
+					attr_II->iKeyLength = spec->iEalgLen;   //If 0 it won't be sent
+					break;
+
+				default:
+					DEBUG_LOG(_L("IPsec Encryption algorithm is not implemented. Wrong algorithms file"));
+	                err = KKmdIkeNoProposalErr;
+	                break;
+			}	
+			
+			if (err != KErrNone)
+			    {
+			    break;
+			    }
+			
+            if (spec->iAalg != SADB_AALG_NONE)
+            {
+                if (spec->iAalg == SADB_AALG_MD5HMAC)
+                    attr_II->iAuthAlg = DOI_HMAC_MD5;
+                else if (spec->iAalg == SADB_AALG_SHA1HMAC)
+                    attr_II->iAuthAlg = DOI_HMAC_SHA;
+                else
+                {
+                    DEBUG_LOG(_L("Unsupported Authentication Algorithm in IPsec Policy"));
+                    err = KKmdIkeNoProposalErr;
+                    break;
+                }
+            }
+        }
+
+        //Check if PFS in use...
+        iPFS = spec->iPfs;
+
+        if (spec->iTransportMode)
+             attr_II->iEncMode = DOI_TRANSPORT;
+        else attr_II->iEncMode = DOI_TUNNEL;
+
+        //////////////////////////////////////////////////////////
+        //
+        // Check if remote identity defined in Security Policy
+        // If it is not set iDefaultLocalID = ETrue.
+        // This prevents destination identity information to IPSEC
+        // in PFKEY Update- and Add primitives
+        // (see UpdateSADatabaseL() method)
+        //
+        //////////////////////////////////////////////////////////
+        if ( spec->iRemoteIdentity.Length() == 0 )
+           iDefaultLocalID = ETrue;
+		if ( !ExamineRemoteIdentity(spec->iRemoteIdentity) )
+		{
+			DEBUG_LOG(_L("Remote Identity mismatch with IPsec Policy"));
+            err = KKmdIkeNoProposalErr;
+            break;
+		}
+		
+        //Only Hard Lifetimes taken into account
+        TInt64 lifetime64 = spec->iHard.iAddTime;
+        TUint high = 0;
+        TUint low = 0;
+        if (lifetime64!=0)
+        {
+            high = ByteOrder::Swap32(I64HIGH(lifetime64));          
+            if (high > 0)
+                attr_II->iLifeDurationSecs.Copy((TUint8 *)&high, sizeof(high));
+            low = ByteOrder::Swap32(I64LOW(lifetime64));                        
+            attr_II->iLifeDurationSecs.Append((TUint8 *)&low, sizeof(low));
+        }
+
+        //Bytes lifetime
+        lifetime64 = spec->iHard.iBytes;
+        lifetime64 = (lifetime64/1024); //Bytes to KB
+        if (lifetime64 != 0)
+        {
+            high = ByteOrder::Swap32(I64HIGH(lifetime64));                      
+            if (high > 0)
+                attr_II->iLifeDurationKBytes.Copy((TUint8 *)&high, sizeof(high));
+            low = ByteOrder::Swap32(I64LOW(lifetime64));                                    
+            attr_II->iLifeDurationKBytes.Append((TUint8 *)&low, sizeof(low));
+        }
+        if (iPFS)
+        {
+            switch (iHostData->iGroupDesc_II)
+            {
+            case IKE_PARSER_MODP_768:
+                attr_II->iGroupDesc = MODP_768;
+                break;
+            case IKE_PARSER_MODP_1024:
+                attr_II->iGroupDesc = MODP_1024;
+                break;
+            case IKE_PARSER_MODP_1536:
+                attr_II->iGroupDesc = MODP_1536;
+                break;
+            case IKE_PARSER_MODP_2048:
+                attr_II->iGroupDesc = MODP_2048;
+                break;
+            default:    //Shouldn't happen but the error will be detected later
+                err = KKmdIkeNoProposalErr;
+                break;
+            }
+            
+            if (err != KErrNone)
+                {
+                break;
+                }            
+        }
+        
+        prop->iReplayWindowLength = spec->iReplayWindowLength;
+
+        i ++;
+    }   //while
+
+    if (err != KErrNone)
+        {
+        delete iProposal_IIList;
+        iProposal_IIList = NULL;        
+        }
+    
+    CleanupStack::PopAndDestroy(SaList);  //SAList
+    
+    return err;
+}
+
+TBool CIkev1Negotiation::ExamineRemoteIdentity(const TDesC8& aRemoteIdInPolicy)
+{
+   //////////////////////////////////////////////////////////////////
+   //
+   // This method is called when we are acting as a Quick mode responder.   
+   // The purpose of this method is compare remote Identity information
+   // received in Quick Mode IKE message (=IDi) to the remote Identity
+   // information in the local Ipsec Policy.
+   // If Identitiea are NOT matching the FALSE response is returned.
+   // There is the following special "kludge" is done in these test:
+   // Identity IPv4 address and IPv4 subnet with prefix 32 are
+   // interpreted to be same as well as IPv6 address and IPv6 subnet
+   // with prefix 128. When this situation occurs a special flag 
+   // (iSwapRemoteIdType = ETrue) is set in CIkev1Negotiation object
+   //
+   //////////////////////////////////////////////////////////////////
+   TBool      AddrMatch;   
+   TInetAddr  IpAddr;
+   TInetAddr  IpMask;
+   TUint8     IdType;
+   TInt       PrefixLength = 0;
+   TInetAddr* PrefixPtr    = NULL;      
+   
+   if ( !ProcessIdentityData(aRemoteIdInPolicy, &IdType, &IpAddr, &IpMask) )
+	  return EFalse;
+   
+   AddrMatch = IpAddr.Match(iRemoteAddr1_ID_II);
+
+   if ( AddrMatch )
+   {	   
+      if ( (IdType == ID_IPV4_ADDR_SUBNET ) || (IdType == ID_IPV6_ADDR_SUBNET) ) 
+      {
+		 // 
+		 // Identity in policy is IP subnet
+		 //
+	     if ( iRemoteIDType_II == IdType )
+		 {
+		    // 
+		    // Both identity in policy and identity in IKE IDi payload are
+		    // IP subnets. The subnet masks MUST match, too
+		    //
+			AddrMatch = IpMask.Match(iRemoteAddr2_ID_II);
+		 }
+		 else
+		 {
+			 if ( ( (IdType == ID_IPV4_ADDR_SUBNET ) && (iRemoteIDType_II == ID_IPV4_ADDR)) ||
+			      ( (IdType == ID_IPV6_ADDR_SUBNET ) && (iRemoteIDType_II == ID_IPV6_ADDR)))
+			 {	 
+			    // 
+			    // Identity in IKE IDi payload is an IP address
+			    // Do the special check: There must be full mask in the
+			    // subnet identity configured in policy
+			    //
+				if ( IdType == ID_IPV6_ADDR_SUBNET )
+					 PrefixLength = 128;
+				else PrefixLength = 32;
+				PrefixPtr = &IpMask;
+				DEBUG_LOG(_L("Peer is using IP address IDi, full mask subnet required in local end!"));
+			 }
+			 else AddrMatch = EFalse;  
+		 }	 
+      }	   
+      else
+      {
+	     // 
+	     // Identity in policy is IP address.
+	     //
+		 if ( ( (IdType == ID_IPV4_ADDR ) && (iRemoteIDType_II == ID_IPV4_ADDR_SUBNET)) ||
+			  ( (IdType == ID_IPV6_ADDR ) && (iRemoteIDType_II == ID_IPV6_ADDR_SUBNET)))
+		 {	 
+				// 
+				// Identity in IKE IDi payload is an IP subnet
+				// Do the special check: There must be full mask in the
+				// subnet identity in IKE IDi payload
+				//
+			 if ( IdType == ID_IPV6_ADDR )
+			      PrefixLength = 128;
+			 else PrefixLength = 32;
+			 PrefixPtr = &iRemoteAddr2_ID_II;
+			 DEBUG_LOG(_L("An IP address ID used in local end, full mask subnet required in peer IDi!"));
+		 }
+		 else if ( iRemoteIDType_II != IdType )
+				 AddrMatch = EFalse;
+		 
+      }
+   }
+
+   if ( PrefixPtr )
+   {	   	   
+	  if ( PrefixLength == PrefixLen(*PrefixPtr) )
+	  {	  
+	  	 iSwapRemoteIdType = ETrue;
+		 DEBUG_LOG(_L("Required ID OK, modified remote IDi informed to IPsec!"));		 
+	  }	 
+	  else AddrMatch = EFalse;
+   }
+   
+   return AddrMatch;
+}
+
+TBool CIkev1Negotiation::ProcessIdentityData(const TDesC8& aIdentity, TUint8* aToIdType,
+										TInetAddr* aToIpAddr1, TInetAddr* aToIpAddr2)
+{
+   if ( !aToIdType || !aToIpAddr1 || !aToIpAddr2 )
+	  return EFalse;
+   
+   aToIpAddr1->Init(KAFUnspec);
+   aToIpAddr2->Init(KAFUnspec);
+   *aToIdType = 0;
+		   
+   if ( aIdentity.Length() )
+   {	   
+      TInt offset = aIdentity.Find(_L8("/"));
+   
+      switch (offset)
+      {
+	     case KErrNotFound:  //Simple address
+         { 
+#ifdef _UNICODE
+		    HBufC *unibuf = HBufC::New(aIdentity.Length());
+			if ( !unibuf )
+			    return EFalse;	
+	        unibuf->Des().Copy(aIdentity);
+	    	if ( aToIpAddr1->Input(unibuf->Des()) != KErrNone )
+	    	{
+				delete unibuf;
+		    	DEBUG_LOG(_L("Bad IP address identity!"));
+				return EFalse;
+	    	}  
+		    delete unibuf;
+#else
+		    if (aToIpAddr1->Input(aIdentity) != KErrNone)
+		    {
+				DEBUG_LOG(_L("Bad IP address identity!"));
+				return EFalse;
+		    }
+#endif  
+		    if ( aToIpAddr1->Family() == KAfInet )
+			     *aToIdType = ID_IPV4_ADDR;
+		    else *aToIdType = ID_IPV6_ADDR;
+		    break;
+     	 }
+		 
+	     default:    //Subnet
+	     {
+				//addr1 - subnet
+		 TInt prefix_len;	 
+#ifdef _UNICODE
+		    HBufC *unibuf = HBufC::New(aIdentity.Length());
+			if ( !unibuf )
+				return EFalse;
+			unibuf->Des().Copy(aIdentity);			
+		    TPtrC addr_buf(unibuf->Ptr(), offset);
+		    if (aToIpAddr1->Input(addr_buf) != KErrNone)
+		    {
+				delete unibuf;				
+			    DEBUG_LOG(_L("Bad Subnet Identity address!"));
+				return EFalse;
+		    }
+		    TPtrC prefix_ptr(unibuf->Ptr() + offset + 1, unibuf->Length() - offset - 1);
+#else
+		    TPtrC addr_buf(aIdentity.Ptr(), offset);
+			if (aToIpAddr1->.Input(addr_buf) != KErrNone)
+			{
+				DEB(LogError(_L("Bad Subnet Identity address!"));)
+				return EFalse;
+			}
+		    TPtrC prefix_ptr(aIdentity.Ptr() + offset + 1, aIdentity.Length() - offset - 1);
+#endif  
+				//addr2 - mask
+		    TLex lex(prefix_ptr);
+		    if (lex.Val(prefix_len) != KErrNone)
+		    {
+			   DEBUG_LOG(_L("Bad Subnet Identity PREFIX Length!"));
+			   return EFalse;
+		    }
+#ifdef _UNICODE
+		    delete unibuf;
+#endif
+			if ( aToIpAddr1->Family() == KAfInet )
+			{
+			   if ( prefix_len > 32 )	
+			   {
+				  DEBUG_LOG(_L("Bad Subnet Identity: Prefix too long!"));
+				  return EFalse;
+			   }
+			   *aToIdType = ID_IPV4_ADDR_SUBNET;
+			   PrefixMask(*aToIpAddr2, prefix_len, KAfInet);
+			}
+			else    //KAfInet6
+			{
+				if ( prefix_len > 128 )	
+				{
+					DEBUG_LOG(_L("Bad Subnet Identity: Prefix too long!"));
+					return EFalse;
+				}
+				*aToIdType = ID_IPV6_ADDR_SUBNET;
+				PrefixMask(*aToIpAddr2, prefix_len, KAfInet);
+			}
+
+		 }
+		 
+	  } //end switch
+   }	  
+
+   return ETrue;
+}
+
+//First msg of PHASE_II as initiator
+void CIkev1Negotiation::InitPhase2L()
+{
+    //Quick mode stage 1
+    DEBUG_LOG(_L("-------- IKE: Initiating PHASE II --------"));
+    iPhase = PHASE_II;
+    iDOI=IPSEC_DOI;
+    iStage = 1;
+
+    GetSPIL();
+    //the rest will be done in ReceiveSPI
+}
+
+//Requests an SPI from the kernel
+
+void CIkev1Negotiation::GetSPIL()
+{
+    CProposal_IIList *propII_List;
+    CProposal_II *prop=NULL;
+    TUint8 sa_type = 0;
+
+    DEBUG_LOG1(_L("GetSPI in stage: %d"), iStage);
+
+    iInboundSPIList = new (ELeave) CArrayFixFlat<TSPINode>(1);
+
+    if (iRole == RESPONDER) //If Phase II proposal Chosen
+        propII_List = iChosenProp_IIList;   //If RESPONDER
+    else
+        propII_List = iProposal_IIList; //If INITIATOR
+
+    TInt i, count = propII_List->Count();
+    for (i = 0; i < count; i++) //May have many Phase_II proposals
+    {
+        prop = propII_List->At(i);
+        if (prop->iProtocol == PROTO_IPSEC_AH)
+            sa_type = SADB_SATYPE_AH;
+        else if (prop->iProtocol == PROTO_IPSEC_ESP)
+            sa_type = SADB_SATYPE_ESP;
+        else
+            sa_type = 0;    //Unknown Protocol
+
+        TInetAddr myAddr(iLocalAddr);
+		if ( myAddr.IsUnspecified() )
+		    User::LeaveIfError( iPluginSession->GetLocalAddress( myAddr ) );
+        TInetAddr peerAddr(iRemoteAddr);
+        peerAddr.SetPort(0);
+        TSPINode node;
+        node.iPropNum = prop->iProposalNum;
+        node.iSeq = iSeq;
+        iInboundSPIList->AppendL(node);
+        
+        
+        __ASSERT_DEBUG( iIpsecSaSpiRetriever != NULL,
+                        User::Invariant() );
+        iIpsecSaSpiRetriever->Cancel();
+        iIpsecSaSpiRetriever->GetIpsecSaSpi( iSeq++, sa_type, peerAddr, myAddr );        
+        iPendingSPI++;      //To know when all received in ReceiveSPIL()
+    }
+
+    DEBUG_LOG1(_L("GetSPI seq= %d"), iSeq);
+}
+
+//aSPI received in Network order.
+void CIkev1Negotiation::ReceiveSPIL(TUint32 aSPI, TUint32 aSeq)
+{
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );
+	
+    DEBUG_LOG2(_L("ReceiveSPIL: SPI=%x, Seq=%u"), ByteOrder::Swap32(aSPI), aSeq);
+
+    CProposal_IIList *propII_List = iProposal_IIList;
+    TInt i;
+    for (i = 0; i < iInboundSPIList->Count(); i++)
+    {
+        if (iInboundSPIList->At(i).iSeq == aSeq)
+        {
+            iInboundSPIList->At(i).iSPI = aSPI;
+            break;
+        }
+        //prop = prop->iNext;   //To assign the SPI to the correct proposal
+    }
+    if (iRole==INITIATOR)
+        propII_List->At(i)->iSPI.Copy((TUint8*)&aSPI,sizeof(TUint32));  //needed to send it to the other Peer
+
+    if (--iPendingSPI)  // Check if still waiting for some SPI
+        return;
+
+    iExchange = IKE_QUICK_MODE; //Current mode being used.
+    //Builds and send the packet
+
+    if ((iHostData->iCommit) && (iRole==RESPONDER)) //Responder  && if commit bit used we set the flag
+        iFlags |= ISAKMP_HDR_CFLAG; //Sets the Commit bit if this side set it else
+
+    msg->IsakmpInit(this);
+    msg->IsakmpHashL();
+    msg->IsakmpSa();
+    ComputeNonceL();     //Computes a new Nonce for PHASE_II
+    msg->IsakmpNonce();
+    if (iPFS)   //Only sent if PFS in use...
+        msg->IsakmpKeyL();
+
+    if (iStage==1)  //Initiator
+    {
+        //
+        // If Internal address private extension used change iLocalAddr1_ID_II to
+        // correspond that address
+        //
+        if ( iInternalAddr ) {
+           iLocalAddr1_ID_II = iInternalAddr->iClientIntAddr;       
+           iLocalIDType_II   = ID_IPV4_ADDR;
+           iDefaultLocalID   = ETrue;  
+        }   
+        DEBUG_LOG(_L("PhaseII IV:"));   //New IV for phase II
+        ComputeIVL(iIV, iMessageId);
+        //IDs must be sent if TUNNEL mode or is explicitly specified in the acquire
+        if ((!iLocalAddr1_ID_II.IsUnspecified()) || (!iRemoteAddr1_ID_II.IsUnspecified()) ||
+            (iIDProtocol != 0) || (iIDLocalPort != 0) || (iIDRemotePort != 0))
+        {
+            msg->IsakmpOwnIdentL();     //Own proxy
+            msg->IsakmpPeerIdentL();    //Peer Proxy
+        }
+    }
+    else if (iStage==2) //Responder
+    {
+        if (iIDReceived)    //If received we send it back, otherwise no
+        {
+            msg->IsakmpPeerIdentL();
+            msg->IsakmpOwnIdentL(); 
+        }
+        if (iHostData->iResponderLifetime)
+            CheckSendResponderLifetime(*msg);    //Adds to the message the RESPONDER_LIFETIME payload if needed
+    }
+    else return;
+
+    if (iHostData->iReplayStatus)
+    {
+        DEBUG_LOG(_L("Constructing REPLAY-STATUS"));
+    
+        TInt i;
+        CProposal_II *prop;
+        for (i = 0 ; i < iProposal_IIList->Count(); i++)
+        {
+            prop = iProposal_IIList->At(i);
+            msg->IsakmpReplayStatus(prop->iProtocol, iInboundSPIList->At(i).iSPI, prop->iReplayWindowLength);
+        }
+    }
+    msg->IsakmpHashContL(); //inserts the hash in the correct position of the buffer
+    SendL(*msg);
+
+    iStage++;   //Next stage
+}
+
+void CIkev1Negotiation::AcquireSAErrorResponse(TInt aError)
+	{
+	DEBUG_LOG(_L("CIkev1Negotiation::AcquireSAErrorResponse"));
+		
+	if ( iProposal_IIList )
+		{
+		for ( TInt j=0; j<iProposal_IIList->Count(); j++ )
+			{			
+			TIpsecSAData sa_data;	
+		    sa_data.iSeq = iAcquireSeq;
+		    sa_data.iPid = iPfkeyAcquirePID;
+			sa_data.iSPI = 0;	
+			sa_data.iDst = iRemoteAddr;
+			
+			CProposal_II* prop_II = iProposal_IIList->At( j );
+
+			if ( prop_II->iProtocol == PROTO_IPSEC_AH )
+				{
+				sa_data.iSAType = SADB_SATYPE_AH;				
+				}
+	        else if ( prop_II->iProtocol == PROTO_IPSEC_ESP )
+	            {
+	            sa_data.iSAType = SADB_SATYPE_ESP;
+	            }
+			iPluginSession->AcquireSAError( sa_data, aError );
+			}
+		}
+    iAcquirePending = EFalse;
+	}
+
+//Will update the outbound
+void CIkev1Negotiation::UpdateSADatabaseL()
+{
+#ifdef _DEBUG
+    TBuf<40> addr_buf;
+#endif    
+    TUint8 sa_type=0;
+    TUint8 auth_alg=0;
+    TUint8 encr_alg=0;
+    TUint32 updateSPI,addSPI;
+    TIpsecSAData sa_data;
+    TBool   TunnelMode;
+	//
+    // Received Phase II key (Might be Auth + Encr keys)
+	// (Buffers are allocated for max 1024 bits key material
+	HBufC8* outboundKey_II = HBufC8::NewLC(128);
+	HBufC8* inboundKey_II  = HBufC8::NewLC(128);     	
+    TPtrC8 in_authKey(0,0), out_authKey(0,0);
+    TPtrC8 in_encrKey(0,0), out_encrKey(0,0);
+    //Identities
+#ifdef _UNICODE	
+	TBuf<80> id_work;
+#endif						
+	HBufC8* local_id   = HBufC8::NewLC(128);
+	HBufC8* remote_id  = HBufC8::NewLC(128);
+    // ESP UDP Encapsulation extension data	
+	HBufC8* gen_ext_data = HBufC8::NewLC(128);     	
+	TPtr8 GenExtData((TUint8*)gen_ext_data->Ptr(), 0, gen_ext_data->Des().MaxLength());
+	
+	DEBUG_LOG(_L("---UPDATING SAD---"));	
+	
+    if ((!iDefaultLocalID) && (iLocalIDType_II != 0))
+    {
+        switch (iLocalIDType_II)
+        {   
+        case ID_IPV4_ADDR:
+        case ID_IPV6_ADDR:
+#ifdef _UNICODE				
+            iLocalAddr1_ID_II.OutputWithScope(id_work);
+			local_id->Des().Copy(id_work);			
+#else
+			iLocalAddr1_ID_II.OutputWithScope(local_id->Des());			
+#endif			
+            break;
+			
+        case ID_IPV4_ADDR_SUBNET:
+        case ID_IPV6_ADDR_SUBNET:
+#ifdef _UNICODE							
+            iLocalAddr1_ID_II.OutputWithScope(id_work);
+			local_id->Des().Copy(id_work);			
+#else
+			iLocalAddr1_ID_II.OutputWithScope(local_id->Des());			
+#endif						
+            local_id->Des().AppendFormat(_L8("/%d"),PrefixLen(iLocalAddr2_ID_II));  //PrefixLen can't fail because checked before
+            break;
+        default:    //Should never come here
+            DEBUG_LOG1(_L("Local ID type %d not supported"), iLocalIDType_II);
+			CleanupStack::PopAndDestroy(5);  //key buffer, identities and ESP UDP encaps data
+            return;
+        }
+    }
+
+    if ((!iDefaultRemoteID) && (iRemoteIDType_II != 0) )
+    {
+        switch (iRemoteIDType_II)
+        {   
+        case ID_IPV4_ADDR:
+        case ID_IPV6_ADDR:
+#ifdef _UNICODE				
+			iRemoteAddr1_ID_II.OutputWithScope(id_work);
+			remote_id->Des().Copy(id_work);			
+#else
+			iRemoteAddr1_ID_II.OutputWithScope(remote_id->Des());			
+#endif
+			if ( iSwapRemoteIdType )
+			{
+			   if ( iRemoteIDType_II == ID_IPV4_ADDR )
+				    remote_id->Des().AppendFormat(_L8("/%d"), 32);
+			   else remote_id->Des().AppendFormat(_L8("/%d"), 128);
+			}	
+            break;
+			
+        case ID_IPV4_ADDR_SUBNET:
+        case ID_IPV6_ADDR_SUBNET:
+#ifdef _UNICODE				
+			iRemoteAddr1_ID_II.OutputWithScope(id_work);
+			remote_id->Des().Copy(id_work);			
+#else
+			iRemoteAddr1_ID_II.OutputWithScope(remote_id->Des());			
+#endif
+			if ( !iSwapRemoteIdType )
+               remote_id->Des().AppendFormat(_L8("/%d"),PrefixLen(iRemoteAddr2_ID_II));    //PrefixLen can't fail because checked before
+            break;
+			
+        default:    //Should never come here
+            DEBUG_LOG1(_L("Remote ID type %d not supported"), iRemoteIDType_II);
+			CleanupStack::PopAndDestroy(5);  //key buffer, identities and ESP UDP encaps data					
+            return;
+        }
+    }
+
+    TUint32 flags = 0;
+    if (iPFS)
+    {
+        flags = SADB_SAFLAGS_PFS;
+        DEBUG_LOG(_L("PFS enabled"));
+    }
+
+    TUint32 addPID;
+    if (iRole==INITIATOR)
+        addPID = iPfkeyAcquirePID;  //Require to remove the Larval SA
+    else
+        addPID = iPluginSession->Uid();
+    
+    DEBUG_LOG2(_L("SAD seq= %d , PID= %d"), iAcquireSeq, addPID);
+
+    TInt i, j;
+    for (i = 0; i < iInboundSPIList->Count(); i++)
+    {
+        if (iInboundSPIList->At(i).iPropNum == iProposalNum)
+            break;
+    }
+
+    CProposal_II *prop;
+    TSPINode inboundspi_node;
+    TInt key_len, encr_len, auth_len;
+    TChosenAttrib_II *attr_II;
+    TInt count = iChosenProp_IIList->Count();
+
+    for (j = 0 ; j < count; j++)
+    {
+        prop = iChosenProp_IIList->At(j);
+        inboundspi_node = iInboundSPIList->At(i);
+        attr_II = (TChosenAttrib_II *)prop->iAttrList->At(0);   //only 1 transform is chosen no matter how many there are
+        if (prop->iProtocol == PROTO_IPSEC_AH)
+        {
+            
+            sa_type  = SADB_SATYPE_AH;
+            encr_alg = 0;
+            auth_alg = attr_II->iTransformID;
+			auth_len = (TInt)HMAC_KeyLength((TUint8)auth_alg);
+			
+			TPtr8 AHOutKey((TUint8*)outboundKey_II->Ptr(), 0, outboundKey_II->Des().MaxLength());
+			TPtr8 AHInKey((TUint8*)inboundKey_II->Ptr(), 0, inboundKey_II->Des().MaxLength());
+			
+            ComputeKeys2L(prop, auth_len, inboundspi_node, AHOutKey, AHInKey);
+            in_encrKey.Set(NULL, 0);
+            out_encrKey.Set(NULL, 0);
+            in_authKey.Set(inboundKey_II->Ptr(), auth_len/8);
+            out_authKey.Set(outboundKey_II->Ptr(),auth_len/8);
+        }
+        else if (prop->iProtocol == PROTO_IPSEC_ESP)
+        {
+            sa_type = SADB_SATYPE_ESP;
+            encr_alg = attr_II->iTransformID;
+            if (attr_II->iKeyLength!=0)
+                encr_len = attr_II->iKeyLength;
+            else    //not sent means constant size or variable and use default
+            {
+				switch ( encr_alg )
+				{
+					case ESP_DES_CBC:
+						encr_len = 64;
+						break;
+					case ESP_3DES_CBC:
+						encr_len = 3*64;
+						break;
+					case ESP_NULL:
+						encr_len = 0;
+						break;
+					case ESP_AES_CBC:
+						encr_len = 128;
+						break;
+					default:	
+						encr_len = 0;
+						break;
+						
+				}	
+            }
+
+            if (attr_II->iAuthAlg==DOI_HMAC_MD5)
+                auth_alg = SADB_AALG_MD5HMAC;
+            else if (attr_II->iAuthAlg==DOI_HMAC_SHA)
+                auth_alg = SADB_AALG_SHA1HMAC;
+            else
+                auth_alg = 0;
+
+            auth_len = (TInt)HMAC_KeyLength((TUint8)auth_alg);
+            key_len = encr_len + auth_len;
+
+			TPtr8 ESPOutKey((TUint8*)outboundKey_II->Ptr(), 0, outboundKey_II->Des().MaxLength());
+			TPtr8 ESPInKey((TUint8*)inboundKey_II->Ptr(), 0, inboundKey_II->Des().MaxLength());			
+            ComputeKeys2L(prop, key_len, inboundspi_node, ESPOutKey, ESPInKey);
+
+            in_encrKey.Set(inboundKey_II->Ptr(), encr_len/8);
+            out_encrKey.Set(outboundKey_II->Ptr(), encr_len/8);
+
+            //If no HMAC selected the next instr does nothing because size will be 0
+            in_authKey.Set(inboundKey_II->Ptr() + in_encrKey.Length(),auth_len/8);
+            out_authKey.Set(outboundKey_II->Ptr() + out_encrKey.Length(),auth_len/8);
+            //
+            // Nokia specific NAT traversal info (=ESP UDP tunneling)  
+            // If iNAT_T_Required is true connection is over NAT:ted
+            // newtork (=local end behind NAT).
+			//
+            if ( iNAT_T_Required ) {
+               flags |= SADB_SAFLAGS_NAT_T;
+            }
+        }
+        else
+		{	
+			DEBUG_LOG1(_L("Unknown IPsec protocol %d"), prop->iProtocol);
+			CleanupStack::PopAndDestroy(5);  //key buffer, identities and ESP UDP encaps data					
+			return;
+		}	
+
+        updateSPI = inboundspi_node.iSPI;
+        Mem::Copy((TUint8*)&addSPI, prop->iSPI.Ptr(), sizeof(TUint32));
+
+        TInetAddr local_addr(iLocalAddr);
+        local_addr.SetPort(iIDLocalPort);
+        TInetAddr remote_addr(iRemoteAddr);    
+        remote_addr.SetPort(iIDRemotePort);
+    
+        //This will be always outbound
+        
+        TInt64 time(0), bytes(0);
+        TPtrC8 time_ptr(attr_II->iLifeDurationSecs);
+        TPtrC8 bytes_ptr(attr_II->iLifeDurationKBytes);
+        if (attr_II->iReducedLifeSecs.Length() != 0)
+            time_ptr.Set(attr_II->iReducedLifeSecs);
+
+        if (attr_II->iReducedLifeKBytes.Length() != 0)
+            bytes_ptr.Set(attr_II->iReducedLifeKBytes);
+
+        ComputeLifetimes_II(time_ptr, bytes_ptr, time, bytes);
+        if (time == 0)  //default lifetime applied
+            time = DEFAULT_IPSEC_SA_LIFETIME;
+        
+        if (iHardLifetime > time)
+            {
+            DEBUG_LOG2(_L("Time %u, hard lifetime %d"),
+                    I64LOW(time), I64LOW(iHardLifetime));
+            time = iHardLifetime;
+            }
+
+        if (attr_II->iEncMode==DOI_TUNNEL)
+        {
+            TunnelMode = ETrue;
+            DEBUG_LOG(_L("TUNNEL MODE"));
+#ifdef _DEBUG            
+            iLocalAddr1_ID_II.OutputWithScope(addr_buf);
+            DEBUG_LOG1(_L("Local ID: net %S"), &addr_buf);
+            
+            if ((iLocalIDType_II == ID_IPV4_ADDR_SUBNET) || (iLocalIDType_II == ID_IPV6_ADDR_SUBNET))
+                {
+                iLocalAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG1(_L(", mask %S"), &addr_buf);
+                }
+            DEBUG_LOG1(_L(" (port %d)"), iIDLocalPort);
+            iRemoteAddr1_ID_II.OutputWithScope(addr_buf);
+            DEBUG_LOG1(_L("Remote ID: addr %S"), &addr_buf);
+            if ((iRemoteIDType_II == ID_IPV4_ADDR_SUBNET) || (iRemoteIDType_II == ID_IPV6_ADDR_SUBNET))
+                {
+                iRemoteAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG1(_L(", mask %S"), &addr_buf);
+                }
+            DEBUG_LOG1(_L(" (port %d)"), iIDRemotePort);
+#endif // _DEBUG            
+            
+        }
+        else {
+            TunnelMode = EFalse;        
+            DEBUG_LOG(_L("TRANSPORT MODE"));
+        }
+        DEBUG_LOG1(_L("Sec Lifetime set to %u"),I64LOW(time));
+        DEBUG_LOG1(_L("KB Lifetime set to %u"),I64LOW(bytes));
+
+        //Inbound SA.
+        sa_data.iSAType = sa_type;
+        sa_data.iSeq = iAcquireSeq;
+        sa_data.iSrc = remote_addr;
+        sa_data.iDst = local_addr;
+        sa_data.iProtocol = iIDProtocol;
+        sa_data.iSrcIdType = iRemoteIDType_II;
+        sa_data.iDstIdType = iLocalIDType_II;       
+        sa_data.iSrcIdent.Set((TUint8 *)remote_id->Ptr(), remote_id->Length(), remote_id->Length());
+        sa_data.iDstIdent.Set((TUint8 *)local_id->Ptr(), local_id->Length(), local_id->Length());
+        sa_data.iPid = iPluginSession->Uid();
+        sa_data.iSPI = updateSPI;
+        sa_data.iAuthAlg = auth_alg;
+        sa_data.iEncrAlg = encr_alg;
+        sa_data.iAuthKey.Set(in_authKey);
+        sa_data.iEncrKey.Set(in_encrKey);
+        TIpsecSALifetime lifetime(0, bytes, time, 0);
+        sa_data.iHard = &lifetime;
+        sa_data.iReplayWindowLength = prop->iReplayWindowLength;
+
+        if ( (sa_type == SADB_SATYPE_ESP) && (GenExtData.Length() == 0) ) {     
+           //
+           // Store possible NAT traversal info for IPSEC to do ESP UDP encapsulation correctly
+           //
+            PFKeyExtDataUtil::BuildUdpEncExtensionData( GenExtData,
+                                                        iNAT_D_Flags,
+                                                        (flags & SADB_SAFLAGS_NAT_T),
+                                                        iHostData->iUseNatProbing,
+                                                        (TUint16)iHostData->iEspUdpPort, 
+                                                        UDP_KEEPALIVE_TIME,
+                                                        iLastRemoteAddr,
+                                                        iRemoteOriginalAddr );
+        }
+        
+        if ( GenExtData.Length() ) {
+           sa_data.iGenericExtension.Set(GenExtData);      
+        }
+
+        if ( TunnelMode ) {
+           //
+           // Get VPN interface index 
+           //
+           TUint32 vpnInterfaceIndex = iPluginSession->VpnInterfaceIndex();
+           if ( vpnInterfaceIndex != 0 )
+               {
+               sa_data.iInternalAddress.Init( KAfInet6 );
+               sa_data.iInternalAddress.SetScope( vpnInterfaceIndex );
+               flags |= SADB_SAFLAGS_INT_ADDR;
+               }
+           }
+        sa_data.iFlags = flags;
+		iPluginSession->UpdateSAL(sa_data);
+		TIpsecSPI SpiData;
+		SpiData.iProtocol = sa_type;
+		SpiData.iSrcAddr  = remote_addr;
+		SpiData.iDstAddr  = local_addr;
+		SpiData.iSPI      = updateSPI;
+		SpiData.iInbound  = ETrue;
+		iPluginSession->AddIpsecSPIToSAL(iSAId, SpiData);
+
+        sa_data.iFlags &= ~SADB_SAFLAGS_INT_ADDR; //No VPN interface index to outbound SA
+        //Outbound SA.
+        //First check there's no other SA with the same parameters and
+        //erase it if happens (very unlikely, but still possible)
+		SpiData.iDstAddr = remote_addr;
+		SpiData.iSrcAddr = local_addr;
+		SpiData.iSPI     = addSPI;
+		SpiData.iInbound = EFalse;
+		if ( iPluginSession->DeleteIpsecSpi(iSAId, addSPI, EFalse) )		
+        {
+            DEBUG_LOG(_L("Deleting previously negotiated IPsec SA"));
+			iPluginSession->DeleteIpsecSA(SpiData.iSPI, SpiData.iSrcAddr, SpiData.iDstAddr, 
+                                              SpiData.iProtocol);
+        }
+        //Some changes in the SA, the rest is the same
+        sa_data.iSrc = local_addr;
+        sa_data.iDst = remote_addr;
+        sa_data.iSrcIdType = iLocalIDType_II;
+        sa_data.iDstIdType = iRemoteIDType_II;
+        sa_data.iSrcIdent.Set((TUint8 *)local_id->Ptr(), local_id->Length(), local_id->Length());
+        sa_data.iDstIdent.Set((TUint8 *)remote_id->Ptr(), remote_id->Length(), remote_id->Length());
+        sa_data.iPid = addPID;
+        sa_data.iSPI = addSPI;
+        sa_data.iAuthKey.Set(out_authKey);
+        sa_data.iEncrKey.Set(out_encrKey);
+        
+        iPluginSession->AddSAL(sa_data);
+		iPluginSession->AddIpsecSPIToSAL(iSAId, SpiData);
+        
+        i++;    //To get the correct SPIs from iInboundSPIList
+	} //end for
+
+	CleanupStack::PopAndDestroy(5);  //key buffer, identities and ESP UDP encaps data
+	
+	iAcquirePending = EFalse;
+	
+}
+
+void CIkev1Negotiation::ComputeLifetimes_II(const TDesC8 &aLifetime, const TDesC8 &aLifesize, TInt64 &aTime, TInt64 &aBytes)
+{
+    TInt64 maxnum = MAKE_TINT64(0x7fffffffu, 0xffffffffu);
+        
+    if (Desc8ToTInt64(aLifetime, aTime) != KErrNone)
+        {
+        DEBUG_LOG(_L("Phase_II Lifetime(sec) Overflowed Setting to maximum value"));
+        }
+    if (Desc8ToTInt64(aLifesize, aBytes) != KErrNone) {
+        DEBUG_LOG(_L("Phase_II Lifetime(kbytes) Overflowed Setting to maximum value"));
+    }       
+    else 
+    {   if (aBytes < maxnum / 1024) //Make sure no overflow
+            aBytes = aBytes * 1024; //KB to Bytes
+        else
+        {
+            aBytes = MAKE_TINT64(KMaxTInt, KMaxTUint);            
+            DEBUG_LOG(_L("Phase_II Lifetime(kbytes) Overflowed Setting to maximum value"));
+        }
+    }
+
+}
+
+
+TBool CIkev1Negotiation::Phase_IExchangeL(const ThdrISAKMP &aHdr)
+{       
+    if (!ProcessHeaderL(aHdr))
+        return EFalse;
+
+    DEBUG_LOG2(_L("---------- Phase %d - Stage %d ----------"),iPhase, iStage);
+    if (iPhase == PHASE_I)
+    {
+        if (aHdr.GetExchange() == ISAKMP_EXCHANGE_ID)
+            MainModeReplyL();   //Main Mode
+        else
+            AggressiveReplyL(); //Aggressive Mode
+    }
+    else
+    {
+        QuickModeReplyL();
+    }
+    return ETrue;
+}
+
+TBool CIkev1Negotiation::Phase_IIExchangeL(const ThdrISAKMP &aHdr)
+{       
+    if (!ProcessHeaderL(aHdr))
+        return EFalse;
+
+    DEBUG_LOG2(_L("---------- Phase %d - Stage %d ----------"),iPhase, iStage);
+
+    QuickModeReplyL();
+
+    return ETrue;
+}
+
+void CIkev1Negotiation::QuickModeReplyL()
+{
+
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );	
+    switch(iStage)
+    {
+    //INITIATOR cases
+    case 3: //Send last message (if no COMMIT)
+        msg->IsakmpInit(this);
+        msg->IsakmpHashL();
+        SendL(*msg);
+        iStage = 4;  
+
+        if (iRecvFlags & ISAKMP_HDR_CFLAG)  //Commit Bit set
+             return; //Not finished yet. We wait for CONNECTED
+        
+        //No Commot bit, Update SA database
+        UpdateSADatabaseL();
+        SetFinished();    //No more stages.
+        break;
+	case 1: 
+		DEBUG_LOG(_L("QuickModeReplyL in Stage 1 ?"));		
+		break;
+    case 5: //Send last message (extra message waiting for commit(
+        //No more processing required
+        SetFinished();    //No more stages.
+        break;
+    //RESPONDER cases
+    case 2:
+        GetSPIL();
+        //rest done in receiveSPI
+        break;
+    case 4:
+        if (iRecvFlags & ISAKMP_HDR_CFLAG)  //Commit Bit set
+        {
+            DEBUG_LOG(_L("Sending CONNECTED Status message"));
+            msg->IsakmpInit(this);
+
+            //HASH Payload only if payload protected with encryption
+            if (iFlags & ISAKMP_HDR_EFLAG)
+                msg->IsakmpHashL();
+        
+            msg->IsakmpNotification(CONNECTED, iChosenProp_IIList->At(0)->iProtocol);
+
+            if (iFlags & ISAKMP_HDR_EFLAG)
+                msg->IsakmpHashContL();
+                
+            SendL(*msg);
+        }
+        SetFinished();
+        break;
+    }
+}
+
+//Builds and sends a Phase I reply for Main Mode
+void CIkev1Negotiation::MainModeReplyL()
+{
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );		
+    TInt          vendor_type;
+ 
+    switch(iStage)
+    {
+    //
+    //RESPONDER replies
+    //
+    case 2: 
+        msg->IsakmpInit(this);
+        msg->IsakmpSa();
+        if ( iHostData->iDPDHeartBeat != 0 )
+           BuildDPDVendorId(*msg);        
+        if ( iNatDiscovery ) {
+           iNatDiscovery->BuildNatVendorId(*msg); 
+           iNatDiscovery->BuildRfcNatVendorId(*msg);
+        }   
+        SendL(*msg);
+        iStage = 3;
+        break;
+    case 4:
+        ComputeNonceL();         //Nonce to be sent
+        msg->IsakmpInit(this);
+        msg->IsakmpKeyL();
+        msg->IsakmpNonce();
+        if (((iChosenProposal_I.iAttrList->iAuthMethod == RSA_SIG) ||
+             (iChosenProposal_I.iAttrList->iAuthMethod == DSS_SIG)) && !iPeerX509Cert)
+           msg->IsakmpCertificateReqL();
+		if ( iNatDiscovery ) {
+			iNatDiscovery->BuildDiscoveryPayloadsL(*msg, iChosenProposal_I.iAttrList->iHashAlg,
+				                                  (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+				                                  iLocalAddr, iLastRemoteAddr);    
+		}
+		SendL(*msg);
+        iStage = 5; //next stage
+        iFlags |= ISAKMP_HDR_EFLAG; //From now on encryption is used
+        if (!ComputeKeysL())    //Generates keying material for encryption stages
+            return; //error don't send reply packet
+        break;
+    case 6:
+        msg->IsakmpInit(this);
+        
+        switch(iChosenProposal_I.iAttrList->iAuthMethod)
+        {
+        case RSA_SIG:
+        case DSS_SIG:
+            msg->IsakmpOwnIdentL();
+            msg->IsakmpCertificateL();
+            msg->IsakmpSignatureL();
+            break;
+        case PRE_SHARED:
+            msg->IsakmpOwnIdentL();
+            msg->IsakmpHashL();
+            break;
+        }
+        
+        if ( iHostData->iInitialContact &&   
+             iRole == INITIATOR &&
+             iSARekeyInfo == NULL ) 
+        {
+           DEBUG_LOG(_L("Constructing INITIAL-CONTACT"));
+           msg->IsakmpNotification(DOI_INITIAL_CONTACT, PROTO_ISAKMP); //Not protected by the hash!
+        }
+        
+        SendL(*msg);
+
+		IsakmpPhase1CompletedL();
+        break;
+    //
+    //INITIATOR replies
+    //
+    case 3:
+        ComputeNonceL();         //Nonce to be sent
+        msg->IsakmpInit(this);
+        msg->IsakmpKeyL();
+        msg->IsakmpNonce();
+        if ( iChosenProposal_I.iAttrList->iAuthMethod == IKE_A_CRACK && !iPeerX509Cert )
+		{
+            msg->IsakmpCertificateReqL();
+        }
+        if ( iHostData->iUseNatProbing )
+             vendor_type = EXPANDED_VENDOR_ID;
+        else vendor_type = HASH_VENDOR_ID;
+        msg->IsakmpVendorId(vendor_type,       
+                              (TUint8*)iCookie_I.Ptr(),
+                              (TUint8*)iCookie_R.Ptr(), iLocalAddr);
+        if ( iNatDiscovery )
+		{
+           iNatDiscovery->BuildDiscoveryPayloadsL(*msg, iChosenProposal_I.iAttrList->iHashAlg,
+                                                 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+                                                 iLocalAddr, iLastRemoteAddr);    
+        }   
+        SendL(*msg);
+        iStage = 4; //next stage
+        break;
+
+    case 5:
+        iFlags |= ISAKMP_HDR_EFLAG; //From now on encryption is used
+        if (!ComputeKeysL())    //Generates keying material for encryption stages
+            return; //error don't send reply packet
+        
+        msg->IsakmpInit(this);
+        
+        switch(iChosenProposal_I.iAttrList->iAuthMethod)
+        {
+        case RSA_SIG:
+        case DSS_SIG:
+            msg->IsakmpOwnIdentL(); //Also fills iOwnIdentPayload!
+            msg->IsakmpCertificateL();
+            msg->IsakmpSignatureL();
+            if (!iPeerX509Cert)
+               msg->IsakmpCertificateReqL(); 
+            break;
+        case PRE_SHARED:
+            msg->IsakmpOwnIdentL();
+            msg->IsakmpHashL();
+            break;
+        }
+        
+        
+        if ( iFamiliarPeer && iHostData->iUseInternalAddr )
+           msg->IsakmpIntnet(0);  /* null IPV4 address as parameter */
+
+		if ( iHostData->iInitialContact &&
+		    !iPluginSession->FindIkev1SADataWithAddr(iRemoteAddr) &&
+            iRole == INITIATOR &&
+		    iSARekeyInfo == NULL ) 
+		{
+			DEBUG_LOG(_L("Constructing INITIAL-CONTACT"));
+			msg->IsakmpNotification(DOI_INITIAL_CONTACT, PROTO_ISAKMP); //Not protected by the hash!
+		}
+		
+        SendL(*msg);
+        iStage = 6; //next stage
+        
+        break;
+    case 7:
+        // CRACK authentication going. No actions required here !
+        break;
+    default:
+        DEBUG_LOG1(_L("Main mode Wrong Phase number requested (%d) !!"),iStage);
+    }
+
+}
+
+
+//Builds and sends a Phase I reply for Aggressive Mode
+void CIkev1Negotiation::AggressiveReplyL()
+{
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );			
+	
+    switch(iStage)
+    {
+    case 2://RESPONDER Sends the 2nd msg. of the exchange
+        ComputeNonceL();         //Nonce to be sent
+        msg->IsakmpInit(this);
+        msg->IsakmpSa();
+        msg->IsakmpKeyL();
+        msg->IsakmpNonce();
+        msg->IsakmpOwnIdentL();
+        
+        if (!ComputeKeysL()) //Needed to compute hash before computing signature
+		{
+		   return;
+		}   
+        
+        if ( iHostData->iDPDHeartBeat != 0 )
+           BuildDPDVendorId(*msg);        
+        if ( iNatDiscovery ) {
+           iNatDiscovery->BuildNatVendorId(*msg);
+           iNatDiscovery->BuildRfcNatVendorId(*msg);
+           iNatDiscovery->BuildDiscoveryPayloadsL(*msg, iChosenProposal_I.iAttrList->iHashAlg,
+                                                 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+                                                 iLocalAddr, iLastRemoteAddr);    
+        }   
+        
+        switch (iChosenProposal_I.iAttrList->iAuthMethod)
+        {
+        case RSA_SIG:
+        case DSS_SIG:
+            msg->IsakmpCertificateL();
+            msg->IsakmpSignatureL();
+            if (!iPeerX509Cert) //No stored cert so send a CR
+            {
+                msg->IsakmpCertificateReqL();
+            }
+            break;
+        case PRE_SHARED:
+            msg->IsakmpHashL();
+            break;
+        }
+        SendL(*msg);
+		
+        iStage = 3; //next stage
+		
+        break;
+    case 3://INITIATOR
+        iFlags |= ISAKMP_HDR_EFLAG; //From now on encryption is used                
+        msg->IsakmpInit(this);
+        if ( iNatDiscovery ) {
+           iNatDiscovery->BuildDiscoveryPayloadsL(*msg, iChosenProposal_I.iAttrList->iHashAlg,
+                                                 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+                                                 iLocalAddr, iLastRemoteAddr);    
+        }   
+        
+        switch (iChosenProposal_I.iAttrList->iAuthMethod)
+        {
+        case RSA_SIG:
+        case DSS_SIG:
+            msg->IsakmpCertificateL();   
+            msg->IsakmpSignatureL(); 
+            break;
+        case PRE_SHARED:
+            msg->IsakmpHashL();
+            break;
+        }
+		if ( iHostData->iInitialContact &&
+		     !iPluginSession->FindIkev1SADataWithAddr(iRemoteAddr) &&
+             iRole == INITIATOR &&
+		     iSARekeyInfo == NULL ) //Only sent if no ISAKMP SA established
+		{
+			DEBUG_LOG(_L("Constructing INITIAL-CONTACT"));
+			msg->IsakmpNotification(DOI_INITIAL_CONTACT, PROTO_ISAKMP); //Not protected by the hash!
+		}
+
+        SendL(*msg);
+        IsakmpPhase1CompletedL();       
+        break;
+	case 4:
+		// Aggressive mode as responder completed
+		DEBUG_LOG(_L("Aggressive mode as responder completed"));		
+		break;
+		
+    case 7:
+        // CRACK authentication going. No actions required here !
+        break;
+    default:
+        DEBUG_LOG1(_L("Main mode Wrong Phase number requested (%d) !! "),iStage);
+    }
+	
+}
+
+void CIkev1Negotiation::SaveISAKMPSAL()
+{
+	//
+	// Create a new IKEv1 SA object       
+	//
+	TIkev1SAData SaData;
+	SaData.iCookie_I       = iCookie_I;
+	SaData.iCookie_R       = iCookie_R;
+	SaData.iSAId           = iSAId;
+	SaData.iSAState        = 0;
+	SaData.iInitiator      = (iRole == INITIATOR);
+	SaData.iAutoLogin      = iAutoLogin;
+	SaData.iDPDSupported   = iDPDSupported;
+	SaData.iFamiliarPeer   = iFamiliarPeer;
+	SaData.iNAT_T_Required = iNAT_T_Required;
+	SaData.iNAT_D_Flags    = iNAT_D_Flags;
+	SaData.iIkeData        = iHostData;
+	SaData.iLocalAddr      = iLocalAddr;
+	SaData.iRemoteAddr     = iRemoteAddr;
+	SaData.iDestinAddr     = iLastRemoteAddr;
+	SaData.iVirtualIp      = iInternalAddr;
+	SaData.iSeq            = iSeq;
+	SaData.iPrevExchange   = iPrevExchange;
+	SaData.iFlags          = iFlags;
+	
+	SaData.iEncrAlg        = iChosenProposal_I.iAttrList->iEncrAlg;
+	SaData.iHashAlg        = iChosenProposal_I.iAttrList->iHashAlg;
+	SaData.iGroupDesc      = iChosenProposal_I.iAttrList->iGroupDesc;
+	SaData.iGroupType      = iChosenProposal_I.iAttrList->iGroupType;				
+	SaData.iKeyLength      = iChosenProposal_I.iAttrList->iKeyLength;
+
+	TUint32 Lifetime = 0;
+	TUint Len = iChosenProposal_I.iAttrList->iLifeDurationSecs.Length();
+	if (Len > 0)
+	{
+		if (Len > sizeof(TUint32))
+		{
+			Lifetime = KMaxTUint32;
+		}
+		else    // (len <= sizeof(TUint32))
+		{
+			Mem::Copy(&Lifetime, iChosenProposal_I.iAttrList->iLifeDurationSecs.Ptr(), Len);
+			Lifetime = ByteOrder::Swap32(Lifetime);
+			Lifetime = Lifetime >> (sizeof(TUint32)*8 - Len*8);   //To set the correct value (shift in bits)
+		}
+	}
+	SaData.iLifeTimeSecs = Lifetime;
+	
+	Lifetime = 0;
+	Len = iChosenProposal_I.iAttrList->iLifeDurationKBytes.Length();
+	if (Len > 0)
+	{
+		if (Len > sizeof(TUint32))
+		{
+			Lifetime = KMaxTUint32;
+		}
+		else    // (len <= sizeof(TUint32))
+		{
+			Mem::Copy(&Lifetime, iChosenProposal_I.iAttrList->iLifeDurationKBytes.Ptr(), Len);
+			Lifetime = ByteOrder::Swap32(Lifetime);
+			Lifetime = Lifetime >> (sizeof(TUint32)*8 - Len*8);   //To set the correct value (shift in bits)
+		}
+	}
+	SaData.iLifeTimeKB = Lifetime;
+
+	SaData.iSKEYID     = iSKEYID;
+	SaData.iSKEYID_d   = iSKEYID_d;
+	SaData.iSKEYID_a   = iSKEYID_a;
+	SaData.iSKEYID_e   = iSKEYID_e;
+	SaData.iLastIV     = iLastIV;
+	SaData.iIV         = iIV;
+
+	if ( iDPDSupported && iHostData->iDPDHeartBeat )
+	{
+	   //
+	   //  Initialize DPD protocol parameters in TIkev1SAData
+	   //
+		TPtr8 ptr((TUint8*)&SaData.iDPDSequence, sizeof(TUint32));	 
+		ptr.SetLength(sizeof(TUint32));
+		TRandom::RandomL(ptr);	
+		SaData.iDPDSequence &= 0x7fffffff;
+		SaData.iDPDRetry = 0;
+		SaData.iPendingDPDSequence  = 0;
+		SaData.iExpectedDPDSequence = 0;		
+	}	
+		
+	iLastIKEMsgInfo.Store(SaData.iLastIKEMsgInfo);
+    SaData.iLastMsg = iLastMsg;
+	iPluginSession->CreateIkev1SAL(SaData, iSARekeyInfo);   // Add rekey info later
+}
+
+TBool CIkev1Negotiation::ProcessHeaderL(const ThdrISAKMP &aHdr)
+{
+    //checks on the header    
+    if (!CheckCookies(aHdr.GetCookieI(), aHdr.GetCookieR()))
+        return EFalse;
+
+    if (iStage == 1)
+    {
+        if (iPhase == PHASE_I)
+        {
+            iCookie_I = aHdr.GetCookieI();  //save initiator cookie
+            iCookie_R = CreateCookieL(); //create responder cookie
+        }
+        iMessageId = aHdr.GetMessageId();
+    }
+    
+    //checks on the header    
+    if (!CheckPayloadCode(aHdr.GetPayload()))
+        return EFalse;
+
+    if (!CheckVersionL(aHdr.GetVersion()))
+        return EFalse;
+    
+    if (!CheckExchangeTypeL(aHdr.GetExchange()))
+        return EFalse;
+
+    if (!CheckFlagsL(aHdr.GetFlags()))
+        return EFalse;
+    iRecvFlags = aHdr.GetFlags();   //Save the flags for later use
+
+    if (!CheckMessageIdL(aHdr.GetMessageId()))
+        return EFalse;
+
+    iLengthLeft -= ISAKMP_HEADER_SIZE;  //Updates the length left in the buffer
+
+    //EVEN stages RESPONDER, ODD ones INITIATOR
+    DEBUG_LOG(_L("Processing packet..."));
+    if (iPhase == PHASE_I)
+    {
+        switch (iStage)
+        {
+            case 1:
+                if (!ProcessStage1L(aHdr))
+                    return EFalse;
+                break;
+            case 2:
+                if (!ProcessStage2L(aHdr))
+                    return EFalse;
+                break;
+            case 3:
+                if (iExchange == ISAKMP_EXCHANGE_ID)
+                {
+                    if (!ProcessStage3MainL(aHdr))
+                        return EFalse;
+                }
+                else    //ISAKMP_EXCHANGE_AGGR
+                {
+                    if (!ProcessStage3AggrL(aHdr))
+                        return EFalse;
+                }
+                break;
+            case 4:
+                if (!ProcessStage4L(aHdr))
+                    return EFalse;
+                break;
+            case 5:
+                if (!ProcessStage5L(aHdr))
+                    return EFalse;
+                break;
+            case 6:
+                if (!ProcessStage6L(aHdr))
+                    return EFalse;
+                break;
+            case 7:
+                if (!ProcessStage7L(aHdr))   /* For CRACK negotiation */
+                    return EFalse;
+                break;
+            default:
+                return EFalse;
+        }
+    }
+    else    //PHASE_II
+    {
+        switch (iStage)
+        {
+            case 1:
+                if (!ProcessStage1Phase2L(aHdr))
+                    return EFalse;
+                break;
+            case 2:
+                if (!ProcessStage2Phase2L(aHdr))
+                    return EFalse;
+                break;
+            case 3:
+                if (!ProcessStage3Phase2L(aHdr))
+                    return EFalse;
+                break;
+            case 4:
+                if (!ProcessCONNECTEDL(aHdr))
+                    return EFalse;
+                break;
+            default:
+                DEBUG_LOG(_L("Quick Bad Stage"));
+        }
+    }
+    return ETrue;
+}
+
+//Process payloads appearing in Stage 1. Responder Role
+TBool CIkev1Negotiation::ProcessStage1L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+	   return EFalse;	
+
+	CleanupStack::PushL(payload);
+	
+    //SA Payload processing (all modes)
+    if (!ProcessSAL(payload->iSa, NULL))
+    {
+		CleanupStack::PopAndDestroy();  //payload
+        return EFalse;
+    }
+
+	//Process vendor ID:s  
+	ProcessVendorL(payload->iVids);
+	
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+	
+	switch (auth_method)
+	{
+		case RSA_SIG:
+		case DSS_SIG:
+			//Process the possible CR payloads
+			if ( !ProcessCertificateReqArrayL(payload->iCertReqs) ) {
+				CleanupStack::PopAndDestroy();  //payload
+				return EFalse;
+			}
+			//Process the possible CERT payloads
+			if ( !ProcessCertificateArrayL(payload->iCerts) ) {
+				CleanupStack::PopAndDestroy();  //payload
+				return EFalse;
+			}
+			break;
+
+		default:
+			break;
+	}
+
+	
+    if (iExchange == ISAKMP_EXCHANGE_ID)
+    {
+		if ( payload->iKe || payload->iNonce || payload->iHash || payload->iSign ||
+			 payload->iIds->Count() )
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}	
+    }
+    else //ISAKMP_EXCHANGE_AGGR
+    {
+		if ( !payload->iKe || !payload->iNonce || (payload->iIds->Count() != 1) )
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}	
+		
+        //Key Payload processing (all modes)
+        if (!ProcessKeyL(payload->iKe))
+        {
+            CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+		TIdentISAKMP* id_payload    = (TIdentISAKMP*)payload->iIds->At(0);  // The first ID		
+		TNonceISAKMP* nonce_payload = (TNonceISAKMP*)payload->iNonce;
+		
+        //Nonce Payload processing
+        if (!ProcessNonceL(nonce_payload))
+        {
+			CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+        //ID Payload processing
+        if (!CheckIdentL(id_payload))
+        {
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+        }
+        //Save the ident payload for HASH_I/R computing
+        delete iPeerIdentPayload;
+		iPeerIdentPayload = NULL;
+        iPeerIdentPayloadSize = id_payload->GetLength() - sizeof(TPayloadISAKMP);
+        iPeerIdentPayload = new (ELeave) TUint8[iPeerIdentPayloadSize];
+        Mem::Copy(iPeerIdentPayload,((TUint8 *)id_payload)+sizeof(TPayloadISAKMP),iPeerIdentPayloadSize);
+        
+        if ( iNatDiscovery )
+		{
+		   if ( payload->iNatDs->Count() )
+		   {	   
+               iNAT_D_Flags = iNatDiscovery->CheckDiscoveryPayloadsL(payload->iNatDs, iChosenProposal_I.iAttrList->iHashAlg,
+                                                                    (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+                                                                     iLocalAddr, iLastRemoteAddr);
+		       if ( iNAT_D_Flags )
+			      iLastRemoteAddr.SetPort(FLOATED_IKE_PORT);
+		   }
+		   else
+		   {
+			   if ( iLastRemoteAddr.Port() == FLOATED_IKE_PORT )
+				   iNAT_D_Flags |= LOCAL_END_NAT; 
+		   }	   
+        }
+        
+    }//end aggressive
+
+				   
+    CleanupStack::PopAndDestroy();  //payload
+    iStage = 2;
+    return ETrue;
+    
+}
+                
+//Process payloads appearing in Stage 3. Initiator Role
+TBool CIkev1Negotiation::ProcessStage2L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+	
+	CleanupStack::PushL(payload);
+	
+	iCookie_R = aHdr.GetCookieR();    //Save the responder Cookie	
+
+    //SA Payload processing (all modes)
+    if (!ProcessSAL(payload->iSa, NULL)) {
+        CleanupStack::PopAndDestroy();  // payload
+        return EFalse;
+    }
+
+	ProcessVendorL(payload->iVids);
+	
+    if ( iAutoLogin && (iLocalAddr.Family() == KAFUnspec ) ) {
+        User::LeaveIfError( iPluginSession->GetLocalAddress( iLocalAddr ) ); //No local address, get it now (used later with NAT traversal)
+    }
+
+    //NOW we know the auth method chosen!
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+
+    switch (auth_method)
+    {
+    case RSA_SIG:
+    case DSS_SIG:
+        //Process the possible CR payloads
+        if ( !ProcessCertificateReqArrayL(payload->iCertReqs) )
+		{
+            CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+	    if (!ProcessCertificateArrayL(payload->iCerts))
+		{
+		    CleanupStack::PopAndDestroy();  //payload
+		    return EFalse;
+ 		}
+        break;
+		
+    default:
+		break;
+    }
+
+	if (iExchange == ISAKMP_EXCHANGE_ID)
+	{
+		if ( payload->iKe || payload->iNonce || payload->iHash || payload->iSign ||
+			 payload->iIds->Count() )
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}	
+	}
+    else //ISAKMP_EXCHANGE_AGGR
+    {
+		if ( !payload->iKe || 
+		     !payload->iNonce || 
+		     (!payload->iHash && auth_method == PRE_SHARED) // hash is a must only with PSK
+		     || (payload->iIds->Count() != 1) )
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}	
+        //Key Payload processing (all modes)
+        if (!ProcessKeyL(payload->iKe))
+		{
+			CleanupStack::PopAndDestroy();  //payload			
+            return EFalse;
+		}
+		TIdentISAKMP* id_payload    = (TIdentISAKMP*)payload->iIds->At(0);  // The first ID		
+		TNonceISAKMP* nonce_payload = (TNonceISAKMP*)payload->iNonce;
+		
+		//Nonce Payload processing
+		if (!ProcessNonceL(nonce_payload))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}
+		
+		//ID Payload processing
+		if (!CheckIdentL(id_payload))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}
+		
+        //Save the ident payload for HASH_I/R computing
+        delete iPeerIdentPayload;
+		iPeerIdentPayload = NULL;
+        iPeerIdentPayloadSize = id_payload->GetLength()-sizeof(TPayloadISAKMP);
+        iPeerIdentPayload = new (ELeave) TUint8[iPeerIdentPayloadSize];
+        Mem::Copy(iPeerIdentPayload,((TUint8 *)id_payload)+sizeof(TPayloadISAKMP),iPeerIdentPayloadSize);
+        
+        if (!ComputeKeysL())    //Computes the keys to be used. Needed to compute HASH_R
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}	
+			
+        switch (auth_method)
+        {
+        case PRE_SHARED:
+			if (!ProcessHashL(payload->iHash))
+			{
+				CleanupStack::PopAndDestroy();  //payload			
+				return EFalse;
+			}
+			DEBUG_LOG(_L("HASH OK!"));
+            break;
+        case RSA_SIG:
+        case DSS_SIG:
+        case IKE_A_CRACK:
+            //Signature payload processing and checking
+            if (!ProcessSignatureL(payload->iSign)) {
+				CleanupStack::PopAndDestroy();  //payload	
+                return EFalse;
+			}	
+            if ( auth_method == IKE_A_CRACK ) {
+			   CleanupStack::PopAndDestroy();  //payload					
+               return StartCRACKAuthL();
+            }
+			else {
+				if (!CertifyRemoteIdentityL(id_payload))
+				{
+					DEBUG_LOG(_L("ProcessStage2L RSA_SIG CertifyRemoteIdentityL failed"));
+					DEBUG_LOG(_L("AUTHENTICATION_FAILED"));
+					SetErrorStatus( KKmdIkeAuthFailedErr );
+					SendNotifyL(AUTHENTICATION_FAILED);
+					CleanupStack::PopAndDestroy();  //payload			
+					return EFalse;
+				}
+			}	
+            break;
+
+		default:
+			break;
+			
+		}
+		
+		if ( iNatDiscovery && payload->iNatDs->Count()) {
+			iNAT_D_Flags = iNatDiscovery->CheckDiscoveryPayloadsL(payload->iNatDs, iChosenProposal_I.iAttrList->iHashAlg,
+				                                                 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+				                                                  iLocalAddr, iLastRemoteAddr);
+			if ( iNAT_D_Flags )
+				iLastRemoteAddr.SetPort(FLOATED_IKE_PORT); 
+		}
+    }
+	
+	CleanupStack::PopAndDestroy();  //payload
+	
+    iStage = 3;
+    return ETrue;
+}
+
+// Process payloads appearing in Stage 4. Order NOT relevant. Only Main Mode
+// Handles message: HDR, KE, [HASH(1),] <IDii>PubKey_r, <Ni>PubKey_r for RSAENCR
+// Handles message: HDR, KE, Ni for the rest [CERTREQ] in certificates
+TBool CIkev1Negotiation::ProcessStage3MainL(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+	if ( payload->iSa || !payload->iNonce || payload->iHash || payload->iSign )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+	
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+	
+    //Process payloads
+    //Main mode (ONLY)
+    //Key Payload processing (all methods)
+    if (!ProcessKeyL(payload->iKe))
+    {
+        CleanupStack::PopAndDestroy();  //payload
+        return EFalse;
+    }
+
+    if ((auth_method == RSA_SIG) || (auth_method == DSS_SIG))
+    {
+        //Process the possible CR payloads
+        if ( !ProcessCertificateReqArrayL(payload->iCertReqs) )
+		{
+            CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+    }
+
+	TNonceISAKMP* nonce_payload = (TNonceISAKMP*)payload->iNonce;
+	
+	ProcessVendorL(payload->iVids);
+	
+	if ( iNatDiscovery && payload->iNatDs->Count() )
+	{ 
+		iNAT_D_Flags = iNatDiscovery->CheckDiscoveryPayloadsL(payload->iNatDs, iChosenProposal_I.iAttrList->iHashAlg,
+		                                                     (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+                                                   			  iLocalAddr, iLastRemoteAddr);
+		if ( iNAT_D_Flags )
+			iLastRemoteAddr.SetPort(FLOATED_IKE_PORT); 
+	}
+	
+    //Nonce Payload processing (all methods)
+	TBool Status = ProcessNonceL(nonce_payload);
+	if ( Status )
+	{
+	   iStage = 4;
+	}   
+	CleanupStack::PopAndDestroy();  //payload
+	
+    return Status;
+}
+
+
+//Process payloads appearing in 3(Aggressive). Order NOT relevant
+TBool CIkev1Negotiation::ProcessStage3AggrL(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+
+    //Mode-dependent processing
+    switch (auth_method)
+    {
+    case PRE_SHARED:
+        //Hash payload processing
+        if (!ProcessHashL(payload->iHash))
+		{
+			CleanupStack::PopAndDestroy();  //payload			
+            return EFalse;
+		}
+        DEBUG_LOG(_L("HASH OK!"));
+        break;
+    case RSA_SIG:
+    case DSS_SIG:
+        //Certificate payload processing
+        if (!ProcessCertificateArrayL(payload->iCerts))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+		}
+        //Signature payload processing
+        if (!ProcessSignatureL(payload->iSign))
+		{	
+			CleanupStack::PopAndDestroy();  //payload			
+            return EFalse;
+		}	
+        break;
+		
+    default:
+		break;
+    }
+
+	ProcessVendorL(payload->iVids);			
+	
+	if ( iNatDiscovery && payload->iNatDs->Count() ) { 
+		iNAT_D_Flags = iNatDiscovery->CheckDiscoveryPayloadsL(payload->iNatDs, iChosenProposal_I.iAttrList->iHashAlg,
+			                                                 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+			                                                  iLocalAddr, iLastRemoteAddr);
+		if ( iNAT_D_Flags )
+			iLastRemoteAddr.SetPort(FLOATED_IKE_PORT); 
+	}
+
+	CleanupStack::PopAndDestroy();  //payload
+	
+    iFlags |= ISAKMP_HDR_EFLAG; //From now on encryption is used
+	IsakmpPhase1CompletedL();
+	iStage = 4;                 
+    return ETrue;
+
+}
+
+
+//Process payloads appearing in Stage 5. Order NOT relevant. ONLY for MAIN Mode
+// Preshared and signatures: HDR, KE, Nr
+// RSA Encr. : HDR, <IDir>PubKey_i, <Nr_b>PubKey_i
+// RSA Revised Encr. : HDR, <Nr_b>PubKey_i , <KE_b>Ke_r, <IDir>Ke_r
+TBool CIkev1Negotiation::ProcessStage4L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+	if (  payload->iSa || !payload->iNonce || !payload->iKe )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+
+	TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;	
+
+    if ((auth_method == RSA_SIG) || (auth_method == DSS_SIG))
+    {
+        //Process the possible CR payloads
+        if ( !ProcessCertificateReqArrayL(payload->iCertReqs) )
+		{
+            CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+    }
+
+    //Key Payload processing (all methods)
+    if (!ProcessKeyL(payload->iKe))
+	{
+		CleanupStack::PopAndDestroy();  //payload		
+        return EFalse;
+	}
+	if ( auth_method != PRE_SHARED ) {
+		if (!ProcessCertificateArrayL(payload->iCerts)) {
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}
+	}	
+	TNonceISAKMP* nonce_payload = (TNonceISAKMP*)payload->iNonce;	
+	
+    //Nonce Payload processing (all modes)
+	TBool Status = ProcessNonceL(nonce_payload);
+    if (!Status)
+    {
+		CleanupStack::PopAndDestroy();  //payload
+        return EFalse;
+    }
+	ProcessVendorL(payload->iVids);
+	
+	if ( iNatDiscovery && payload->iNatDs->Count() )
+	{ 
+		iNAT_D_Flags = iNatDiscovery->CheckDiscoveryPayloadsL(payload->iNatDs, iChosenProposal_I.iAttrList->iHashAlg,
+		                                                   	 (TUint8*)iCookie_I.Ptr(), (TUint8*)iCookie_R.Ptr(),
+			                                                  iLocalAddr, iLastRemoteAddr);
+		if ( iNAT_D_Flags )
+			iLastRemoteAddr.SetPort(FLOATED_IKE_PORT); 
+	}
+
+    if ( auth_method == IKE_A_CRACK )
+	{
+       /*---------------------------------------------------
+        * Process message: HDR, [CERT], KEr, Nr, SIG
+        * - Verify CRACK signature and if OK
+        * - Initialize CRACK authentication
+        *---------------------------------------------------*/
+		Status = ComputeKeysL();
+        if ( Status )  //Generates keying material for encryption stages
+		{
+			Status = ProcessSignatureL(payload->iSign); 
+			if ( Status ) //Signature payload processing and checking
+			{
+				Status = StartCRACKAuthL();   			   
+			} 	   
+		}
+    }
+	else
+	{
+	    iStage = 5;	    
+	}	
+
+	CleanupStack::PopAndDestroy();  //payload			
+    return Status;
+}
+
+
+//Process payloads appearing in Stage 6. Order NOT relevant
+TBool CIkev1Negotiation::ProcessStage5L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+	if (  payload->iSa || payload->iNonce || payload->iKe )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+
+    TUint16 auth_method      = iChosenProposal_I.iAttrList->iAuthMethod;
+	TIdentISAKMP* id_payload = NULL;
+	// ID Payload processing (all modes)
+	if ( payload->iIds->Count() != 1 )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}
+	id_payload = (TIdentISAKMP*)payload->iIds->At(0);  // The first ID						
+	if (!CheckIdentL(id_payload))
+	{
+		CleanupStack::PopAndDestroy();  //payload						
+		return EFalse;
+	}	
+		//Save the ident payload for HASH_I/R computing
+	delete iPeerIdentPayload;
+	iPeerIdentPayload = NULL;		
+	iPeerIdentPayloadSize=id_payload->GetLength()-sizeof(TPayloadISAKMP);
+	iPeerIdentPayload = new (ELeave) TUint8[iPeerIdentPayloadSize];
+	Mem::Copy(iPeerIdentPayload,((TUint8 *)id_payload)+sizeof(TPayloadISAKMP),iPeerIdentPayloadSize);
+
+    //Mode-dependent processing
+    switch (auth_method)
+    {
+    case PRE_SHARED:
+        //Hash payload processing
+        if (!ProcessHashL(payload->iHash))
+		{
+			CleanupStack::PopAndDestroy();  //payload			
+            return EFalse;
+		}
+		DEBUG_LOG(_L("HASH OK!"));		
+        break;
+    case RSA_SIG:
+    case DSS_SIG:
+        //Certificate payload processing
+        if (!ProcessCertificateArrayL(payload->iCerts))
+		{
+			CleanupStack::PopAndDestroy();  //payload									
+            return EFalse;
+		}
+		if (!CertifyRemoteIdentityL(id_payload))
+		{
+    		DEBUG_LOG(_L("ProcessStage5L RSA_SIG CertifyRemoteIdentityL failed"));
+			DEBUG_LOG(_L("AUTHENTICATION_FAILED"));
+			SetErrorStatus( KKmdIkeAuthFailedErr );
+			SendNotifyL(AUTHENTICATION_FAILED);
+			CleanupStack::PopAndDestroy();  //payload			
+			return EFalse;
+		}
+        //Signature payload processing and checking
+        if (!ProcessSignatureL(payload->iSign))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+		}
+		//Process the possible CR payloads (needed if we are responder)
+		if ( iRole == RESPONDER )
+		{	
+		   if ( !ProcessCertificateReqArrayL(payload->iCertReqs) )
+		   {
+			  CleanupStack::PopAndDestroy();  //payload
+			  return EFalse;
+		   }
+		   if ( !iOwnCert ) 
+			   ReadOwnCertL(); // Peer does not required a specific cert. Get any
+		}   
+        break;
+		
+    default:
+		break;
+    }//end switch
+
+    // Process notification payloads
+	TInt i = 0;
+	while ( i < payload->iNotifs->Count() ) {
+		if (!ProcessNotificationL(payload->iNotifs->At(i)))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}		
+        i ++; 		
+	}	
+
+	ProcessVendorL(payload->iVids);
+
+	CleanupStack::PopAndDestroy();  //payload			
+	
+    if (iExchange == ISAKMP_EXCHANGE_ID)
+         iStage = 6;
+    else iStage = 3;
+
+    return ETrue;
+}
+
+
+//Process payloads appearing in Stage 6(Main)  Order NOT relevant
+TBool CIkev1Negotiation::ProcessStage6L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+	if (  payload->iSa || payload->iNonce || payload->iKe )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+	
+
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+	TIdentISAKMP* id_payload = NULL;
+    //ID Payload processing (all modes)
+	if ( payload->iIds->Count() != 1 )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}
+	id_payload = (TIdentISAKMP*)payload->iIds->At(0);  // The first ID						
+	if (!CheckIdentL(id_payload))
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+	//Save the ident payload for HASH_I/R computing
+    delete iPeerIdentPayload;
+	iPeerIdentPayload = NULL;		
+	iPeerIdentPayloadSize=id_payload->GetLength()-sizeof(TPayloadISAKMP);
+	iPeerIdentPayload = new (ELeave) TUint8[iPeerIdentPayloadSize];
+	Mem::Copy(iPeerIdentPayload,((TUint8 *)id_payload)+sizeof(TPayloadISAKMP),iPeerIdentPayloadSize);
+
+    //Mode-dependent processing
+    switch (auth_method)
+    {
+    case PRE_SHARED:
+        //Hash payload processing
+        if (!ProcessHashL(payload->iHash))
+		{
+			CleanupStack::PopAndDestroy();  //payload			
+            return EFalse;
+		}
+		DEBUG_LOG(_L("HASH OK!"));		
+        break;
+    case RSA_SIG:
+    case DSS_SIG:
+		//Certificate payload processing
+		if (!ProcessCertificateArrayL(payload->iCerts))
+		{
+			CleanupStack::PopAndDestroy();  //payload									
+			return EFalse;
+		}
+		if (!CertifyRemoteIdentityL(id_payload))
+		{
+			DEBUG_LOG(_L("ProcessStage6L RSA_SIG CertifyRemoteIdentityL failed"));
+			DEBUG_LOG(_L("AUTHENTICATION_FAILED"));
+			SetErrorStatus( KKmdIkeAuthFailedErr );
+			SendNotifyL(AUTHENTICATION_FAILED);
+			CleanupStack::PopAndDestroy();  //payload			
+			return EFalse;
+		}
+		//Signature payload processing and checking
+		if (!ProcessSignatureL(payload->iSign))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}
+        break;
+    default:
+        break;
+    }
+
+	// Process notification payloads
+	TInt i = 0;
+	while ( i < payload->iNotifs->Count() ) {
+		if (!ProcessNotificationL(payload->iNotifs->At(i)))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}		
+		i ++; 		
+	}	
+
+	ProcessVendorL(payload->iVids);	
+    // Internal address payload processing
+    ProcessIntAddrL(payload->iIaddr);
+
+	CleanupStack::PopAndDestroy();  //payload	
+
+	return IsakmpPhase1CompletedL();	
+	
+}
+
+//Process payloads appearing in Stage 7 = CRACK authentication going
+TBool CIkev1Negotiation::ProcessStage7L(const ThdrISAKMP &aHdr)
+{
+TBool status = ETrue;
+TInt  crack_status;
+
+    if ( iCRACKneg ) {
+       crack_status = iCRACKneg->ExecuteCRACKMsgL(aHdr);
+       
+       switch ( crack_status ) {
+           
+           case CRACK_SUCCESS:
+               /*-------------------------------------------------------
+                * CRACK authentication has been succesfully completed
+                * Take actions to start Quick mode negotiation
+                *------------------------------------------------------*/
+               delete iCRACKneg;
+               iCRACKneg = NULL;
+               iLastIV.Copy(iIV);  //Saves last IV in Phase 1
+               DEBUG_LOG(_L("Last IV Saved!"));
+               IsakmpPhase1CompletedL();
+               break;
+               
+           case CRACK_CONTINUE:
+               /*----------------------------------------------------------
+                * CRACK authentication continues, no further actions needed
+                *----------------------------------------------------------*/
+               break;
+
+           case CRACK_IGNORE_MSG:
+               /*----------------------------------------------------------
+                * CRACK authentication continues, received message ignored
+                *----------------------------------------------------------*/
+               status = EFalse;            
+               break;
+               
+           default:
+               /*----------------------------------------------------------
+                * CRACK authentication failed, negotiation failed
+                *----------------------------------------------------------*/
+			   LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+			                  R_VPN_MSG_VPN_GW_AUTH_FAIL,
+			                  KKmdIkeAuthFailedErr,
+			                  iPluginSession->VpnIapId(),
+			                  &iRemoteAddr );		   			   
+               status    = EFalse;                         
+			   SetErrorStatus(KKmdIkeAuthFailedErr);
+               AcquireSAErrorResponse(KKmdIkeAuthFailedErr);
+               break;
+
+       }       
+    }
+
+    return status;
+}
+
+//Called as a RESPONDER for PHASE_II
+//Checks HASH(1),SA,KE,NONCE,[ID,ID] from INITIATOR
+TBool CIkev1Negotiation::ProcessStage1Phase2L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+	
+	if (  !payload->iSa || !payload->iNonce )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+	
+    //Payload Processing
+
+    CProposal_IIList *recv_proposals = new (ELeave) CProposal_IIList(1);    //, *prop
+    CleanupStack::PushL(recv_proposals);
+
+    //SA
+    if (!ProcessSAL(payload->iSa, (TUint8 *)recv_proposals))
+    {
+        CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+        return EFalse;
+    }
+
+    //ID payloads (if existing)
+	if ( payload->iIds->Count() == 2 )
+	{
+       if (!ProcessStage1_II_IDsL(payload->iIds->At(0), payload->iIds->At(1), recv_proposals))
+       {
+          CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+          return EFalse;
+       }
+	}
+	else if ( payload->iIds->Count() != 0 )
+	{
+		DEBUG_LOG(_L("Unsupported Phase II ID payload count"));		
+		CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+		return EFalse;
+	}	
+    //After ID to know what address to search in the "SAD"
+	TInt err = BuildProposals2L();
+    if (err != KErrNone)
+    {
+        DEBUG_LOG(_L("NO_PROPOSAL_CHOSEN: No policy matching"));
+        SendNotifyL(NO_PROPOSAL_CHOSEN);
+        CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+        return EFalse;
+    }
+
+    //Contains the transform nums matching if multiple proposals
+    CTransModifierList *trans_array = new (ELeave) CTransModifierList(1);
+    CleanupStack::PushL(trans_array);
+
+    TInt num = iProposal_IIList->MultiMatchL(recv_proposals, iRole == RESPONDER, trans_array);//If RESPONDER relaxed comparison (no lifetimes checked)
+    iProposalNum = num; // Set to num not 1
+#ifdef _DEBUG
+    TBuf<128> err_buf;
+#endif    
+    if (num < 0)
+    {
+#ifdef _DEBUG    
+        err_buf.Copy(_L("NO_PROPOSAL_CHOSEN: Phase II proposal not accepted - "));
+        AppendAttributeError(num, err_buf);
+        DEBUG_LOG(err_buf);
+#endif        
+        SetErrorStatus( KKmdIkeNoProposalErr );
+        SendNotifyL(NO_PROPOSAL_CHOSEN);
+        CleanupStack::PopAndDestroy(3); //transarray + recv_proposals + payload
+        return EFalse;
+    }
+
+    //Copy the chosen transform
+    //Actually is the same one as recv_proposals because we should always receive a single proposal with a single transform.
+    CreateChosenProposalL(recv_proposals, num, trans_array);
+
+    CleanupStack::PopAndDestroy(2); //transarray + recv_proposals
+
+    //Process the possible NOTIFICATION payloads
+    for (TInt i = 0; i < payload->iNotifs->Count(); i++)
+    {
+        if (!ProcessNotificationL(payload->iNotifs->At(i)))
+        {
+            CleanupStack::PopAndDestroy();  //payload
+            return EFalse;
+        }
+    }
+    
+    if (!ProcessNonceL(payload->iNonce))
+	{
+		CleanupStack::PopAndDestroy();  //payload		
+        return EFalse;
+	}
+    //HASH
+    if (!ProcessHash2L(aHdr, payload->iHash, payload->iPadding))
+	{
+		CleanupStack::PopAndDestroy();  //payload				
+        return EFalse;
+	} 
+    
+    if (!ProcessKeyL(payload->iKe))
+	{
+		CleanupStack::PopAndDestroy();  //payload								
+        return EFalse;
+	}
+
+	ProcessVendorL(payload->iVids);		
+	
+    if ( iNatDiscovery ) {
+       iNAT_D_Flags |= iNatDiscovery->GetPeerOriginalAddress(payload->iNatOa, iRemoteOriginalAddr, iChosenProp_IIList);
+    }
+	
+	CleanupStack::PopAndDestroy();  //notif_payload_array	
+    iStage = 2;
+    return ETrue;
+}
+
+//Creates a new proposal list from a selected part of another list (Certain proposal and transforms) 
+void CIkev1Negotiation::CreateChosenProposalL(CProposal_IIList* aPropList, TInt aPropNum, CTransModifierList *aTransArray)
+{
+
+    CProposal_II *prop, *new_propII;
+    TAttrib_II *attr_II;
+    TChosenAttrib_II *new_attr_II;
+    TInt count = aPropList->Count();
+    TInt i = 0;
+    TInt j = 0;
+
+    //
+    // Find selected proroposal from list
+    //
+    while ( i < count)
+    {
+        if (aPropList->At(i)->iProposalNum == aPropNum)
+            break;
+        i ++;
+    }
+    
+    TTransModifier *tmodif;
+    TInt64 own_time, own_bytes, peer_time, peer_bytes;
+    delete iChosenProp_IIList;  //Must be erased because can contain data from previous retransmissions
+	iChosenProp_IIList = NULL;	
+    iChosenProp_IIList = new (ELeave) CProposal_IIList(1);
+    while ( i < count )
+    {
+        prop = aPropList->At(i);
+        if ( prop->iProposalNum != aPropNum)
+            break; // Stop, another Proposal 
+
+        new_propII = new (ELeave) CProposal_II();
+        CleanupStack::PushL(new_propII);
+        new_propII->ConstructL(1);
+        iChosenProp_IIList->AppendL(new_propII);
+        CleanupStack::Pop();    //new_propII safe
+
+        new_propII->iProtocol = prop->iProtocol;
+        new_propII->iNumTransforms = 1; //We only choose 1 transform for each proposal
+        new_propII->iProposalNum   = (TUint8)aPropNum;
+        new_propII->iSPI.Copy(prop->iSPI);
+        tmodif = aTransArray->At(j);
+        new_propII->iReplayWindowLength = tmodif->iReplayWindowLength;
+
+        attr_II = prop->iAttrList->At(tmodif->iTransNum);   //look for the chosen transform in the prop
+        ComputeLifetimes_II(tmodif->iReducedLifeSecs, tmodif->iReducedLifeKBytes, own_time, own_bytes);
+        ComputeLifetimes_II(attr_II->iLifeDurationSecs, attr_II->iLifeDurationKBytes, peer_time, peer_bytes);
+        
+        //Only copy the chosen transform
+        new_attr_II = new (ELeave) TChosenAttrib_II();
+        CleanupStack::PushL(new_attr_II);
+        new_attr_II->Copy(*attr_II);
+        if ((peer_time > own_time) && (own_time != 0))
+        {
+            new_attr_II->iReducedLifeSecs.Set(tmodif->iReducedLifeSecs);
+            DEBUG_LOG1(_L("Lifetime bigger than the one set. Reducing to %d"), own_time);
+        }
+        else
+            new_attr_II->iReducedLifeSecs.Set(NULL, 0);
+            
+        if ((peer_bytes > own_bytes) && (own_bytes != 0))
+        {
+            new_attr_II->iReducedLifeKBytes.Set(tmodif->iReducedLifeKBytes);
+            DEBUG_LOG1(_L("Lifesize bigger than the one set. Reducing to %d"), own_bytes);
+        }
+        else
+            new_attr_II->iReducedLifeKBytes.Set(NULL, 0);
+
+        new_propII->iAttrList->AppendL(new_attr_II);
+        CleanupStack::Pop();    //new_attrII safe
+
+        j++;  // Next transform modifer
+        i++;  // Next proposal
+        
+    }
+}
+
+
+//Called as a INITIATOR for PHASE_II
+//Checks HASH(1),SA, ,NONCE,[KE] [ID,ID] from RESPONDER
+TBool CIkev1Negotiation::ProcessStage2Phase2L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+	if (  !payload->iSa || !payload->iNonce  )
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+
+    CProposal_IIList *recv_proposals = new (ELeave) CProposal_IIList(1);
+    CleanupStack::PushL(recv_proposals);
+
+	//SA
+	if (!ProcessSAL(payload->iSa, (TUint8 *)recv_proposals))
+	{
+		CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+		return EFalse;
+	}
+
+	//ID payloads (if existing)
+	if ( payload->iIds->Count() == 2 )
+	{
+		if (!ProcessStage2_II_IDsL(payload->iIds->At(0), payload->iIds->At(1)))
+		{
+			CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+			return EFalse;
+		}
+	}
+	else if ( payload->iIds->Count() != 0 )
+	{
+		DEBUG_LOG(_L("Unsupported Phase II ID payload count"));		
+				CleanupStack::PopAndDestroy(2); //recv_proposals + payload
+		return EFalse;
+	}	
+	
+    //Contains the transform nums matching if multiple proposals
+    CTransModifierList *trans_array = new (ELeave) CTransModifierList(1);
+    CleanupStack::PushL(trans_array);
+
+    //Check the received proposals match the proposed one (Got from
+    //acquire msg.) 
+   	TInt num = iProposal_IIList->MultiMatchL(recv_proposals, iRole == RESPONDER, trans_array);//If RESPONDER relaxed comparison (no lifetimes checked)
+#ifdef _DEBUG   	
+    TBuf<128> err_buf;
+#endif    
+    if (num < 0)
+    {
+#ifdef _DEBUG    
+        err_buf.Copy(_L("BAD_PROPOSAL_SYNTAX: Phase II reply doesn't match proposal - "));
+        AppendAttributeError(num, err_buf);
+        DEBUG_LOG(err_buf);
+#endif        
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(BAD_PROPOSAL_SYNTAX);
+        CleanupStack::PopAndDestroy(3); //transarray + recv_proposals + payload
+        return EFalse;
+    }
+    // iProposalNum set to correspond local proposal numbering
+    iProposalNum = trans_array->At(0)->iPropNum; 
+    //Copy the chosen transform
+    CreateChosenProposalL(recv_proposals, num, trans_array);
+
+    CleanupStack::PopAndDestroy(2); //transarray + recv_proposals
+
+	//Process the possible NOTIFICATION payloads
+	for (TInt i = 0; i < payload->iNotifs->Count(); i++)
+	{
+		if (!ProcessNotificationL(payload->iNotifs->At(i)))
+		{
+			CleanupStack::PopAndDestroy();  //payload
+			return EFalse;
+		}
+	}
+	//NONCE
+   	if (!ProcessNonceL(payload->iNonce))
+   	{
+    	CleanupStack::PopAndDestroy();  //payload		
+	    return EFalse;
+	}
+	//HASH
+	if (!ProcessHash2L(aHdr, payload->iHash, payload->iPadding))
+	{
+		CleanupStack::PopAndDestroy();  //payload				
+		return EFalse;
+	} 
+	//KEY (if present (PFS))
+	if (!ProcessKeyL(payload->iKe))
+	{
+	    SetErrorStatus( KKmdIkeNegotFailed );
+		SendNotifyL(PAYLOAD_MALFORMED);					
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}   
+
+	ProcessVendorL(payload->iVids);
+	
+	if ( iNatDiscovery ) {
+		iNAT_D_Flags |= iNatDiscovery->GetPeerOriginalAddress(payload->iNatOa, iRemoteOriginalAddr, iChosenProp_IIList);
+	}
+
+    if ( iRecvFlags & ISAKMP_HDR_CFLAG )   //Commit Bit set       
+    {
+        iFlags |= ISAKMP_HDR_CFLAG; //Sets the Commit bit if this side set it else
+        DEBUG_LOG(_L("SAD update delayed until CONNECTED received"));
+    }
+
+	CleanupStack::PopAndDestroy();  //payload				
+    iStage = 3;
+    return ETrue;
+
+}
+
+TBool CIkev1Negotiation::ProcessStage3Phase2L(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+	if ( payload->iSa || payload->iNonce || payload->iKe || payload->iIds->Count() != 0 ) 
+	{
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+	
+    //Hash Payload
+	TBool Status = ProcessHash2L(aHdr, payload->iHash, payload->iPadding);
+    if ( Status )
+	{
+       	//END OF THE PHASE II (Quick mode) negotiation.
+		//Now we need to update the PFKEY SA database
+		ProcessVendorL(payload->iVids);				
+		UpdateSADatabaseL();
+		iStage = 4;
+	}
+	CleanupStack::PopAndDestroy();  //payload		
+    return Status;
+}
+
+TBool CIkev1Negotiation::ProcessCONNECTEDL(const ThdrISAKMP &aHdr)
+{
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *this, iDebug);
+	if (!payload)
+		return EFalse;
+
+	CleanupStack::PushL(payload);
+
+	if ( !payload->iHash || (payload->iNotifs->Count() != 1) || payload->iSa ||
+		 payload->iNonce || payload->iKe || (payload->iIds->Count() != 0) ) 
+	{
+		DEBUG_LOG(_L("PAYLOAD_MALFORMED (no hash or notfic payload)"));
+		SetErrorStatus( KKmdIkeNegotFailed );
+		SendNotifyL(PAYLOAD_MALFORMED);
+		CleanupStack::PopAndDestroy();  //payload
+		return EFalse;
+	}	
+
+    //Checks if the hash value is OK. Here because need the
+    //notification payload
+	const TNotificationISAKMP* notif_payload = payload->iNotifs->At(0);
+	TBool Status = VerifyInformationalHashL(payload->iHash, notif_payload, iMessageId);	 
+    if ( Status )
+    {  //Hash OK
+		if ((notif_payload->GetDOI() == IPSEC_DOI) && (notif_payload->GetMsgType() == CONNECTED))
+		{
+			//END OF THE PHASE II (Quick mode) negotiation.
+			//Now we need to update the PFKEY SA database
+			DEBUG_LOG(_L("CONNECTED message received. Updating SAD"));
+			UpdateSADatabaseL();
+			iStage = 5;			
+		}
+    }
+    else   
+    {
+		DEBUG_LOG(_L("AUTHENTICATION_FAILED (Informational hash)"));
+		SetErrorStatus( KKmdIkeAuthFailedErr );
+		SendNotifyL(AUTHENTICATION_FAILED);
+    }
+	CleanupStack::PopAndDestroy();  //payload		
+    return Status;
+}
+
+//returns KErrNone if OK, otherwise error already treated.
+TBool CIkev1Negotiation::ProcessSAL(const TSAISAKMP *aSA, TUint8 *aRecvProposals)
+{
+    //payload not present
+    if (!aSA)
+    {
+        DEBUG_LOG(_L("NO SA PAYLOAD"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    //requires a special length check to know the proposals and transforms are not bigger than 
+    //the size specified in th SA
+    TUint32 SALengthLeft = aSA->GetLength() - aSA->Size();
+
+    TUint8 next_payload = aSA->GetPayload();
+    if ((next_payload == ISAKMP_PAYLOAD_P) || (next_payload == ISAKMP_PAYLOAD_T))
+    {
+        DEBUG_LOG(_L("INVALID_PAYLOAD_TYPE (Bad next payload for the SA)"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_PAYLOAD_TYPE);   // Payloads and transforms are processed as a part of the SA,
+        return EFalse;
+    }
+
+    TUint32 doi=aSA->GetDOI();
+    if (!CheckDOI(doi))
+    {
+        DEBUG_LOG(_L("DOI_NOT_SUPPORTED in SA payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(DOI_NOT_SUPPORTED);  //send the informational exchange
+        return EFalse;
+    }
+
+    if (iStage == 1)
+        iDOI = doi;
+
+    //Process SITuation depending on DOI. In this implementation always is IPSEC DOI
+    if (!CheckSituationL(aSA->GetSIT()))
+        return EFalse;
+
+    if (aSA->HasLDId()) //If no Labeled Domain Identifier no more processing for the SA
+    {
+        DEBUG_LOG(_L("Label Domain Identifier (LDI) not supported"));
+        return EFalse;
+    }
+    
+    if (iPhase==PHASE_I)    //Only used in Phase_I. PHASE_II hashs check it directly from received paylaod
+    {
+        //Store the SA payload for further calculations in Hash.
+        if (iRole==RESPONDER)
+        {
+            iSAPayloadSize = aSA->GetLength()-sizeof(TPayloadISAKMP);
+            delete iSAPayload;
+			iSAPayload = NULL;
+            iSAPayload = new (ELeave) (TUint8[iSAPayloadSize]); //Generic payload NOT included
+            Mem::Copy(iSAPayload,(((TUint8 *)aSA)+sizeof(TPayloadISAKMP)),iSAPayloadSize);
+        }
+    }
+    const TPayloadISAKMP *payload = aSA->Payload();
+    return ProcessProposalsL(payload, SALengthLeft, aRecvProposals);
+}
+
+
+//Do the process required for proposals and transforms. The aPayload given must be a proposal
+TBool CIkev1Negotiation::ProcessProposalsL(const TPayloadISAKMP *aPayload, TUint32 aLengthLeft, TUint8 *aRecvProposals)
+{
+    TProposalISAKMP *proposal;
+    const TPayloadISAKMP *ppayload=aPayload;
+    TUint8 payType = ppayload->GetPayload();
+    TUint32 len_left;
+    CProposal_IIList *recv_proposals = (CProposal_IIList *)aRecvProposals;
+    CProposal_II *auxProp_II;
+    TBool found = EFalse;   //At least 1 transform matching
+
+    //Many Proposals. The RESPONDER MUST choose a transform for each proposal or reject the 
+    //full suite of attributes.
+    do  
+    {       
+        //General payload check
+        if ((payType != ISAKMP_PAYLOAD_NONE) && (payType != ISAKMP_PAYLOAD_P))
+        {
+            DEBUG_LOG(_L("INVALID_PAYLOAD_TYPE (Bad next payload for the proposal)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_PAYLOAD_TYPE);
+            return EFalse;
+        }
+
+        if (aPayload->GetReserved() != 0)   //Must be always 0
+        {
+            DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return EFalse;
+        }
+        
+        //requires special length check
+        if ((aPayload->GetLength() < MIN_ISAKMP_PAYLOAD_SIZE) || (aPayload->GetLength() > aLengthLeft))
+        {
+            DEBUG_LOG(_L("BAD PAYLOAD SIZE"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return EFalse;
+        }
+
+        aLengthLeft -= aPayload->GetLength();   //dcreases the length of the prop. and its transforms
+
+        proposal = TProposalISAKMP::Ptr(ppayload);
+        
+        
+        if (!CheckProtocolL(proposal->GetProtocol()))
+            return EFalse;
+
+        if (!CheckSPIL(proposal))
+            return EFalse;
+
+        len_left = proposal->GetLength() - (proposal->Size() + proposal->GetSPISize()); 
+        //len_left contains the length of the transforms only
+
+        TInt ret = KErrNotFound;
+        if (iPhase == PHASE_I)
+        {
+            iChosenProposal_I.iProtocol = proposal->GetProtocol();
+            iChosenProposal_I.iSPI.Copy((TUint8 *)proposal->SPI(), proposal->GetSPISize());
+            iChosenProposal_I.iNumTransforms = 1;   //Phase I only one transf chosen
+            iChosenProposal_I.iProposalNum = proposal->GetNum();//Not compulsory but preferable to speed up the search process in the peer
+            
+            ret = ProcessTransformsL(ppayload,len_left);
+            
+            if (ret == KErrNone)
+                return ETrue;//valid transform found
+            else if (ret != KErrNotFound)
+            {
+                DEBUG_LOG(_L("ATTRIBUTES_NOT_SUPPORTED"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+                return EFalse;
+            }
+            //If not found there may be other proposal to check
+        }
+        else    //PHASE_II
+        {
+            auxProp_II = new (ELeave) CProposal_II();
+            CleanupStack::PushL(auxProp_II);
+            auxProp_II->ConstructL(proposal->GetNumTrans());
+            auxProp_II->iProtocol=proposal->GetProtocol();
+            auxProp_II->iSPI.Copy((TUint8 *)proposal->SPI(), proposal->GetSPISize());
+            auxProp_II->iNumTransforms = proposal->GetNumTrans();   //Number of transforms in the proposal
+            auxProp_II->iProposalNum = proposal->GetNum();  //Proposal num
+            
+            ret = ProcessTransforms2L(ppayload, auxProp_II, len_left);
+            if (ret==KErrNone)//valid transform found
+            {   
+                //Adds the new proposal to the list of chosen proposals
+                recv_proposals->AppendL(auxProp_II);
+                CleanupStack::Pop();    //auxProp_II safe
+                found = ETrue;
+                //go for the next proposal
+            }
+            else
+            {
+                DEBUG_LOG(_L("ATTRIBUTES_NOT_SUPPORTED"));
+                SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+                CleanupStack::PopAndDestroy();  //delete auxProp_II;    //delete the current proposal
+                return EFalse;
+            }
+        }
+
+        payType = ppayload->GetPayload();
+        ppayload = ppayload->Next();    //Next payload if there's any
+    } while (payType!=ISAKMP_PAYLOAD_NONE); //Proposal loop
+
+    if (!found)
+    {
+        DEBUG_LOG(_L("ATTRIBUTES_NOT_SUPPORTED"));
+        SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+        return EFalse;
+    }
+
+    return found;
+}
+
+//processes all the  PHASE I transforms. The parameter payload is the proposal containing
+//the transforms to be able to access the # of transforms.
+//Returns if any transform accepted (KErrNone) or not (KErrNotFound) or processing error (KErrGeneral)
+TInt CIkev1Negotiation::ProcessTransformsL(const TPayloadISAKMP *aPayload,TUint32 aLengthLeft)
+{
+    DEBUG_LOG(_L("-> CIkev1Negotiation::ProcessTransformsL()"));
+    TUint16 reason;             
+    TInt ret = KErrGeneral;
+     const TTransformISAKMP *transf;
+    const TProposalISAKMP *proposal=TProposalISAKMP::Ptr(aPayload);
+    //First transform. Not Next() because would be the next proposal or non-sa payload
+    const TPayloadISAKMP *tpayload=proposal->Payload();
+    
+    TInt payType = tpayload->GetPayload();  //Type of the payload following the first transform
+    transf = TTransformISAKMP::Ptr(tpayload);
+    
+    TInt numTransf  = (TInt)transf->GetNum();  // First transform number
+    TInt lastTransf = numTransf + (TInt)proposal->GetNumTrans(); // Last transform number
+    
+    while ( numTransf < lastTransf ) 
+    {
+        //only permited payload codes
+        if ((payType != ISAKMP_PAYLOAD_NONE) && (payType != ISAKMP_PAYLOAD_T))
+        {
+            DEBUG_LOG(_L("INVALID_PAYLOAD_TYPE (Bad next payload for the transform)"));
+            SendNotifyL(INVALID_PAYLOAD_TYPE);
+            return KErrGeneral;
+        }
+
+        if (tpayload->GetReserved() != 0)   //Must be always 0
+        {
+            DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return KErrGeneral;
+        }
+        
+        //requires special length check
+        if ((tpayload->GetLength() < MIN_ISAKMP_PAYLOAD_SIZE) || (tpayload->GetLength() > aLengthLeft))
+        {
+            DEBUG_LOG(_L("BAD PAYLOAD SIZE"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return KErrGeneral;
+        }
+        
+        if (!CheckTransformID(PROTO_ISAKMP,transf->GetID()))
+            {
+            DEBUG_LOG(_L(" Continue"));
+
+            numTransf++;                          // Next supposed transform #              
+            payType = tpayload->GetPayload();
+            tpayload = tpayload->Next();    //next payload (transform)
+            transf = TTransformISAKMP::Ptr(tpayload);
+
+            continue;   //If fails, transform discarded!, not error
+            }
+        
+        if ( transf->GetNum() != numTransf )  //Not the correct #
+        {
+            DEBUG_LOG1(_L("BAD_PROPOSAL_SYNTAX (Non conscutive transform number (%d)"),transf->GetNum());
+            SendNotifyL(BAD_PROPOSAL_SYNTAX);
+            DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrGeneral"));
+            return KErrGeneral;
+        }
+
+        if (transf->GetReserved() != 0 )    //Should be always 0
+        {
+            DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrGeneral"));
+            return KErrGeneral;
+        }
+
+        numTransf++;                          // Next supposed transform #              
+        //Attributes to be checked depending on Transf ID
+        TAttrib attrib;
+        
+        ret = ProcessAttributesL(tpayload, &attrib);
+        
+        if (ret != KErrNone)
+        {
+            if (ret != KErrNotFound)
+                {
+                DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrGeneral"));
+                return KErrGeneral; //Error in the attributes. Already reported
+                }
+            //Not accepted but correct
+        }
+        else    // Accepted attributes if (AttrChosen(attrib))
+        {  
+            //Checks the response or proposal is the same as one of our proposals
+            TAttrib *attr_list = iProposal_I.iAttrList;
+            TInt ret = KErrNotFound;
+#ifdef _DEBUG            
+            TBuf<256> buf;
+#endif            
+            while (attr_list && (ret != KErrNone) )
+            {
+                ret = attrib.Compare(*attr_list, iRole==RESPONDER); //If RESPONDER relaxed comparison (no lifetimes checked)                
+                if (ret != KErrNone)
+                {
+#ifdef _DEBUG                
+                    DEBUG_LOG1(_L("Transform #%d not matching proposal Reason: "), attrib.iTransformNum);
+                    AppendAttributeError(ret, buf);
+                    DEBUG_LOG(buf);
+#endif                    
+                }
+                attr_list = attr_list->iNext;   //next transform proposed
+
+            }
+            if (ret == KErrNone)
+            {
+               *iChosenProposal_I.iAttrList = attrib;       
+               DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrNone"));
+               return KErrNone; //If the attibute are supported there's no need to check more SA
+            }   
+            else    //No proposal matches
+            {
+               if ( numTransf == lastTransf ) //Is there more transforms to check
+               {    
+                  if (iRole == INITIATOR)
+                  {
+                      reason = BAD_PROPOSAL_SYNTAX;
+                      DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Phase I reply don't match proposal)"));
+                      SetErrorStatus( KKmdIkeNegotFailed );
+                  }                           
+                  else
+                  {
+                      reason = NO_PROPOSAL_CHOSEN;                    
+                      DEBUG_LOG(_L("NO_PROPOSAL_CHOSEN (Received Proposal doesn't match accepted attributes (Check own proposals))"));
+                  }           
+                  SendNotifyL(reason);
+                  DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrNotFound"));
+                  return KErrNotFound;
+               }    
+            }
+        }
+
+        payType = tpayload->GetPayload();
+        tpayload = tpayload->Next();    //next payload (transform)
+        transf = TTransformISAKMP::Ptr(tpayload);
+        
+    }
+
+    DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransformsL() KErrNotFound"));
+
+    //if reaches this point meanse no transform accepted in this proposal
+    //Notifies to the upper level
+    return KErrNotFound;
+
+}
+
+
+//Logs the error when comparing a proposal
+//void CIkev1Negotiation::LogAttributeError(TInt aTransformNum, TInt aErr)
+void CIkev1Negotiation::AppendAttributeError(TInt aErr, TDes &aBuf) const
+{
+#ifndef _DEBUG
+    (void)aErr;
+    (void)aBuf;
+#endif
+
+#ifdef _DEBUG
+    switch (aErr)
+    {
+    case KErrNotFound:
+        aBuf.Append(_L("No proposals\n"));
+        break;
+    case KErrTransformID:
+        aBuf.Append(_L("Different Transform Algorithm\n"));
+        break;
+    case KErrEncrAlg:
+        aBuf.Append(_L("Different Encryption Algorithm\n"));
+        break;
+    case KErrHashAlg:
+        aBuf.Append(_L("Different Hash Algorithm\n"));
+        break;
+    case KErrAuthMethod:
+        aBuf.Append(_L("Different Authentication Method\n"));
+        break;
+    case KErrGroupDesc:
+        aBuf.Append(_L("Different Group Description\n"));
+        break;
+    case KErrGroupType:
+        aBuf.Append(_L("Different Group Type\n"));
+        break;
+    case KErrGroupPrime:
+        aBuf.Append(_L("Different Group Prime\n"));
+        break;
+    case KErrGroupGen1:
+        aBuf.Append(_L("Different Group Generator 1\n"));
+        break;
+    case KErrGroupGen2:
+        aBuf.Append(_L("Different Group Generator 2\n"));
+        break;
+    case KErrGroupCurveA:
+        aBuf.Append(_L("Different Group Curve A\n"));
+        break;
+    case KErrGroupCurveB:
+        aBuf.Append(_L("Different Group Curve A\n"));
+        break;
+    case KErrPRF:
+        aBuf.Append(_L("Different PRF\n"));
+        break;
+    case KErrKeyLength:
+        aBuf.Append(_L("Different Key Length\n"));
+        break;
+    case KErrFieldSize:
+        aBuf.Append(_L("Different Field Size\n"));
+        break;
+    case KErrGroupOrder:
+        aBuf.Append(_L("Different Group Order\n"));
+        break;
+    case KErrLifeTime:
+        aBuf.Append(_L("Different Lifetime\n"));
+        break;
+    case KErrLifeSize:
+        aBuf.Append(_L("Different LifeSize\n"));
+        break;
+    case KErrEncMode:
+        aBuf.Append(_L("Different Encapsulation Mode\n"));
+        break;
+    case KErrAuthAlg:
+        aBuf.Append(_L("Different Authentication Algorithm\n"));
+        break;
+    case KErrKeyRounds:
+        aBuf.Append(_L("Different Key Rounds\n"));
+        break;
+    case KErrComprDicSize:
+        aBuf.Append(_L("Different Compress Dictionary Size\n"));
+        break;
+    case KErrComprPrivAlg:
+        aBuf.Append(_L("Different Compress Private Algorithm\n"));
+        break;
+    case KErrTransformNum:
+        aBuf.Append(_L("Different Transform Num.\n"));
+        break;
+    case KErrPropProtocol:
+        aBuf.Append(_L("Proposals have different protocol.\n"));
+        break;
+    case KErrNoTransforms:
+        aBuf.Append(_L("Proposal has no transforms \n"));
+        break;
+    case KErrNoRemoteProposals:
+        aBuf.Append(_L("Remote Proposals list is empty\n"));
+        break;
+    case KErrNoLocalProposals:
+        aBuf.Append(_L("Local Proposals list is empty\n"));
+        break;
+    case KErrPropNumberMismatch:
+        aBuf.Append(_L("The proposals lists have diferent number of AND'd proposals"));
+        break;
+    default:
+        aBuf.Append(_L("Unknown\n"));
+    }
+#endif  
+}
+
+//processes all the PHASE II transforms. The parameter payload is the proposal containing
+//the transforms to be able to access the # of transforms.
+//Returns if any transform accepted (KErrNone) or not (KErrNotFound) or processing error (KErrGeneral)
+TInt CIkev1Negotiation::ProcessTransforms2L(const TPayloadISAKMP *aPayload,CProposal_II *aProp,TUint32 aLengthLeft)
+{
+    DEBUG_LOG(_L("-> CIkev1Negotiation::ProcessTransforms2L()"));
+
+    TInt ret;
+    const TTransformISAKMP *transf;
+    const TProposalISAKMP *proposal=TProposalISAKMP::Ptr(aPayload);
+    //First transform. Not Next() because would be the next proposal or non-sa payload
+    const TPayloadISAKMP *tpayload = proposal->Payload();
+
+    TAttrib_II *attr_II = NULL; 
+    TInt payType = tpayload->GetPayload();  //Type of the payload following the first transform
+    transf = TTransformISAKMP::Ptr(tpayload);
+    
+    TInt numTransf  = (TInt)transf->GetNum();  // First transform number
+    TInt lastTransf = numTransf + (TInt)proposal->GetNumTrans(); // Last transform number   
+
+    while ( numTransf < lastTransf ) 
+    {
+        //only permited payload codes
+        if ((payType != ISAKMP_PAYLOAD_NONE) && (payType != ISAKMP_PAYLOAD_T))
+        {
+            DEBUG_LOG(_L("INVALID_PAYLOAD_TYPE (Bad next payload for the transform)"));
+            SendNotifyL(INVALID_PAYLOAD_TYPE);
+            return KErrGeneral;
+        }
+        
+        if (tpayload->GetReserved() != 0)   //Must be always 0
+        {
+            DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return KErrGeneral;
+        }
+        
+        //requires special length check
+        if ((tpayload->GetLength() < MIN_ISAKMP_PAYLOAD_SIZE) || (tpayload->GetLength() > aLengthLeft))
+        {
+            DEBUG_LOG(_L("BAD PAYLOAD SIZE"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return KErrGeneral;
+        }
+        
+        if (!CheckTransformID(aProp->iProtocol,transf->GetID()))
+            {
+            DEBUG_LOG(_L(" Transform doesn't match, moving on to the next one"));
+            payType = tpayload->GetPayload();
+            tpayload = tpayload->Next();    //next payload (transform)
+            transf = TTransformISAKMP::Ptr(tpayload);
+            numTransf++;                          // Next supposed transform #
+            continue;   //If fails, transform discarded!, not error
+            }
+        
+        if ( transf->GetNum() != numTransf )  //Not the correct #. Must be consecutive
+        {   
+            DEBUG_LOG1(_L("BAD_PROPOSAL_SYNTAX (Non conscutive transform number (%d)"),transf->GetNum());
+            SendNotifyL(BAD_PROPOSAL_SYNTAX);
+            return KErrGeneral;
+        }
+
+        if (transf->GetReserved() != 0 )    //Must be always 0
+        {
+            DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return KErrGeneral;
+        }
+        
+        //Attributes to be checked depending on Transf ID
+        attr_II = new (ELeave) TAttrib_II();
+        CleanupStack::PushL(attr_II);
+        ret = ProcessAttributes2L(tpayload, attr_II, aProp->iProtocol);
+        if (ret != KErrNone)    //Some invalid attribute
+        {
+            DEBUG_LOG(_L(" Invalid attribute"));
+            CleanupStack::PopAndDestroy();  //delete attr_II;
+            if (ret != KErrNotFound)
+                return KErrGeneral; //Error in the attributes. Already reported
+            else    //Invalid transform- Ignored
+            {
+                DEBUG_LOG2(_L("Transform %d of proposal %d ignored"), transf->GetNum(), aProp->iProposalNum);
+            }
+        }
+        else    //Accepted, must check if really proposed or if matches the configuration if RESPONDER
+        {
+            DEBUG_LOG(_L(" Adding new attribute"));
+            aProp->iAttrList->AppendL(attr_II); //Add the new attribute
+            CleanupStack::Pop();    //attr_II saf
+        }
+        payType = tpayload->GetPayload();
+        tpayload = tpayload->Next();    //next payload (transform)
+        transf = TTransformISAKMP::Ptr(tpayload);
+        numTransf++;                          // Next supposed transform #
+        
+    }
+
+    //No valid transform found
+    if (aProp->iAttrList->Count() == 0)
+        {
+        DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransforms2L() KErrNotFound"));
+        return KErrNotFound;
+        }
+
+    DEBUG_LOG(_L("<- CIkev1Negotiation::ProcessTransforms2L() KErrNone"));
+    return KErrNone;
+}
+
+
+//Copies and checks the values of the attributes. The parameter aPayload must be a transform
+//aAttrib will contain the sent attributes if the return value is KErrNone, otherwise should be
+//ignore because there was an error reading them (KErrGeneral) or the transform was not accepted (KErrNotFound)
+TInt CIkev1Negotiation::ProcessAttributesL(const TPayloadISAKMP *aPayload, TAttrib *aAttrib)
+{
+    const TTransformISAKMP *transf = TTransformISAKMP::Ptr(aPayload);
+    TInt length= aPayload->GetLength() - sizeof(*transf); //To process the attribs
+    TDataISAKMP *attr= transf->SAAttrib();
+    
+    aAttrib->iTransformNum = transf->GetNum();
+    aAttrib->iTransformID  = transf->GetID();
+    //
+	// Store parameters for extended authentication
+	//
+	aAttrib->iXauthUsed = iHostData->iUseXauth;
+	aAttrib->iRole      = iRole;
+	
+    TUint16 lifeType  = 0; //No type assigned yet
+    TUint32 lifeValue = 0; //No value assigned yet
+    TUint16 val;
+    
+    while ( length>0 )
+    {
+        length = length - attr->Size();
+        if (length<0)   //Mismatch between lengths!!!
+        {
+            DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Length mismatch in the attibutes)"));
+            SendNotifyL(BAD_PROPOSAL_SYNTAX);
+            return KErrGeneral;
+        }
+        switch (attr->Type())
+        {
+        case OAKLEY_ATTR_TYPE_ENCR_ALG:
+            if (!CheckEncrAlg(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iEncrAlg=attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_HASH_ALG:
+            if (!CheckHashAlg(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iHashAlg = attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_AUTH_METH:
+            val = CTransNegotiation::GetAuthMethod(attr->Value(), iHostData->iUseXauth, iRole);
+            if (!CheckAuthMethod(val))
+                return KErrNotFound;
+            aAttrib->iAuthMethod = val;
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_DESC:
+            if (!CheckGroupDesc(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iGroupDesc = attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_TYPE:
+            if (!CheckGroupType(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iGroupType = attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_PRIME:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupPrime.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupPrime.Copy(attr->VarValue(),attr->Length());
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_GEN1:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupGen1.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupGen1.Copy(attr->VarValue(),attr->Length());
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_GEN2:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupGen2.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupGen2.Copy(attr->VarValue(),attr->Length());
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_CRVA:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupCurveA.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupCurveA.Copy(attr->VarValue(),attr->Length());
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_CRVB:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupCurveB.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupCurveB.Copy(attr->VarValue(),attr->Length());
+            break;
+        case OAKLEY_ATTR_TYPE_LIFE_TYPE:
+            lifeType = attr->Value();
+            if (!CheckLifeType(lifeType))
+            {
+                DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Invalid lifetime type)"));
+                SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                return KErrGeneral;
+            }
+            break;
+        case OAKLEY_ATTR_TYPE_LIFE_DUR:
+            if (attr->IsBasic())
+            {
+                lifeValue = ByteOrder::Swap32(attr->Value());
+                if (lifeType == SECONDS)
+                    aAttrib->iLifeDurationSecs.Copy((TUint8 *)&lifeValue, sizeof(lifeValue));
+                else if (lifeType == KBYTES)
+                    aAttrib->iLifeDurationKBytes.Copy((TUint8 *)&lifeValue, sizeof(lifeValue));
+                else
+                {
+                    DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Invalid lifetime type)"));
+                    SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                    return KErrGeneral;
+                }
+            }
+            else    //Not basic
+            {
+                if (lifeType == SECONDS)
+                    aAttrib->iLifeDurationSecs.Copy(attr->VarValue(),attr->Length());
+                else if (lifeType == KBYTES)
+                    aAttrib->iLifeDurationKBytes.Copy(attr->VarValue(),attr->Length());
+                else
+                {
+                    DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Invalid lifetime type)"));
+                    SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                    return KErrGeneral;
+                }
+            }
+            break;
+        case OAKLEY_ATTR_TYPE_PRF:
+            if (!CheckPRF(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iPRF=attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_KEY_LEN:
+            aAttrib->iKeyLength = attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_FIELD_SIZE:
+            if (!CheckFieldSize(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iFieldSize=attr->Value();
+            break;
+        case OAKLEY_ATTR_TYPE_GROUP_ORDER:
+            if (attr->IsBasic())
+            {
+                val = attr->Value();
+                aAttrib->iGroupOrder.Copy((TUint8*)&val, sizeof(val));
+            }
+            else
+                aAttrib->iGroupOrder.Copy(attr->VarValue(),attr->Length());
+            break;
+        default:
+            DEBUG_LOG(_L("ATTRIBUTES_NOT_SUPPORTED (Invalid attribute number)"));
+            SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+            return KErrGeneral;
+        }
+        attr = attr->Next();
+    }
+    
+    //Done here to ensure both received
+    if (aAttrib->iKeyLength !=0)
+        if (!CheckKeyLength(aAttrib->iKeyLength, (TUint8)aAttrib->iEncrAlg ,PROTO_ISAKMP))
+            return KErrNotFound;
+
+    return KErrNone;
+}
+
+//Copies and checks the values of the attributes. The parameter aPayload must be a transform
+//aAttrib will contain the sent attributes if the return value is KErrNone, otherwise should be
+//ignore because there was an error reading them (KErrGeneral) or the transform was not accepted (KErrNotFound)
+TInt CIkev1Negotiation::ProcessAttributes2L(const TPayloadISAKMP *aPayload, TAttrib_II *aAttrib,TUint8 aProtocol)
+{
+    const TTransformISAKMP *transf = TTransformISAKMP::Ptr(aPayload);
+    TInt length= aPayload->GetLength() - sizeof(*transf); //To process the attribs
+    
+    aAttrib->iTransformNum = transf->GetNum();
+    aAttrib->iTransformID = transf->GetID();
+    TDataISAKMP *attr= transf->SAAttrib();
+    TUint16 lifeType = 0;   //No type assigned yet
+    TUint32 lifeValue = 0;
+    while (length>0)
+    {
+        length = length - attr->Size();
+        if (length<0)   //Mismatch between lengths!!!
+        {
+            DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Length mismatch in the attibutes)"));
+            SendNotifyL(BAD_PROPOSAL_SYNTAX);
+            return KErrGeneral;
+        }
+        switch (attr->Type())
+        {
+        case DOI_ATTR_TYPE_LIFE_TYPE:
+            lifeType=attr->Value();
+            if (!CheckLifeType(lifeType))
+            {
+                DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (Invalid lifetime type)"));
+                SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                return KErrGeneral;
+            }
+            break;
+        case DOI_ATTR_TYPE_LIFE_DUR:
+            if (attr->IsBasic())
+            {
+                lifeValue = ByteOrder::Swap32(attr->Value());
+                if (lifeType==SECONDS)
+                    aAttrib->iLifeDurationSecs.Copy((TUint8 *)&lifeValue, sizeof(lifeValue));
+                else if (lifeType==KBYTES)
+                    aAttrib->iLifeDurationKBytes.Copy((TUint8 *)&lifeValue, sizeof(lifeValue));
+                else
+                {
+                    DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (No lifetime type received)"));
+                    SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                    return KErrGeneral;
+                }
+            }
+            else
+            {
+                if (lifeType==SECONDS)
+                    aAttrib->iLifeDurationSecs.Copy(attr->VarValue(),attr->Length());
+                else if (lifeType==KBYTES)
+                    aAttrib->iLifeDurationKBytes.Copy(attr->VarValue(),attr->Length());
+                else
+                {
+                    DEBUG_LOG(_L("BAD_PROPOSAL_SYNTAX (No lifetime type received)"));
+                    SendNotifyL(BAD_PROPOSAL_SYNTAX);
+                    return KErrGeneral;
+                }
+            }
+            lifeType = 0;   //Cannot received another lifetime without setting the type again
+            break;
+        case DOI_ATTR_TYPE_GROUP_DESC:
+            if (!CheckGroupDesc(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iGroupDesc=attr->Value();
+            break;
+        case DOI_ATTR_TYPE_ENC_MODE:    //Encapsulation Mode
+            if (!CheckEncMode(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iEncMode=attr->Value();
+            if ( aAttrib->iEncMode == UDP_ENC_TUNNEL || aAttrib->iEncMode == UDP_RFC_ENC_TUNNEL  )
+               aAttrib->iEncMode = DOI_TUNNEL;
+            if ( aAttrib->iEncMode == UDP_ENC_TRANSPORT || aAttrib->iEncMode == UDP_RFC_ENC_TRANSPORT)
+               aAttrib->iEncMode = DOI_TRANSPORT;
+            break;
+        case DOI_ATTR_TYPE_AUTH_ALG:
+            if (!CheckAuthAlg(attr->Value()))
+                return KErrNotFound;
+            aAttrib->iAuthAlg=attr->Value();
+            break;
+        case DOI_ATTR_TYPE_KEY_LEN:
+            aAttrib->iKeyLength = attr->Value();
+            break;  
+        case DOI_ATTR_TYPE_KEY_ROUNDS:
+            aAttrib->iKeyRounds=attr->Value();
+            break;
+/*          
+        case DOI_ATTR_TYPE_COMP_DIC_SIZE:   //Compress Dictionary size
+            aAttrib->iComprDicSize=attr->Value();
+            break;  
+        case DOI_ATTR_TYPE_COMP_PRIV_ALG:   //Compress Dictionary size
+            aAttrib->iComprPrivAlg=attr->Value();
+            break;
+*/          
+        default:
+            DEBUG_LOG(_L("ATTRIBUTES_NOT_SUPPORTED (Invalid attribute number)"));
+            SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+            return KErrGeneral;
+        }
+        attr = attr->Next();
+    }
+
+    if (lifeType != 0)  //Type set but not sent
+    {
+        DEBUG_LOG(_L("Lifetime type set but value not sent!"));
+        return KErrNotFound;
+    }
+
+    if (aAttrib->iKeyLength !=0)
+        if (!CheckKeyLength(aAttrib->iKeyLength,transf->GetID(),aProtocol)) //Check key length correct
+            return KErrNotFound;
+
+    return KErrNone;
+}
+
+
+//returns KErrNone if OK, otherwise error already treated.
+TBool CIkev1Negotiation::ProcessKeyL(const TKeyISAKMP *aKey)
+{
+    //const TKeyISAKMP *key = TKeyISAKMP::Ptr(aPayload);
+    
+    //payload not present
+    if (iPhase==PHASE_I)
+    {
+        if (!aKey)
+        {
+            DEBUG_LOG(_L("NO KEY Payload"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(PAYLOAD_MALFORMED);
+            return EFalse;
+        }
+        //Doesn't return yet because it needs to copy the received key
+    }
+    else    //PHASE_II
+    {
+        if (!aKey)
+        {
+            if (iPFS)
+            {
+                DEBUG_LOG(_L("KEY Payload Expected (PFS is enabled)"));
+                return EFalse;
+            }
+
+            return ETrue;
+            
+        }
+        else    // Key present
+        {
+            if (!iPFS)
+            {
+                DEBUG_LOG(_L("KEY Payload NOT Expected (PFS is disabled)"));
+                return EFalse;
+            }
+            //Doesn't return yet because it needs to copy the received key
+        }
+    }
+        
+    //stores the public key sent by the other peer. Only if key received and PFS enabled (PHASE II only)
+    iPeerPublicKey.Copy(aKey->KeyData(), aKey->GetLength() - sizeof(*aKey));
+    return ETrue;
+}
+
+
+TBool CIkev1Negotiation::ProcessNonceL(const TPayloadISAKMP *aPayload)
+{
+    const TNonceISAKMP *nonce = TNonceISAKMP::Ptr(aPayload);
+
+    //payload not present
+    if (!nonce)
+    {
+        DEBUG_LOG(_L("NO NONCE PAYLOAD"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    //stores the nonce sent by the other peer
+    if (iRole==RESPONDER)
+        iNONCE_I.Copy(nonce->NonceData(),nonce->NonceDataLen());
+    else
+        iNONCE_R.Copy(nonce->NonceData(),nonce->NonceDataLen());
+
+    return ETrue;
+
+}
+
+TBool CIkev1Negotiation::ProcessStage1_II_IDsL(const TIdentISAKMP *aInit_ID_payload,const TIdentISAKMP *aResp_ID_payload, CProposal_IIList *aRecv_proposals)
+{
+    //IDci
+    //First we check the received IDs to be able to build the proposals for phase_II
+    TInt32 addr;        //Contains a numeric IPv4 addr to be sent
+    TBuf<40> addr_buf;  //Contains a text IPv4/IPv6 addr to be sent
+
+    TIp6Addr ip6addr;   //IPV6 raw address
+
+    //We receive the peer proxy address or gateway client
+    TAttrib_II *attr_II = aRecv_proposals->At(0)->iAttrList->At(0);
+    if (aInit_ID_payload)   //ID Payload received
+    {
+        iIDReceived = ETrue;
+        if (!CheckIdentL(aInit_ID_payload))  
+            return EFalse;
+
+        iIDRemotePort = aInit_ID_payload->GetPort();
+        iIDProtocol = aInit_ID_payload->GetProtocol();
+        iRemoteIDType_II = aInit_ID_payload->GetIDType();
+
+        switch (aInit_ID_payload->GetIDType())
+        {
+            case ID_IPV4_ADDR:
+                Mem::Copy((TUint8 *)&addr, aInit_ID_payload->IDData(),sizeof(TInt32));
+                iRemoteAddr1_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                DEBUG_LOG(_L("Remote ID received"));
+                DEBUG_LOG(_L("Setting Remote ID to:"));
+                iRemoteAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (iRemoteAddr.Match(iRemoteAddr1_ID_II))
+                    iDefaultRemoteID = ETrue;   //Must be sent but won't be used when updating the SAD
+                else if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Received ID MUST match the Remote addr in Transport mode)"));
+                    SendNotifyL(ADDRESS_NOTIFICATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV4_ADDR_SUBNET:
+                Mem::Copy((TUint8 *)&addr, aInit_ID_payload->IDData(),sizeof(TInt32));  //Address
+                iRemoteAddr1_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                Mem::Copy((TUint8 *)&addr, aInit_ID_payload->IDData() + sizeof(TInt32),sizeof(TInt32)); //Mask
+                iRemoteAddr2_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                iRemoteAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(_L("Setting Remote ID to: addr = "));
+                DEBUG_LOG(addr_buf);
+                iRemoteAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(_L(" mask = "));
+                DEBUG_LOG(addr_buf);
+                if (PrefixLen(iRemoteAddr2_ID_II) < KErrNone)   //Invalid Mask  (can't be > 32 bec. we get only 4 bytes)
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Invalid peer proxy mask for type ID_IPV4_ADDR_SUBNET)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    if (!iRemoteAddr.Match(iRemoteAddr1_ID_II, iRemoteAddr2_ID_II))
+                    {
+                        DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Remote ID MUST match the net & mask received)"));
+                        SetErrorStatus( KKmdIkeNegotFailed );
+                        SendNotifyL(ADDRESS_NOTIFICATION);
+                        return EFalse;
+                    }
+                }
+                break;
+            case ID_IPV6_ADDR:
+                Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+                iRemoteAddr1_ID_II.SetAddress(ip6addr);
+                DEBUG_LOG(_L("Remote ID received"));
+                DEBUG_LOG(_L("Setting Remote ID to:"));
+                iRemoteAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (iRemoteAddr.Match(iRemoteAddr1_ID_II))
+                    iDefaultRemoteID = ETrue;   //Must be sent but won't be used when updating the SAD
+                else if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Remote ID doesn't match received IDi in Transport mode)"));
+                    SendNotifyL(ADDRESS_NOTIFICATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV6_ADDR_SUBNET:
+                Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8)); //Address               
+                iRemoteAddr1_ID_II.SetAddress(ip6addr);
+                Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData() + sizeof(ip6addr.u.iAddr8), sizeof(ip6addr.u.iAddr8));  //Mask
+                iRemoteAddr2_ID_II.SetAddress(ip6addr);
+                DEBUG_LOG(_L("Remote ID (subnet) received"));
+                DEBUG_LOG(_L("Setting Remote ID to: addr = "));
+                iRemoteAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                DEBUG_LOG(_L(" mask = "));
+                iRemoteAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (PrefixLen(iRemoteAddr2_ID_II) < 0)  //Invalid Mask
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Invalid peer proxy mask for type ID_IPV6_ADDR_SUBNET)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    if (!iRemoteAddr.Match(iRemoteAddr1_ID_II, iRemoteAddr2_ID_II))
+                    {
+                        DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Remote ID MUST match the net & mask received)"));
+                        SetErrorStatus( KKmdIkeNegotFailed );
+                        SendNotifyL(ADDRESS_NOTIFICATION);
+                        return EFalse;
+                    }
+                }
+                break;
+            default:    //redundant. Detected in CheckIdentL()
+                DEBUG_LOG(_L("INVALID_ID_INFORMATION (ID Type not supported)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+        }//switch
+    }
+    else    //No id received (That means we're negotiating directly with the end host) (RFC 2409 5.5)
+    {
+        //For TRANSPORT we don't need to do anything
+        iIDLocalPort = 0;
+        iIDRemotePort = 0;
+        iIDProtocol = 0;
+        return ETrue;   //No need to check the Responder ID if no Initiator ID received
+    }
+
+    //IDcr
+    //Receive our proxy. We don't know it because we are responders so the other peer tells us who does it
+    //want to communicate with
+    if (aResp_ID_payload)   //ID Payload received
+    {
+        if (!CheckIdentL(aResp_ID_payload))
+            return EFalse;
+
+        iIDLocalPort = aResp_ID_payload->GetPort();
+        iLocalIDType_II = aResp_ID_payload->GetIDType();
+        if (iIDProtocol != aResp_ID_payload->GetProtocol()) //Must be the same sent in the IDCi
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (Local ID Protocol different from Remote ID Protocol. Must be the same)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+
+        switch (aResp_ID_payload->GetIDType())
+        {
+            case ID_IPV4_ADDR:
+                Mem::Copy((TUint8 *)&addr, aResp_ID_payload->IDData(),sizeof(TInt32));
+                iLocalAddr1_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                DEBUG_LOG(_L("Local ID received"));
+                DEBUG_LOG(_L("Setting Local ID to:"));
+                iLocalAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if ( iInternalAddr ) {
+                   //
+                   // Check ID against internal address instead of local address
+                   //
+                   if (iInternalAddr->iClientIntAddr.Match(iLocalAddr1_ID_II))
+                       iDefaultLocalID = ETrue;  //Must be sent but won't be used when updating the SAD
+                }
+                else {
+                   if (iLocalAddr.Match(iLocalAddr1_ID_II))
+                        iDefaultLocalID = ETrue; //Must be sent but won't be used when updating the SAD
+                   else if (attr_II->iEncMode == DOI_TRANSPORT)
+                   {
+                       DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Local ID MUST match the net & mask received)"));
+                       SetErrorStatus( KKmdIkeNegotFailed );
+                       SendNotifyL(ADDRESS_NOTIFICATION);
+                       return EFalse;
+                   }   
+                }
+                break;
+            case ID_IPV4_ADDR_SUBNET:
+                Mem::Copy((TUint8 *)&addr, aResp_ID_payload->IDData(),sizeof(TInt32));  //Address
+                iLocalAddr1_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                Mem::Copy((TUint8 *)&addr, aResp_ID_payload->IDData() + sizeof(TInt32),sizeof(TInt32)); //Mask
+                iLocalAddr2_ID_II.SetAddress(ByteOrder::Swap32(addr));
+                DEBUG_LOG(_L("Setting Local ID to: addr = "));
+                iLocalAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                DEBUG_LOG(_L(" mask = "));
+                iLocalAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (PrefixLen(iLocalAddr2_ID_II) < 0)   //Invalid Mask
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Invalid Remote ID mask for type ID_IPV4_ADDR_SUBNET)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    if (!iLocalAddr.Match(iLocalAddr1_ID_II, iLocalAddr2_ID_II))
+                    {
+                        DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Local ID MUST match the net & mask received)"));
+                        SetErrorStatus( KKmdIkeNegotFailed );
+                        SendNotifyL(ADDRESS_NOTIFICATION);
+                        return EFalse;
+                    }
+                }
+                break;
+            case ID_IPV6_ADDR:
+                Mem::Copy(&ip6addr.u.iAddr8, aResp_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+                //iOwnProxyAddr.SetAddress(ip6addr);
+                iLocalAddr1_ID_II.SetAddress(ip6addr);
+                DEBUG_LOG(_L("Own Proxy received"));
+                DEBUG_LOG(_L("Setting Own Proxy address to:"));
+                iLocalAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (iLocalAddr.Match(iLocalAddr1_ID_II))
+                    iDefaultLocalID = ETrue;    //Must be sent but won't be used when updating the SAD
+                else if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Local ID MUST match the net & mask received)"));
+                    SendNotifyL(ADDRESS_NOTIFICATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV6_ADDR_SUBNET:
+                Mem::Copy(&ip6addr.u.iAddr8, aResp_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8)); //Address
+                iLocalAddr1_ID_II.SetAddress(ip6addr);
+                Mem::Copy(&ip6addr.u.iAddr8, aResp_ID_payload->IDData() + sizeof(ip6addr.u.iAddr8), sizeof(ip6addr.u.iAddr8));  //Mask
+                iLocalAddr2_ID_II.SetAddress(ip6addr);
+                DEBUG_LOG(_L("Setting Own Proxy to: addr = "));
+                iLocalAddr1_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                DEBUG_LOG(_L(" mask = "));
+                iLocalAddr2_ID_II.OutputWithScope(addr_buf);
+                DEBUG_LOG(addr_buf);
+                if (PrefixLen(iLocalAddr2_ID_II) < 0)   //Invalid Mask
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Invalid Remote ID mask for type ID_IPV6_ADDR_SUBNET)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                if (attr_II->iEncMode == DOI_TRANSPORT)
+                {
+                    if (!iLocalAddr.Match(iLocalAddr1_ID_II, iLocalAddr2_ID_II))
+                    {
+                        DEBUG_LOG(_L("ADDRESS_NOTIFICATION (Local ID MUST match the net & mask received)"));
+                        SetErrorStatus( KKmdIkeNegotFailed );
+                        SendNotifyL(ADDRESS_NOTIFICATION);
+                        return EFalse;
+                    }
+                }
+                break;
+            default:
+                DEBUG_LOG(_L("INVALID_ID_INFORMATION (ID Type not supported)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+        }//switch
+    }
+
+    return ETrue;
+}
+
+
+TBool CIkev1Negotiation::ProcessStage2_II_IDsL(const TIdentISAKMP *aInit_ID_payload,const TIdentISAKMP *aResp_ID_payload)//, CProposal_IIList *aRecv_proposals)
+{
+    TInt32 addr4_int;       //Contains a numeric IPv4 addr to be sent
+    TIp6Addr ip6addr;   //IPV6 raw address
+    TInetAddr tmp_addr;
+    //Here we check the initator proxy (Our client) sent by us has been received correctly
+    if (aInit_ID_payload)   //ID Payload received
+    {
+        if (!CheckIdentL(aInit_ID_payload))
+            return EFalse;
+
+        if (aInit_ID_payload->GetPort() != iIDLocalPort)
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (Local ID Port different from the one sent)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+
+        if (aInit_ID_payload->GetProtocol() != iIDProtocol)
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (Local ID Protocol different from the one sent)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+
+        switch (aInit_ID_payload->GetIDType())
+        {
+        case ID_IPV4_ADDR:
+            Mem::Copy((TUint8 *)&addr4_int,aInit_ID_payload->IDData(),sizeof(TInt32));
+            tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));
+            if (!tmp_addr.Match(iLocalAddr1_ID_II))
+            {
+                DEBUG_LOG(_L("Wrong Own ID received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            break;
+        case ID_IPV4_ADDR_SUBNET:
+            //Subnet
+            Mem::Copy((TUint8 *)&addr4_int,aInit_ID_payload->IDData(),sizeof(TInt32));
+            tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));
+            if (!tmp_addr.Match(iLocalAddr1_ID_II))
+            {
+                //The ID subnet is not the one we sent!
+                DEBUG_LOG(_L("Wrong Own ID subnet received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            //Mask
+            Mem::Copy((TUint8 *)&addr4_int,aInit_ID_payload->IDData() + sizeof(TInt32),sizeof(TInt32));
+            tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));          
+            if (!tmp_addr.Match(iLocalAddr2_ID_II))
+            {
+                //The ID mask is not the one we sent!
+                DEBUG_LOG(_L("Wrong Own ID mask received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            break;
+        case ID_IPV6_ADDR:
+            Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+            tmp_addr.SetAddress(ip6addr);
+            if (!tmp_addr.Match(iLocalAddr1_ID_II))
+            {
+                //The ID is not the one we sent!
+                DEBUG_LOG(_L("Wrong Local ID received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            break;
+        case ID_IPV6_ADDR_SUBNET:
+            //subnet
+            Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+            tmp_addr.SetAddress(ip6addr);
+            if (!tmp_addr.Match(iLocalAddr1_ID_II))
+            {
+                //The ID is not the one we sent!
+                DEBUG_LOG(_L("Wrong Local ID subnet received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            //mask
+            Mem::Copy(&ip6addr.u.iAddr8, aInit_ID_payload->IDData() + sizeof(ip6addr.u.iAddr8), sizeof(ip6addr.u.iAddr8));
+            tmp_addr.SetAddress(ip6addr);
+            if (!tmp_addr.Match(iLocalAddr2_ID_II))
+            {
+                //The ID is not the one we sent!
+                DEBUG_LOG(_L("Wrong Local ID mask received (Different from the one sent)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+            }
+            break;
+        default:
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (ID Type not supported)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }//switch
+    }
+    else    //No id sent (That means we're negotiating directly with the end host
+    {
+        if (!iLocalAddr1_ID_II.IsUnspecified())
+        {
+            DEBUG_LOG(_L("IDci expected and not received!"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+    }
+
+    //We receive the peer (responder) proxy address or gateway client
+    if (aResp_ID_payload)   //ID Payload received
+    {
+        if (!CheckIdentL(aResp_ID_payload))
+            return EFalse;
+
+        if (aResp_ID_payload->GetPort() != iIDRemotePort)
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (Remote Port different from the one sent)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+
+        if (aResp_ID_payload->GetProtocol() != iIDProtocol)
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION (Responder ID Protocol different from the one sent)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+
+        switch (aResp_ID_payload->GetIDType())
+        {
+            case ID_IPV4_ADDR:
+                Mem::Copy((TUint8 *)&addr4_int,aResp_ID_payload->IDData(),sizeof(TInt32));
+                tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));
+                DEBUG_LOG(_L("IDcr received"));
+                if (!iRemoteAddr1_ID_II.Match(tmp_addr))
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Wrong Remote ID, doesn't match sent one)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV4_ADDR_SUBNET:
+                //subnet address
+                Mem::Copy((TUint8 *)&addr4_int,aResp_ID_payload->IDData(),sizeof(TInt32));
+                tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));
+                if (!tmp_addr.Match(iRemoteAddr1_ID_II))
+                {
+                    //The ID subnet is not the one we sent!
+                    DEBUG_LOG(_L("Wrong Remote ID subnet received (Different from the one sent)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                //Mask address
+                Mem::Copy((TUint8 *)&addr4_int,aResp_ID_payload->IDData() + sizeof(TInt32),sizeof(TInt32));
+                tmp_addr.SetAddress(ByteOrder::Swap32(addr4_int));          
+                if (!tmp_addr.Match(iRemoteAddr2_ID_II))
+                {
+                    //The ID mask is not the one we sent!
+                    DEBUG_LOG(_L("Wrong Remote ID mask received (Different from the one sent)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV6_ADDR:
+                Mem::Copy(&ip6addr.u.iAddr8,aResp_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+                tmp_addr.SetAddress(ip6addr);
+                DEBUG_LOG(_L("IDcr received"));
+                if (!iRemoteAddr1_ID_II.Match(tmp_addr))
+                {
+                    DEBUG_LOG(_L("INVALID_ID_INFORMATION (Wrong ID, doesn't match sent proxy)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                break;
+            case ID_IPV6_ADDR_SUBNET:
+                //subnet
+                Mem::Copy(&ip6addr.u.iAddr8, aResp_ID_payload->IDData(), sizeof(ip6addr.u.iAddr8));
+                tmp_addr.SetAddress(ip6addr);
+                if (!tmp_addr.Match(iRemoteAddr1_ID_II))
+                {
+                    //The ID is not the one we sent!
+                    DEBUG_LOG(_L("Wrong Remote ID subnet received (Different from the one sent)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                //mask
+                Mem::Copy(&ip6addr.u.iAddr8, aResp_ID_payload->IDData() + sizeof(ip6addr.u.iAddr8), sizeof(ip6addr.u.iAddr8));
+                tmp_addr.SetAddress(ip6addr);
+                if (!tmp_addr.Match(iRemoteAddr2_ID_II))
+                {
+                    //The ID is not the one we sent!
+                    DEBUG_LOG(_L("Wrong Remote ID mask received (Different from the one sent)"));
+                    SetErrorStatus( KKmdIkeNegotFailed );
+                    SendNotifyL(INVALID_ID_INFORMATION);
+                    return EFalse;
+                }
+                break;
+            default:    //Only these 2 modes make sense no reason for subnets or range
+                DEBUG_LOG(_L("INVALID_ID_INFORMATION (Remote ID Type not supported)"));
+                SetErrorStatus( KKmdIkeNegotFailed );
+                SendNotifyL(INVALID_ID_INFORMATION);
+                return EFalse;
+        }//switch
+    }
+    else    //No id sent (That means we're negotiating directly with the end host. We check it's TRUE!
+    {
+        if (!iRemoteAddr1_ID_II.IsUnspecified())
+        {
+            DEBUG_LOG(_L("IDcr expected and not received!"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+    }
+
+    return ETrue;
+}
+
+
+TBool CIkev1Negotiation::CheckIdentL(const TPayloadISAKMP *aPayload)
+{
+    const TIdentISAKMP *ident = TIdentISAKMP::Ptr(aPayload);
+    
+    //payload not present
+    if (!ident)
+    {
+        DEBUG_LOG(_L("NO ID PAYLOAD"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    if (iPhase  == PHASE_I)
+    {
+        TUint8 protocol = ident->GetProtocol();
+        if ((protocol != KProtocolInetUdp) && (protocol != 0))
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION: Bad Phase I Protocol (Only UDP(17) or 0 accepted)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+        TUint16 port = ident->GetPort();
+        if ((port != 0) && (port != IKE_PORT) && (port != FLOATED_IKE_PORT) )
+        {
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION: Invalid Bad Phase I Port. (Only 0, 500 or 4500 accepted)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+        switch (ident->GetIDType())
+        {
+        case ID_IPV4_ADDR:
+        case ID_IPV6_ADDR:
+        case ID_FQDN:                       
+        case ID_USER_FQDN:
+        case ID_DER_ASN1_DN:
+            break;
+        default:
+            DEBUG_LOG(_L("INVALID_ID_INFORMATION: Invalid Type (Only IPV4/IPV6/User FQDN and DER ASN1 DN accepted in PHASE I)"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_ID_INFORMATION);
+            return EFalse;
+        }
+    }
+
+    return ETrue;
+}
+
+
+//Certificate Request Payload processing (all modes).
+TBool CIkev1Negotiation::ProcessCertificateReqL(const TCertificateReqISAKMP *aCertReq)
+{
+    if (iChosenProposal_I.iAttrList->iAuthMethod == IKE_A_CRACK)
+    {
+        DEBUG_LOG(_L("CR ignored when CRACK auth !)"));
+        return ETrue;
+    }
+
+    TInt ret = CheckEncodingL(aCertReq->GetEncoding());
+    switch (ret)
+    {
+    case KErrGeneral:
+        return EFalse;
+    case KErrNotSupported:  //Not supported but not an error, just ignored
+        return ETrue;   
+    }
+
+	if ( !iPkiService )
+	   return EFalse;
+	TBool Status = EFalse;
+	    //
+        // No specific CA asked. Find a certificate using own trusted CA list
+        //
+    if ( ReadOwnCertL())
+        {
+         Status = ETrue; 
+        }
+   
+    return Status;
+
+}
+
+
+//Certificate Request Payload(s) processing (all modes).
+TBool CIkev1Negotiation::ProcessCertificateReqArrayL(const CArrayFixFlat<const TCertificateReqISAKMP *> *aCRPayloadArray)
+{
+	
+    TInt count = aCRPayloadArray->Count();
+    if ( count == 0 )
+	{
+       return ETrue;   // No Certificate requests   
+    }
+    
+    if ( ProcessCertificateReqL(aCRPayloadArray->At(0)) )
+       {
+        DEBUG_LOG(_L("User Certificate required by peer found"));           
+        iSendCert = ETrue;  //Requires sending our cert in next interchange where allowed/expected, otherwise not sent
+        return ETrue;
+       }
+    HBufC8* CAName = NULL;
+    CIkeCaList* trustedCaList = iPkiService->CaList();
+    
+    TInt Status=0;
+    
+    for (TInt i=0; i < trustedCaList->Count(); i++)
+        {
+        CIkeCaElem* CaElem = (*trustedCaList)[i];                     
+                
+        CAName = IkeCert::GetCertificateFieldDERL(CaElem->Certificate(), KSubjectName);
+        CleanupStack::PushL(CAName);
+        
+        TRAP_IGNORE(Status=iPkiService->ReadChainL(iHostData, CAName)); 
+        
+        CleanupStack::PopAndDestroy(CAName);
+        CAName=NULL;
+        
+        if ( Status == KErrNone )
+            {
+             delete iOwnCert;
+             iOwnCert = iPkiService->GetCertificate();
+             
+             iICA1 = iPkiService->GetTrustedICA1();
+                    
+             iICA2 = iPkiService->GetTrustedICA2();
+             
+             iPeerTrustedCA = iPkiService->GetTrustedCA();
+             
+             iSendCert = ETrue;  //Requires sending our cert in next interchange where allowed/expected, otherwise not sent
+             
+             DEBUG_LOG(_L("Certificate chain Found!"));
+             return ETrue;
+             }
+        }
+    
+   
+    if ( Status == KVpnErrInvalidCaCertFile)
+        {
+         SetErrorStatus(KVpnErrInvalidCaCertFile);  
+         
+         SendNotifyL(CERTIFICATE_UNAVAILABLE);
+         
+         DEBUG_LOG(_L("Certificate chain read failed!"));
+           
+         return EFalse;
+        }
+	
+    SetErrorStatus(KKmdIkeNoCertFoundErr);  
+    SendNotifyL(CERTIFICATE_UNAVAILABLE);
+    DEBUG_LOG(_L("Certificate Chain r!"));
+    
+    return EFalse;
+}
+
+//Certificate Payload(s) processing (all modes).
+TBool CIkev1Negotiation::ProcessCertificateArrayL(CArrayFixFlat<const TCertificateISAKMP *>* aCertArray)
+{
+	TBool Status;	
+	if ( iCertRequested )
+		 Status = EFalse;
+	else Status = ETrue;
+
+	if ( iPkiService && aCertArray->Count() )
+	{	        
+        const CIkeCaList* trustedCaList = iPkiService->CaList();
+    	CX509Certificate* PeerCert = IkePkiUtils::VerifyCertificateL(*aCertArray,
+    	                                                             *trustedCaList);
+    	if ( PeerCert )
+	    {
+		   delete iPeerX509Cert;
+		   iPeerX509Cert = PeerCert;
+	       DEBUG_LOG(_L("Peer Certificate is OK"));
+		   Status = ETrue; 		
+	    }
+		else
+		{
+		   Status = EFalse;					
+	       DEBUG_LOG(_L("Peer Certificate is rejected"));
+		}			   
+	}			
+			
+	return Status; 
+}
+
+//Checks the signature sent by the peer host
+TBool CIkev1Negotiation::ProcessSignatureL(const TSignatureISAKMP *aSigPayload)
+{
+    TBool ret;
+    //payload not present
+    if (!aSigPayload || !iPeerX509Cert )
+    {
+        DEBUG_LOG(_L("NO SIG PAYLOAD"));
+		SetErrorStatus(KKmdIkePeerAuthFailed);  				
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    //DSS only allows SHA1 as hash
+    TUint16 tmp = iChosenProposal_I.iAttrList->iHashAlg;
+    if (iChosenProposal_I.iAttrList->iAuthMethod==DSS_SIG)
+        iChosenProposal_I.iAttrList->iHashAlg = HASH_SHA1;
+
+    TBuf8<ISAKMP_HASH_SIZE> hash;
+    //Verify the peer signature
+    if (iRole==RESPONDER)
+    {
+        ComputeHash1L(hash);   //Computes the value of iHASH_I the signature checking
+                            //Nothing else to compute.
+    }
+    else    //Initiator
+    {
+        ComputeHashrL(hash); //Computes the value of CRACK digest for signature checking
+    }
+
+    ret = VerifySignatureL(iPeerX509Cert, (TUint8 *)hash.Ptr(), hash.Length(), aSigPayload->SigData(),aSigPayload->GetDataLength());
+
+    //restores the value of the Hash alg.
+    iChosenProposal_I.iAttrList->iHashAlg = tmp;
+
+    if (!ret)
+    {
+        DEBUG_LOG(_L("INVALID_SIGNATURE 2"));
+		SetErrorStatus(KKmdIkePeerAuthFailed);				
+        SendNotifyL(INVALID_SIGNATURE);
+        return EFalse;
+    }
+
+	DEBUG_LOG(_L("Peer Signature is OK"));           	
+    return ETrue;
+}
+
+
+TBool CIkev1Negotiation::ProcessHashL(const THashISAKMP *aHashPayload)
+{
+	TBool Status = EFalse;
+	if (aHashPayload)
+	{
+        //Compute peer's hash							
+		TBuf8<ISAKMP_HASH_SIZE> hash;
+		if ( (iStage == 6) || ((iStage == 2) && (iExchange == ISAKMP_EXCHANGE_AGGR)))
+			 ComputeHashrL(hash);
+		else ComputeHash1L(hash);
+		Status = (Mem::Compare((TUint8 *)hash.Ptr(), hash.Length(), aHashPayload->Data(), aHashPayload->DataLen()) == 0 );
+		if ( !Status )
+		{
+			DEBUG_LOG(_L("INVALID_HASH_INFORMATION"));
+			SendNotifyL(INVALID_HASH_INFORMATION);
+		}
+	}	
+	
+    return Status;
+}
+
+
+TBool CIkev1Negotiation::ProcessHash2L(const ThdrISAKMP &aHdr, const THashISAKMP *aHashPayload, TUint aPadding)
+{
+	TBool Status = EFalse;
+    if ( aHashPayload )
+	{
+	   TUint8* hashMsg = (TUint8*)aHashPayload->Next();
+	   TInt hashMsgLen = aHdr.GetLength() - sizeof(aHdr) - aHashPayload->GetLength() - aPadding;
+	   Status = VerifyHash2L(aHashPayload, hashMsg, hashMsgLen);
+	   if (!Status)
+	   {
+		   DEBUG_LOG(_L("INVALID_HASH_INFORMATION"));
+		   SendNotifyL(INVALID_HASH_INFORMATION);
+       }
+	}   
+	else   
+    {
+       DEBUG_LOG(_L("PAYLOAD_MALFORMED"));
+       SendNotifyL(PAYLOAD_MALFORMED);
+    }
+
+    return Status;
+}
+
+
+//Check a notification Payload inserted in a normal exchange (MAIN , AGGR, QUICK)
+TBool CIkev1Negotiation::ProcessNotificationL(const TNotificationISAKMP *aNotifPayload)
+{
+    if (!aNotifPayload)
+        return ETrue;   //optional so noting happens
+
+    if (!CheckDOI(aNotifPayload->GetDOI()))
+    {
+        DEBUG_LOG(_L("Bad DOI in the NOT payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(DOI_NOT_SUPPORTED);  //send the informational exchange
+        return EFalse;
+    }
+    
+    switch(aNotifPayload->GetMsgType())
+    {
+    case DOI_RESPONDER_LIFETIME:
+        return ProcessResponderLifetimeL(aNotifPayload);
+    case DOI_REPLAY_STATUS:
+        return ProcessReplayStatus(aNotifPayload);
+    case DOI_INITIAL_CONTACT:
+        return ProcessInitialContactL(aNotifPayload);
+    default:
+        DEBUG_LOG(_L("INVALID MESSAGE TYPE in NOT payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+}
+
+
+//Processes a RESPONDER-LIFETIME NOT payload
+TBool CIkev1Negotiation::ProcessResponderLifetimeL(const TNotificationISAKMP *aNotifPayload)
+{
+    TBuf8<2 * ISAKMP_COOKIE_SIZE> spi, own_neg_spi;
+    DEBUG_LOG(_L("Processing RESPONDER-LIFETIME"));
+
+			
+    if (!((iPhase == PHASE_II) && (iStage == 2)))
+    {
+		if ( iPhase == PHASE_I ) {
+		   DEBUG_LOG(_L("RESPONDER-LIFETIME payload in phase 1, ignored !!"));
+		   return ETrue;		
+		}
+		else {
+  		   DEBUG_LOG(_L("Unexpected RESPONDER-LIFETIME payload (Bad stage)"));
+  		   SetErrorStatus( KKmdIkeNegotFailed );
+		   SendNotifyL(INVALID_PAYLOAD_TYPE);
+    	   return EFalse;
+		}	
+    }
+
+    TUint8 protocol = aNotifPayload->GetProtocol();
+    if ((protocol != PROTO_IPSEC_AH) && (protocol != PROTO_IPSEC_ESP) &&
+        (protocol != PROTO_ISAKMP)   && (protocol != 0))
+    {
+        DEBUG_LOG(_L("Bad protocol in the RESPONDER-LIFETIME payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_PROTOCOL_ID);
+        return EFalse;
+    }
+
+    TUint8 spi_size = aNotifPayload->GetSPISize();
+    CProposal_II *prop;
+    TInt i;
+    //If SPI sent
+    switch (spi_size)
+    {
+    case 2 * ISAKMP_COOKIE_SIZE:    //ISAKMP spi
+        spi.Copy(aNotifPayload->GetSPI(), aNotifPayload->GetSPISize());
+        own_neg_spi.Copy(iCookie_I);
+        own_neg_spi.Append(iCookie_R);
+
+        if (spi.Compare(own_neg_spi) != 0)
+        {
+            DEBUG_LOG(_L("Invalid SPI size in the RESPONDER-LIFETIME payload. Payload ignored"));
+            SetErrorStatus( KKmdIkeNegotFailed );
+            SendNotifyL(INVALID_SPI);
+            return EFalse;
+        }
+        if (iChosenProp_IIList->Count() > 1)    
+        {
+            DEBUG_LOG(_L("RESPONDER-LIFETIME ignored. More than one SA (need a IPsec SPI to know which one to use) "));
+            return EFalse;
+        }
+        prop = iChosenProp_IIList->At(0);       //Only one proposal
+        break;
+    case 0: //Compatibility with Alchemy cc500
+        if (iChosenProp_IIList->Count() > 1)    
+        {
+            DEBUG_LOG(_L("RESPONDER-LIFETIME ignored. More than one SA (need a IPsec SPI to know which one to use) "));
+            return EFalse;
+        }
+
+        prop = iChosenProp_IIList->At(0);       //Only one proposal
+        break;
+    case sizeof(TUint32):           //IPSEC SPI
+        spi.Copy(aNotifPayload->GetSPI(), aNotifPayload->GetSPISize());
+        prop = NULL;    //Only for the debugger, the loop will have at least one proposal
+        for (i = 0; i < iChosenProp_IIList->Count(); i++)
+        {
+            prop = iChosenProp_IIList->At(i);       //Only one proposal
+            if (((prop->iSPI.Compare(spi) == 0) && prop->iProtocol == protocol)) //right prop   
+                break;
+        }
+
+        if (i == iChosenProp_IIList->Count())   //No prop matches
+        {
+            DEBUG_LOG(_L("RESPONDER-LIFETIME ignored. IPsec SPI doesn't match any chosen proposal"));
+            return EFalse;
+        }
+        break;
+    default:
+        DEBUG_LOG(_L("Bad SPI size in the RESPONDER-LIFETIME payload"));
+        return EFalse;
+    }
+    TAttrib_II *transform = prop->iAttrList->At(0); //Only one transform
+    TInt data_len = aNotifPayload->GetNotifDataSize();
+    TUint8 *data_ptr = aNotifPayload->GetNotifData();
+    TUint16 lifeType = 0;   //No type assigned yet
+    TInt64 lifeValue = 0;   //No type assigned yet
+    TInt64 lifeValue32;
+    TInt64 curr_lifeValue = 0;
+    TInt32 duration;
+
+    TDataISAKMP *attr = (TDataISAKMP*)data_ptr;
+    while (data_len > 0)
+    {
+        data_len = data_len - attr->Size();
+        if (data_len < 0)   //Mismatch between lengths!!!
+        {
+            DEBUG_LOG(_L("RESPONDER-LIFETIME (Length mismatch in the attibutes)"));
+            return EFalse;
+        }
+        switch (attr->Type())
+        {
+        case DOI_ATTR_TYPE_LIFE_TYPE:           
+        case OAKLEY_ATTR_TYPE_LIFE_TYPE:
+            lifeType = attr->Value();
+            if (!CheckLifeType(lifeType))
+            {
+                DEBUG_LOG(_L("RESPONDER-LIFETIME (Invalid lifetime type)"));
+                return EFalse;
+            }
+            break;
+        case DOI_ATTR_TYPE_LIFE_DUR:                        
+        case OAKLEY_ATTR_TYPE_LIFE_DUR:
+            if (attr->IsBasic())
+            {
+                duration = ByteOrder::Swap32(attr->Value());
+                lifeValue = MAKE_TINT64(0, duration);
+                lifeValue32 = I64LOW(lifeValue);                
+                if (lifeType == SECONDS)
+                {
+                    Desc8ToTInt64(transform->iLifeDurationSecs, curr_lifeValue);        //can't fail
+                    if (lifeValue < curr_lifeValue)
+                        transform->iLifeDurationSecs.Copy((TUint8 *)&lifeValue32, sizeof(lifeValue32));
+                }
+                else if (lifeType == KBYTES)
+                {
+                    Desc8ToTInt64(transform->iLifeDurationKBytes, curr_lifeValue);  //can't fail
+                    if (lifeValue < curr_lifeValue)
+                        transform->iLifeDurationKBytes.Copy((TUint8 *)&lifeValue32, sizeof(lifeValue32));
+                }
+                else
+                {
+                    DEBUG_LOG(_L("RESPONDER-LIFETIME (Invalid lifetime type)"));
+                    return EFalse;
+                }
+            }
+            else    //Not basic
+            {
+                TPtrC8 ptr(attr->VarValue(),attr->Length());
+
+                if (lifeType == SECONDS)
+                {
+                    if (Desc8ToTInt64(ptr, lifeValue) != KErrNone)
+                        {
+                        DEBUG_LOG(_L("RESPONDER-LIFETIME Lifetime(Sec) Overflowed Setting to maximum value"));
+                        }
+                    Desc8ToTInt64(transform->iLifeDurationSecs, curr_lifeValue);        //can't fail
+                    if (lifeValue < curr_lifeValue)
+                        transform->iLifeDurationSecs.Copy(attr->VarValue(),attr->Length());
+                }
+                else if (lifeType == KBYTES)
+                {
+                    if (Desc8ToTInt64(ptr, lifeValue) != KErrNone)
+                        {
+                        DEBUG_LOG(_L("RESPONDER-LIFETIME Lifetime(KBytes) Overflowed Setting to maximum value"));
+                        }
+                    Desc8ToTInt64(transform->iLifeDurationKBytes, curr_lifeValue);  //can't fail
+                    if (lifeValue < curr_lifeValue)
+                        transform->iLifeDurationKBytes.Copy(attr->VarValue(),attr->Length());
+                }
+                else
+                {
+                    DEBUG_LOG(_L("RESPONDER-LIFETIME (Invalid lifetime type)"));
+                    return EFalse;
+                }
+            }
+            break;
+        default:
+            DEBUG_LOG1(_L("RESPONDER-LIFETIME (Invalid attribute (%d) received)"), attr->Type());
+            return EFalse;
+        }//switch
+        attr = attr->Next();
+    }//while
+
+    return ETrue;
+}
+
+//Processes a REPLAY-STATUS NOT payload
+TBool CIkev1Negotiation::ProcessReplayStatus(const TNotificationISAKMP *aNotifPayload)
+{
+    TBuf8<2 * ISAKMP_COOKIE_SIZE> spi, own_neg_spi;
+
+    DEBUG_LOG(_L("Processing REPLAY-STATUS"));
+
+    if (!((iPhase == PHASE_II) && ((iStage == 1) || (iStage == 2))))
+    {
+        DEBUG_LOG(_L("Unexpected REPLAY-STATUS payload (Bad stage)"));
+        return EFalse;
+    }
+
+    TUint8 protocol = aNotifPayload->GetProtocol();
+    if ((protocol != PROTO_IPSEC_AH) && (protocol != PROTO_IPSEC_ESP) &&
+        (protocol != PROTO_ISAKMP)   && (protocol != 0))
+    {
+        DEBUG_LOG(_L("Bad protocol in the REPLAY-STATUS payload"));
+        return EFalse;
+    }
+    
+    TInt i;
+    TUint8 spi_size = aNotifPayload->GetSPISize();
+    CProposal_II *prop;
+    //If SPI sent
+    switch (spi_size)
+    {
+    case 2 * ISAKMP_COOKIE_SIZE:    //ISAKMP spi
+        spi.Copy(aNotifPayload->GetSPI(), aNotifPayload->GetSPISize());
+        own_neg_spi.Copy(iCookie_I);
+        own_neg_spi.Append(iCookie_R);
+        if (spi.Compare(own_neg_spi) != 0)
+        {
+            DEBUG_LOG(_L("Invalid SPI size in the REPLAY-STATUS payload. Payload ignored"));
+            return EFalse;
+        }
+        if (iChosenProp_IIList->Count() > 1)    
+        {
+            DEBUG_LOG(_L("REPLAY-STATUS ignored. More than one IPsec SA (need an IPsec SPI to know which one to use) "));
+            return EFalse;
+        }
+        break;
+    case 0: //Compatibility with Alchemy cc500
+        if (iChosenProp_IIList->Count() > 1)
+        {
+            DEBUG_LOG(_L("RESPONDER-LIFETIME ignored. More than one SA (need a IPsec SPI to know which one to use) "));
+            return EFalse;
+        }
+        prop = iChosenProp_IIList->At(0);       //Only one proposal
+        break;
+    case sizeof(TUint32):           //IPSEC SPI
+        spi.Copy(aNotifPayload->GetSPI(), aNotifPayload->GetSPISize());
+        for (i = 0; i < iChosenProp_IIList->Count(); i++)
+        {
+            prop = iChosenProp_IIList->At(i);       //Only one proposal
+            if (((prop->iSPI.Compare(spi) == 0) && prop->iProtocol == protocol)) //right prop
+                break;
+        }
+        if (i == iChosenProp_IIList->Count())   //No prop matches
+        {
+            DEBUG_LOG(_L("REPLAY-STATUS ignored. IPsec SPI doesn't match any chosen proposal"));
+            return EFalse;
+        }
+        break;
+    default:
+        DEBUG_LOG(_L("Bad SPI size in the REPLAY-STATUS payload"));
+        return EFalse;
+    }
+
+    TInt data_len = aNotifPayload->GetNotifDataSize();
+    TUint32 *data = (TUint32 *)aNotifPayload->GetNotifData();
+    if (STATIC_CAST(TUint, data_len) < sizeof(*data))
+    {
+        DEBUG_LOG(_L("REPLAY-STATUS (Length mismatch in the attibutes)"));
+        return EFalse;
+    }
+
+#ifdef _DEBUG
+    if (ByteOrder::Swap32(*data) == 0)
+        DEBUG_LOG(_L("Anti-Replay Disabled on Peer Host"));
+    else
+        DEBUG_LOG(_L("Anti-Replay Enabled on Peer Host"));
+#endif        
+    return ETrue;
+}
+
+
+TBool CIkev1Negotiation::ProcessInitialContactL(const TNotificationISAKMP *aNotifPayload)
+{
+    TBuf8<2 * ISAKMP_COOKIE_SIZE> spi, neg_spi;
+
+    DEBUG_LOG(_L("Processing INITIAL-CONTACT"));
+                                                              // 7 = CRACK 
+    if (!(iPhase == PHASE_I && (iStage == 5 || iStage == 6 || iStage == 7)))
+    {
+        DEBUG_LOG(_L("Unexpected INITIAL-CONTACT payload (Bad stage)"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_PAYLOAD_TYPE);
+        return EFalse;
+    }
+
+    if (aNotifPayload->GetProtocol() != PROTO_ISAKMP &&
+        aNotifPayload->GetProtocol() != 0 )
+        
+    {
+        DEBUG_LOG(_L("Bad protocol in the INITIAL_CONTACT payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_PROTOCOL_ID);
+        return EFalse;
+    }
+
+    if (aNotifPayload->GetSPISize() != 2 * ISAKMP_COOKIE_SIZE)
+    {
+        DEBUG_LOG(_L("Bad SPI size in the INITIAL_CONTACT payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_SPI);
+        return EFalse;
+    }
+    spi.Copy(aNotifPayload->GetSPI(), aNotifPayload->GetSPISize());
+    neg_spi.Copy(iCookie_I);
+    neg_spi.Append(iCookie_R);
+
+    if (spi.Compare(neg_spi) != 0)
+    {
+        DEBUG_LOG(_L("Invalid SPI size in the INITIAL_CONTACT payload"));
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(INVALID_SPI);
+        return EFalse;
+    }
+   
+    if ( iRole == RESPONDER )
+        {        
+        // Expired SAs are not returned.
+        TIkev1SAData* sa = iPluginSession->FindIkev1SADataWithAddr( iRemoteAddr );	
+        while ( sa != NULL )
+            {
+            iPluginSession->UpdateIkev1SAL( sa->iSAId, ETrue );
+            sa = iPluginSession->FindIkev1SADataWithAddr( iRemoteAddr );
+            }
+        
+        // Delete other ongoing negotiations.
+        CIkev1Negotiation* next = iPluginSession->FirstNegotiation();    
+        while ( next != NULL )
+            {
+            CIkev1Negotiation* current = next;
+            next = current->iNext;
+            if ( current != this )
+                {
+                delete current;
+                }
+            }
+        }
+
+    return ETrue;
+}
+
+
+
+void CIkev1Negotiation::ProcessVendorL(CArrayFixFlat<const TVendorISAKMP*>* aVids)
+{
+	TBool result;	
+    TInt i = 0;
+
+	while ( i < aVids->Count() )
+	{
+    	TVendorISAKMP* VendorPayload = (TVendorISAKMP*)aVids->At(i);
+        DEBUG_LOG(_L("Vendor ID received!\nHex: "));
+        DEBUG_LOG_ARRAY(VendorPayload->VIDData(), VendorPayload->GetLength() - sizeof(*VendorPayload));
+				
+        if ( iLocalAddr.Family() == KAFUnspec )
+            User::LeaveIfError( iPluginSession->GetLocalAddress( iLocalAddr ) ); // No local address info, get it !
+
+		result = EFalse;
+        iNAT_T_Required = ProcessVendorId(&result,
+                                          (TUint8*)iCookie_I.Ptr(),
+                                          (TUint8*)iCookie_R.Ptr(),
+                                          iLocalAddr,
+                                          VendorPayload);
+        if ( result )
+		{
+           iFamiliarPeer = result;
+#ifdef _DEBUG           
+           DEBUG_LOG(_L("Nokia VPN gateway in peer!"));
+		   if ( iNAT_T_Required  ) { 
+	  	      DEBUG_LOG(_L("NAT Traversal needed!"));
+		      if ( !iHostData->iUseNatProbing )
+		      DEBUG_LOG(_L(" NAT probe not requested! NAT-T not used!"));    
+		   }
+#endif // _DEBUG	   
+		   iNAT_T_Required = iNAT_T_Required & iHostData->iUseNatProbing;				   
+        }   
+        else
+		{
+		   if ( CheckDPDVendorId(VendorPayload) )
+		   {
+			  DEBUG_LOG(_L("Peer supports IETF Dead Peer Detection!"));			   
+			  iDPDSupported = ETrue;
+		   }	  
+		   else if ( iNatDiscovery )
+		   {
+              result = iNatDiscovery->CheckNatVendorId(VendorPayload);
+              if ( result )
+              {
+              	DEBUG_LOG(_L("Peer supports IETF (draft-03) NAT Traversal!"));              	
+              }
+              else
+              {
+              	result = iNatDiscovery->CheckRfcNatVendorId(VendorPayload);
+              	if ( result )
+              	    {
+              		iVendorIDRfc=ETrue;
+              	    DEBUG_LOG(_L("Peer supports IETF NAT Traversal!"));
+              	    }
+              }	
+		   }		  
+		}
+
+		i ++;		
+	}
+
+}
+
+//
+//Process Internal address payload received
+//
+void CIkev1Negotiation::ProcessIntAddrL(const TINTNETISAKMP *aIntnetPayload)
+{
+    if ( aIntnetPayload && iFamiliarPeer && iHostData->iUseInternalAddr ) {
+       delete iInternalAddr; //delete if already exists (old)
+	   iInternalAddr = NULL;
+       iInternalAddr = ProcessIntNetL((TINTNETISAKMP*) aIntnetPayload);
+#ifdef _DEBUG       
+       if ( iInternalAddr) {  
+          TBuf<80> buf;
+          TBuf<40> txt_addr;
+          iInternalAddr->iClientIntAddr.OutputWithScope(txt_addr);
+          DEBUG_LOG1(_L("Internal address received: %S"),&txt_addr);
+       }
+#endif       
+    }   
+}
+
+//Computes the hash for phase II
+void CIkev1Negotiation::ComputeHash2L(TDes8& aHash, TInt aStage, const TUint8 *aHashMsg, TInt aHashMsgLen)
+{
+	
+	HBufC8* prf_data =
+    HBufC8::NewLC(((aHashMsgLen + iNONCE_I.Length() + iNONCE_R.Length() + (2*sizeof(TUint32))) | 0x3) + 1);
+
+    if (aStage == 3)
+        prf_data->Des().Append(0);
+
+    TUint32 id = ByteOrder::Swap32(iMessageId);
+    prf_data->Des().Append((TUint8*)&id,sizeof(iMessageId));
+    DEBUG_LOG(_L("ID"));
+    switch (aStage)
+    {
+    case 2:
+        prf_data->Des().Append(iNONCE_I);
+        //No break is intended
+    case 1:
+        prf_data->Des().Append(aHashMsg,aHashMsgLen);
+        break;
+    case 3:
+        
+        prf_data->Des().Append(iNONCE_I);
+        DEBUG_LOG(_L("iNONCE_I"));
+        prf_data->Des().Append(iNONCE_R);
+        DEBUG_LOG(_L("iNONCE_R"));
+        break;
+    default:
+		CleanupStack::PopAndDestroy();  //prf_data		
+        return;
+    }
+
+    DEBUG_LOG1(_L("Hash_II(%d) prf"),aStage);
+
+    ComputePRFL(aHash, iSKEYID_a, prf_data->Des());
+    
+    DEBUG_LOG(_L("HASH"));
+
+	CleanupStack::PopAndDestroy();  //prf_data
+
+}
+
+//Computes the hash for a protected informational exchange
+void CIkev1Negotiation::ComputeHashInfL(TDes8& aHash, const TUint8 *aHashMsg, TInt aHashMsgLen)
+{
+	
+	HBufC8* prf_data =
+    HBufC8::NewLC(((aHashMsgLen + sizeof(iMessageId)) | 0x3) + 1);
+
+    //prf(SKEYID_a, M_ID | N/D)
+    TUint32 id = ByteOrder::Swap32(iMessageId);
+    prf_data->Des().Append((TUint8*)&id, sizeof(iMessageId));
+
+    prf_data->Des().Append(aHashMsg, aHashMsgLen);
+    
+    DEBUG_LOG(_L("Hash_NOT prf"));
+
+    ComputePRFL(aHash, iSKEYID_a, prf_data->Des());
+
+    DEBUG_LOG(_L("HASH"));
+
+	CleanupStack::PopAndDestroy();  //prf_data			
+
+}
+
+//Verifies that aHash is correct
+TBool CIkev1Negotiation::VerifyHash2L(const THashISAKMP *aHash,const TUint8 *aHashMsg, TInt aHashMsgLen)
+{
+	TBuf8<ISAKMP_HASH_SIZE> tmp_hash;	
+	
+    ComputeHash2L(tmp_hash, iStage, aHashMsg, aHashMsgLen);    //Computes the specified phase II hash
+
+    TBool Status = (Mem::Compare((TUint8*)tmp_hash.Ptr(), tmp_hash.Length(), aHash->Data(), aHash->DataLen()) == 0);
+
+	return Status;
+}
+
+//Verifies the hash of a Notification or Delete payload
+// Used also to verify the hash of Transaction exchange (Attribute payload) 
+TBool CIkev1Negotiation::VerifyInformationalHashL(const THashISAKMP *aHash,const TPayloadISAKMP *aPayload, TUint32 aMessageId)
+{
+    TBuf8<MAX_PRF_LENGTH> tmp_hash;
+
+    TUint32 tmp_id = ByteOrder::Swap32(aMessageId);
+    HBufC8 *prf_buf = HBufC8::NewLC(sizeof(tmp_id) + aPayload->GetLength());
+    prf_buf->Des().Copy((TUint8 *)&tmp_id , sizeof(tmp_id));
+    prf_buf->Des().Append((TUint8 *)aPayload, aPayload->GetLength());
+
+    ComputePRFL(tmp_hash, iSKEYID_a, prf_buf->Des());
+    TPtrC8 hash_ptr(aHash->Data(),aHash->DataLen());
+    TBool b = (tmp_hash.Compare(hash_ptr)==0);
+    CleanupStack::PopAndDestroy();  //prf_buf
+    return (b);
+}
+
+
+//Computes Own Nonce using current time a seed
+void CIkev1Negotiation::ComputeNonceL()
+{
+    DEBUG_LOG(_L("Computed NONCE."));
+    if (iRole==INITIATOR)
+    {
+        iNONCE_I.SetLength(OAKLEY_DEFAULT_NONCE_SIZE);
+        TRandom::RandomL(iNONCE_I);
+    }
+    else
+    {       
+        iNONCE_R.SetLength(OAKLEY_DEFAULT_NONCE_SIZE);
+        TRandom::RandomL(iNONCE_R);
+    }
+}
+
+//Computes HASH_R value
+void CIkev1Negotiation::ComputeHashrL(TDes8 &aHash)
+{
+    TInt    id_size = 0;
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod;
+
+    DEBUG_LOG(_L("Computing HASH_R"));
+
+    if ( auth_method != IKE_A_CRACK ) {         
+       if (iRole==INITIATOR)   
+       {  //peer id. payload
+          id_size = iPeerIdentPayloadSize;
+          DEBUG_LOG(_L("PeerID"));
+       }
+       else    
+       {  //Own identification payload
+          id_size = iOwnIdentPayloadSize;
+          DEBUG_LOG(_L("OwnID"));
+       }
+    }   
+            
+    DEBUG_LOG(_L("SKEYID"));
+
+    HBufC8 *prf_data;
+    if (iRole==INITIATOR)   //peer id. payload
+    {
+        prf_data = HBufC8::NewLC(iPeerPublicKey.Length() + iOwnPublicKey_ptr.Length() + iCookie_R.Length()
+        + iCookie_I.Length() + iSAPayloadSize + id_size);
+        prf_data->Des().Copy(iPeerPublicKey);
+        prf_data->Des().Append(iOwnPublicKey_ptr);
+        prf_data->Des().Append(iCookie_R);
+        prf_data->Des().Append(iCookie_I);
+        prf_data->Des().Append(iSAPayload,iSAPayloadSize);  //stored at the begining
+        if ( auth_method != IKE_A_CRACK )
+           prf_data->Des().Append(iPeerIdentPayload, iPeerIdentPayloadSize);
+    }
+    else    //RESPONDER
+    {
+        prf_data = HBufC8::NewLC(iOwnPublicKey_ptr.Length() + iPeerPublicKey.Length() + iCookie_R.Length()
+        + iCookie_I.Length() + iSAPayloadSize + id_size);
+        prf_data->Des().Copy(iOwnPublicKey_ptr);
+        prf_data->Des().Append(iPeerPublicKey);
+        prf_data->Des().Append(iCookie_R);
+        prf_data->Des().Append(iCookie_I);
+        prf_data->Des().Append(iSAPayload,iSAPayloadSize);  //stored at the begining
+        if ( auth_method != IKE_A_CRACK )
+           prf_data->Des().Append(iOwnIdentPayload, iOwnIdentPayloadSize);
+    }
+
+    DEBUG_LOG(_L("PRF"));
+
+    ComputePRFL(aHash, iSKEYID, prf_data->Des());
+
+    CleanupStack::PopAndDestroy();  //prf_data
+
+    DEBUG_LOG(_L("HASH_R"));
+
+}
+
+
+//Computes the value of iHASH_I
+void CIkev1Negotiation::ComputeHash1L(TDes8 &aHash)
+{
+    TInt    id_size = 0;
+    TUint16 auth_method = iChosenProposal_I.iAttrList->iAuthMethod; 
+
+    DEBUG_LOG(_L("Computing HASH_I"));
+
+    if ( auth_method != IKE_A_CRACK ) {         
+       if (iRole==INITIATOR)   //Own identification payload
+       {
+          id_size = iOwnIdentPayloadSize;
+          DEBUG_LOG(_L("OwnID"));
+       }
+       else    //peer id. payload
+       {
+          id_size = iPeerIdentPayloadSize;
+          DEBUG_LOG(_L("PeerID"));
+       }
+    }   
+            
+            
+    DEBUG_LOG(_L("SKEYID"));
+
+    HBufC8 *prf_data;
+    if (iRole==INITIATOR)
+    {
+        prf_data = HBufC8::NewLC(iOwnPublicKey_ptr.Length() + iPeerPublicKey.Length() + iCookie_I.Length()
+        + iCookie_R.Length() + iSAPayloadSize + id_size);
+        prf_data->Des().Copy(iOwnPublicKey_ptr);
+        prf_data->Des().Append(iPeerPublicKey);
+        prf_data->Des().Append(iCookie_I);
+        prf_data->Des().Append(iCookie_R);
+        prf_data->Des().Append(iSAPayload,iSAPayloadSize);  //stored at the begining
+        if ( auth_method != IKE_A_CRACK )
+           prf_data->Des().Append(iOwnIdentPayload,iOwnIdentPayloadSize);      
+    }
+    else    //RESPONDER
+    {
+        prf_data = HBufC8::NewLC(iPeerPublicKey.Length() + iOwnPublicKey_ptr.Length() + iCookie_I.Length()
+                                 + iCookie_R.Length() + iSAPayloadSize + id_size);
+        prf_data->Des().Copy(iPeerPublicKey);
+        prf_data->Des().Append(iOwnPublicKey_ptr);
+        prf_data->Des().Append(iCookie_I);
+        prf_data->Des().Append(iCookie_R);
+        prf_data->Des().Append(iSAPayload,iSAPayloadSize);  //stored at the begining
+
+        if ( auth_method != IKE_A_CRACK )       
+           prf_data->Des().Append(iPeerIdentPayload, iPeerIdentPayloadSize);        
+    }   
+
+    DEBUG_LOG(_L("PRF"));
+
+    ComputePRFL(aHash, iSKEYID, prf_data->Des());
+    CleanupStack::PopAndDestroy();  //prf_buf
+    DEBUG_LOG(_L("HASH_I"));
+}
+
+
+//Checks the encryption alg is valid
+TBool CIkev1Negotiation::CheckEncrAlg(TUint16 aValue)
+{
+    switch (aValue)
+    {
+    case DES_CBC:
+    case DES3_CBC:
+    case AES_CBC:
+        return ETrue;
+    case IDEA_CBC:
+    case BLOWFISH_CBC:
+    case RC5_R16_B64_CBC:
+    case CAST_CBC:
+        DEBUG_LOG(_L("Not implemented Encr algorithm"));
+        return ETrue; // Unknown attribute value NOT a fatal error !            
+    }
+    DEBUG_LOG(_L("Bad Encr algorithm"));
+
+    return ETrue; // Unknown attribute value NOT a fatal error !
+}
+
+
+
+TBool CIkev1Negotiation::CheckHashAlg(TUint16 aValue)
+{
+    switch (aValue)
+    {
+    case HASH_MD5:
+    case HASH_SHA1:
+        return ETrue;
+    case HASH_TIGER:
+        DEBUG_LOG(_L("Not implemented Hash algorithm"));
+        return ETrue; // Unknown attribute value NOT a fatal error !                            
+    }
+    DEBUG_LOG(_L("Bad Hash algorithm"));
+        return ETrue; // Unknown attribute value NOT a fatal error !                        
+
+}
+
+
+TBool CIkev1Negotiation::CheckAuthMethod(TUint16 aValue)
+{
+    switch (aValue)
+    {   
+    case PRE_SHARED:
+        if (iHostData->iPresharedKey.iKey.Length()==0)  //No preshared key defined
+        {
+            DEBUG_LOG(_L("Authentication method error (No Preshared key available"));
+            return EFalse;
+        }
+        return ETrue;
+    case RSA_SIG:
+    case DSS_SIG:
+    case IKE_A_CRACK:       
+        return ETrue;
+    }
+    DEBUG_LOG(_L("Bad Authentication method"));
+    return ETrue; // Unknown attribute value NOT a fatal error !
+
+}
+
+TBool CIkev1Negotiation::CheckGroupDesc(TUint16 aValue)
+{
+    switch (aValue)
+    {
+    case MODP_768:
+    case MODP_1024:
+    case MODP_1536:     
+    case MODP_2048:
+        return ETrue;
+    case EC2N_155:
+    case EC2N_185:
+        break;
+    }
+
+    return ETrue; // Unknown attribute value NOT a fatal error !    
+}
+
+
+TBool CIkev1Negotiation::CheckGroupType(TUint16 aValue)
+{
+    switch(aValue)
+    {
+    case MODP:
+        return ETrue;
+    case ECP:
+    case EC2N:
+        break;      
+    }
+
+    return ETrue; // Unknown attribute value NOT a fatal error !        
+
+}
+
+TBool CIkev1Negotiation::CheckGroupPrime(const TUint8* /* aValue */, TUint16 /* length */)
+{
+    return ETrue;
+}
+
+TBool CIkev1Negotiation::CheckGroupGen(const TUint8* /* aValue */, TUint16 /* length */)
+{
+    return ETrue;
+}
+
+TBool CIkev1Negotiation::CheckGroupCurve(const TUint8* /* aValue */, TUint16 /* length */)
+{
+    return ETrue;
+}
+
+//Used for Phase I and II
+TBool CIkev1Negotiation::CheckLifeType(TUint16 aValue)
+{
+    switch(aValue)
+    {
+    case SECONDS:
+    case KBYTES:
+        return ETrue;
+    }
+    return EFalse;
+}
+
+TBool CIkev1Negotiation::CheckLifeDuration(const TUint8* /* aValue */, TUint16 /* length */)
+{
+    return ETrue;
+}
+
+TBool CIkev1Negotiation::CheckPRF(TUint16 aValue)
+{
+    if (aValue!=OAKLEY_PRF_3DES_CBC_MAC)
+    {
+        DEBUG_LOG(_L("Bad PRF"));    
+        return EFalse;
+    }
+    return ETrue;
+}
+
+TBool CIkev1Negotiation::CheckKeyLength(TUint16 /*aValue*/,TUint8 aID,TUint8 aProtocol)
+{
+    TBool Status = ETrue;
+    switch (aProtocol)
+    {
+    case PROTO_ISAKMP:
+        if ( aID != AES_CBC )
+		{	
+           Status = EFalse; //all other supported algs have fixed size
+		   DEBUG_LOG(_L("Key length specified with fixed ISAKMP encryption algorithm"));
+		}
+        break;
+    case PROTO_IPSEC_AH:
+        Status = EFalse;      //Supported algorithms have fixed key length
+		DEBUG_LOG(_L("Key length specified with fixed AH integrity algorithm"));
+        break;
+    case PROTO_IPSEC_ESP:
+		if ( aID != ESP_AES_CBC )
+		{	
+		   Status = EFalse;
+		   DEBUG_LOG(_L("Key length specified with fixed ESP encryption algorithm"));		   
+		}   
+        break;
+    default:    //Unsupported SA type
+		Status = EFalse;      //Supported algorithms have fixed key length
+		break;
+    }
+
+	return Status;
+}
+
+TBool CIkev1Negotiation::CheckFieldSize(TUint16 /* aValue */)
+{
+    DEBUG_LOG(_L("Field size not supported"));
+    return EFalse;
+}
+
+TBool CIkev1Negotiation::CheckGroupOrder(const TUint8* /* aValue */, TUint16 /* length */)
+{
+    DEBUG_LOG(_L("Group Order not supported "));
+    return ETrue; // Unknown attribute value NOT a fatal error !                    
+}
+
+//Encapsulation mode
+TBool CIkev1Negotiation::CheckEncMode(TUint16 aValue)
+{
+    switch (aValue)
+    {
+    case DOI_TUNNEL:
+    case DOI_TRANSPORT:
+        return ETrue;
+    case UDP_ENC_TUNNEL:
+    case UDP_RFC_ENC_TUNNEL:
+//  case UDP_ENC_TRANSPORT:  
+        if ( iNAT_D_Flags )
+           return ETrue;
+        break;
+    }
+
+    DEBUG_LOG(_L("Bad Encapsulation mode"));
+    return EFalse;
+    
+}
+
+//defined authentication algorithm types. Other are invalid.
+TBool CIkev1Negotiation::CheckAuthAlg(TUint16 aValue)
+{
+    switch (aValue)
+    {
+    case DOI_HMAC_MD5:
+    case DOI_HMAC_SHA:
+        return ETrue;
+	case DOI_DES_MAC:		
+    case DOI_KPDK:
+        DEBUG_LOG(_L("Unimplemented Auhentication Algorithm"));
+    }
+    DEBUG_LOG(_L("Bad Auhentication Algorithm"));
+    return ETrue; // Unknown attribute value NOT a fatal error !                        
+}
+
+//By now only X509_CERT_SIG. Tristate error codes:
+//KErrNone -> accepted
+//KErrNotSupported ignored but no error Notification.
+//KErrGeneral: NOT accepted 
+TInt CIkev1Negotiation::CheckEncodingL(TUint8 aEncoding)
+{
+    switch (aEncoding)
+    {
+    case X509_CERT_SIG://X.509 Certificate - Signature
+        break;
+    case CRL://Certificate Revocation List (CRL)
+        DEBUG_LOG(_L("WARNING: CRL ignored because not supported"));
+        return KErrNotSupported;    //No notification, just ignored!
+    case PKCS://PKCS #7 wrapped X.509 certificate
+    case PGP://PGP Certificate
+    case DNS ://DNS Signed Key
+    case X509_CERT_KE://X.509 Certificate - Key Exchange
+    case KERBEROS://Kerberos Tokens
+    case ARL://Authority Revocation List (ARL)
+    case SPKI://SPKI Certificate
+    case X509_CERT_ATTR://X.509 Certificate - Attribute
+        DEBUG_LOG(_L("CERT_TYPE_UNSUPPORTED (not supported CERT type)"));
+        SendNotifyL(CERT_TYPE_UNSUPPORTED);
+        return KErrNotSupported;    // No notification, just ignored!        
+
+    default://Invalid encoding type
+        DEBUG_LOG(_L("INVALID_CERT_ENCODING (not existent CERT type)"));
+        SendNotifyL(INVALID_CERT_ENCODING);
+        return KErrNotSupported;    // No notification, just ignored!                
+
+    }
+
+    return KErrNone;
+}
+
+
+//Provisional (Uses as a seed time, Address and port)
+TCookie CIkev1Negotiation::CreateCookieL() const
+{
+    TCookie c;
+    //Cookie generation is Random no longer uses known data like addr
+    //or port (wrong?)
+    c.SetLength(ISAKMP_COOKIE_SIZE);
+	TRandom::RandomL(c);
+    return c;
+}
+
+TInt32 CIkev1Negotiation::RandomMessageId()
+{
+    TTime tmp_time;
+    tmp_time.UniversalTime();
+    TInt64 seed = tmp_time.Int64();
+    TInt32 rand = Math::Rand(seed);
+    return rand;
+}
+
+TBool CIkev1Negotiation::CheckCookies(const TCookie& aInit, const TCookie& aResp)
+    {
+    TCookie NULL_COOKIE;
+    NULL_COOKIE.FillZ(ISAKMP_COOKIE_SIZE);
+
+    if ( iCookie_I.Compare(NULL_COOKIE) != 0 &&
+         iCookie_I.Compare(aInit) != 0 )
+        {
+        DEBUG_LOG(_L("Initiator COOKIE incorrect"));
+        return EFalse;
+        }
+    if ( iCookie_R.Compare(NULL_COOKIE) != 0 &&
+         iCookie_R.Compare(aResp) != 0 )
+        {
+        DEBUG_LOG(_L("Responder COOKIE incorrect"));
+        return EFalse;
+        }
+
+    return ETrue;    
+    }
+
+//Checks if the payload value is correct
+TBool CIkev1Negotiation::CheckPayloadCode(TUint8 aPayload)
+{
+    switch (aPayload)
+    {
+    case ISAKMP_PAYLOAD_NONE:
+    case ISAKMP_PAYLOAD_SA:
+    case ISAKMP_PAYLOAD_P:
+    case ISAKMP_PAYLOAD_T:
+    case ISAKMP_PAYLOAD_KE:
+    case ISAKMP_PAYLOAD_ID:
+    case ISAKMP_PAYLOAD_CERT:
+    case ISAKMP_PAYLOAD_CR:
+    case ISAKMP_PAYLOAD_HASH:
+    case ISAKMP_PAYLOAD_SIG:
+    case ISAKMP_PAYLOAD_NONCE:
+    case ISAKMP_PAYLOAD_NOTIF:
+    case ISAKMP_PAYLOAD_D:
+    case ISAKMP_PAYLOAD_VID:
+    case ISAKMP_PAYLOAD_ATTRIBUTES:                         
+    case ISAKMP_PAYLOAD_CHRE:
+    case ISAKMP_INT_NETWORK:
+    case IETF_NAT_DISCOVERY:
+    case IETF_RFC_NAT_DISCOVERY:
+    case IETF_NAT_ORIG_ADDR:
+    case IETF_RFC_NAT_ORIG_ADDR:
+        return ETrue;   //supported payload type
+    }
+    DEBUG_LOG1(_L("INVALID_PAYLOAD_TYPE (%x)"),aPayload);
+    return EFalse;
+
+}
+
+
+//Checks if the version (major,minor) is supported
+TBool CIkev1Negotiation::CheckVersionL(TUint8 aVersion)
+{
+    if (aVersion >> 4  > MAJOR)
+    {
+        DEBUG_LOG(_L("INVALID_MAJOR_VERSION"));
+        SendNotifyL(INVALID_MAJOR_VERSION);
+        return EFalse;
+    }
+
+    if (aVersion & (0x0f) > MINOR)
+    {
+        DEBUG_LOG(_L("INVALID_MINOR_VERSION"));
+        SendNotifyL(INVALID_MINOR_VERSION);
+        return EFalse;
+    }
+
+    return ETrue;   //version correct
+}
+
+//Checks if the exchange type is valid and the same as in the negotiation
+TBool CIkev1Negotiation::CheckExchangeTypeL(TUint8 aType)
+{
+    switch (aType)
+    {
+    case ISAKMP_EXCHANGE_ID:    //Main
+    case ISAKMP_EXCHANGE_AGGR:  // Agressive
+    case ISAKMP_EXCHANGE_INFO:
+    case IKE_QUICK_MODE:
+        //invalid Exchange Type Not the same being used and not an error notification
+        if (aType != iExchange)
+        {
+            DEBUG_LOG(_L("INVALID_EXCHANGE_TYPE"));  //send the informational exchange
+            SendNotifyL(INVALID_EXCHANGE_TYPE);  //send the informational exchange
+            return EFalse;  //invalid Exchange Type
+        }
+        break;
+    case ISAKMP_EXCHANGE_BASE:  // Base
+    case ISAKMP_EXCHANGE_NONE:  // Identity Protection (Main mode in IKE)
+    case ISAKMP_EXCHANGE_AUTH:  // Authentication Only
+    case IKE_NEW_GROUP_MODE:    // New Group Mode
+        DEBUG_LOG(_L("INVALID_EXCHANGE_TYPE"));  //send the informational exchange
+        SendNotifyL(UNSUPPORTED_EXCHANGE_TYPE);  //send the informational exchange
+        return EFalse;
+    }
+
+    return ETrue;
+}
+
+//Checks the non-relevant bits are 0. Other comprovations are done when needed
+TBool CIkev1Negotiation::CheckFlagsL(TUint8 aFlags)
+{
+    if (aFlags >> 3 != 0)
+    {
+        DEBUG_LOG(_L("INVALID_FLAGS"));  //send the informational exchange
+        SendNotifyL(INVALID_FLAGS);  //send the informational exchange
+        return EFalse;
+    }
+
+    return ETrue;
+}
+
+//Checks the Id has a correct value. 0 in Phase I, the correct one in Phase II
+TBool CIkev1Negotiation::CheckMessageIdL(TUint32 aId)
+{
+    if (aId != iMessageId)    //iMessageId will be 0 during Phase I
+    {
+        DEBUG_LOG2(_L("INVALID_MESSAGE_ID %u (neg=%u)"),aId, iMessageId);
+        SendNotifyL(INVALID_MESSAGE_ID); //send the informational exchange
+        return EFalse;
+    }
+    return ETrue;
+}
+
+//Checks the DOI is valid
+TBool CIkev1Negotiation::CheckDOI(TUint32 aDOI)
+{
+    if (aDOI > IPSEC_DOI)    //Not IPSEC nor ISAKMP DOI
+        return EFalse;
+
+    return ETrue;
+}
+
+//Checks the SIT is valid
+TBool CIkev1Negotiation::CheckSituationL(TUint32 aSIT)
+{
+    //Secrecy and integrity not yet supported
+    if ((aSIT & IPSEC_SIT_SECRECY) || (aSIT & IPSEC_SIT_INTEGRITY))
+    {
+        DEBUG_LOG(_L("SITUATION_NOT_SUPPORTED"));    //send the informational exchange
+        SendNotifyL(SITUATION_NOT_SUPPORTED);    //send the informational exchange
+        return EFalse;
+    }
+
+    return ETrue;
+}
+//check the generic payload is OK. Correct payload + Reserved==0
+TBool CIkev1Negotiation::CheckGenericPayloadL(const TPayloadISAKMP *aPayload)
+{
+    if (!CheckPayloadCode(aPayload->GetPayload()))
+        return EFalse;
+
+    if (aPayload->GetReserved() != 0)   //Must be always 0
+    {
+        DEBUG_LOG(_L("INVALID RESERVED FIELD"));
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    if ((aPayload->GetLength() < MIN_ISAKMP_PAYLOAD_SIZE) || (aPayload->GetLength() > iLengthLeft))
+    {
+        DEBUG_LOG(_L("BAD PAYLOAD SIZE"));
+        SendNotifyL(PAYLOAD_MALFORMED);
+        return EFalse;
+    }
+
+    iLengthLeft -= aPayload->GetLength();   //Updates the length left in the buffer
+
+    return ETrue;
+
+}
+
+//checks if protocol supported
+TBool CIkev1Negotiation::CheckProtocolL(TUint8 aProtocol)
+{
+    switch (aProtocol)
+    {
+        //PHASE_I Protocol
+        case PROTO_ISAKMP:  //Only when establishing own SA??
+            if (iPhase != PHASE_I)
+            {
+                DEBUG_LOG(_L("INVALID_PROTOCOL_ID (ISAKMP only allowed in Phase I)"));
+                SendNotifyL(INVALID_PROTOCOL_ID);
+                return EFalse;
+            }
+            return ETrue;
+			
+        //PHASE_II Protocols
+        case PROTO_IPSEC_AH:
+        case PROTO_IPSEC_ESP:
+            if (iPhase != PHASE_II)
+            {
+                DEBUG_LOG1(_L("INVALID_PROTOCOL_ID (Prot (%u) only allowed in Phase II)"),aProtocol);
+                SendNotifyL(INVALID_PROTOCOL_ID);
+                return EFalse;
+            }
+            return ETrue;
+    }
+    DEBUG_LOG1(_L("INVALID_PROTOCOL_ID (Unknown Protocol (%u))"),aProtocol);
+    SendNotifyL(INVALID_PROTOCOL_ID);
+    return EFalse;
+}
+
+TBool CIkev1Negotiation::CheckSPIL(const TProposalISAKMP *aProposal)
+{
+
+    TUint size=aProposal->GetSPISize();
+    if (iPhase == PHASE_I)
+    {
+        if (size > MAX_SPI_SIZE)
+        {
+            DEBUG_LOG(_L("INVALID_SPI (Bad Size)"));
+            SendNotifyL(INVALID_SPI);
+            return EFalse;
+        }
+    }
+    else    //Phase II
+    {
+        TUint32 spi = 0;
+        if (aProposal->GetSPISize() > sizeof(TUint32))
+        {
+            DEBUG_LOG(_L("INVALID_SPI (Too big. Max. is 32 bits)"));
+            SendNotifyL(INVALID_SPI);
+            return EFalse;
+        }
+        Mem::Copy((TUint8 *)&spi, ((TProposalISAKMP *)aProposal)->SPI(), aProposal->GetSPISize());
+        spi = ByteOrder::Swap32(spi);
+        if (spi < 256)  //The first 256 are reserved
+        {
+            DEBUG_LOG(_L("INVALID_SPI (spi's < 256 are RESERVED)"));
+            SendNotifyL(INVALID_SPI);
+            return EFalse;
+        }
+    }
+    return ETrue;
+}
+
+//Checks for transform payloads. MUST NOT abort processing, just discard the payload
+TBool CIkev1Negotiation::CheckTransformID(TUint8 aProtocol,TUint8 aID)
+{
+    switch (aProtocol)
+    {
+    case PROTO_ISAKMP:
+        if (aID != KEY_IKE)
+            return EFalse;
+        break;
+		
+    case PROTO_IPSEC_AH:
+		if ( (aID != AH_MD5) && (aID != AH_SHA))
+		{
+			DEBUG_LOG(_L("Unsupported Authentication Algorithm"));					
+			return EFalse;
+		}
+        break;
+    case PROTO_IPSEC_ESP:
+		switch ( aID )
+		{
+			case ESP_DES_CBC:
+			case ESP_3DES_CBC:
+			case ESP_NULL:
+			case ESP_AES_CBC:				
+				break;
+			default:
+				DEBUG_LOG(_L("Unsupported Encryption Algorithm"));
+				return EFalse;
+		}	
+        break;
+		
+    default:
+        return EFalse;
+    }
+
+    return ETrue;
+}
+
+
+//Diffie-Hellman key exchange
+//The info in iNegotiation MUST be correct
+TBool CIkev1Negotiation::ComputeDHPublicValueL()
+{
+    TUint desc;
+    if (iPhase == PHASE_I)
+    {
+        //If aggressive sends the SA and KE at the same time b4 knowing the chosen group.
+        //The group in the first proposed transform is chosen. Shouldn't be transforms with 
+        //different groups sent. Checked when using the configuration tool?
+        if ((iExchange == ISAKMP_EXCHANGE_AGGR) && (iRole == INITIATOR))
+            desc = iProposal_I.iAttrList->iGroupDesc;
+        else
+            desc = iChosenProposal_I.iAttrList->iGroupDesc;
+    }
+    else
+    {
+        if (iRole == INITIATOR) //We have to use one of the proposals because we don't have the reply yet
+                                //Anyay only one group can be specified for phase II so it's fine
+            desc = iProposal_IIList->At(0)->iAttrList->At(0)->iGroupDesc;
+        else    //RESPONDER
+            desc = iChosenProp_IIList->At(0)->iAttrList->At(0)->iGroupDesc;
+    }
+
+    delete iOwnKeys;    //Happens in phase II because we may recalculate the DH value.
+	iOwnKeys = NULL;
+    delete iOwnPublicKey;   // Happens in phase II because we may recalculate the DH value.
+    iOwnPublicKey = NULL;
+
+    iOwnKeys = GeneratePubPrivKeysL(desc);
+    if (!iOwnKeys)
+    {
+        DEBUG_LOG(_L("Error generating DH public and private keys"));
+        return EFalse;
+    }
+    iOwnPublicKey = iOwnKeys->GetPubKey();    //save the public key in a buffer to have easy access
+    iOwnPublicKey_ptr.Set(iOwnPublicKey->Des());
+    return ETrue;
+}
+
+
+//Initial IV computation
+//Pre:Requires correct Public keys alredy stored!!!
+TBool CIkev1Negotiation::InitIVL()
+{
+	HBufC8* prf_data =
+    HBufC8::NewLC(((iOwnPublicKey_ptr.Length() + iPeerPublicKey.Length()) | 0x3) + 1);
+	
+    if (iRole == INITIATOR)
+    {
+        prf_data->Des().Copy(iOwnPublicKey_ptr);
+        prf_data->Des().Append(iPeerPublicKey);
+
+    }
+    else    //RESPONDER
+    {
+        prf_data->Des().Copy(iPeerPublicKey);
+        prf_data->Des().Append(iOwnPublicKey_ptr);
+    }
+    if (iChosenProposal_I.iAttrList->iHashAlg == HASH_MD5)
+         MD5HashL(prf_data->Des(), iIV);
+    else SHA1HashL(prf_data->Des(), iIV);
+
+    if (iChosenProposal_I.iAttrList->iEncrAlg == AES_CBC )
+         iIVSize = 16;
+    else iIVSize = 8;
+    iIV.SetLength(iIVSize); 
+    DEBUG_LOG(_L("Init"));
+
+	CleanupStack::PopAndDestroy();  //prf_data
+    
+    return ETrue;
+}
+
+
+
+//subsequent IV computations. Like when send notifications or beginning of Phase II
+TBool CIkev1Negotiation::ComputeIVL(TDes8 &aIV, TInt32 aMessageId)
+{ 
+	HBufC8* prf_data =
+    HBufC8::NewLC(((aIV.Length() + sizeof(aMessageId)) | 0x3) + 1);
+	
+    if ((iChosenProposal_I.iAttrList->iEncrAlg != DES3_CBC) &&
+	    (iChosenProposal_I.iAttrList->iEncrAlg != AES_CBC)  &&
+	    (iChosenProposal_I.iAttrList->iEncrAlg != DES_CBC))
+    {
+        return EFalse;
+    }
+    //former IV
+    prf_data->Des().Copy(aIV);
+    //Message ID
+    TInt32 id = ByteOrder::Swap32(aMessageId);  //Needed to add it
+
+    prf_data->Des().Append((TUint8 *)&id, sizeof(id));
+    
+    DEBUG_LOG(_L("prf"));
+    if (iChosenProposal_I.iAttrList->iHashAlg == HASH_MD5)
+		 MD5HashL(prf_data->Des(), aIV);
+    else SHA1HashL(prf_data->Des(), aIV);
+		
+    DEBUG_LOG(_L("Computed IV"));
+			
+    CleanupStack::PopAndDestroy();  //prf_data			
+    return ETrue;
+}
+
+//Generates all the keying material SKEYID,SKEYID_d,SKEYID_a,SKEYID_e
+TBool CIkev1Negotiation::ComputeKeysL()
+{
+	TUint desc;			
+    //If aggressive sends the SA and KE at the same time b4 knowing the chosen group.
+    //The group in the first proposed transform is chosen. Shouldn't be transforms with 
+    //different groups sent
+    if ((iExchange == ISAKMP_EXCHANGE_AGGR) && (iRole == INITIATOR))
+        desc = iProposal_I.iAttrList->iGroupDesc;
+    else
+        desc = iChosenProposal_I.iAttrList->iGroupDesc;
+	//
+	//Computes agreed key 
+	//
+	HBufC8* agreedKey = ComputeAgreedKeyL(desc, iPeerPublicKey, iOwnKeys);  //(gxy)
+	if ( !agreedKey ) {
+		DEBUG_LOG(_L("DH secret creation failed (ComputeAgreedKeyL)"));
+		SetErrorStatus( KKmdIkeNegotFailed );
+		SendNotifyL(INVALID_KEY_INFORMATION);				
+		return EFalse;
+	}
+	CleanupStack::PushL(agreedKey);  //agreedKey
+
+	// Use prf and agreed DH-key to generate keying material
+	HBufC8* prf_data =
+    HBufC8::NewLC(((iNONCE_I.Length() + iNONCE_R.Length() + 2*ISAKMP_COOKIE_SIZE) | 0x3) + 1);
+	HBufC8* prf_key  =
+    HBufC8::NewLC(((iNONCE_I.Length() + iNONCE_R.Length() ) | 0x3) + 1);
+
+    DEBUG_LOG(_L("Agreed Key."));
+
+    switch(iChosenProposal_I.iAttrList->iAuthMethod)
+    {
+    case RSA_SIG:
+    case DSS_SIG:
+    case IKE_A_CRACK:       
+        //For signatures:
+        //SKEYID = prf(Ni_b|Nr_b, g^xy)
+        //key
+        prf_key->Des().Copy(iNONCE_I);
+        prf_key->Des().Append(iNONCE_R);
+        ComputePRFL(iSKEYID, prf_key->Des(), agreedKey->Des());
+        break;
+    case PRE_SHARED:
+        {
+        //pre-shared keys:
+        //SKEYID=prf(pre_shared key, Ni_b | Nr_b);
+        //data
+        prf_data->Des().Copy(iNONCE_I.Ptr(),iNONCE_I.Length());
+        prf_data->Des().Append(iNONCE_R.Ptr(),iNONCE_R.Length());
+        DEBUG_LOG(_L("Pre-shared Key"));
+#ifdef _UNICODE
+        HBufC8 *preshared_key_buf = HBufC8::NewLC(iHostData->iPresharedKey.iKey.Length());
+        preshared_key_buf->Des().Copy(iHostData->iPresharedKey.iKey);
+        TPtrC8 preshared_key_ptr(preshared_key_buf->Des());
+#else
+        TPtrC8 preshared_key_ptr(iHostData->iPresharedKey.iKey);
+#endif
+        ComputePRFL(iSKEYID, preshared_key_ptr, prf_data->Des());
+#ifdef _UNICODE
+        CleanupStack::PopAndDestroy();  //presharedkey_buf
+#endif
+        }
+        break;
+    default://method not implemented
+        DEBUG_LOG1(_L("ATTRIBUTES_NOT_SUPPORTED:Auth Method %d not supported "),iChosenProposal_I.iAttrList->iAuthMethod);
+        SetErrorStatus( KKmdIkeNegotFailed );
+        SendNotifyL(ATTRIBUTES_NOT_SUPPORTED);
+        return EFalse;
+    }
+	
+	CleanupStack::PopAndDestroy(2);  //prf_data and prf_key
+	prf_data =
+	HBufC8::NewLC(((agreedKey->Length() + iSKEYID.Length() + 2*ISAKMP_COOKIE_SIZE + 4) | 0x3) + 1);
+	
+    prf_data->Des().Copy(agreedKey->Des());
+    prf_data->Des().Append(iCookie_I);
+    prf_data->Des().Append(iCookie_R);
+    prf_data->Des().Append(0);
+    ComputePRFL(iSKEYID_d, iSKEYID, prf_data->Des());
+
+    prf_data->Des().Copy(iSKEYID_d);
+    prf_data->Des().Append(agreedKey->Des());
+    prf_data->Des().Append(iCookie_I);
+    prf_data->Des().Append(iCookie_R);
+    prf_data->Des().Append(1);
+    ComputePRFL(iSKEYID_a, iSKEYID, prf_data->Des());
+
+    prf_data->Des().Copy(iSKEYID_a);
+    prf_data->Des().Append(agreedKey->Des());
+    prf_data->Des().Append(iCookie_I);
+    prf_data->Des().Append(iCookie_R);
+    prf_data->Des().Append(2);
+    ComputePRFL(iSKEYID_e, iSKEYID, prf_data->Des());
+
+	agreedKey->Des().FillZ();  // Zeroe DH secret g^xy
+
+    //Builds the IV 
+    if (!InitIVL())
+    {
+        DEBUG_LOG(_L("Error Computing IV"));
+        return EFalse;
+    }
+    if (iExchange == ISAKMP_EXCHANGE_AGGR)
+    {
+        iLastIV.Copy(iIV);      //Saves last IV in Phase 1
+        iLastIV.SetLength(iIVSize);   
+        DEBUG_LOG(_L("Last IV Saved!"));
+    }
+
+    //if key extension required:
+    TUint8 *key;
+    TInt key_len=0;
+    TInt total_key_len = ISAKMPEncrKeyLength((TUint8)iChosenProposal_I.iAttrList->iEncrAlg);
+    if (iSKEYID_e.Length() < total_key_len)
+    {
+        DEBUG_LOG(_L("Extending encrytion key..."));
+        key = new (ELeave) TUint8[total_key_len*2];
+        CleanupStack::PushL(key);
+        key[0] = 0;
+        TPtr8 kx0_ptr(key, 1, 1);
+        TPtr8 kx1_ptr(key, 0, total_key_len * 2);
+        ComputePRFL(kx1_ptr, iSKEYID_e, kx0_ptr); //K1=prf(SKEYID_e,0)
+        key_len += kx1_ptr.Length();
+        
+        while (key_len < total_key_len)
+        {
+            kx0_ptr.Set(&key[key_len - kx1_ptr.Length()], kx1_ptr.Length(), total_key_len);
+            kx1_ptr.Set(&key[key_len], 0, total_key_len);
+            ComputePRFL(kx1_ptr, iSKEYID_e, kx0_ptr); //Kx=prf(SKEYID_e,K<x-1>)
+            key_len += kx1_ptr.Length();
+        }
+        iSKEYID_e.Copy(key, total_key_len);
+        CleanupStack::PopAndDestroy();  //key
+        DEBUG_LOG(_L(" SKEYID_e (EXTENDED)"));
+    }
+	else
+	{
+		iSKEYID_e.SetLength(total_key_len);		
+		DEBUG_LOG(_L(" SKEYID_e"));
+	}
+    
+    DEBUG_LOG(_L(" Init IV"));
+
+	CleanupStack::PopAndDestroy(2);  //prf_data and agreedKey
+	
+    return ETrue;
+}
+
+//Computes the IPSEC keys needed for each IPSEC SA
+//KEYMAT = prf(SKEY_ID, protocol | SPI | Ni_b | Nr_b)
+//if PFS:
+//KEYMAT = prf(SKEY_ID, g(qm)^xy | protocol | SPI | Ni_b | Nr_b)
+void CIkev1Negotiation::ComputeKeys2L(const CProposal_II *aProp, TInt aKeyLen, TSPINode &aInboundSpiNode, TDes8& aOutboundKey_II, TDes8& aInboundKey_II)
+{
+    DEBUG_LOG(_L("Computing PHASE II keys "));
+    
+    aOutboundKey_II.SetLength(0);
+    aInboundKey_II.SetLength(0);
+    DEBUG_LOG(_L("Total Computed Key Length="));
+    DEBUG_LOG_NUM(aKeyLen);
+
+	HBufC8* agreedKey = NULL; //g(qm)^xy
+	TInt  prf_len = iSKEYID_d.Length() + iNONCE_I.Length() + iNONCE_R.Length() + 8; // 8 for protocol and SPI
+	
+    if (iPFS)
+    {
+        agreedKey = ComputeAgreedKeyL(iChosenProp_IIList->At(0)->iAttrList->At(0)->iGroupDesc, iPeerPublicKey, iOwnKeys);
+		if ( !agreedKey )
+			User::Leave(KErrGeneral);
+		CleanupStack::PushL(agreedKey);
+		prf_len += agreedKey->Length(); 
+        DEBUG_LOG(_L(" Agreed Key"));
+    }
+#ifdef _DEBUG    
+	else DEBUG_LOG(_L("(NO PFS)"));
+#endif // _DEBUG	
+
+    DEBUG_LOG(_L("Protocol:"));
+    DEBUG_LOG_NUM(aProp->iProtocol);
+  
+    TUint32 in_spi = aInboundSpiNode.iSPI;  //inbound spi in Network Order
+    DEBUG_LOG(_L("InSPI:"));
+    DEBUG_LOG_NUM(ByteOrder::Swap32(in_spi));
+    TUint32 out_spi;
+    Mem::Copy((TUint8 *)&out_spi, aProp->iSPI.Ptr(), aProp->iSPI.Length());
+    DEBUG_LOG1(_L("OutSPI: %x"), out_spi);
+    //Inbound and outbound calculations only differ in the SPI
+    //If the key is not long enough we need to extend it
+    TPtr8 key_ptr((TUint8 *)aOutboundKey_II.Ptr() + aOutboundKey_II.Length(), 0, aOutboundKey_II.MaxLength());
+	
+	HBufC8* prf_data = HBufC8::NewLC((prf_len | 0x3) + 1);
+	
+    while ((aOutboundKey_II.Length() * 8) < aKeyLen)  //include the key extension algorithm
+    {
+        prf_data->Des().Copy(key_ptr);
+        if (agreedKey)//Only used if PFS
+        {
+            prf_data->Des().Append(agreedKey->Des());
+        }
+        prf_data->Des().Append(&aProp->iProtocol, sizeof(aProp->iProtocol));
+        prf_data->Des().Append(aProp->iSPI.Ptr(),aProp->iSPI.Length());
+        prf_data->Des().Append(iNONCE_I);
+        prf_data->Des().Append(iNONCE_R);
+        key_ptr.Set((TUint8 *)aOutboundKey_II.Ptr() + aOutboundKey_II.Length(), 0, aOutboundKey_II.MaxLength() - aOutboundKey_II.Length());
+        ComputePRFL(key_ptr, iSKEYID_d, prf_data->Des());
+        aOutboundKey_II.SetLength(aOutboundKey_II.Length() + key_ptr.Length());
+    }
+
+    key_ptr.Set((TUint8 *)aInboundKey_II.Ptr() + aInboundKey_II.Length(), 0, aOutboundKey_II.MaxLength());
+    while ((aInboundKey_II.Length() * 8) < aKeyLen)  //include the key extension algorithm
+    {
+        prf_data->Des().Copy(key_ptr);
+        if (agreedKey)//Only used if PFS
+        {
+            prf_data->Des().Append(agreedKey->Des());
+        }
+        prf_data->Des().Append(&aProp->iProtocol,sizeof(aProp->iProtocol));
+        prf_data->Des().Append((TUint8 *)&in_spi, sizeof(TUint32));
+        prf_data->Des().Append(iNONCE_I);
+        prf_data->Des().Append(iNONCE_R);
+        
+        key_ptr.Set((TUint8 *)aInboundKey_II.Ptr() + aInboundKey_II.Length(), 0, aInboundKey_II.MaxLength() - aInboundKey_II.Length());
+        ComputePRFL(key_ptr, iSKEYID_d, prf_data->Des());
+        aInboundKey_II.SetLength(aInboundKey_II.Length() + key_ptr.Length());
+    }
+
+	if ( agreedKey )		
+	     CleanupStack::PopAndDestroy(2);  //prf_data and agreedKey
+	else CleanupStack::PopAndDestroy();   //prf_data
+			
+}
+
+
+/* This function is called by oakley module to do pseudo random computation for
+   given data */
+//IMPORTANT: If some func added or modified check MAX_PRF_LENGTH is correct in ike.h
+
+void CIkev1Negotiation::ComputePRFL(TDes8 &prf_output, const TDesC8 &prf_key, const TDesC8 &prf_data)
+{
+// All actions taken are moved into the crypto module IKE_CRYPTO.CPP
+    
+    if ( iChosenProposal_I.iAttrList->iPRF == OAKLEY_PRF_3DES_CBC_MAC)
+    {
+       DEBUG_LOG(_L("PRF (3DES_CBC_MAC)"));        
+       Hmac3DesCbcL(prf_data, prf_output, prf_key);  
+    }
+    else
+    {
+      // Use HMAC version of the negotiated hash function as default PRF
+        if ( iChosenProposal_I.iAttrList->iHashAlg == HASH_MD5 ) {
+           DEBUG_LOG(_L("PRF (MD5)"));           
+           MD5HmacL(prf_data, prf_output, prf_key);
+        }   
+        else {
+           if ( iChosenProposal_I.iAttrList->iHashAlg == HASH_SHA1 ) {
+              DEBUG_LOG(_L("PRF (SHA1)"));              
+              SHA1HmacL(prf_data, prf_output, prf_key);
+           }
+        }   
+    }
+
+}
+
+
+//NOTE: Must be called after ProcessCertificate() !!!
+TBool CIkev1Negotiation::CertifyRemoteIdentityL(const TIdentISAKMP *aIdPayload)
+{
+  TBool Status = EFalse;
+  TInt id_len  = aIdPayload->IDDataLen();
+
+  if ( id_len && iPkiService && iPeerX509Cert )
+  {
+    TPtrC8 IdData((TUint8 *)aIdPayload->IDData(), id_len);
+
+    // Leave is trapped and handled here because the event log is easily accessible
+    // and in the upper layers it would not be possible to identify the
+    // cause of the error based on the generic leave code.
+    TRAPD(err, Status = IkePkiUtils::CertifyIdentityL(iPeerX509Cert, IdData, (TInt)aIdPayload->GetIDType()));
+
+    if( KErrNotSupported == err )
+    {
+      LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+                     R_VPN_MSG_CERT_ERROR,
+                     KErrNotSupported,
+                     iPluginSession->VpnIapId(),
+                     &iRemoteAddr );
+    }
+
+#ifdef _DEBUG    
+    if (Status)
+        DEBUG_LOG(_L("Remote identity has been certified"));
+#endif // _DEBUG    
+  }
+       
+  return Status;
+}
+
+
+//Digests aHash with the key in aCert and compares it to the stored value aSig
+//Needs to be check after the Signature payload has been processed
+TBool CIkev1Negotiation::VerifySignatureL(CX509Certificate *aCert,TUint8 *aHash, TInt aHashLength,TUint8 *aSig, TUint aSigLength)
+{
+
+	TBool ret = EFalse;
+	if ( iPkiService )
+	{
+		TPtrC8 Signature(aSig, aSigLength);
+		TPtrC8 RefHash(aHash, aHashLength);	   							   			
+	    ret = IkePkiUtils::VerifyIkev1SignatureL(Signature, RefHash, *aCert);
+	}   
+	
+    return ret;
+
+
+}
+
+//NOTE!!! The func sets iFinished to TRUE always so after detecting an error the communication finishes.
+//If it doesn't have to iFinished should be set outside the function.
+void CIkev1Negotiation::SendNotifyL(TUint16 aError)
+{
+	SetFinished();  //Ends the negotiation (error condition detected) If CONNECTED also should end
+	
+#ifdef _DEBUG	
+    TBuf<60> buf;
+    DEBUG_LOG(_L("SendNotifyL(), Reason: "));
+    buf.Append(TextNotifyType(aError));
+    DEBUG_LOG(buf);
+#endif // _DEBUG    
+    TUint8 protocol = PROTO_ISAKMP;
+    TUint8 tmp_exchange = iExchange;
+    TUint32 tmp_msg_id = iMessageId;
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );			
+    //If configured to send notification payloads for errors
+    if (iHostData->iNotify)
+    {
+        iExchange = ISAKMP_EXCHANGE_INFO;
+        iMessageId = RandomMessageId();
+        msg->IsakmpInit(this);
+		
+        //HASH Payload only if payload protected with encyption
+        if (iFlags & ISAKMP_HDR_EFLAG)
+      		msg->IsakmpHashL();		
+
+        if (iPhase == PHASE_I)
+            protocol = iChosenProposal_I.iProtocol;
+        else
+        {
+            if (iChosenProp_IIList) //May be the begining of PHASE_II when still not decided
+                protocol = iChosenProp_IIList->At(0)->iProtocol;
+        }
+        msg->IsakmpNotification(aError, protocol);
+
+        if (iFlags & ISAKMP_HDR_EFLAG)
+        {
+            msg->IsakmpHashContL();
+        }
+
+        iExchange  = tmp_exchange;
+        iMessageId = tmp_msg_id;
+
+		SendL(*msg);
+
+  		LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+  		               R_VPN_MSG_SENT_ERROR_RESPONSE,
+  		               aError,
+  		               iPluginSession->VpnIapId(),
+  		               &iRemoteAddr );
+    }
+
+}
+
+
+//Hash function key length (in bytes)
+TInt CIkev1Negotiation::HashLength()
+{
+    if (iChosenProposal_I.iAttrList->iPRF == OAKLEY_PRF_3DES_CBC_MAC)
+        return 24;
+        
+    //If no PRF hash alg used instead.
+    if (iChosenProposal_I.iAttrList->iPRF==0)
+    {
+        if (iChosenProposal_I.iAttrList->iHashAlg==HASH_MD5)
+            return HMAC_MD5_SIZE/8; //16 bytes
+            //return MD5_DIGEST_LENGTH;
+        else if (iChosenProposal_I.iAttrList->iHashAlg==HASH_SHA1)
+            return HMAC_SHA1_SIZE/8;
+            //return SHA_DIGEST_LENGTH;
+    }
+    
+    return 0;
+}
+
+
+//Could be done using directly iEncrAlg from the chosen transform (in bytes)
+TUint32 CIkev1Negotiation::ISAKMPEncrKeyLength(TUint8 aAlgId) const
+{
+    TUint32 KeyLth = 0;
+    switch (aAlgId) {
+        case DES_CBC:
+            KeyLth = 8;
+            break;
+        case DES3_CBC:
+            KeyLth = 24;
+            break;
+        case AES_CBC:
+            if ( iChosenProposal_I.iAttrList->iKeyLength )
+                 KeyLth = (TUint32)(iChosenProposal_I.iAttrList->iKeyLength/8);
+            else KeyLth = 16;  // default
+            break;
+        default:
+            break;
+    }           
+        
+    return KeyLth;
+}
+
+TIkev1IsakmpStream* CIkev1Negotiation::SaveIkeMsgBfr(TIkev1IsakmpStream* aMsg)
+{
+	delete iSavedIkeMsgBfr;
+    iSavedIkeMsgBfr = aMsg;
+	return aMsg;
+}	
+
+//Returns the key length (in bits) of an algorithm for iAuth (TAttrib_II) field when protocol is AH
+TUint32 CIkev1Negotiation::HMAC_KeyLength(TUint8 aId) const
+{
+    if (aId == SADB_AALG_MD5HMAC)
+        return (HMAC_MD5_SIZE);
+    else if (aId == SADB_AALG_SHA1HMAC)
+        return (HMAC_SHA1_SIZE);
+
+  return (0); // Error 
+}
+
+//Exchange Type
+TPtrC CIkev1Negotiation::TextNotifyType(TUint16 aNotif)
+{
+#ifndef _DEBUG
+    (void)aNotif;
+#endif
+
+#ifdef _DEBUG
+    //TBuf<35> err;
+    switch(aNotif)
+    {
+    case INVALID_PAYLOAD_TYPE:
+        return _L("INVALID_PAYLOAD_TYPE");
+    case DOI_NOT_SUPPORTED:
+        return _L("DOI_NOT_SUPPORTED");
+    case SITUATION_NOT_SUPPORTED:
+        return _L("SITUATION_NOT_SUPPORTED");
+    case INVALID_COOKIE:
+        return _L("INVALID_COOKIE");
+    case INVALID_MAJOR_VERSION:
+        return _L("INVALID_MAJOR_VERSION");
+    case INVALID_MINOR_VERSION:
+        return _L("INVALID_MINOR_VERSION");
+    case INVALID_EXCHANGE_TYPE:
+        return _L("INVALID_EXCHANGE_TYPE");
+    case INVALID_FLAGS:
+        return _L("INVALID_FLAGS");
+    case INVALID_MESSAGE_ID:
+        return _L("INVALID_MESSAGE_ID");
+    case INVALID_PROTOCOL_ID:
+        return _L("INVALID_PROTOCOL_ID");
+    case INVALID_SPI:
+        return _L("INVALID_SPI");
+    case INVALID_TRANSFORM_ID:
+        return _L("INVALID_TRANSFORM_ID");
+    case ATTRIBUTES_NOT_SUPPORTED:
+        return _L("ATTRIBUTES_NOT_SUPPORTED");
+    case NO_PROPOSAL_CHOSEN:
+        return _L("NO_PROPOSAL_CHOSEN");
+    case BAD_PROPOSAL_SYNTAX:
+        return _L("BAD_PROPOSAL_SYNTAX");
+    case PAYLOAD_MALFORMED:
+        return _L("PAYLOAD_MALFORMED");
+    case INVALID_KEY_INFORMATION:
+        return _L("INVALID_KEY_INFORMATION");
+    case INVALID_ID_INFORMATION:
+        return _L("INVALID_ID_INFORMATION");
+    case INVALID_CERT_ENCODING:
+        return _L("INVALID_CERT_ENCODING");
+    case INVALID_CERTIFICATE:
+        return _L("INVALID_CERTIFICATE");
+    case CERT_TYPE_UNSUPPORTED:
+        return _L("CERT_TYPE_UNSUPPORTED");
+    case INVALID_CERT_AUTHORITY:
+        return _L("INVALID_CERT_AUTHORITY");
+    case INVALID_HASH_INFORMATION:
+        return _L("INVALID_HASH_INFORMATION");
+    case AUTHENTICATION_FAILED:
+        return _L("AUTHENTICATION_FAILED");
+    case INVALID_SIGNATURE:
+        return _L("INVALID_SIGNATURE");
+    case ADDRESS_NOTIFICATION:
+        return _L("ADDRESS_NOTIFICATION");
+    case NOTIFY_SA_LIFETIME:
+        return _L("NOTIFY_SA_LIFETIME");
+    case CERTIFICATE_UNAVAILABLE:
+        return _L("CERTIFICATE_UNAVAILABLE");
+    case UNSUPPORTED_EXCHANGE_TYPE:
+        return _L("UNSUPPORTED_EXCHANGE_TYPE");
+    case UNEQUAL_PAYLOAD_LENGTHS:
+        return _L("UNEQUAL_PAYLOAD_LENGTHS");
+    case CONNECTED:
+        return _L("CONNECTED");
+	case DOI_RESPONDER_LIFETIME:
+		return _L("RESPONDER_LIFETIME");
+	case DOI_REPLAY_STATUS:
+		return _L("REPLAY_STATUS");
+	case DOI_INITIAL_CONTACT:
+		return _L("INITIAL_CONTACT");
+    }
+    return _L("Unknown ");
+#else
+    return NULL;
+#endif          
+}
+
+
+void CIkev1Negotiation::TextPayload(TDes &aBuf, TUint8 aPayload)
+{
+#ifndef _DEBUG
+    (void)aBuf;
+    (void)aPayload;
+#endif
+
+#ifdef _DEBUG
+    switch(aPayload)
+    {
+    case ISAKMP_PAYLOAD_NONE:// (Terminator)
+        aBuf = _L("ISAKMP_PAYLOAD_NONE");
+        break;
+    case ISAKMP_PAYLOAD_SA:// Security Association
+        aBuf = _L("ISAKMP_PAYLOAD_SA");
+        break;
+    case ISAKMP_PAYLOAD_P:// Proposal
+        aBuf = _L("ISAKMP_PAYLOAD_P");
+        break;
+    case ISAKMP_PAYLOAD_T:// Transform
+        aBuf = _L("ISAKMP_PAYLOAD_T");
+        break;
+    case ISAKMP_PAYLOAD_KE:// Key Exchange
+        aBuf = _L("ISAKMP_PAYLOAD_KE");
+        break;
+    case ISAKMP_PAYLOAD_ID:// Identification
+        aBuf = _L("ISAKMP_PAYLOAD_ID");
+        break;
+    case ISAKMP_PAYLOAD_CERT:// Certificate
+        aBuf = _L("ISAKMP_PAYLOAD_CERT");
+        break;
+    case ISAKMP_PAYLOAD_CR:// Certificate Request
+        aBuf = _L("ISAKMP_PAYLOAD_CR");
+        break;
+    case ISAKMP_PAYLOAD_HASH:// Hash
+        aBuf = _L("ISAKMP_PAYLOAD_HASH");
+        break;
+    case ISAKMP_PAYLOAD_SIG:// Signature
+        aBuf = _L("ISAKMP_PAYLOAD_SIG");
+        break;
+    case ISAKMP_PAYLOAD_NONCE:// Nonce
+        aBuf = _L("ISAKMP_PAYLOAD_NONCE");
+        break;
+    case ISAKMP_PAYLOAD_NOTIF:// Notification
+        aBuf = _L("ISAKMP_PAYLOAD_NOTIF");
+        break;
+    case ISAKMP_PAYLOAD_D:// Delete
+        aBuf = _L("ISAKMP_PAYLOAD_D");
+        break;
+    case ISAKMP_PAYLOAD_VID:// Vendor ID
+        aBuf = _L("ISAKMP_PAYLOAD_VID");
+        break;
+    case ISAKMP_PAYLOAD_PRIVATE:// Private use (up to 255)
+        aBuf = _L("ISAKMP_PAYLOAD_PRIVATE");
+        break;
+    default:
+        aBuf.Format(_L("Unknown (%d) "),aPayload);
+    }
+#endif                  
+}
+
+//Sends the built message through the socket
+void CIkev1Negotiation::SendL(TIkev1IsakmpStream &aMsg)
+{
+    if (aMsg.iError)
+    {
+        DEBUG_LOG(_L("Error Building message"));
+        return;
+    }
+    TBuf8<IKEV1_MAX_IV_SIZE> tmp_IV;
+    
+    ThdrISAKMP *hdr = (ThdrISAKMP *)aMsg.iBuf.Ptr();
+    hdr->SetLength(aMsg.iBuf.Length());
+    DEBUG_LOG(_L("Sending (clear)..."));
+    
+    TBool FloatedPort = EFalse; 
+    if ( iNAT_D_Flags & (REMOTE_END_NAT + LOCAL_END_NAT) )
+        FloatedPort = ETrue;
+    
+#ifdef _DEBUG
+    const TPtrC8 ikeMsgPtr( aMsg.iBuf.Ptr(), aMsg.iBuf.Length() );
+    TInetAddr localAddr;
+    iPluginSession->GetLocalAddress( localAddr );    
+    TInt port = ( FloatedPort ? IkeSocket::KIkePort4500 : IkeSocket::KIkePort500 );
+    localAddr.SetPort( port );
+    TRACE_MSG_IKEV1( ikeMsgPtr, localAddr, iLastRemoteAddr );
+#endif // _DEBUG
+    
+    TPtr8 lastMsg(iLastMsg->Des());   
+
+    if (hdr->GetFlags() & ISAKMP_HDR_EFLAG)
+    {
+        DEBUG_LOG(_L("Encrypting..."));
+
+        if (hdr->GetExchange()==ISAKMP_EXCHANGE_INFO || hdr->GetExchange()==ISAKMP_EXCHANGE_TRANSACT )
+        {
+            if ( hdr->GetExchange()==ISAKMP_EXCHANGE_TRANSACT )
+            {
+               //
+               // Get current IV via CTransNegotiation object linked into
+               // CIkev1Negotiation  
+               //
+               if ( !iTransactionNeg ||
+                    !iTransactionNeg->GetIV(hdr->GetMessageId(), tmp_IV) )
+               {
+                   DEBUG_LOG(_L("Send error ! Cannot get Transaction IV !"));
+                   return;
+               }       
+               DEBUG_LOG(_L("Transaction IV"));                     
+               EncryptL(aMsg.iBuf, lastMsg, tmp_IV, iSKEYID_e, iChosenProposal_I.iAttrList->iEncrAlg);
+               iTransactionNeg->SetIV(hdr->GetMessageId(), tmp_IV);
+            }   
+            else
+            {
+               if (iLastIV.Length() != 0)
+                    tmp_IV.Copy(iLastIV);
+               else    //iLastIV not yet computed so current iIV is used
+                    tmp_IV.Copy(iIV);
+               ComputeIVL(tmp_IV, hdr->GetMessageId());
+               DEBUG_LOG(_L("Notif IV"));
+               EncryptL(aMsg.iBuf, lastMsg, tmp_IV, iSKEYID_e, iChosenProposal_I.iAttrList->iEncrAlg);
+            }   
+
+        }
+        else    //Normal exchange MAIN, AGGR or QUICK
+        {
+            DEBUG_LOG(_L("IV"));
+            EncryptL(aMsg.iBuf, lastMsg, iIV, iSKEYID_e, iChosenProposal_I.iAttrList->iEncrAlg);
+            DEBUG_LOG(_L("New IV (dec)"));
+            //Saves last iIV in Phase 1
+            if (((iStage==6) && (iExchange == ISAKMP_EXCHANGE_ID)) ||
+                ((iStage==3) && (iExchange == ISAKMP_EXCHANGE_AGGR)))
+            {
+                iLastIV.Copy(iIV);  
+                DEBUG_LOG(_L("Last IV Saved!"));
+            }
+        }
+
+        DEBUG_LOG(_L("Sending ..."));
+        DEBUG_LOG1(_L("EncrLen = %d"), lastMsg.Length());
+    }
+    else
+        {
+        lastMsg.Copy(aMsg.iBuf);
+        }
+
+    hdr = (ThdrISAKMP *)lastMsg.Ptr();
+    hdr->SetLength(lastMsg.Length());  //Set the total length!!!		
+
+    if (hdr->GetExchange() == ISAKMP_EXCHANGE_INFO)
+    {
+        SendAndSaveIkeMsgL(lastMsg, iLastRemoteAddr, FloatedPort);   //No timers!
+    }
+    else    //Normal msg.
+    {
+        iTimer->Cancel();   //Cancel previous timer because reply received & processed
+        DEBUG_LOG(_L("Timer Cancelled!"));
+        iRetryNum = 0;
+		SendAndSaveIkeMsgL(lastMsg, iLastRemoteAddr, FloatedPort);
+        iTimer->IssueRequest(MAX_RETRANS_TIMER * 1000000); // 1000000 = 1 second
+    }
+    
+}
+
+
+void CIkev1Negotiation::ReSendL()
+{
+    //Will resend a packet in the interval (MAX_RETRANS_TIMER/2 , MAX_RETRANS_TIMER)
+    if ( iRetryNum < MAX_RETRANS_COUNT ) 
+    {
+        DEBUG_LOG2(_L("---------- Phase %d - Stage %d ----------"),iPhase, iStage - 1);
+        DEBUG_LOG1(_L("ReSending(%d)..."), iRetryNum);
+		TBool FloatedPort = EFalse;	
+		if ( iNAT_D_Flags & (REMOTE_END_NAT + LOCAL_END_NAT) )
+			FloatedPort = ETrue;
+		TPtr8 lastMsg(iLastMsg->Des());
+		iPluginSession->SendIkeMsgL(lastMsg, iLastRemoteAddr, FloatedPort);  
+        //next retransmission between MAX_RETRANS_TIMER/2 and MAX_RETRANS_TIMER seconds
+        TTime tmp_time;
+        TReal secs = 0;
+        tmp_time.UniversalTime();
+        TInt64 seed = tmp_time.Int64();
+        TInt rand = Math::Rand(seed);
+        TInt err = Math::Round(secs, rand / (KMaxTInt / MAX_RETRANS_TIMER/2), 0);
+        secs = Math::Round(secs, secs + MAX_RETRANS_TIMER/2, 0);
+        if ((!secs) || (err != KErrNone))
+            secs = MAX_RETRANS_TIMER/2;
+        iTimer->IssueRequest((TInt)secs * 1000000);  // 1000000 = 1 second
+        iRetryNum++;
+    }
+    else
+    {
+		SendDeleteL(PROTO_ISAKMP);
+		if ( iPhase == PHASE_I )
+		{	
+           DEBUG_LOG(_L("Max num retries reached!!!"));
+		}		
+		else
+		{		    
+		    DEBUG_LOG(_L("Quick mode failed, Max num retries reached!!!"));
+		}
+	
+		if ( iPhase == PHASE_I &&
+		     iPluginSession->FindIkev1SA() == NULL )
+		{
+            // Set error status in Phase 1, if there are no IKE SAs.
+            if ( GetNotifyStatus() )
+                 SetErrorStatus(KKmdIkeNoProposalErr);                                           
+            else SetErrorStatus(KKmdIkeNoResponseErr);
+		}
+		
+        LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+                       R_VPN_MSG_VPN_GW_NO_RESP,
+                       ErrorStatus(),
+                       iPluginSession->VpnIapId(),
+                       &iRemoteAddr );								
+        iPluginSession->DeleteNegotiation( this );
+    }
+}
+
+void CIkev1Negotiation::SendDeleteL(TUint8 aProtocol, TUint32 aIpsecSPI)
+{
+	TIkev1IsakmpStream* msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );							
+	
+    TBuf8<MAX_SPI_SIZE> SPI;
+
+    DEBUG_LOG(_L("Sending Delete payload..."));
+    
+    //Creates a DUMMY negotiation with the info to send the packet
+    TUint8 tmp_exchange = iExchange;
+    iExchange=ISAKMP_EXCHANGE_INFO; //Set the exchange type as info
+
+    msg->IsakmpInit(this);
+
+    //HASH Payload only if payload protected with encyption
+    if (iFlags & ISAKMP_HDR_EFLAG)
+	    msg->IsakmpHashL();	
+
+    if (aProtocol == PROTO_ISAKMP)  //ISAKMP SPI are the cookies
+    {
+        SPI.Copy(iCookie_I);
+        SPI.Append(iCookie_R);
+    }
+    else    //IPSECSPI
+    {
+        SPI.Copy((TUint8 *)&aIpsecSPI, sizeof(TUint32));
+    }
+    msg->IsakmpDelete(SPI, aProtocol);
+
+    if (iFlags & ISAKMP_HDR_EFLAG)
+    {
+        msg->IsakmpHashContL();
+    }
+    DEBUG_LOG(_L("Sending Delete Payload..."));
+	SendL(*msg);
+
+    iExchange = tmp_exchange;
+}
+
+void CIkev1Negotiation::CheckSendResponderLifetime(TIkev1IsakmpStream &aMsg)
+{
+    TInt count = iChosenProp_IIList->Count();
+    CProposal_II *prop;
+    TChosenAttrib_II *attr_II;
+    TSPINode inboundspi_node;
+    TInt j;
+    for (j = 0 ; j < count; j++)    //Check all the chosen proposals (Probably one)
+    {
+        prop = iChosenProp_IIList->At(j);
+        inboundspi_node = iInboundSPIList->At(j);
+        attr_II = (TChosenAttrib_II *)prop->iAttrList->At(0);   //only 1 transform is chosen no matter how many there are
+
+        if ((attr_II->iReducedLifeSecs.Length() != 0) || (attr_II->iReducedLifeKBytes.Length() != 0))   //Any lifetime to update
+            aMsg.IsakmpResponderLifetime(prop->iProtocol, inboundspi_node.iSPI, attr_II->iReducedLifeSecs, attr_II->iReducedLifeKBytes);
+
+    }
+}
+
+
+/**--------------------------------------------------------------------
+ *
+ *  The following methods are used to implement the Dead Peer Detection
+ *  protocol defined in <draft-ietf-ipsec-dpd-04.txt>
+ *  When timeout expires the R-U-THERE notify message is transmitted
+ *  if there has not been any activity during the last timeout
+ *
+ *--------------------------------------------------------------------*/
+void CIkev1Negotiation::DpdNotifyMessageReceivedL(TIkev1SAData* aSa, TUint16 aMsgType, TUint32 aSequence)
+{
+
+	if ( aMsgType == DPD_R_U_THERE )
+	{
+	  //
+	  // -- Assure that sequence number in notify data is what expected
+	  // -- If ok, transmit a R-U-THERE-ACK
+	  //
+		DEBUG_LOG(_L("DPD R-U-THERE Notify received"));	  
+		if ( (aSa->iExpectedDPDSequence == aSequence) || (aSa->iExpectedDPDSequence == 0) )
+		{
+			aSa->iExpectedDPDSequence = GetNextSequence(aSequence);
+			DEBUG_LOG(_L("Sending DPD R-U-THERE_ACK notify"));
+			SendDpdNotifyMessageL(DPD_R_U_THERE_ACK, aSequence);
+			iPluginSession->UpdateIkev1SAL(aSa->iSAId, EFalse, aSa);			
+		}
+#ifdef _DEBUG		
+		else DEBUG_LOG(_L("Wrong sequence number in DPD notify message"));
+#endif // _DEBUG		
+	}
+	else if ( aMsgType == DPD_R_U_THERE_ACK )
+	{
+	  //
+	  // -- Assure that sequence number in notify data is corresponds
+	  //    current pending sequence
+	  //
+		DEBUG_LOG(_L("DPD R-U-THERE-ACK Notify received"));
+		if ( aSa->iPendingDPDSequence == aSequence )
+		{
+			aSa->iPendingDPDSequence = 0;
+			aSa->iDPDRetry           = 0;
+			iPluginSession->UpdateIkev1SAL(aSa->iSAId, EFalse, aSa);
+		}
+#ifdef _DEBUG		
+		else DEBUG_LOG(_L("Wrong sequence number in DPD notify ack message"));
+#endif // _DEBUG		
+	}	
+}
+
+void CIkev1Negotiation::SendKeepAliveMsgL(TIkev1SAData* aSa)
+{
+	if ( aSa->iDPDRetry > KMaxDpdRetryCount )
+	{
+		//
+		//  DPD Retry count exhausted, current IKE SA in interpreted to
+		//  be closed
+		//
+        LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
+                       R_VPN_MSG_VPN_GW_NO_RESP,
+                       KKmdIkeNoResponseErr,
+                       iPluginSession->VpnIapId(),
+                       &iRemoteAddr );      	
+        
+		iPluginSession->DeleteIpsecSAs(aSa->iSAId);		
+		iPluginSession->UpdateIkev1SAL(aSa->iSAId, ETrue);
+	}
+	else
+	{
+	    //
+	    //  Send DPD R-U-THERE notify message 
+	    //
+		if ( aSa->iPendingDPDSequence == 0 )
+		{	
+			aSa->iPendingDPDSequence = aSa->iDPDSequence;
+			aSa->iDPDSequence = GetNextSequence(aSa->iDPDSequence);			
+		}	
+		else
+		{
+		    aSa->iDPDRetry ++;
+		}
+		DEBUG_LOG(_L("Sending DPD R-U-THERE notify"));		
+		SendDpdNotifyMessageL(DPD_R_U_THERE, aSa->iPendingDPDSequence);
+	}
+	SetFinished();
+}
+
+MKmdEventLoggerIf& CIkev1Negotiation::EventLogger()
+{
+    return iPluginSession->EventLogger();
+}
+
+void CIkev1Negotiation::IpsecSaSpiRetrieved(TUint32 aSpiRequestId, 
+                                            TInt aStatus, 
+                                            TUint32 aSpi) 
+{
+    DEBUG_LOG3(_L("IPsec SA SPI retrieved, seq=%d, SPI=%d, status=%d"),
+            aSpiRequestId, aSpi, aStatus);
+    if ( aStatus == KErrNone )
+        {
+        TRAP( aStatus, ReceiveSPIL( aSpi, aSpiRequestId ) );
+        }
+    else
+        {
+        iPluginSession->HandleError( aStatus );
+        }
+}
+
+TBool CIkev1Negotiation::IsRekeyingIkeSa()
+{
+    return ( iSARekeyInfo != NULL );
+}
+
+void CIkev1Negotiation::PreparePhase2L(const TPfkeyMessage &aReq)
+{
+    DEBUG_LOG(_L("Prepare for Phase II"));
+    GetAcquireDataL(aReq);
+    iPhaseIIAfterIkeSaRekey = ETrue;
+}
+
+TUint32 CIkev1Negotiation::GetNextSequence(TUint32 aSequence)
+{
+	aSequence ++;
+	if ( aSequence == 0 )
+		aSequence = 1;
+	return aSequence;
+}
+
+void CIkev1Negotiation::SendDpdNotifyMessageL(TUint16 aMsgType, TUint32 aSequence)
+{
+	iExchange  = ISAKMP_EXCHANGE_INFO;
+	iMessageId = RandomMessageId();
+	TIkev1IsakmpStream* Msg = SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );
+	Msg->IsakmpInit(this);
+	Msg->IsakmpHashL();
+	TUint32 NotifData = ByteOrder::Swap32(aSequence);
+	Msg->IsakmpNotification(aMsgType, PROTO_ISAKMP, (TUint8*)&NotifData, sizeof(NotifData));
+	Msg->IsakmpHashContL();
+	SendL(*Msg);
+}
+
+TInt CIkev1Negotiation::ErrorStatus()
+{
+    TInt ret( KErrNone );
+    if ( iPluginSession )
+    {
+        ret = iPluginSession->ErrorStatus();
+    }
+    return ret;
+}
+
+void CIkev1Negotiation::SetErrorStatus(TInt aStatus)
+{
+    SetFinished();
+    iPluginSession->SetErrorStatus(aStatus);
+}
+
+void CIkev1Negotiation::SendAndSaveIkeMsgL( const TDesC8& aIkeMsg,
+                                            TInetAddr& aDestAddr,
+                                            TBool aUseNatPort )
+{
+    iPluginSession->SendIkeMsgL( aIkeMsg, aDestAddr, aUseNatPort );
+    SaveLastMsgL();
+}
+
+
+TBool CIkev1Negotiation::IsRetransmit(TLastIKEMsg& aRef)
+{       
+    TBool isRetransmit(EFalse);
+    if (iLastIKEMsgInfo.IsUninitialized())
+        {
+        TIkev1SAData* ikev1SAData = iPluginSession->FindIkev1SAData(iSAId);
+        if (ikev1SAData && ikev1SAData->iLastIKEMsgInfo.IsReTransmit(aRef))
+            {
+            isRetransmit = ETrue;
+            }
+        }
+    else
+        {
+        isRetransmit = iLastIKEMsgInfo.IsReTransmit(aRef);
+        }
+    return isRetransmit;
+}
+
+void CIkev1Negotiation::SaveRetransmitInfo(TLastIKEMsg& aRef)
+{
+    aRef.Store(iLastIKEMsgInfo);
+    TIkev1SAData* ikev1SAData = iPluginSession->FindIkev1SAData(iSAId);
+    if (ikev1SAData != NULL)
+        {
+        aRef.Store(ikev1SAData->iLastIKEMsgInfo);
+        }
+}
+
+void CIkev1Negotiation::SaveLastMsgL()
+{
+    if ( iLastMsg != NULL )
+        {
+        TIkev1SAData* ikev1SAData = iPluginSession->FindIkev1SAData(iSAId);
+        if ( ikev1SAData != NULL )
+            {
+            delete ikev1SAData->iLastMsg;
+            ikev1SAData->iLastMsg = iLastMsg->AllocL(); 
+            }                
+        }    
+}
+
+
+