vpnengine/ikev2lib/src/ikev2negotiation.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 19 Feb 2010 23:50:52 +0200
branchRCL_3
changeset 8 032d3a818f49
parent 1 c9c2ad51f972
child 12 68dc8923de26
permissions -rw-r--r--
Revision: 201003 Kit: 201007

/*
* 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:   IKEv2/IPSEC SA negotiation
*
*/

#include <random.h>
#include <in_sock.h>

#include "ikev2Negotiation.h"
#include "ikedebug.h"
#include "ikev2natt.h"
#include "ikev2mobike.h"
#include "ikev2proposal.h"
#include "ikev2SAdata.h"
#include "ikev2pluginsession.h"
#include "ikev2pfkey.h"
#include "ikev2config.h"
#include "ikev2EapInterface.h"
#include "ikev2payloads.h"
#include "ikev2const.h"
#include "ikemsgrec.h"
#include "ipsecproposal.h"
#include "ipsecselectors.h"
#include "ikepolparser.h"
#include "kmdapi.h"
#include "ikecaelem.h"
#include "ikecalist.h"
#include "ikepkiutils.h"
#include "vpnapidefs.h"
#include "kmdeventloggerif.h"
#include "ipsecsalist.h"
#include "ikev2message.h"
#include "ikev2identity.h"
#include "ikev2acquire.h"
#include "ikev2expire.h"
#include "ikev2ipsecsarekeydata.h"
#include "ikev2messagesendqueue.h"

_LIT8(KIkev2PSKData, "Key Pad for IKEv2");
_LIT8(KZeroDesc, "");

CIkev2Negotiation* CIkev2Negotiation::NewL(CIkev2PluginSession& aIkeV2PlugInSession,
                                           CPFKeySocketIf& aPfKeySocketIf,
                                           MKmdEventLoggerIf& aEventLogger,
                                           CIkev2MessageSendQueue& aMessageSendQue,
                                           MIkeDebug& aDebug,
                                           CIkeData* aIkeData, 
                                           TUint32 aVpnIapId,
                                           TUint32 aSaId,
                                           TInetAddr aPhysicalInterfaceAddress,
                                           TInetAddr aRemoteAddress)
    {
    
    CIkev2Negotiation* self = new (ELeave) CIkev2Negotiation(aIkeV2PlugInSession, aPfKeySocketIf, 
                                                             aEventLogger, aMessageSendQue, 
                                                             aDebug, aSaId);
    CleanupStack::PushL(self);
    self->ConstructL();

    self->iHdr.iIkeData = aIkeData;
    self->iHdr.iVpnIapId = aVpnIapId;
    self->iProcessEvents     = ETrue;
    self->iHdr.iRemoteAddr = aRemoteAddress;
    self->iHdr.iRemoteAddr.SetPort(IKE_PORT);      
    
    //
    // Get IP address information for IKE SA negotiation
    // Remote address is taken from current IKE policy data (CIkeData)
    // Local address is resolved via IKE policy using policy handle
    //
    if ( self->iHdr.iRemoteAddr.IsUnspecified() )
    {        
        self->iHdr.iRemoteAddr = self->iHdr.iIkeData->iAddr;
        self->iHdr.iRemoteAddr.SetPort(IKE_PORT);
    }   
    self->iHdr.iDestinAddr = self->iHdr.iRemoteAddr;
    self->iHdr.iLocalAddr = aPhysicalInterfaceAddress;
    TInt Scope = self->iHdr.iRemoteAddr.Scope();
    if ( Scope )
        self->iHdr.iLocalAddr.SetScope(Scope); // Set local scope same with remote scope        

    CleanupStack::Pop(self);
    return self;
    }


CIkev2Negotiation* CIkev2Negotiation::NewL(CIkev2PluginSession& aIkeV2PlugInSession,
                                           CPFKeySocketIf& aPfKeySocketIf,
                                           MKmdEventLoggerIf& aEventLogger,
                                           CIkev2MessageSendQueue& aMessageSendQue,
                                           MIkeDebug& aDebug,
                                           TIkev2SAData& aIkev2SAdata)
    {
    CIkev2Negotiation* self = new (ELeave) CIkev2Negotiation(aIkeV2PlugInSession, aPfKeySocketIf, 
                                                             aEventLogger, aMessageSendQue, 
                                                             aDebug, aIkev2SAdata.SaId());
    CleanupStack::PushL(self);
    self->ConstructL();
    
    self->iHdr.Copy(aIkev2SAdata);
    self->iState = KStateIkeSaCompleted;
    
    CleanupStack::Pop(self);
    return self;
    }


CIkev2Negotiation::CIkev2Negotiation(CIkev2PluginSession& aIkeV2PlugInSession, CPFKeySocketIf& aPfKeySocketIf,
                                     MKmdEventLoggerIf& aEventLogger, CIkev2MessageSendQueue& aMessageSendQue,
                                     MIkeDebug& aDebug, TUint32 aSaId) 
: iChild(aDebug), iIkeV2PlugInSession(aIkeV2PlugInSession), iPfKeySocketIf(aPfKeySocketIf), 
  iEventLogger(aEventLogger), iMessageSendQue(aMessageSendQue),iDebug(aDebug), iDHGroupGuess(1) 
    {
    DEBUG_LOG1(_L("CIkev2Negotiation::CIkev2Negotiation: 0x%08x"), this);

    iHdr.SetSaId(aSaId);
    iHdr.iWindowSize = DEF_MSG_ID_WINDOW;        
    }   


void CIkev2Negotiation::ConstructL()
    {  
    iTimer = CIkev2RetransmitTimer::NewL(*this);    
    iSpiRetriever = CIpsecSaSpiRetriever::NewL(*this, iPfKeySocketIf);
        
    iIkeV2PlugInSession.LinkNegotiation(this); // <- takes ownership of this
    iProcessEvents = ETrue;
    }


CIkev2Negotiation::~CIkev2Negotiation()
    {
    
    delete iSpiRetriever;
    // Turn off event processing to prevent EAPVPNIF event
	iProcessEvents = EFalse;
    delete iTimer;
    
    DEBUG_LOG1(_L("CIkev2Negotiation::~CIkev2Negotiation: 0x%08x"), this);        
    iIkeV2PlugInSession.RemoveNegotiation(this);

    iHdr.CleanUp();
    
    //
    // Purge Acquire, Expire and Info message queues
    //
    CIkev2Acquire::PurgeQue(GetAcquireQue());
    CIkev2Expire::PurgeQue(GetExpireQue());
	
	delete iPeerCert;					   
    delete iSavedSaInit;
    delete iProposedSA;
    delete iDHKeys;
    delete iDHPublicPeer;
    delete iNonce_I;
    delete iNonce_R;
    delete iAuthMsgInit;
    delete iAuthMsgResp;
    delete iRemoteIdentity;
    delete iLocalIdentity;
    delete iNatNotify;
    delete iConfigMode;
    delete iEapPlugin;
    delete iPkiService; 
    delete iPresharedKey;
    delete iChildSaRequest;
    }

void CIkev2Negotiation::StartIkeSANegotiationL()
    {
    __ASSERT_DEBUG(iChildSaRequest == NULL, User::Invariant());
    
    //This method should be called only if we have IA in use.
    //Otherwise the negotiation should start with ProcessAcquire
    __ASSERT_DEBUG(iHdr.iIkeData->iUseInternalAddr, User::Invariant());
    
	//
	// This method is called when an IKE SA negotiation is started due
	// a RKMD::Activate() request with policy that uses IA.   
	//    
	iHdr.iInitiator = ETrue;
    LoadEapPluginL();
    
    GetNonceDataL(ETrue);

    CIkev2Acquire* Acquire = IpsecSelectors::BuildVirtualAcquireL(iIkeV2PlugInSession);
    CleanupStack::PushL(Acquire);
           
	if ( !InitPkiServiceL() )
	    {
	    //No PkiService Needed.
	    //Continue by requesting SPI for IPsecSA.	    
	    CIkev2Acquire::Link(Acquire, GetAcquireQue());    
        //
        // Get SPI for inbound SA with PFKEY GETSPI primitive
        //
        GetIpsecSPI(Acquire);
	    }
	else
	    {
	    iChildSaRequest = Acquire;
	    }
	CleanupStack::Pop(Acquire);	
	}

TBool CIkev2Negotiation::StartRespondingL(const ThdrISAKMP& aIkeMessage)
    {
	//
	// This method is called when local end is going to ACT as a
	// responder of an IKE SA negotiation.
	// Initialize PKI service usage, if needed. Because PKI service
	// initialisation is an asynchronous operation we must take a copy
	// of incoming IKE message from where it is processed when PKI
	// service initialisation is completed.
	//
	TBool Status( InitPkiServiceL() );
	if ( Status )
	    {
	    TInt MsgLth = (TInt)aIkeMessage.GetLength(); 	
	    delete iSavedSaInit;
	    iSavedSaInit = NULL;
	    iSavedSaInit = HBufC8::NewL(MsgLth);
	    iSavedSaInit->Des().Copy((TUint8*)&aIkeMessage, MsgLth);
	    }
	return !Status;
    }

void CIkev2Negotiation::StartIkeSADeleteL()
{
	//
	// This method is called when an IKE SA shall be deleted either due
	// IKE SA timeout or due a RKMD::Deactivate() request
	//
	BuildDeleteRequestL(NULL);
}


void CIkev2Negotiation::IkeSaCompletedL()
{

	//
	// This method is when an IKE SA negotiation has been succesfully
	// completed.
	// The following actions are taken:
	// -- Get Virtual IP from iConfigMode object, if present and
	//    modify IKE SA lifetime if Virtual Ip expiration time is
	//    shorter than configured iKE SA lifetime  
	// -- Create a new IKE SA object, if not a rekeyd IKE SA
	// -- If activation going, call IkeSaCompleted method in plug-in
	//
    TVPNAddress VirtualIp;
	if ( iConfigMode )
	{
	   VirtualIp = iConfigMode->VirtualIp();
	   iHdr.StoreVirtualIp(VirtualIp.iVPNIfAddr);
	   TUint32 ExpireTime = iConfigMode->ExpireTime();
	   if ( ExpireTime && (ExpireTime < iHdr.iLifetime) )
		   iHdr.iLifetime = ExpireTime;
	}	
	
	if(!iIkeV2PlugInSession.FindIkev2SA(iHdr.SaId(), KSaStateNotDefined, KSaStateNotDefined))
	    {
	    iIkeV2PlugInSession.CreateIkev2SAL(iHdr);	
	    }
	
	iIkeV2PlugInSession.IkeSaCompleted(KErrNone, VirtualIp);
	
	iEventLogger.LogEvent(MKmdEventLoggerIf::KLogInfo, R_VPN_MSG_VPN_GW_AUTH_OK, KErrNone, 
	                      iHdr.iVpnIapId, &iHdr.iRemoteAddr);
	iEventLogger.LogEvent(MKmdEventLoggerIf::KLogInfo, R_VPN_MSG_ADDR_INFO_FOR_VPN_AP,
                          iHdr.iNATFlags, iHdr.iVpnIapId,
                          (!VirtualIp.iVPNIfAddr.IsUnspecified() ? &(VirtualIp.iVPNIfAddr) : NULL));			

	if ( iChildSaRequest )
	{	
	   IpsecSANegotiatedL();
	}	
    if ( RequestsPending() )
	{	
	   ContinueIkeNegotiationL();
	}   
	else
	{	
       if ( !iHdr.iInitiator )
	   {	   
	       iIkeV2PlugInSession.StopResponding();
	       delete this;   // Current negotiation can be deleted
	   }
	   else iStopped = ETrue;
	}
}

void CIkev2Negotiation::IkeSaFailed(TInt Status)
    {
	//
	// This method is when a IKE SA negotiation has failed
	// The following actions are taken:
	//

    TVPNAddress dummyVirtualIp;

	iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);	
	
	if ( !iHdr.iInitiator )
	    iIkeV2PlugInSession.StopResponding();
	
	if ( (iSendAttempt <= KMaxSendAttemps ) &&
	     ((iState == KStateIkeSaEapStarted) || 
	      (iState == KStateIkeSaEapGoing)))
		 iDeleteIkeSA = ETrue;
	else iStopped = ETrue;

	iEventLogger.LogEvent(MKmdEventLoggerIf::KLogError, R_VPN_MSG_REAL_IAP_ACT_FAILED, Status, 
	                      iHdr.iVpnIapId, &iHdr.iRemoteAddr);
	
    iIkeV2PlugInSession.IkeSaCompleted(Status, dummyVirtualIp);
    }

void CIkev2Negotiation::IpsecSANegotiatedL()
{
	//
	// This method is when an Ipsec SA negotiation has been succesfully
	// completed.
	// -- Update Ipsec SADB using PFKEY Update and Add primitives	
	// -- Find a new IKE SA object and queue Ipsec SA data into it
	// -- Try to start a new exchange from queue, if there is nothing
	//    to start in queues mark current negotiation stopped
	//
	iChild.iSrcSpecific = iChildSaRequest->SrcSpecific();  
	Ikev2Pfkey::UpdateIpsecSaDataBaseL(iHdr, iChild, iIkeV2PlugInSession, *iChildSaRequest);
	
	CIpsecSARekeyData* rekeyData = 
	    CIpsecSARekeyData::NewL(iChildSaRequest->ReplayWindow(),
                                iChildSaRequest->HardLifetime(),
                                iChildSaRequest->SoftLifetime(),
                                iChildSaRequest->TS_i(),
                                iChildSaRequest->TS_r(),
                                *iChildSaRequest->LocalId(),
                                *iChildSaRequest->RemoteId());
	
	iChild.PurgeKeyMaterial();	// Ipsec Keymaterial not saved into IKE SA
	iChild.DeleteRekeyData();
	iChild.iRekeyData = rekeyData;
	
	iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, &iChild);
	
	delete iChildSaRequest;
	iChildSaRequest = NULL;
	
	if ( RequestsPending() )	
	     ContinueIkeNegotiationL();
	else
	{	if ( iState == KStateIkeChildSAResponse )
		     delete this;
		else iStopped = ETrue;
	}	
}


void CIkev2Negotiation::ProcessIkeMessageL(const ThdrISAKMP& aIkeMessage, 
                                           const TInetAddr& aRemote, 
                                           TUint16 aLocalPort)
    {
	//
	// Start to process received IKE message by constructing a
	// CIkev2Payloads object. CIkev2Payloads construction takes also
	// care of the decryption of an Encrypted payload if present.  
	//    
	TBool Status( ETrue );
	
	CIkev2Payloads* IkeMsg = CIkev2Payloads::NewL(aIkeMessage, iHdr);
	CleanupStack::PushL(IkeMsg);				 	
	
    DEBUG_LOG2(_L("Process IKE message, SAID=%d, Msg ID=%d"),
            iHdr.SaId(), aIkeMessage.GetMessageId());	
	if ( IkeMsg->Status() )
	    {
	    //
	    //  An error occurred during IKE message parsing
	    //
	    SetNotifyCode(IkeMsg->Status());
        DEBUG_LOG1(_L("Error in parsing of received IKE message: %d"), IkeMsg->Status());

	    if ( !iHdr.iInitiator && iState == KStateIdle )
	        {
		    iStopped = ETrue;   // Negotiation object shall be released
	        }
	    else 
	        {
	        CheckNotifyCodeL(IkeMsg);
	        }
	    CleanupStack::PopAndDestroy(IkeMsg); // IkeMsg
	    return;
	    }
	
	if ( (iHdr.iNATFlags & (REMOTE_END_NAT + MOBIKE_USED)) && 
	    IkeMsg->Encrypted() )
	    {
	    //
	    // Received IKE message contains Encrypted payload. Save source
	    // IP as new destination IP to negotiation object
	    //
	    iHdr.iDestinAddr = aRemote;
	    iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);
	    }	
	
	TPtrC8 ikeMsgDes((TUint8*)&aIkeMessage, aIkeMessage.GetLength());
	
	TInetAddr localAddr(iHdr.iLocalAddr);
	localAddr.SetPort(aLocalPort);
	TRACE_MSG(ikeMsgDes, aRemote, localAddr, 
              (CIkePcapTrace::TEncryptionType)iHdr.iEncrAlg);

	//
	// Process received IKE message according to Exchange type
	//
	switch ( aIkeMessage.GetExchange() )
	{
		case IKE_SA_INIT:
		    DEBUG_LOG(_L("IKE_SA_INIT message received"));
			Status = ProcessIkeSaInitL(IkeMsg, aRemote);
			if ( !Status )
			   IkeSaFailed(KKmdIkeNegotFailed);	
			break;
			
		case IKE_AUTH:
		    DEBUG_LOG(_L("IKE_AUTH message received"));
			Status = ProcessIkeAuthL(IkeMsg);
			if ( !Status )
			   IkeSaFailed(KKmdIkeAuthFailedErr);
			break;
			
		case CREATE_CHILD_SA:
		    DEBUG_LOG(_L("CREATE_CHILD_SA message received"));
			Status = ProcessChildSaL(IkeMsg);
			break;

		case INFORMATIONAL:
		    DEBUG_LOG(_L("INFORMATION message received"));
			Status = ProcessInfoMsgL(IkeMsg);			
			break;

		default:
		    DEBUG_LOG(_L("UNKNOWN message received\n"));
			Status = EFalse;  // Negotiation object shall be released			
			break;
	}

	if ( !Status )
	{
	   if ( iDeleteIkeSA )
	   {
		  //
		  // Used IKE SA shall be deleted due the fatal error occurred.
		  //
		   iDeleteIkeSA = EFalse;
		   iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());			   
		   BuildDeleteRequestL(NULL);
	   }
	   else
	   {	   
	       CheckNotifyCodeL(IkeMsg);
	   }	  
	}			
	CleanupStack::PopAndDestroy(IkeMsg);	
}

void CIkev2Negotiation::ProcessAcquireL(const TPfkeyMessage &aPfkeyMsg)
    {
	//
	// Process received PFKEY Acquire primitive
	// There is now the following possibilities:
	// -- There already exists an IKE SA so new IPSEC SA is negotiated
	//    using IKE_CHILD_SA exchange
	// -- The is no IKE SA yet.
	//    IPSEC SA can be negotiated concatenated during IKE_AUTH.	
	//    If Virtual IP is specified, the CP payload is used to get
	//    that virtual IP address. 
	//
	CIkev2Acquire* Acquire = CIkev2Acquire::NewL(aPfkeyMsg, iIkeV2PlugInSession.GetSAId(), 
	    GetLocalAddr(),
		Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II), ImplicitChildSa());	

	if ( iState == KStateIdle )
	    {
		CleanupStack::PushL(Acquire);				 								
		LoadEapPluginL();		
		iHdr.iInitiator = ETrue;
		GetNonceDataL(ETrue);  // For IKE SA		
		if ( iHdr.iIkeData->iUseInternalAddr )
		    {
		    CArrayFix<TIkeV2TrafficSelector>* TsI = new (ELeave) CArrayFixFlat<TIkeV2TrafficSelector>(1);
		    CleanupStack::PushL(TsI);
		    
		    TInetAddr StartIp;
			TInetAddr EndIp;	
			StartIp.SetAddress(KInetAddrNone);    // 0.0.0.0
			StartIp.SetPort(0);
			EndIp.SetAddress(KInetAddrAll);	      // 255.255.255.255
			EndIp.SetPort(0xffff);
			
			TIkeV2TrafficSelector ts(StartIp, EndIp, 
                                     aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);
			TsI->AppendL(ts);			
			CleanupStack::Pop(TsI);
			Acquire->ReplaceTS_i(TsI);						
			Acquire->SetVirtualIp();						     						
		    }
		
		if ( InitPkiServiceL() )
		    {
		    // Store Acquire to wait PKI service init
			iChildSaRequest = Acquire;
			CleanupStack::Pop(Acquire); 			 							
			return;
		    }
		CleanupStack::Pop(Acquire);	
	    }
	CIkev2Acquire::Link(Acquire, GetAcquireQue());
	GetIpsecSPI(Acquire);
    }


void CIkev2Negotiation::ProcessExpireL(const TPfkeyMessage &aPfkeyMsg)
    {
	//
	// Process received PFKEY Expire primitive
	// Try to find first IPSEC SA data from the "parent" IKE SA and set
	// inbound SA to zero in TIpsecSAData 
	//
    TPtrC8 spi(reinterpret_cast<const TUint8*>(&aPfkeyMsg.iSa.iExt->sadb_sa_spi),
               sizeof(aPfkeyMsg.iSa.iExt->sadb_sa_spi));    
    
	TIkeV2IpsecSAData* SaData = 
                iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), spi, ETrue);
	if ( !SaData )
	    {
	    DEBUG_LOG(_L("PFKEY Expire received but no SA data found, stop negotiation"));    	

	    iStopped = ETrue;	
	    return;	
	    }	
	SaData->iSPI_In.Zero();	
	CIkev2Expire* Expire = CIkev2Expire::NewL(aPfkeyMsg);	
	CIkev2Expire::Link(Expire, GetExpireQue());
	
	ContinueIkeNegotiationL();
}

void CIkev2Negotiation::StartIpsecSaRekeyingL(const TPfkeyMessage &aPfkeyMsg)
{

    TPtrC8 spi(reinterpret_cast<const TUint8*>(&aPfkeyMsg.iSa.iExt->sadb_sa_spi),
               sizeof(aPfkeyMsg.iSa.iExt->sadb_sa_spi));    
    TIkeV2IpsecSAData* SaData = 
                iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), spi, ETrue);
	if ( !SaData )
	{
	    DEBUG_LOG(_L("No IPSec SA data found, stop rekeying"));    	
	    iStopped = ETrue;	
	    return;	
    }

	iStopped = ETrue;  
    
    CArrayFix<TIkeV2TrafficSelector>* tsIArray = SaData->iRekeyData->TsIL();
    CleanupStack::PushL(tsIArray);

    CArrayFix<TIkeV2TrafficSelector>* tsRArray = SaData->iRekeyData->TsRL();
    CleanupStack::PushL(tsRArray);
    
    __ASSERT_DEBUG(tsIArray->Count() > 0, User::Invariant());
    __ASSERT_DEBUG(tsRArray->Count() > 0, User::Invariant());

    TIkeV2TrafficSelector tsI = (*tsIArray)[0];
    TIkeV2TrafficSelector tsR = (*tsRArray)[0];

    CleanupStack::PopAndDestroy(tsRArray);
    CleanupStack::PopAndDestroy(tsIArray);
    
    
    TInetAddr localSelector;
    TInetAddr localSelectorMask;
    
    TInetAddr remoteSelector;
    TInetAddr remoteSelectorMask;

    if (iHdr.iInitiator)
        {
        localSelector = tsI.StartingAddress();
        localSelectorMask = tsI.Mask();
        
        remoteSelector = tsR.StartingAddress();
        remoteSelectorMask = tsR.Mask(); 
        }
    else
        {
        localSelector = tsR.StartingAddress();
        localSelectorMask = tsR.Mask();
        
        remoteSelector = tsI.StartingAddress();
        remoteSelectorMask = tsI.Mask();        
        }
    
    CIpsecSaSpecList* SaList = iIkeV2PlugInSession.GetIPsecSaSpecListL(localSelector, localSelectorMask, //local address/port info
                                                                       remoteSelector, remoteSelectorMask,
                                                                       aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);

    
    CleanupStack::PushL(SaList);
    __ASSERT_DEBUG(SaList != NULL, User::Invariant());
    __ASSERT_DEBUG(SaList->Count() > 0, User::Invariant());
    iStopped = EFalse;  
    
    const TIpsecSaSpec& saSpec = SaList->At(0);
	    
	CIkev2Acquire* Acquire = CIkev2Acquire::NewL(aPfkeyMsg, iIkeV2PlugInSession.GetSAId(), GetLocalAddr(),
									   Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II), ImplicitChildSa(), 
									   &saSpec, SaData->iRekeyData);	
	CleanupStack::PopAndDestroy(SaList); //SaList
	
	Acquire->SetSPI_ToBeRekeyed(spi);

	if ( iState == KStateIdle )
	{
		CleanupStack::PushL(Acquire);				 								
		LoadEapPluginL();		
		iHdr.iInitiator = ETrue;
		GetNonceDataL(ETrue);  // For IKE SA		
		if ( iHdr.iIkeData->iUseInternalAddr )
		{			
			CArrayFix<TIkeV2TrafficSelector>* TsI = new (ELeave) CArrayFixFlat<TIkeV2TrafficSelector>(1);
			CleanupStack::PushL(TsI);

			TInetAddr StartIp;
            TInetAddr EndIp;    
            StartIp.SetAddress(KInetAddrNone);    // 0.0.0.0
            StartIp.SetPort(0);
            EndIp.SetAddress(KInetAddrAll);       // 255.255.255.255
            EndIp.SetPort(0xffff);
			
            TIkeV2TrafficSelector ts(StartIp, EndIp, 
                                     aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);
            TsI->AppendL(ts);
			Acquire->ReplaceTS_i(TsI);			
			CleanupStack::Pop(TsI);
			Acquire->SetVirtualIp();
        }

		if ( InitPkiServiceL() )
		{
			iChildSaRequest = Acquire;  // Store Acquire to wait PKI service init
			CleanupStack::Pop(Acquire); 			 							
			return;
		}
		CleanupStack::Pop(Acquire); 	
	}
	CIkev2Acquire::Link(Acquire, GetAcquireQue());
	GetIpsecSPI(Acquire);
}

void CIkev2Negotiation::GetIpsecSPI(CIkev2Acquire* aAcquire)
    {
    ASSERT(aAcquire);
	//
	// Get SPI for inbound SA with PFKEY GETSPI primitive
	//
	TInetAddr DstAddr;
	if ( aAcquire->SrcSpecific() )
		 DstAddr = iHdr.iLocalAddr;
	else DstAddr.Init(0); 
	DstAddr.SetPort(0);	
	TInetAddr SrcAddr = iHdr.iRemoteAddr;
	SrcAddr.SetPort(0);

	iSpiRetriever->GetIpsecSaSpi(aAcquire->Id(),
                                 aAcquire->IpsecProtocol(),
                                 SrcAddr, DstAddr);
    }


void CIkev2Negotiation::IpsecSaSpiRetrieved(TUint32 aSpiRequestId, 
                                            TInt aStatus, 
                                            TUint32 aSpi)
    {
    if (aStatus == KErrNone)
        {
        TRAP(aStatus, IpsecSaSpiRetrievedL(aSpiRequestId, aSpi));
        }
    
    if (aStatus != KErrNone)
        {
        //Leave that we have not been able to handle
        //above layers. We bail out and report error.
        iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());                         
        iIkeV2PlugInSession.IkeSaDeleted(aStatus); 
        delete this;
        }
    }

void CIkev2Negotiation::CancelOperation()
    {
    if ( iTimer != NULL )
        {
        iTimer->Cancel();
        }
    if ( iSpiRetriever != NULL )
        {
        iSpiRetriever->Cancel();
        }
    }

void CIkev2Negotiation::IpsecSaSpiRetrievedL(TUint32 aSpiRequestId, TUint32 aSpi)
    {
    DEBUG_LOG(_L("CIkev2Negotiation::SpiRetrievedL"));
    
	//
	// Ipsec SPI received. Find an Acquire object for received SPI and
	// save SPI into found object.
	//
	CIkev2Acquire* Acquire = CIkev2Acquire::Find(aSpiRequestId, GetAcquireQue());
	__ASSERT_DEBUG(Acquire, User::Invariant());

	TPtrC8 spiPtr(reinterpret_cast<TUint8*>(&aSpi), sizeof(aSpi));
	Acquire->SetSPI_In(spiPtr);
	//
	// Ipsec SPI received. Find an Acquire object for received SPI and
	// save SPI into found object.
	//	
    ContinueIkeNegotiationL();
    }

void CIkev2Negotiation::ContinueIkeNegotiationL()
{
	//
	// This method takes actions according to current state (iState) of
	// the negotiation.     
	//
	CIkev2Acquire* Acquire;
	CIkev2Expire*  Expire;

	switch ( iState )
	{
    case KStateIdle:
         //
         // Start IKE_SA_INIT exchange
         //
         StartIkeSaInitL();			 
         break;

    case KStateIkeSaAuthWaitSpi:
         {			    			 
         //
         // Complete IKE_AUTH exchange (with concatenated Child SA)
         //
         iChildSaRequest = CIkev2Acquire::GetNext(GetAcquireQue(), ETrue);
                     
         DEBUG_LOG(_L("CIkev2Negotiation::ContinueIkeNegotiationL"));
         DEBUG_LOG1(_L("iChildSaRequest is %d"), (TInt)iChildSaRequest);
         
         SendIkeAuthMessageL();			 
         }
         break;
         
    case KStateIkeSaCompleted:
         //
         // There is no activity going on this negotiation
         // If there is something in request queues start process
         // them in the following order:
         // -- Check if there is something in info queue (NIY)
         // -- Check if there is something in expire queue (NIY)
         // -- Check if there is ready responses in acquire queue
         // -- Check if there is ready request in acquire queue			 
         //
         Expire = CIkev2Expire::GetNext(GetExpireQue());
         if ( Expire )
         {
            CleanupStack::PushL(Expire);				 
            BuildDeleteRequestL(Expire);
            CleanupStack::PopAndDestroy(Expire);								
         }	
         else 
         {
            Acquire = CIkev2Acquire::GetNext(GetAcquireQue(), ETrue);
            if  ( Acquire )
            {
                BuildChildSAMessageL(Acquire, EFalse);
            }
            else
            {
                Acquire = CIkev2Acquire::GetNext(GetAcquireQue(), EFalse);				 
                BuildChildSAMessageL(Acquire, ETrue);
            }
         }
         break;
    
    default:
         break;
	}		
}	

void CIkev2Negotiation::StartIkeSaInitL()
    {
	//
	// Create Initiator SPI for the new IKE SA
	//
	CreateIkeSPI(iHdr.SpiI());

	//
	// Get required peer identity from policy (IDr)
	//
	iRemoteIdentity = Ikev2Proposal::GetRemoteIdentityL(iHdr.iIkeData);
	
	__ASSERT_ALWAYS(iHdr.iInitiator, User::Invariant());
	//
	// Build and send the first IKE_SA_INIT message (request)
	// HDR, SAi1, KEi, Ni, N[NAT_SRC], N[NAT_DST]
	//
	CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                iHdr.SpiR(),
                                                IKE_SA_INIT,
                                                iHdr.iInitiator,
                                                EFalse,
                                                iHdr.NextRequestId(),
                                                iDebug); 
	CleanupStack::PushL(ikeMsg);
	
    HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
    CleanupStack::PushL(saBfr);
	ikeMsg->AppendSaPayloadL(*saBfr);
	CleanupStack::Pop(saBfr);
	SetProposedSa(saBfr);

    AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
    ikeMsg->AppendNoncePayloadL(*iNonce_I);
	if ( !iHdr.iIkeData->iUseNatProbing )
	    {
	    delete iNatNotify;
	    iNatNotify = NULL;
	    
	    TInetAddr LocalIp;	
	    if ( iHdr.iIkeData->iUseMobIke )
		    LocalIp.SetAddress(KInetAddrNone);
	    else LocalIp = iHdr.iLocalAddr; 	   
	    iNatNotify = CIkev2NatT::NewL(
	        LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());
	    	    	   
	    ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP, 
                                     iNatNotify->SourceNofify());
	    ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP, 
                                     iNatNotify->DestinNofify());		  
	    }	
	CleanupStack::Pop(ikeMsg);
	
	SendIkeMsgL(ikeMsg);	
    iState = KStateIkeSaInitRequest;
    }

void CIkev2Negotiation::SendIkeAuthMessageL()
{
	//
	// Build and send IKE_AUTH message
	// IKE_AUTH message sent by the initiator is the following:
	//  HDR(A,B), SK {IDi, [CERT] [CERTREQ], [IDr], [AUTH], [CP], [SAi2,
	//  TSi, TSr]} 
	// IKE_AUTH message sent by the responder is the following:
	//  HDR(A,B), SK {IDr, [CERT,] AUTH, [CP], [SAr2, TSi, TSr]}
	// CERT and CERTREQ payloads are added into message on when needed.
	// AUTH payload is missing from initiators message when EAP in use.
	// IPSEC SA:s are not always negotiated within IKE_AUTH messages.
	// In this sitution SAx2, TSi and TSr payloads shall be missing.
	// CP payload is used the Virtual IP address (secure network DNS
	// IP:s) for client Virtual IP interface.
	// Initiators CP payload shall contain CFG_REQUEST and and
	// responders CP payload CFG_REPLY.
	// When CP payload is used IKE_AUTH message MUST always contain
	// IPSEC SA negotiation payloads within. 
	// In case INITIAL_CONTACT is used, the first IKE_AUTH request on given 
	// IKE SA contains INITIAL_CONTACT Notification Payload that is added in
	// the end of the IKE_AUTH message.
	//

	if ( !iLocalIdentity )
	{
	   //
	   // Own identity does not exists yet. Do not build IKE_AUTH
	   // message now
	   //
	   iState = KStateIkeWaitingId;
	   return;
	}
	
	TUint32 MsgId = (iHdr.iInitiator) ? iHdr.NextRequestId() : iHdr.ExpectedRequestId();	
    CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                iHdr.SpiR(),
                                                IKE_AUTH,
                                                iHdr.iInitiator,
                                                !iHdr.iInitiator, //Initiator sends only requests
                                                MsgId,
                                                iDebug); 
    CleanupStack::PushL(ikeMsg);
	
    ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);

    __ASSERT_DEBUG(iLocalIdentity != NULL, User::Invariant());
    if (iHdr.iInitiator)
        {
        ikeMsg->AppendIdiPayloadL(*iLocalIdentity);
        }
    else
        {        
        ikeMsg->AppendIdrPayloadL(*iLocalIdentity);
        }

	if ( iPkiService &&
	     iPkiService->UserCertificateData().Length() > 0)
	    {        
        ikeMsg->AppendCertPayloadL(iPkiService->UserCertificateData());
        }
	
	if ( iPkiService &&
	     iPkiService->I2CertificateData().Length() > 0)
	    {
	    ikeMsg->AppendCertPayloadL(iPkiService->I2CertificateData());
	    }
	
	if ( iPkiService &&
	     iPkiService->I1CertificateData().Length() > 0)
	    {
	    ikeMsg->AppendCertPayloadL(iPkiService->I1CertificateData());
	    }
	  
	if ( iHdr.iInitiator && iHdr.iIkeData->iInitialContact )
        {
        ikeMsg->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, INITIAL_CONTACT, KZeroDesc);
        }


    if ( iHdr.iInitiator && iPkiService != NULL &&  iPkiService->CaList().Count() > 0)  
       {	    
       ikeMsg->AppendCertReqPayloadL(iPkiService->CaList());
       }

	if ( iHdr.iInitiator && iRemoteIdentity )
	    {
	    //
	    // Add IDr payload 
	    //
	    ikeMsg->AppendIdrPayloadL(*iRemoteIdentity);
	    }	
    if ( !iEapPlugin )
	    {	 
        HBufC8* authData = NULL; 
	    if ( iHdr.iInitiator )
	        {
	        authData = SignAuthDataL(*iAuthMsgInit, (TUint8)iHdr.iAuthMethod);
	        }
	    else 
	        {
	        authData = SignAuthDataL(*iAuthMsgResp, (TUint8)iHdr.iAuthMethod);
	        }
	    CleanupStack::PushL(authData);
	    ikeMsg->AppendAuthPayloadL(iHdr.iAuthMethod, *authData);	   
	    CleanupStack::PopAndDestroy(authData);
	    }
	if ( iHdr.iIkeData->iUseMobIke )
	    {
	    //
	    // Add MOBIKE_SUPPORTED notify payload
	    //
	    ikeMsg->AppendNotifyPayloadL(IKEV2_PROT_NONE,
                                     KZeroDesc,
                                     MOBIKE_SUPPORTED,
                                     KZeroDesc);
	    }	


	//
	// Add Child SA and Traffic selector payloads into IKE_AUTH message
	// if required
	//
	if ( iChildSaRequest )
	{
		iChild.iSPI_In = iChildSaRequest->SPI_In();
		iChildSaRequest->AddIpsecSpiToSa(iChild.iSPI_In);
		if ( iChildSaRequest->ForVirtualIp() )
		    {
		    //
		    // As Virtual Ip from peer SGW using Config Payload
		    // Build CP request data by constructing CIkev2Config Object
		    //
		    if ( !iConfigMode )
		        iConfigMode = CIkev2Config::NewL(iChildSaRequest);

            ikeMsg->AppendConfigurationPayloadL(iConfigMode->CpType(), iConfigMode->Cp());
		    }	
		ikeMsg->AppendSaPayloadL(*iChildSaRequest->SA());
	 
		ikeMsg->AppendTsiPayloadL(iChildSaRequest->TS_i());
		ikeMsg->AppendTsrPayloadL(iChildSaRequest->TS_r());
	}
	
	CleanupStack::Pop(ikeMsg);
	SendIkeMsgL(ikeMsg);
	
	if ( iHdr.iInitiator )
	{	
	   if ( iEapPlugin )
	        iState = KStateIkeSaEapStarted;			   
	   else iState = KStateIkeSaAuthRequest;	
	}
	else 
	{    
       iState = KStateIkeSaCompleted;
       IkeSaCompletedL();
	}

}

void CIkev2Negotiation::SendKeepAliveMsgL()
    {
    CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), 
                                                iHdr.SpiR(), 
                                                INFORMATIONAL, 
                                                iHdr.iInitiator,
                                                EFalse,
                                                iHdr.NextRequestId(), 
                                                iDebug);
    
    ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            
    SendIkeMsgL(ikeMsg);
    iState = KStateIkeInfoRequest;
    
	DEBUG_LOG(_L("CIkev2Negotiation::SendKeepAliveMsgL"));
    }


void CIkev2Negotiation::BuildChildSAMessageL(
    CIkev2Acquire* aAcquire, TBool aInitiator)
    {
    ASSERT(aAcquire);
	//
	// Build and send CREATE_CHILD_SA message
	// CREATE_CHILD_SA request message sent is the following:
	//  HDR(A,B), SK {[N], SA, Ni, [KEi], [TSi, TSr]}
	// CREATE_CHILD_SA response message is the following:
	//  HDR(A,B), SK {SA, Nr, [KEi], [TSi, TSr]}
	//
	iChild.iSPI_In  = aAcquire->SPI_In();	
	iChildSaRequest = aAcquire;
	//TPayloadIkev2* PreviousPayload;
	//TPayloadIkev2* EncrPayload;
	GetNonceDataL(aInitiator);
	aAcquire->AddIpsecSpiToSa(aAcquire->SPI_In());
		
	TUint32 MsgId = (aInitiator) ? iHdr.NextRequestId() : iHdr.ExpectedRequestId();
	
	CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                iHdr.SpiR(),
                                                CREATE_CHILD_SA,
                                                iHdr.iInitiator,
                                                !aInitiator,
                                                MsgId,
                                                iDebug);
	
    ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            
	
	if (aInitiator && aAcquire->SPI_ToBeRekeyed().Length() > 0)
        {         
        ikeMsg->AppendNotifyPayloadL(aAcquire->IpsecProtocol(),
                                     aAcquire->SPI_ToBeRekeyed(),
                                     REKEY_SA, KZeroDesc);        
        }
	ikeMsg->AppendSaPayloadL(*aAcquire->SA());
	
	if ( aInitiator )
	    {
	    ikeMsg->AppendNoncePayloadL(*iNonce_I);
	    }
	else 
	    {
	    ikeMsg->AppendNoncePayloadL(*iNonce_R);	
	    }
	
	delete iDHKeys;   // Delete old DH object 
	iDHKeys = NULL;
	if ( aAcquire->DHGroup() )
	    {	    
	    AppendKEPayloadL(*ikeMsg, aAcquire->DHGroup());
	    }
	ikeMsg->AppendTsiPayloadL(aAcquire->TS_i());
	ikeMsg->AppendTsrPayloadL(aAcquire->TS_r());
	      
	SendIkeMsgL(ikeMsg);

	if ( aInitiator	)
	{	
	   iState = KStateIkeChildSARequest;	   
    }
	else
	{
        if (iDHKeys && iDHPublicPeer)
            {
            HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
            CleanupStack::PushL(g_ir);
        
            iChild.GenerateIpsecKeysL(iHdr.iSK_d, *g_ir, 
                                      *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
                
            g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
            CleanupStack::PopAndDestroy();  //g_ir
            }
        else
            {
            iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc, 
                                      *iNonce_I, *iNonce_R, iHdr.iPRFAlg);            
            }
        
	   IpsecSANegotiatedL();
	   iState = KStateIkeChildSAResponse;
	}	
}

void CIkev2Negotiation::BuildDeleteRequestL(CIkev2Expire* aExpire)
{
	//
	//  Build and send INFORMATIONAL exchange message with delete payload
	//  HDR(A,B), SK {D}
	//  If CIkev2Expire object defined, build a Delete payload with Ipsec
	//  SPI and protocl stored into CIkev2Expire object. If no CIkev2Expire build
	//  Delete payload for IKE SA.
	//    
    CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), 
                                                iHdr.SpiR(), 
                                                INFORMATIONAL, 
                                                iHdr.iInitiator,
                                                EFalse,
                                                iHdr.NextRequestId(), 
                                                iDebug);
    
    ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            

    CDesC8Array* spiArray = new (ELeave) CDesC8ArrayFlat(2);
    CleanupStack::PushL(spiArray);
	if ( aExpire )
	    {	    	    
	    spiArray->AppendL(aExpire->SPI());
	    ikeMsg->AppendDeletePayloadL(aExpire->Protocol(), *spiArray);	    	        
	    }
	else
	    {	    
	    ikeMsg->AppendDeletePayloadL(IKEV2_PROTOCOL, *spiArray);
	    }
	CleanupStack::PopAndDestroy(spiArray);
	
	SendIkeMsgL(ikeMsg);
    DEBUG_LOG(_L("CIkev2Negotiation::BuildDeleteRequestL() Delete send OK"));
    
    if ( aExpire ) 
        {
        iState = KStateChildDeleteRequest;
        }
    else 
        {
        iState = KStateIkeDeleteRequest;
        }
}

void CIkev2Negotiation::BuildIkeSaRekeyMsgL(TBool aRequest)
{
	//
	//  Build and send CHILD_SA exchange message which contains IKE SA
	//  rekey message (either request or response)
	//  HDR, SA, Nonce, KE	
	//
	HBufC8* SaBfr;		
	HBufC8* Nonce;	
	TUint32 MsgId;
	
	if ( aRequest )
	    {
	    // Get a new SA Id for rekeyed IKE SA		   
		iSAid_Rekey = iIkeV2PlugInSession.GetSAId(); 
		CreateIkeSPI(iSPI_Rekey, ETrue);
		SaBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess, ETrue);
		SetProposedSa(SaBfr); // Save SA payload buffer
		GetNonceDataL(ETrue);
		Nonce = iNonce_I;
		MsgId = iHdr.NextRequestId();
	    }
	else
	    {
		SaBfr = PeekProposedSa();			
		Ikev2Proposal::ChangeSpiInProposal(SaBfr, iSPI_Rekey);
		GetNonceDataL(EFalse);
		Nonce = iNonce_R;
        MsgId = iHdr.ExpectedRequestId();
	    }	

	CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), 
                                                iHdr.SpiR(), 
                                                CREATE_CHILD_SA, 
                                                iHdr.iInitiator, 
                                                !aRequest,
                                                MsgId, 
                                                iDebug);

    ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            
    ikeMsg->AppendSaPayloadL(*SaBfr);
    ikeMsg->AppendNoncePayloadL(*Nonce);	    
    AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
	     	
	SendIkeMsgL(ikeMsg);

	if ( aRequest )
	{	
       iState = KStateIkeSARekeyRequest;
	}
}

void CIkev2Negotiation::CheckNotifyCodeL(CIkev2Payloads* aIkeMsg)
    {
    ASSERT(aIkeMsg);
	//
	// Some error has occurred during incoming IKE message handling
	// Build an error response with specified Notify message type
	//
	TInt MsgType( GetNotifyCode() );
	
	if ( MsgType )
	    {
        //
        // Build and error response/request with Notify payload
        // If received message with error condition is a request
        // Notify payload is transmitted in the response IKE message
        // of ongoing exchange (with erronous request message id)
        // If received message with error conditions is a response
        // an informational exchange is initiated with Notify payload
        //
		CIkeV2Message* XmitHdr = NULL;
		TBool Response(aIkeMsg->GetIkeMsg()->GetFlags() & IKEV2_RESPONSE_MSG);		  
		if ( Response )
		    {
		    iState  = KStateIkeInfoRequest;
            TUint32 MsgId = aIkeMsg->GetIkeMsg()->GetMessageId();		  
		    XmitHdr = CIkeV2Message::NewL(iHdr.SpiI(), 
                                          iHdr.SpiR(),
                                          INFORMATIONAL, 
                                          iHdr.iInitiator,
                                          EFalse,
                                          MsgId,
                                          iDebug); 
		    		   
		    }
		else
		    {		    
            XmitHdr = CIkeV2Message::NewL(iHdr.SpiI(), 
                                          iHdr.SpiR(),
                                          aIkeMsg->GetIkeMsg()->GetExchange(), 
                                          iHdr.iInitiator,
                                          ETrue,
                                          iHdr.ExpectedRequestId(),
                                          iDebug); 
		    }
		
		if (aIkeMsg->Encrypted())
		    {
		    XmitHdr->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            		    
		    }
		
		TInt notifyDataLength = 0;
		TUint8* notifyData = NotifyData(notifyDataLength);
		
		if (notifyDataLength == 0)
		    {
		    XmitHdr->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, MsgType, KZeroDesc);
		    }
		else
		    {
		    TPtrC8 notifyDataPtrC(notifyData, notifyDataLength);
		    XmitHdr->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, MsgType, notifyDataPtrC);
		    iNotifyDataLth = 0; //Reset notifydata
		    }
		
		SendIkeMsgL(XmitHdr);
		
		iEventLogger.LogEvent(MKmdEventLoggerIf::KLogError, R_VPN_MSG_SENT_ERROR_RESPONSE, 
		    MsgType, iHdr.iVpnIapId, &iHdr.iRemoteAddr);		
	    }	
    }


void CIkev2Negotiation::GetNatStatus(TBool aSupported, const TInetAddr& aRemote)
{
	//
	// Examine NAT discovery status (from iHdr.iNATFlags) and set
	// floated port usage indicator, if required.
	//
	if ( aSupported )
	{
		if ( iHdr.iNATFlags & (REMOTE_END_NAT + LOCAL_END_NAT) )
		{
			if ( iHdr.iNATFlags & REMOTE_END_NAT )
			{	
			   //
	           // Remote end is behind NAT. Save current source IP to be
	           // used as further destination address. 
			   // When remote and is behind NAT it is supposed that it
			   // must be pure mapping between public- and private IP
			   // addresses (remote NAPT is NOT supported) 
			   // 
			   DEBUG_LOG(_L("Remote end is behind NAT"));
			   iHdr.iDestinAddr = aRemote; // Remote end behind NAT, use current source IP as destin
		    }
			
			if ( iHdr.iNATFlags & LOCAL_END_NAT ) 
			    {
			    DEBUG_LOG(_L("NAT discovery result: Local end is behind NAT"));
			    }
			iHdr.iFloatedPort = ETrue;			
		    iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);			
		}
		else
		{
		   if ( iHdr.iMobikeUsed )
		   {
			   iHdr.iFloatedPort = ETrue;			
			   iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);			
		   }	   
		   DEBUG_LOG(_L("NAT discovery result: There is no NAT between negotiating ends"));
		}			   
	}
	else
    {
        DEBUG_LOG(_L("NAT discovery operation failed"));
    }		
}

void CIkev2Negotiation::CreateIkeSPI(TIkeSPI& aSPI, TBool aRekey)
{
	//
	// Create IKE SPI for local end.
	// The SPI value is created from the following "parameters" in
	// IKEv2 negotiation object:
	// - The first 4 octets of SPI value are the SAId (32 bit value)
	// - The last 4 octets of SPI contains "pseudo random" value:
	//   X = (SAId + negotiation object pointer) >> (SAId & 3)
	//
	TUint32 SpiValue1;
	TUint32 SpiValue2;
	if ( aRekey )
		 SpiValue1 = iSAid_Rekey;		
	else SpiValue1 = iHdr.SaId();		
	Mem::Copy((TUint8*)&SpiValue2, (TUint8*)this, 4);
	SpiValue2 = (SpiValue2 + SpiValue1) >> (SpiValue1 & 3);  
	PUT32(aSPI.Ptr(), SpiValue1);	
	PUT32((aSPI.Ptr() + 4), SpiValue2);
	aSPI.SetLength(IKEV2_SPI_SIZE);
}

void CIkev2Negotiation::LoadEapPluginL()
{
	//
	// If EAP configured in policy, construct EAP interface object to
	// communicate EAP ECOM plug-in
	// If consruction causes an error, stop negotiation request
	//
	iHdr.iEAPType = iHdr.iIkeData->iEAPProtocol;
	if ( !iEapPlugin && iHdr.iEAPType )
	{	
	   iEapPlugin = CIkev2EapIf::NewL(*this, (TUint8)iHdr.iEAPType, iHdr.iIkeData, iDebug);
	   TInt Status = iEapPlugin->Status();
	   if ( Status != KErrNone )
	   {
		  iStopped = ETrue;
	   }
	   else iEapPlugin->QueryIdentity();
	}									  
}

TBool CIkev2Negotiation::InitPkiServiceL()
{
    DEBUG_LOG(_L("-> CIkev2Negotiation::InitPkiServiceL"));
	//
	// If EAP configured in policy, construct EAP interface object to
	// communicate EAP ECOM plug-in
	// If consruction causes an error, return corresponding error code
	// to stop negotiation request
	//
	TBool Status = EFalse;
	if ( !iPkiService && Ikev2Proposal::PkiServiceNeeded(iHdr.iIkeData) )
	{
	   iPkiService = CIkeV2PkiService::NewL(*this, iDebug);
	   
	   if (iHdr.iIkeData->iCAList->Count() == 0)
    	   {
    	   User::Leave(KVpnErrInvalidCaCertFile);
    	   }
    	   
       iPkiService->InitIkeV2PkiService(iHdr.iIkeData);    	   
       iState = KStateIkeInitPkiService;
       Status = ETrue;
	}	

    DEBUG_LOG(_L("<- CIkev2Negotiation::InitPkiServiceL"));
	return Status;
}


void CIkev2Negotiation::SendIkeMsgL(CIkeV2Message* aMsg)
{
    ASSERT(aMsg);
    
    TPtrC8 encryptionKey;
    TPtrC8 integrityKey;
    if ( iHdr.iInitiator )
    {   
        encryptionKey.Set(iHdr.iSK_ei);
        integrityKey.Set(iHdr.iSK_ai);
    }
    else
    {
        encryptionKey.Set(iHdr.iSK_er);
        integrityKey.Set(iHdr.iSK_ar);    
    }   

    TInetAddr sourceAddr(iHdr.iLocalAddr);
    if (iHdr.iFloatedPort)
        {
        sourceAddr.SetPort(FLOATED_IKE_PORT);
        }
    else
        {
        sourceAddr.SetPort(IKE_PORT);
        }
    aMsg->PrepareIkeMessageDatagramL(iHdr.iEncrAlg, encryptionKey,
                                     iHdr.iIntegAlg, integrityKey, 
                                     sourceAddr, iHdr.iDestinAddr);
    iMessageSendQue.SendIkeMessageL(aMsg->IkeMessageDatagram(), iHdr.iFloatedPort);     
    	
	if (aMsg->Flags() & IKEV2_RESPONSE_MSG )
	{
        iHdr.SaveRespMsg(aMsg);
        iHdr.iRespRetryCount = 0;
	}
	else
	{
        iSendAttempt = 1;
        iTimer->Cancel();
        iTimer->IssueRequest(iSendAttempt);     // Start retry timer
    
        iHdr.SaveRequestMsg(aMsg);
	}
}

void CIkev2Negotiation::RetransmitRequest()
    {
    TRAPD(err, DoRetransmitL(EFalse));
    if ( err != KErrNone )
        {
        iIkeV2PlugInSession.IkeSaDeleted( err );
        }
    }

void CIkev2Negotiation::DoRetransmitL(TBool aResponse)
{	
	if ( aResponse )
	{
		//
		// Peer has retransmitted a request, retransmit last response
		// message saved.  
		//
		if ( iHdr.iLastResponse && (iHdr.iRespRetryCount <= KMaxSendAttemps) )
		{
			iHdr.iRespRetryCount ++;
			//iHdr.iLastResponse = NULL;
			DEBUG_LOG3(_L("IKE response message rexmitted on SAId: %d , Retry: %d  , State: %d"), iHdr.SaId(), iHdr.iRespRetryCount, iState );

			iMessageSendQue.SendIkeMessageL(iHdr.iLastResponse->IkeMessageDatagram(), 
                                            iHdr.iFloatedPort);
		}
		else iStopped = ETrue;
	}	
	else
	{	
	    //
	    // No response received to a transmitted IKE request message
	    // Retransmit message if retry count not exhausted
	    //	
	    DEBUG_LOG(_L("No response received for transmitted IKE request."));

	    iSendAttempt++;            
	    iMessageSendQue.CancelSend(iHdr.iLastRequest->IkeMessageDatagram());
				
		if ( iSendAttempt <= KMaxSendAttemps )
		{	   		  
           DEBUG_LOG3(_L("IKE Message rexmitted on SAId: %d , State: %d , Retry: %d"),iHdr.SaId(), iState, iSendAttempt );		   
           iMessageSendQue.SendIkeMessageL(iHdr.iLastRequest->IkeMessageDatagram(), 
                                           iHdr.iFloatedPort);
	       iTimer->IssueRequest(iSendAttempt); 	// Restart retry timer
		}
		else
		    {
		    DEBUG_LOG3(_L("Transmit retry count reached on SAId: %d , State: %d , retry: %d"),iHdr.SaId(), iState, iSendAttempt );
		    if ( iState < KStateIkeSaCompleted )
		        {
			    IkeSaFailed(KKmdIkeNegotFailed);  // IKE SA negotiation going 
		        }
		    else
		       {
			   iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());			   			   
			   iIkeV2PlugInSession.IkeSaDeleted(KKmdIkeNoResponseErr);	 //IKE SA deletion going
			   delete this;
		       }	    
		    }	
	    }	
    }


void CIkev2Negotiation::IkeV2PkiInitCompleteL(TInt aStatus)
    {

    DEBUG_LOG(_L("-> CIkev2Negotiation::IkeV2PkiInitCompleteL"));
	//
	// The implementation for class MPkiServiceComplete virtual function
	// This method is called when a PKI service operation is
	// completed.
	//
	
	__ASSERT_ALWAYS( iPkiService != NULL, User::Invariant());            	    
    __ASSERT_ALWAYS(iState == KStateIkeInitPkiService, User::Invariant());

    switch(aStatus)
        {
        case KErrNone:
            //
            // PKI service object has been constructed
            // Start IKE_SA_INIT exchange
            //
            iState = KStateIdle;
            if ( iChildSaRequest )
                {	   
                CIkev2Acquire* Acquire = iChildSaRequest;
                iChildSaRequest = NULL;				   
                CIkev2Acquire::Link(Acquire, GetAcquireQue());
                GetIpsecSPI(Acquire);
                }
            else if ( iSavedSaInit )
                {
                TPtr8 IkeMsg(iSavedSaInit->Des());
                const ThdrISAKMP* IkeMessage = ThdrISAKMP::Ptr(IkeMsg);
                ProcessIkeMessageL(*IkeMessage, iHdr.iRemoteAddr, IKE_PORT);
                if ( Stopped() )
                   delete this;
                }	   
            break;                
        case KErrNotFound:       
            DEBUG_LOG(_L("IKEv2 CA certificate retrieve failed. Certificate not found"));
            IkeSaFailed(KVpnErrInvalidCaCertFile);
            break;
        default:                
            {
            DEBUG_LOG1(_L("IKEv2 CA certificate retrieve failed (%d)"), aStatus);
            IkeSaFailed(aStatus);
            }               		   
            break;
        }
        
    DEBUG_LOG(_L("<- CIkev2Negotiation::IkeV2PkiInitCompleteL"));        
    }
    

void CIkev2Negotiation::SendEapDataL(HBufC8* aEapData)
{
	//
	// Send an IKE containing an EAP payload (within Encrypted Payload)
	// The entire EAP payload data is provided in aEapData buffer
	//
    CleanupStack::PushL(aEapData);
	if ( iState == KStateIkeSaEapGoing )
	{
        __ASSERT_DEBUG(iHdr.iInitiator, User::Invariant());
	
        CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
                                                    IKE_AUTH, 
                                                    iHdr.iInitiator,
                                                    EFalse,
                                                    iHdr.NextRequestId(), 
                                                    iDebug);
        CleanupStack::PushL(ikeMsg);               
        ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
        ikeMsg->AppendEapPayloadL(*aEapData);
        CleanupStack::Pop(ikeMsg);
		SendIkeMsgL(ikeMsg);
	}	
	CleanupStack::PopAndDestroy(aEapData);
}

void CIkev2Negotiation::EapEventL(TInt aEvent)
    {
    // See whether the object is accepting any events
    // (it is, by default, but will not take events during destruction phase)
    if (!iProcessEvents) 
    {
        return;
    }
	//
	// An event idicated by the EAP plugin process event according to
	// event type
	//
	switch ( aEvent )
	    {
		case KEapEventSuccess:
			if ( (iState == KStateIkeSaEapGoing) || (iState == KStateIkeSaEapStarted) )
			    {			    
			    //
			    // EAP auhtentication succeeded.
			    // Build IKE message HDR, SK {AUTH}
			    //
			    __ASSERT_DEBUG( iHdr.iInitiator, User::Invariant());
			    
			    CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
                                                            IKE_AUTH, 
                                                            iHdr.iInitiator,
                                                            EFalse,
                                                            iHdr.NextRequestId(), 
                                                            iDebug);
			    CleanupStack::PushL(ikeMsg);               
                ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
								
		        
		        HBufC8* authData = SignAuthDataL(*iAuthMsgInit, (TUint8)iHdr.iAuthMethod);	           
		        CleanupStack::PushL(authData);
		        ikeMsg->AppendAuthPayloadL(iHdr.iAuthMethod, *authData);       
		        CleanupStack::PopAndDestroy(authData);				

				CleanupStack::Pop(ikeMsg);
				SendIkeMsgL(ikeMsg);
				iState = KStateIkeSaAuthRequest;
				iEapCompleted = ETrue;				
			    } 
			break;

		case KEapEventGetIdentity:
			GetOwnIdentityL(ETrue);  // Gets the Identity from EAP plugin			
			if ( iState == KStateIkeWaitingId )
			    {
			    //
			    // Identity data provided by the EAP plug-in
			    // Complete local signed data and send the first
			    // IKE_AUTH message
			    //
			    AddIdToSignedDataL(ETrue, iAuthMsgInit, iLocalIdentity->PayloadData()); 
			    SendIkeAuthMessageL();			    
			    }	
			break;

		case KEapEventGetPSK:
			if ( iState == KStateIkeSaEapGoing )
			    {
			    //
			    // Preshared key provided by the EAP plug-in
			    // Get key data and link it into negotiation object
			    //
				iPresharedKey = iEapPlugin->MSK();
			    }	
			break;

		default:  // = KEapEventFailed     
		    //
		    // EAP authentication is failed. Stop negotiation
		    //
		    IkeSaFailed(KKmdIkeAuthFailedErr);  // IKE SA negotiation going 
			break;
	    }	
    }

TBool CIkev2Negotiation::ProcessIkeSaInitL(CIkev2Payloads* aIkeMsg, const TInetAddr& aRemote)
{
    ASSERT(aIkeMsg);
	//
	// Process IKE message of exchange type IKE_SA_INIT
	//
	ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg();  // IKE Message fixed header
	TBool   Response   = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
	TBool   Initiator  = IkeHdr->GetFlags() & IKEV2_INITIATOR;
	TUint32 MsgId      = IkeHdr->GetMessageId();
			
	if ( iHdr.iInitiator )
	{
		if ( Initiator ) {
			DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
			return ETrue;		
		}	
		if ( !Response )
		{
			DEBUG_LOG1(_L("IKEv2 Message is not response; state: %d"), iState);
			return ETrue;		
		}
		if ( MsgId != iHdr.ExpectedResponseId() )
		{
			DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);
			return ETrue;		
		}
		
		if (iState == KStateIkeSaInitRequest)
		{
            //record responder SPI
            aIkeMsg->GetIkeMsg()->GetSPI_R(iHdr.SpiR());			    
            
            //
            // Received message should be a response to a
            // IKE_SA_INIT request transmitted.
            //
            if (IkeHdr->GetPayload() == IKEV2_PAYLOAD_NOTIF)
            {
                return ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_SA_INIT);		
            }	
            //
            // Response message should be format:
            // HDR(A,B), SAr1, KEr, Nr, [CERTREQ]
            //
            if ( !CheckPayloadsOrder(aIkeMsg, IKE_SA_INIT, ETrue) )
            {
                DEBUG_LOG1(_L("Erroneous IKE_SA_INIT response: %d"), iState);
                return EFalse;
            }
            if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *PeekProposedSa(), *aIkeMsg) )
            {
                DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA_INIT response: %d"),iState);				    
                return EFalse;
            }
            if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
            {
                DEBUG_LOG1(_L("Nonce data too short %d"), iState);
                return EFalse;
            }
    
            if ( iNatNotify )
            {
                TBool Supported;
                TInetAddr LocalIp;	
                if ( iHdr.iIkeData->iUseMobIke )
                     LocalIp.SetAddress(KInetAddrNone);
                else LocalIp = iHdr.iLocalAddr; 	   
                
#ifdef _DEBUG
                TBuf<80> debugBuf;
                DEBUG_LOG(_L("Calculating NAT detection:"));
                LocalIp.Output(debugBuf);					
                DEBUG_LOG2(_L("LocalIp %S:%d"), &debugBuf, IKE_PORT);
                iHdr.iRemoteAddr.Output(debugBuf);
                DEBUG_LOG2(_L("RemoteIp %S:%d"), &debugBuf, IKE_PORT);
#endif
                
                iHdr.iNATFlags = CIkev2NatT::CheckPeerNotifysL(*aIkeMsg->iNotifs, LocalIp, iHdr.iRemoteAddr, IKE_PORT,
                                                              iHdr.SpiI(), iHdr.SpiR(), Supported);
                GetNatStatus(Supported, aRemote); 
            }	
    
            delete iNonce_R;
            iNonce_R = NULL;
    
            iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
            iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());				
            if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, iHdr.iDHGroup) )
            {
               return EFalse;
            }   
    
            //
            // IKE_SA_INIT request is completed enter IKE_AUTH
            //
            GenerateIkeKeysL();				
            TPtrC8 ikeHdrPtr((TUint8*)IkeHdr, IkeHdr->GetLength());
            SaveSignedDataL(EFalse, ikeHdrPtr);  // Save IKE_AUTH message 2
            
            //We ignore possible cert req payloads and just work
            //according our policy
            if ( !iHdr.iEAPType &&
                 (iHdr.iAuthMethod == RSA_DIGITAL_SIGN || iHdr.iAuthMethod == DSS_DIGITAL_SIGN) )
            {                    			
                SaveSignedDataL(ETrue, iHdr.iLastRequest->IkeMessageDatagram()); // Own identity not yet saved to signed data																			
    
                GetOwnIdentityL();    // Get own Identity from Certificate (or policy)                    
                AddIdToSignedDataL(ETrue, iAuthMsgInit, iLocalIdentity->PayloadData());    			    
            }
            else
            {
                //
                // Check if "implicit" Child SA exchange required
                // by getting request CIkev2Acquire object from queue
                //
                GetOwnIdentityL();
                SaveSignedDataL(ETrue, iHdr.iLastRequest->IkeMessageDatagram()); // Own identity saved to signed data   				            
            }	
            iChildSaRequest = CIkev2Acquire::GetNext(GetAcquireQue(), EFalse);				
            SendIkeAuthMessageL();
		}
		else
		{
            //
            // Ignore received message silently
            //
            DEBUG_LOG1(_L("IKE_SA_INIT response received in state %d"), iState);
		}	
	}
	else {
		if ( !Initiator )
		{
			DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong, state: %d"), iState);
			return ETrue;		
		}	
		if ( Response )
		{
		    DEBUG_LOG1(_L("IKEv2 Message is not request, state: %d"), iState);			
			return ETrue;		
		}
		
		switch ( iState )
		{
			case KStateIdle:
			case KStateIkeSaInitResponse:
			    //Record Initiator SPI
			    aIkeMsg->GetIkeMsg()->GetSPI_I(iHdr.SpiI());
			    iHdr.SpiI().SetLength(IKEV2_SPI_SIZE);
			    
				//
				// Received message should be an IKE_SA_INIT request
				// Request message should be format:
				// HDR(A,0), SAi1, KEi, Ni, [CERTREQ]
				//
			    {
				if ( !CheckPayloadsOrder(aIkeMsg, IKE_SA_INIT, EFalse) )
				{
				    DEBUG_LOG1(_L("Erroneous IKE_SA_INIT request: %d"), iState);
					return EFalse;	
				}
				if ( MsgId != iHdr.ExpectedRequestId() ) {
					if ( iHdr.iLastResponse != NULL && 
					     MsgId == iHdr.iLastResponse->MessageId() && 
					     iState == KStateIkeSaInitResponse )
					{
					   //
					   // Retransmission of an earlier IKE_SA_INIT
					   // request. Retransmit current IKE_SA_INIT
					   // response (if retry count not exhausted)
					   //
					   DoRetransmitL(ETrue);
					   return ETrue;
					}
					else {	
					   DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);					   
					   return EFalse;
					}  		   
				}
				if ( iState == KStateIkeSaInitResponse )
				   return EFalse; // IKE_SA_INIT request retry with a new message ID
				iIkeV2PlugInSession.StartResponding();

				//
				// Build a SA payload from current IKE policy and
				// verify received IKE SA request with it
				//
				HBufC8* SaBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
				CleanupStack::PushL(SaBfr);
				HBufC8* proposedSa = NULL;
				TBool SaOk = Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild, 
                                                                                   *SaBfr, *aIkeMsg, 
                                                                                   proposedSa);
				CleanupStack::PopAndDestroy();				
				if ( !SaOk )
				{
				    DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA_INIT request: %d"),iState);
					SetNotifyCode(NO_PROPOSAL_CHOSEN);
					return EFalse;  							
				}
				SetProposedSa(proposedSa);
				proposedSa = NULL;
				if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
				{
				    DEBUG_LOG1(_L("Nonce data too short %d"), iState);
					return EFalse;	
				}
		
				//Check peer NAT status
				TBool useNatDetection = EFalse;
                if ( !iHdr.iIkeData->iUseNatProbing )
                {
                    TInetAddr LocalIp;  
                    if ( iHdr.iIkeData->iUseMobIke )
                         LocalIp.SetAddress(KInetAddrNone);
                    else LocalIp = iHdr.iLocalAddr;        
                    iHdr.iNATFlags = CIkev2NatT::CheckPeerNotifysL(*aIkeMsg->iNotifs, LocalIp, 
                                                                   iHdr.iRemoteAddr, IKE_PORT,
                                                                   iHdr.SpiI(), iHdr.SpiR(), useNatDetection);
                }

                if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, iHdr.iDHGroup) )
                    return EFalse;

                
				//
				// Create own SPI (responder)
				//
  				CreateIkeSPI(iHdr.SpiR());
				delete iNonce_I;
				iNonce_I = NULL;
				iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
				iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
				GetNonceDataL(EFalse);

				TPtrC8 ikeHdrPtr((TUint8*)IkeHdr, IkeHdr->GetLength());
				SaveSignedDataL(EFalse, ikeHdrPtr);  // Save IKE_AUTH message 2 
				
				//
				// Build IKE_SA_INIT response message: HDR, SAr1, KEr, Nr, [CERTREQ]
				//
				__ASSERT_DEBUG(!iHdr.iInitiator, User::Invariant());				
				CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
                                                            IKE_SA_INIT, 
                                                            iHdr.iInitiator,
                                                            ETrue, 
                                                            iHdr.ExpectedRequestId(),
                                                            iDebug);
				CleanupStack::PushL(ikeMsg);

                HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
                CleanupStack::PushL(saBfr);
                ikeMsg->AppendSaPayloadL(*saBfr);
                CleanupStack::Pop(saBfr);
                SetProposedSa(saBfr);
				
                AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
                ikeMsg->AppendNoncePayloadL(*iNonce_R);
                
				if ( iPkiService )
				    {
				    ikeMsg->AppendCertReqPayloadL(iPkiService->CaList());
				    }
				
				if ( useNatDetection )
				{   
                    delete iNatNotify;
                    iNatNotify = NULL;
				
					TInetAddr LocalIp;	
					if ( iHdr.iIkeData->iUseMobIke )
						 LocalIp.SetAddress(KInetAddrNone);
					else LocalIp = iHdr.iLocalAddr; 	   
                    
                    
					iNatNotify = CIkev2NatT::NewL(LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());				       
				    ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP, 
				                                 iNatNotify->SourceNofify());
			        ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP, 
				                                 iNatNotify->DestinNofify());         					
				}
				GetNatStatus(useNatDetection, aRemote);
				CleanupStack::Pop(ikeMsg);
				SendIkeMsgL(ikeMsg);
				GenerateIkeKeysL();								
				
				SaveSignedDataL(ETrue, ikeMsg->IkeMessageDatagram()); // Own identity is not yet saved to signed data
			    iState = KStateIkeSaInitResponse;
				}
                break;

			default:
				//
				// Ignore received message silently
				//
			    DEBUG_LOG1(_L("IKE_SA_INIT message received in state %d"), iState);
				break;
				
		}	
	}
	
	return ETrue;
}

TBool CIkev2Negotiation::ProcessIkeAuthL(CIkev2Payloads* aIkeMsg)
{
    ASSERT(aIkeMsg);
	//
	// Process IKE message of exchange type IKE_AUTH
	//
	ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg();  // IKE Message fixed header
	TBool   Response   = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
	TBool   Initiator  = IkeHdr->GetFlags() & IKEV2_INITIATOR;
	TUint32 MsgId      = IkeHdr->GetMessageId();

	if ( iHdr.iInitiator )
	{
		if ( Initiator )
		{
		    DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
			return ETrue;  	
		}	
		if ( !Response )
		{
		    DEBUG_LOG1(_L("IKEv2 Message is not response; state: %d"), iState);
			return ETrue;
		}
		if ( MsgId != iHdr.ExpectedResponseId() )
		{
		    DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);
		    return ETrue;		
		}

		switch ( iState )
		{
			case KStateIkeSaAuthRequest:
			    DEBUG_LOG(_L("Handling IKE_AUTH response"));
				//
				// Received message should be a response to a
				// IKE_AUTH request transmitted.
				// Response message should be format:
				// HDR(A,B), SK {IDr, [CERT,] AUTH, [CP], SAr2, TSi, TSr}				
				//
				if ( aIkeMsg->iEncr )
				{	
				   ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_AUTH);
				   if ( iDeleteIkeSA )
				   {
				      DEBUG_LOG1(_L("Error Notify in IKE_AUTH response: %d"), iState);			
					  
		              //Because we are just in IKE_AUTH no IKE_SAs exists --> we don't 
    		          //want to delete one. So we set iDeleteIkeSA back to false.			          
			          iDeleteIkeSA = EFalse;
					 	
					  return EFalse;
				   }
				}   
				if ( !CheckPayloadsOrder(aIkeMsg, IKE_AUTH, ETrue) )
				{
				    DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
					SetNotifyCode(INVALID_SYNTAX);
				
				    if ( iChildSaRequest && !iChildSARejected && !aIkeMsg->iSa )
				        {
						iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);	
						}
					
				    return EFalse;	
				}
				DEBUG_LOG(_L("IKE_AUTH payload order check passed"));
				TBool Status;
				if ( iEapCompleted )
				{	
				    Status = AuthenticatePeerL(aIkeMsg->iAuth);
				}   
				else
				{
					if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdR) )
					{
						SetNotifyCode(AUTHENTICATION_FAILED);					
						return EFalse;
					}
				    Status = AddIdAndAuthenticatePeerL(aIkeMsg);
				}	
				if ( !Status )
				{
					SetNotifyCode(AUTHENTICATION_FAILED);
					return EFalse;
				}
				//
				// If implicit Child SA negotiation requested,
				// verify IPSEC SA- and Traffic selector payloads, too
				//
				if ( iChildSaRequest )
				{
                    DEBUG_LOG(_L("Processing CHILD_SA creation"));
					if ( !iChildSARejected )
					{
						if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *iChildSaRequest->SA(), *aIkeMsg) )
						{
							DEBUG_LOG1(_L("Unaccepted SA payload content in IKE_AUTH response: %d"),iState);
							SetNotifyCode(NO_PROPOSAL_CHOSEN);
							iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);							
							return EFalse;
						}
						DEBUG_LOG(_L("SA response verified"));
						if ( !IpsecSelectors::VerifyTrafficSelectorsL(iChildSaRequest, (TTSPayloadIkev2*)aIkeMsg->iTsI, (TTSPayloadIkev2*)aIkeMsg->iTsR ) )
						{
						    DEBUG_LOG1(_L("Unaccepted Traffic Selectors in IKE_AUTH response: %d"),iState);
							SetNotifyCode(TS_UNACCEPTABLE);
							iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
							return EFalse;
						}
						DEBUG_LOG(_L("Traffic selectors verified"));
						if ( aIkeMsg->iCp )
						{
							if ( iConfigMode )
							    {
								iConfigMode->ProcessCpL(aIkeMsg->iCp);
							    }
							else
							    {
							    DEBUG_LOG(_L("Unsolicited CP payload in IKE_AUTH response"));
							    }							
						}
						iChildSaRequest->SetSPI_Out(iChild.iSPI_Out);	
						DEBUG_LOG(_L("Generating IPsec keys"));
						iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc, 
                                                  *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
						DEBUG_LOG(_L("IPsec keys generated"));
					}	
					else	
					{
					    DEBUG_LOG1(_L("Implicit CHILD_SA rejected Notify in IKE_AUTH response: %d"), iState);
						iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
					}	
				}	
				//
				// IKE_AUTH request is completed and IKE SA has been
				// negotiated
				//
				IkeSaCompletedL();				   
				break;

			case KStateIkeSaEapStarted:
				//
				// Received message should be an IKE_AUTH response
				// containing an EAP payload.
				// The content of received IKE message shall be:
				// HDR, SK {IDr, [CERT,] AUTH, EAP }
				//
				if ( !aIkeMsg->iEncr || !aIkeMsg->iIdR || !aIkeMsg->iAuth || !aIkeMsg->iEap )
				{
					DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
					SetNotifyCode(INVALID_SYNTAX);			
					return EFalse;	
				}
				if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdR) )
				{
					SetNotifyCode(AUTHENTICATION_FAILED);										
					return EFalse;
				}
                if ( !AddIdAndAuthenticatePeerL(aIkeMsg) )
                {
                    SetNotifyCode(AUTHENTICATION_FAILED);										
                    return EFalse;
                }
				iState = KStateIkeSaEapGoing;
                iEapPlugin->EapDataInbound(aIkeMsg->iEap);
                break;
				
			case KStateIkeSaEapGoing:
				//
				// Received message should be an IKE_AUTH response
				// containing an EAP payload.
				// The content of received IKE message shall be:
				// HDR, SK {EAP}				
                //
				if ( !aIkeMsg->iEncr || !aIkeMsg->iEap )
				{
					DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
					SetNotifyCode(INVALID_SYNTAX);				
					return EFalse;	
				}
				iEapPlugin->EapDataInbound(aIkeMsg->iEap);
				break;

			default:
				//
				// Ignore received message silently
				//
				DEBUG_LOG1(_L("IKE_AUTH response received in state %d"), iState);
				break;

		}	
	}
	else
	{
		if ( !Initiator )
		{
			DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong, state: %d"), iState);
			return ETrue;		
		}	
		if ( Response )
		{
			DEBUG_LOG1(_L("IKEv2 Message is not request, state: %d"), iState);
			return ETrue;		
		}
		switch ( iState )
		{
			case KStateIkeSaInitResponse:
			case KStateIkeSaCompleted:	
				//
				// Received message should be an IKE_AUTH request
				// Request message should be format:
				// HDR(A,B), SK {IDi, [CERT,] [CERTREQ,] [IDr,] AUTH, SAi2, TSi, TSr} 
				//
				if ( !CheckPayloadsOrder(aIkeMsg, IKE_AUTH, EFalse) )
				{
					DEBUG_LOG1(_L("Erroneous IKE_AUTH request: %d"), iState);
					SetNotifyCode(INVALID_SYNTAX);
					return EFalse;	
				}
				if ( MsgId != iHdr.ExpectedRequestId() ) {
					if ( iHdr.iLastResponse != NULL &&
					     MsgId == iHdr.iLastResponse->MessageId() && 
					     iState == KStateIkeSaCompleted )
					{
					   //
					   // Retransmission of an earlier IKE_SA_INIT
					   // request. Retransmit current IKE_SA_INIT
					   // response (if retry count not exhausted)
					   //
						DoRetransmitL(ETrue);
						return ETrue;
					}
					else {	
						DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);					
						SetNotifyCode(INVALID_MESSAGE_ID);
						StoreNotifyData32(MsgId);
						return EFalse;  								   
					}  		   
				}
				if ( iState == KStateIkeSaCompleted )
				   return EFalse; // IKE_AUTH request retry with a new message ID

				//if ( aIkeMsg->iEncr )
				//{	
					ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_AUTH);
					if ( iDeleteIkeSA )
					{
						DEBUG_LOG1(_L("Error Notify in IKE_AUTH response: %d"), iState);
						return EFalse;
					}
				//}
				
				if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdI) )
				{
				    DEBUG_LOG(_L("Peer certificate validation failed."));
					SetNotifyCode(AUTHENTICATION_FAILED);
					return EFalse;
				}
				if ( !AddIdAndAuthenticatePeerL(aIkeMsg) )
				{	
					SetNotifyCode(AUTHENTICATION_FAILED);
					return EFalse;
		        }
				//
				// Process "concatenated" Child SA- and Traffic
				// Selector payloads if present  
				//
				if ( aIkeMsg->iSa )
				{
				    DEBUG_LOG(_L("IKE_AUTH request has SA and TS payload."));				
					CIkev2Acquire* Acquire = IpsecSelectors::GetIpsecPolicyL(iIkeV2PlugInSession, aIkeMsg);
					if ( !Acquire )
					{
					    DEBUG_LOG1(_L("Unaccepted Traffic Selectors in IKE_AUTH request: %d"),iState);
						SetNotifyCode(TS_UNACCEPTABLE);						
						return EFalse;
					}
					CleanupStack::PushL(Acquire);						
					HBufC8* proposedSaBuffer = NULL;
					if (!Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild, 
                                                                               *Acquire->SA(), *aIkeMsg,
                                                                               proposedSaBuffer))
					{
						CleanupStack::PopAndDestroy(Acquire);  
						DEBUG_LOG1(_L("Unaccepted SA content in IKE_AUTH request: %d"),iState);
						SetNotifyCode(NO_PROPOSAL_CHOSEN);						
						return EFalse;  							
					}
					SetProposedSa(proposedSaBuffer);
					proposedSaBuffer = NULL;
					//
					// Replace SA payload buffer in CIkev2Acquire with
					// selected SA payload built in VerifySaRequestL
					//
					CleanupStack::Pop(Acquire); 							
					Acquire->ReplaceSA(GetProposedSa()); 
					Acquire->SetSPI_Out(iChild.iSPI_Out);
					Acquire->SetResponse();
					if ( iChild.iTransport )
    					{
					    
						Acquire->SetTransport();				
    					}
 					CIkev2Acquire::Link(Acquire, GetAcquireQue());
 					DEBUG_LOG(_L("Acquire linked."));
 					
					if ( aIkeMsg->iCp )
					{
						//
						// CP payload received as IKE SA responder
						// Handle CP payload and return "dummy"
						// virtual IP to initiator. 
						//
						delete iConfigMode;
						iConfigMode = NULL;
						iConfigMode = CIkev2Config::NewL(Acquire, (TInetAddr*)&iHdr.iRemoteAddr);
						iConfigMode->ProcessCpL(aIkeMsg->iCp);
						Acquire->SetVirtualIp();
					}
	        		//
			        // Get SPI for new inbound SA
        			//
                    iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc, 
                                               *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
					
				    if ( iPkiService && !iEapPlugin && 
				         aIkeMsg->iCertReqs && 
				         aIkeMsg->iCertReqs->Count() )
                	{
     			       GetOwnIdentityL();    // Get own Identity from Certificate (or policy)    			       
    			       AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
            					
        			   CIkev2Acquire* Acquire = CIkev2Acquire::PeekFirst(GetAcquireQue());
        			   if ( Acquire )
        			   {
        				   GetIpsecSPI(Acquire);
        				   iState = KStateIkeSaAuthWaitSpi;
        			   }
        			   else 
        			   {       
        			       DEBUG_LOG(_L("CIkev2Acquire::PeekFirst returned NULL."));			    
        			       DEBUG_LOG(_L("Sending IKE_AUTH response."));			    
        			       SendIkeAuthMessageL();
        			   }

                	}	
                    else
					{
						GetOwnIdentityL();
						AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
						GetIpsecSPI(Acquire);						
					    iState = KStateIkeSaAuthWaitSpi;
					}	
				}
				else
				{
					if ( iPkiService && !iEapPlugin && 
					     aIkeMsg->iCertReqs && 
					     aIkeMsg->iCertReqs->Count() )
                    {                       
       			        GetOwnIdentityL();    // Get own Identity from Certificate (or policy)
        			    AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
        			               						
        			    CIkev2Acquire* Acquire = CIkev2Acquire::PeekFirst(GetAcquireQue());
        			    if ( Acquire )
        			    {
        				   GetIpsecSPI(Acquire);
        				   iState = KStateIkeSaAuthWaitSpi;
        			    }
        			    else 
        			    {        			        
        			       SendIkeAuthMessageL();
        			    }
					}
					else
					{	
				       //
				       // Build and send an IKE_AUTH response
				       //
						GetOwnIdentityL();
						AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
				        SendIkeAuthMessageL();
					}		
				}   
				break;

			default:
				//
				// Ignore received message silently
				//
				DEBUG_LOG1(_L("IKE_SA_INIT message received in state %d"), iState);
				break;
		}	
	}
	
	return ETrue;
}

TBool CIkev2Negotiation::ProcessChildSaL(CIkev2Payloads* aIkeMsg)
{
    ASSERT(aIkeMsg);
	//
	// Process IKE message of exchange type CREATE_CHILD_SA
	//
	TUint16 PfsDHGroup;
	ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg();  // IKE Message fixed header
	TBool   Response   = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
	TBool   Initiator  = IkeHdr->GetFlags() & IKEV2_INITIATOR;
	TUint32 MsgId      = IkeHdr->GetMessageId();
			
	if ( iHdr.iInitiator )
	{
		if ( Initiator )
		{
			DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
			SetNotifyCode(INVALID_SYNTAX);		
			return EFalse;  	
		}	
	}
	else
	{
		if ( !Initiator )
		{
			DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong state: %d"), iState);
			SetNotifyCode(INVALID_SYNTAX);		
			return EFalse;  	
		}	
	}

	if ( Response )
	{
	   //
	   // CREATE_CHILD_SA response message received
	   //
        switch ( iState )
	    {
		   case KStateIkeChildSARequest:
			  //
			  // Received message should be a response to a
			  // CREATE_CHILD_SA request transmitted.
			  // Response message should be format:
			  // HDR(A,B), SK { SA, Nr, [KEr], [TSi, TSr]}
			  //
			  if ( MsgId != iHdr.ExpectedResponseId() )
			  {
				   DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);

				   SetNotifyCode(INVALID_MESSAGE_ID);
				   StoreNotifyData32(MsgId);	 
				   return EFalse; 	
			  }
			  if ( aIkeMsg->iEncr )
			  {	
			      ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, CREATE_CHILD_SA);
			      if ( iDeleteIkeSA )
			      {
				     DEBUG_LOG1(_L("Error Notify in CREATE_CHILD_SA response: %d"), iState);
				     return EFalse;
				  }
				  if ( iChildSARejected )
				  {
					  DEBUG_LOG1(_L("CHILD_SA rejected Notify in CREATE_CHILD_SA response: %d"), iState);					  
					  iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
					  iStopped = ETrue;
					  return EFalse;
				  } 
			  }	
			  if ( !CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, ETrue) )
			  {
			     DEBUG_LOG1(_L("Erroneous CREATE_CHILD_SA response: %d"), iState);
				 SetNotifyCode(INVALID_SYNTAX);
				 iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
				 return EFalse;	
			  }
	  		  if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
			  {
			     DEBUG_LOG1(_L("Nonce data too short %d"), iState);
				 iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
				 iStopped = ETrue;
				 return EFalse;
			  }
			  
		      if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *iChildSaRequest->SA(), *aIkeMsg) )
			  {
			     DEBUG_LOG1(_L("Unaccepted SA content in CREATE_CHILD_SA response: %d"),iState);				
				 SetNotifyCode(NO_PROPOSAL_CHOSEN);
				 iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
			     return EFalse;
			  }
			  if ( !IpsecSelectors::VerifyTrafficSelectorsL(iChildSaRequest, (TTSPayloadIkev2*)aIkeMsg->iTsI, (TTSPayloadIkev2*)aIkeMsg->iTsR ) )
			  {
			     DEBUG_LOG1(_L("Unaccepted Traffic Selectors in CREATE_CHILD_SA response: %d"),iState);	  						 
				 SetNotifyCode(TS_UNACCEPTABLE);
				 iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
				 return EFalse;
			  }
			  delete iNonce_R;
			  iNonce_R = NULL;
			  iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
			  iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
			  PfsDHGroup = iChildSaRequest->DHGroup(); 
			  if ( PfsDHGroup  )
			  {
		         if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, PfsDHGroup) )
				 {	 					 
					 iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
					 return EFalse;
				 }	
                 HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
		         CleanupStack::PushL(g_ir);

		         iChild.GenerateIpsecKeysL(iHdr.iSK_d, *g_ir, 
                                           *iNonce_I, *iNonce_R, iHdr.iPRFAlg);

		         
		         g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
		         CleanupStack::PopAndDestroy();  //g_ir

			  }
			  else if ( aIkeMsg->iKe )
			  {
			      DEBUG_LOG1(_L("Unsolicted Key Exchange payload present in CREATE_CHILD_SA response: %d"),iState);
				  SetNotifyCode(INVALID_KE_PAYLOAD);
				  iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);				  
				  return EFalse;
			  }
			  else
              {
                  iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc, 
                                            *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
              
              }
			  //
			  //  CREATE_CHILD_SA request is completed Update 
			  //			  
			  IpsecSANegotiatedL();
			  break;

		   case KStateIkeSARekeyRequest:
			  //
			  // Received message should be a response to a
			  // IKE SA rekey CHILD_SA request transmitted.
			  // Response message should be format:
			  // HDR(A,B), SK { SA, Nr, KEr }
			  //
			  if ( CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, ETrue) && aIkeMsg->iKe )
			  {
			     DEBUG_LOG1(_L("IKE SA rekey message received as CHILD_SA response: %d"), iState);
				 ProcessIkeSARekeyL(aIkeMsg);
			  }
			  else
		      {
                  DEBUG_LOG1(_L("Erroneous IKE SA rekey message received as CHILD_SA response: %d"),iState);		      
		      }
			  //iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL, EFalse);								  
			  BuildDeleteRequestL(NULL);  // Delete IKE SA rekeyed
			  iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());			  
			  break; 

		   default:
			  //
			  // Ignore received message silently
			  //
			  DEBUG_LOG1(_L("CREATE_CHILD_SA response received in state %d"), iState);
			  break;

	    }	
	}
	else
	{
	    //
	    // CREATE_CHILD_SA request message received
	    //
		if ( MsgId != iHdr.ExpectedRequestId() ) {
			if ( iHdr.iLastResponse != NULL &&
			     MsgId == iHdr.iLastResponse->MessageId() )
			{
			   //
			   // Retransmission of an earlier request.
			   // Retransmit current response 
			   //
				iState = KStateIkeChildSAResponse;
				DoRetransmitL(ETrue);
				return ETrue;
			}
			else {	
				DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);
				SetNotifyCode(INVALID_MESSAGE_ID);
				StoreNotifyData32(MsgId);
				return EFalse;  								   
			}  		   
		}
	   
		if ( iState >= KStateIkeSaCompleted )
		{
		   //
		   // Received CREATE_CHILD_SA message can be one of the
		   // following:
		   // -- Create new Ipsec SA request:  
	       //    HDR(A,B), SK { SA, Nr, [KEi], [TSi, TSr]}
		   // -- Rekey Ipsec SA request:
		   //    HDR(A,B), SK { N, SA, Ni, [KEi], [TSi, TSr]} 
		   // -- Rekey IKE SA request: 
		   //    HDR(A,B), SK { SA, Ni, KEi} 
		   //   
			if ( !CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, EFalse) )
			{
				DEBUG_LOG1(_L("Erroneous CREATE_CHILD_SA request: %d"), iState);
				SetNotifyCode(INVALID_SYNTAX);						
				return EFalse;	
			}
		   //
		   // Check is the current request an IKE SA rekey by checking
		   // Proposal payload protocol value
		   //
            if ( Ikev2Proposal::IkeSaRekey(aIkeMsg) ) 
			{
				TBool Status;
				if ( iState == KStateIkeSARekeyRequest )
				{
				   DEBUG_LOG1(_L("IKE SA Rekey collision for SAID: %d"), iHdr.SaId());										   
				   SetNotifyCode(NO_ADDITIONAL_SAS);
				   Status = EFalse;
				}
				else
				{	
				   DEBUG_LOG1(_L("IKE SA Rekey started by peer for SAID: %d"), iHdr.SaId());							   						   
				   iState = KStateIkeSARekeyResponse;
				   Status = ProcessIkeSARekeyL(aIkeMsg);
				   iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
				}
				return Status;
			}
			if ( CIkev2Acquire::Responding(GetAcquireQue()) )
			{
				DEBUG_LOG1(_L("CREATE_CHILD_SA IKE SA request already pending: %d"), iState);
				SetNotifyCode(NO_ADDITIONAL_SAS);
				return EFalse;	
			}
		    	
		   //
		   // Get acceptable Ipsec policy for peer defined traffic
		   // selectors (and peer address)
		   //
		    CIkev2Acquire* Acquire = IpsecSelectors::GetIpsecPolicyL(iIkeV2PlugInSession, aIkeMsg, 
                                                                     iHdr.iIkeData->iGroupDesc_II);
			if ( !Acquire )
			{
				DEBUG_LOG1(_L("Unaccepted Traffic Selectors in CREATE_CHILD_SA request: %d"),iState);
				SetNotifyCode(TS_UNACCEPTABLE);						
				return EFalse;
			}
			CleanupStack::PushL(Acquire);			
			HBufC8* proposedSaBuffer = NULL;
			if (!Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild, *Acquire->SA(), 
                                                                       *aIkeMsg, proposedSaBuffer))
			{
				CleanupStack::PopAndDestroy(Acquire);				
				DEBUG_LOG1(_L("Unaccepted SA content in CREATE_CHILD_SA request: %d"),iState);
				SetNotifyCode(NO_PROPOSAL_CHOSEN);						
				return EFalse;  							
			}
			this->SetProposedSa(proposedSaBuffer);
			proposedSaBuffer = NULL;
			delete iNonce_I;
			iNonce_I = NULL;
			iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
			iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
			if ( aIkeMsg->iKe )
			{
				PfsDHGroup = Acquire->DHGroup();
				if ( PfsDHGroup == 0 )
				{	
					PfsDHGroup = Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II);
					Acquire->DHGroup(PfsDHGroup);
				}	
				if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, PfsDHGroup) )
				    {
				    CleanupStack::PopAndDestroy(Acquire);
					return EFalse;
				    }
			}
			CleanupStack::Pop(Acquire);						
			Acquire->SetSPI_Out(iChild.iSPI_Out);
			Acquire->SetResponse();
			if ( iChild.iTransport )
				Acquire->SetTransport();				
			CIkev2Acquire::Link(Acquire, GetAcquireQue());			
		    //
		    // Get SPI for new inbound SA
		    //
			GetIpsecSPI(Acquire);									
		}
		else
		{
		    //
			// Ignore received message silently
			//
			DEBUG_LOG1(_L("CREATE_CHILD_SA request received in state %d"), iState);
		}	
	}	

	return ETrue;
}

TBool CIkev2Negotiation::ProcessIkeSARekeyL(CIkev2Payloads* aIkeMsg)
{	
    ASSERT(aIkeMsg);
	//
	// Process IKE SA rekey message (as IKE_CHILD_SA exchange)
    // HDR(A,B), SK { SA, Nonce, KE}	
	//

			
	if ( (iState == KStateIkeSARekeyRequest) || (iState == KStateIkeSARekeyResponse) )
	{
	   //
	   // Received CREATE_CHILD_SA message for IKE SA rekey must
	   // look like the following:  HDR(A,B), SK { SA, Ni, [KEi]}
	   // Allocate a new CIkev2Negotiation object for new IKE SA
	   //
	   //
        CIkev2Negotiation* NewSA  = new (ELeave) CIkev2Negotiation(iIkeV2PlugInSession, iPfKeySocketIf, 
                                                                   iEventLogger, iMessageSendQue, iDebug, 0);
    	CleanupStack::PushL(NewSA);
    	
    	//Do not copy the previous sent request and response:
   	    CIkeV2Message* lastResponse = iHdr.iLastResponse;
   	    iHdr.iLastResponse = NULL;
  	    CIkeV2Message* lastRequest = iHdr.iLastRequest; 
  	    iHdr.iLastRequest = NULL;  	    
		NewSA->iHdr.Copy(iHdr);
        iHdr.iLastResponse = lastResponse; 
        iHdr.iLastRequest = lastRequest;       
		
		
		NewSA->iHdr.iWindowSize   = 1;
		NewSA->iHdr.iEncrAlg = 0;
		NewSA->iHdr.iPRFAlg = 0;
		NewSA->iHdr.iIntegAlg = 0;
		NewSA->iHdr.iDHGroup = 0;
		NewSA->iHdr.iAuthMethod = 0;
		NewSA->iHdr.iCipherKeyLth = 0;
		NewSA->iHdr.iCipherBlkLth = 0;
		NewSA->iHdr.iIntChkSumLth = 0;
				
		if ( iState == KStateIkeSARekeyRequest )
		{
		   NewSA->iHdr.iInitiator = ETrue;
		   NewSA->iHdr.SetSaId(iSAid_Rekey);		   
		   NewSA->iHdr.SetSpiI(iSPI_Rekey);
		   NewSA->iNonce_I    = iNonce_I; // Nonce was created in BuildIkeSaRekeyMsgL() earlier
		   NewSA->iDHKeys     = iDHKeys;  // DH keys object was created in BuildIkeSaRekeyMsgL() earlier		   
		   iNonce_I = NULL;
		   iDHKeys  = NULL;
		}
		else
		{
		   NewSA->iHdr.iInitiator = EFalse;
		   NewSA->iHdr.SetSaId(iIkeV2PlugInSession.GetSAId()); // Get a new SA Id		   
		   NewSA->CreateIkeSPI(NewSA->iHdr.SpiR());
		} 
		//
		// Build a SA payload from current IKE policy and
		// verify received IKE SA request with it
		//
		HBufC8* SaBfr = Ikev2Proposal::FromPolicyToProposaL(NewSA->iHdr, NewSA->iSPI_Rekey, NewSA->iDHGroupGuess, ETrue);
		CleanupStack::PushL(SaBfr);
		HBufC8* proposedSaBuffer = NULL;
		TBool SaOk = Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(NewSA->iHdr, NewSA->iChild, 
                                                                           *SaBfr, *aIkeMsg, proposedSaBuffer);
		CleanupStack::PopAndDestroy();
		if ( iState == KStateIkeSARekeyRequest )
	      	 SaOk &= Ikev2Proposal::GetRekeySpi(aIkeMsg, NewSA->iHdr.SpiR());			
	    else SaOk &= Ikev2Proposal::GetRekeySpi(aIkeMsg, NewSA->iHdr.SpiI());			
		if ( !SaOk )
		{
			DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA Rekey request: %d"), iState);
			SetNotifyCode(NO_PROPOSAL_CHOSEN);
	    	CleanupStack::PopAndDestroy(NewSA);					
			return EFalse;  							
		}
		NewSA->SetProposedSa(proposedSaBuffer);
		proposedSaBuffer = NULL;
		if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
		{
		    DEBUG_LOG1(_L("Nonce data too short in IKE_SA Rekey request %d"), iState);
			SetNotifyCode(INVALID_SYNTAX);				
	    	CleanupStack::PopAndDestroy(NewSA);
			return EFalse;	
		}
		if ( iState == KStateIkeSARekeyRequest )
		{
		    NewSA->iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
		    NewSA->iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(),	aIkeMsg->iNonce->PlDataLen()); 
	    }
	    else
	    {
		    NewSA->iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
		    NewSA->iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(),	aIkeMsg->iNonce->PlDataLen()); 
		}

		if ( !NewSA->ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, NewSA->iHdr.iDHGroup) )
		{
		    //If there was notify code set, copy it to current negotiation before destroying NewSa
		    if(NewSA->GetNotifyCode())
		        {
		        SetNotifyCode(NewSA->GetNotifyCode());
		        }
		    TInt dataLth(0);
		    TUint8* notifyData = NewSA->NotifyData(dataLth);
            if(dataLth == 2)
                {
                StoreNotifyData16(GET16(notifyData));
                }
            else if(dataLth == 4)
                {
                StoreNotifyData32(GET32(notifyData));
                }
	        CleanupStack::PopAndDestroy(NewSA);
		    return EFalse;
		}

		if ( iState == KStateIkeSARekeyResponse )
		{
		    //
		    // Build IKE SA rekey response (CHILD_SA response):
		    // HDR, SAr, Nr, KEr
		    //
		   iDHKeys    = NewSA->iDHKeys; // To calculate own DH value
		   iSPI_Rekey = NewSA->iHdr.SpiR();	
		   SetProposedSa(NewSA->GetProposedSa());	
		   BuildIkeSaRekeyMsgL(EFalse);
		   NewSA->iNonce_R = iNonce_R;  // Nonce is created in BuildIkeSaRekeyMsgL()
		   iNonce_R   = NULL;
		   iDHKeys    = NULL;		    
		}   
		//
		// Generate key material for new IKE SA
		//
		NewSA->GenerateIkeKeysL(&iHdr);
		
		//
		// Create a new IKE SA and swap IPSec SA from rekeyed IKE SA
		// to the new just created SA
		//
       	iIkeV2PlugInSession.CreateIkev2SAL(NewSA->iHdr);
		iIkeV2PlugInSession.InheritIpsecSas(NewSA->iHdr.SaId(), iHdr.SaId());
		
		CleanupStack::PopAndDestroy(NewSA);		
	}

	return ETrue;
}

TBool CIkev2Negotiation::ProcessInfoMsgL(CIkev2Payloads* aIkeMsg)
{
    ASSERT(aIkeMsg);
	//
	// Process IKE message of exchange type INFORMATIONAL
	// HDR, SK {[N,] [D,] [CP,] ...}
	// Only encyrpted and authenitcated are processed.
	//
	if ( !aIkeMsg->Encrypted() )
	{	
	   if ( iState == KStateIdle)
		  iStopped = ETrue;
       return EFalse;
	}
	ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg();  // IKE Message fixed header
	TBool   Response   = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
	TUint32 MsgId      = IkeHdr->GetMessageId();
	
    if ( Response )
	{
	   if ( (iState == KStateIkeInfoRequest) || (iState == KStateIkeDeleteRequest) )
	   {
          //
		  // A response received to a transmitted Informational request
		  //
	      DEBUG_LOG(_L("Response received to a transmitted Informational request"));
	   
		  if ( MsgId == iHdr.ExpectedResponseId() )
		  {
			 iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);			 
			 if ( iState == KStateIkeDeleteRequest )
			 {	 
			    iIkeV2PlugInSession.IkeSaDeleted(KErrNone); //IKE SA deletion going
			 }	
			 else
			 {
				 if ( aIkeMsg->iNotifs->Count() )
				 {
					 ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, INFORMATIONAL);   
				 }
			 }
			 iStopped = ETrue;
			 return EFalse;
		  }
	   }
	   else if ( iState == KStateChildDeleteRequest )
	   {
		  //
		  // A response received to a transmitted Child SA delete request
		  //
		   if ( aIkeMsg->iDeletes->Count() )
		   {
			  ProcessDeletePayloadsL(*aIkeMsg->iDeletes, EFalse);   
		   }
		   
		   //
		   // Update sequence numbers and IKE SA data
		   //
		   iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
		   iStopped = ETrue;		   
		   return EFalse;
	   }	   
	}
	else
	{
	   //
	   // A Informational request received. Process request according
	   // to payload content and send informational response.       
	   // 
	   DEBUG_LOG1(_L("INFORMATIONAL request received in state %d"), iState);
	   if ( MsgId == iHdr.ExpectedRequestId() )
	   {
		  TBool BuildResponse = ETrue;
		  if ( aIkeMsg->iDeletes->Count() )
		  {
             BuildResponse = ProcessDeletePayloadsL(*aIkeMsg->iDeletes, ETrue);   
		  }
		  if ( aIkeMsg->iNotifs->Count() )
		  {
			 BuildResponse = ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, ETrue, INFORMATIONAL);   
		  }
		  if ( BuildResponse )
		  {	  		                                
              CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                          iHdr.SpiR(),
                                                          INFORMATIONAL,
                                                          iHdr.iInitiator,
                                                          ETrue,
                                                          iHdr.ExpectedRequestId(), 
                                                          iDebug);
             CleanupStack::PushL(ikeMsg);
             ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);            
		     CleanupStack::Pop(ikeMsg);
		     SendIkeMsgL(ikeMsg);
             if ( (iState != KStateIkeInfoRequest) && (iState != KStateIkeDeleteRequest) && (iState != KStateIkeDeleteResponse) )
                 {
                 iState = KStateIkeSaCompleted;
                 }
		  }
	   }
	}	

	return ETrue;
}

TBool CIkev2Negotiation::ProcessNotifyPayloadsL(const CArrayFixFlat<TNotifPayloadIkev2*>& aNotifys, 
                                                TBool aRequest, TInt aExchange)
{
	if  ( Ikev2MobIke::ProcessNotifysL(this, aNotifys, aRequest, aExchange) )
	{	
		return EFalse; // Notify payload(s) was processed by MOBIKE protocol 
	}
	
	TInt MsgType;			
	TNotifPayloadIkev2* Payload;  
	TInt Count = aNotifys.Count();
	TInt i     = 0;
	
	while ( i < Count )
	{
	    Payload = aNotifys.At(i);
		MsgType = (TInt)Payload->GetMsgType();
		DEBUG_LOG1(_L("Received Notify payload message type %d"), MsgType);
        // 
		//  Process possible error type Notify messages 
		//
		if (aExchange == IKE_SA_INIT)
		    {
		    switch ( MsgType )
    		    {	
    			case INVALID_SYNTAX:
    			    //Fall through
    			case NO_PROPOSAL_CHOSEN:
    			    return EFalse;
    		    case INVALID_KE_PAYLOAD:
    		        ProcessInvalidKePayloadNotifyL();
    		        return ETrue;
    		    case COOKIE:
    		    	return ProcessCookieL(aNotifys, aRequest);
    			default:
    				break;	
    		    }
		    }
		else
		    {
		    switch ( MsgType )
    		    {	
    			case UNSUPPORTED_CRITICAL_PAYLOAD:
    			case INVALID_SYNTAX:
    			case INVALID_MESSAGE_ID:
    			case AUTHENTICATION_FAILED:
    			case INTERNAL_ADDRESS_FAILURE:
    			case FAILED_CP_REQUIRED:
    				//
    				// When some of these error types received IKE SA shall
    				// corresponding IKE SA shall be deleted
    				//
    				iDeleteIkeSA = ETrue;
    				break;

    			case NO_PROPOSAL_CHOSEN:
    			case SINGLE_PAIR_REQUIRED:
    			case NO_ADDITIONAL_SAS:				
    			case TS_UNACCEPTABLE:
    			case INVALID_SELECTORS:
    				//
    				// When some of these error types received within
    				// IKE_AUTH or CREATE_CHILD_SA exchange (in response)
    				// Child SA request is interpreted to be failed 
    				//
    				if ( ((aExchange == IKE_AUTH) || (aExchange == CREATE_CHILD_SA) ) && !aRequest )
    				   iChildSARejected = ETrue;
    				break;
    				
    			default:
    				break;	
    		    }
		    }
	
	    i++;   
	}	
			
	return ETrue;
}

TBool CIkev2Negotiation::ProcessCookieL(const CArrayFixFlat<TNotifPayloadIkev2*>& aNotifys, TBool aRequest)
{

	//
	// Special handling for COOKIE Notify payload.
	// The following actions are taken:
	// - Assure that the first Notify payload in array is cookie
	// - When the COOKIE is received in response (aRequest = EFalse)
	//   - Retransmit IKE_SA_INIT request again in format:
	//     HDR(A,0), N(COOKIE), SAi1, KEi, Ni, [Nat Notifies]
	// - When the COOKIE is received in request (aRequest = ETrue)
	//   - Assure that COOKIE returned by the initiator is the we
	//     have earlier transmitted.  
	//			   		
	if ( aNotifys.Count() )
	{
		const TNotifPayloadIkev2* NotifyPayload = aNotifys.At(0);
		if ( NotifyPayload->GetMsgType() == COOKIE && !aRequest)
		{
        //
        // Local end COOKIE usage has not been implemented yet
        //

            //
            // Init a new IKE message buffer and copy received COOKIE
            // Notify to the first payload. Concatenate then all
            // payloads from original IKE_SA_INIT request to this new
            // IKE message (and set next payload field in Notify)
            //
            DEBUG_LOG1(_L("Cookie received, IKE_SA_INIT repeated: %d"), iState);
            if ( iCookieReturned )
            {	
               //
               // One cookie already returned. Avoid cookie-loop
               // by stopping ongoing IKE_SA_INIT exchange  
               //
               DEBUG_LOG(_L("Cookie already returned once, IKE_SA_INIT exchange stopped"));				   
               return EFalse;
            }		
            
            CIkeV2Message* originalIkeSaInitRequest = iHdr.iLastRequest;            
            
            const TPtrC8 cookieData(NotifyPayload->NotifData(), NotifyPayload->NotifDataLength());
            
            // Use protocol id sent by gateway. RFC says id should be zero, but some GWs
            // work against the spec.
            TUint8 protocolId = NotifyPayload->GetProtocolId();
            
            originalIkeSaInitRequest->PrependCookieNotifyPayloadL(protocolId, cookieData);
            iHdr.iLastRequest = NULL; //claims the ownership of the message    
            
            SendIkeMsgL(originalIkeSaInitRequest);
            iTimer->Cancel();    // Reset transmit retry timer                      
            iTimer->IssueRequest(iSendAttempt);     // Start retry timer                        
            iCookieReturned = ETrue;
            return ETrue;
        }
	}   
	DEBUG_LOG1(_L("Cookie required, NO COOKIE Notify found: %d"), iState);
	
	return EFalse;
}



TBool CIkev2Negotiation::ProcessDeletePayloadsL(const CArrayFixFlat<TDeletePlIkev2*>& aDeletes, 
                                                TBool aRequest)
{
	//
	// Process delete payloads received.
	//
	CDesC8ArrayFlat* SpiList = NULL;
	TUint8  Protocol = IKEV2_PROT_NONE;

	for (TInt i = 0; i < aDeletes.Count(); ++i)
	{
		const TDeletePlIkev2* Payload  = aDeletes.At(i);
		Protocol = Payload->GetProtocolId();
		switch ( Protocol )
		{
			case IKEV2_PROTOCOL:
				//
				// Deletion of current existing IKE SA. All IPSEC SA:s
				// negotiated within IKE SA are deleted implicitly 
				//
				iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
				delete SpiList;
				SpiList = NULL;
				i = aDeletes.Count();   // Stop outer while loop
				iState = KStateIkeDeleteResponse;  // Set next state here
				break;

			case IKEV2_IPSEC_AH:
			case IKEV2_IPSEC_ESP:
				if ( Payload->GetSPISize() == 4 )
				{
				   //
				   // Delete Ipsec SPI:s from IKE SA (and IPSEC SADB)
				   // If Delete payload received within Info request
				   // build inbound SPI list of corresponding inbound
				   // SA:s
				   //
				   TUint SpiCount = (TInt)Payload->GetNbrOfSpis();
				   if ( TPayloadIkev2::Cast(Payload)->GetLength() ==
					  ( TDeletePlIkev2::Size() + 4*SpiCount) )
				   {
                      const TUint8* Spis = Payload->SPIs();
					  if ( aRequest && !SpiList )
					      {
					      SpiList = new (ELeave) CDesC8ArrayFlat(2);
					      CleanupStack::PushL(SpiList);
					      }
					  while ( SpiCount )
					  {	                            
                          TPtrC8 Spi(Spis, 4);
						  if ( SpiList )
						  {	                               
                             const TIkeV2IpsecSAData* IpsecSa = 
                                 iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), Spi, EFalse);
							 if ( IpsecSa && IpsecSa->iSPI_In.Length() > 0 )
							 {                                
                                SpiList->AppendL(IpsecSa->iSPI_In);
							 }	
						  }	 
						  iIkeV2PlugInSession.DeleteIpsecSAData(iHdr.SaId(), Spi, EFalse);
						  Spis += 4;
						  SpiCount--;
					  }	  
				   }
				}   
				break;
			default:
			    break;				
		}
	}
		
	if ( SpiList )
	{
	    //
	    // Build Informational exchange response with a
	    // Delete payload containing SPI:s of corresponding
	    // inbound SA:s.  
	    //        
        CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                    iHdr.SpiR(),
                                                    INFORMATIONAL,
                                                    iHdr.iInitiator,
                                                    ETrue,
                                                    iHdr.ExpectedRequestId(), iDebug);
        CleanupStack::PushL(ikeMsg);
        ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);          
        ikeMsg->AppendDeletePayloadL(Protocol, *SpiList);
        CleanupStack::Pop(ikeMsg);
        SendIkeMsgL(ikeMsg);
    	CleanupStack::PopAndDestroy(SpiList); 
		iState = KStateIkeSaCompleted;		
		aRequest = EFalse;
	}
		
	return aRequest;
}

void CIkev2Negotiation::ProcessInvalidKePayloadNotifyL()
{
    // Build and send new IKE_SA_INIT message (request) with another DH group #
    // HDR, SAi1, KEi, Ni, N[NAT_SRC], N[NAT_DST]
    //
    iDHGroupGuess++;
    delete iDHKeys;   // Delete old DH object 
    iDHKeys = NULL;
    iHdr.iDHGroup = 0;
    
    TUint32 lastRequestMsgId = 0;
    if(iHdr.iLastRequest != NULL)
        {
        lastRequestMsgId = iHdr.iLastRequest->MessageId();
        }    
    
    CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
                                                iHdr.SpiR(),
                                                IKE_SA_INIT,
                                                iHdr.iInitiator,
                                                EFalse,
                                                lastRequestMsgId,
                                                iDebug); 
    CleanupStack::PushL(ikeMsg);

    HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
    CleanupStack::PushL(saBfr);
    ikeMsg->AppendSaPayloadL(*saBfr);
    CleanupStack::Pop(saBfr);
    SetProposedSa(saBfr);

    AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
    ikeMsg->AppendNoncePayloadL(*iNonce_I);
    if ( !iHdr.iIkeData->iUseNatProbing )
        {
        delete iNatNotify;
        iNatNotify = NULL;
        
        TInetAddr LocalIp;  
        if ( iHdr.iIkeData->iUseMobIke )
            LocalIp.SetAddress(KInetAddrNone);
        else LocalIp = iHdr.iLocalAddr;        
        iNatNotify = CIkev2NatT::NewL(
            LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());
                       
        ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP, 
                                     iNatNotify->SourceNofify());
        ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP, 
                                     iNatNotify->DestinNofify());         
        }   
          
    CleanupStack::Pop(ikeMsg);
    SendIkeMsgL(ikeMsg);
    
    iState = KStateIkeSaInitRequest;
}



void CIkev2Negotiation::GetNonceDataL(TBool aInitiator)
{
	//
	//  Get random data for local nonce
	//
	HBufC8* Nonce;
	if ( aInitiator )
	{
		Nonce = HBufC8::NewL(IKEV2_DEF_NONCE_SIZE);
		delete iNonce_I;		
		iNonce_I = Nonce;
	}
	else
	{
		Nonce = HBufC8::NewL(IKEV2_DEF_NONCE_SIZE);
		delete iNonce_R;		
		iNonce_R = Nonce;
	}
    TPtr8 RandOctet(Nonce->Des());	
    RandOctet.SetLength(IKEV2_DEF_NONCE_SIZE);
    TRandom::RandomL(RandOctet);
}

void CIkev2Negotiation::GetOwnIdentityL(TBool aEapIdResponse)
{
    if ( iLocalIdentity )
    {
        return;   // We already have own identity data
    }      

    //
    // The own IKE identity data is built with the following system:
    // -- If Own Certificate exist take try to get identity data from it
    // If no Certificate or identity cannot be get from certificate
    // -- If EAP used use identity speficied by the EAP plugin
    // -- If EAP not used, get own identity data information from current IKE policy
    // If no identity information found use local IP address as
    // identity.  Own IKE Identity information is stored in iLocalIdentity
    // buffer (linked into negotiation object) in format of Identity
    // payload (TIDPayloadIkev2)
    //
  

    HBufC8* IdBfr = NULL;
    TUint8 IdType = ID_NOT_DEFINED;  
    
    
    //Try to get the identity from the user certificate
    if ( iPkiService && iPkiService->UserCertificateData().Length() > 0  )
    {
       IdType = iHdr.iIkeData->iIdType;
       IdBfr  = IkePkiUtils::GetIdentityFromCertL(IdType, iPkiService->UserCertificateData());
       if ( IdBfr != NULL)
       {
           if (IdType == ID_NOT_DEFINED)
           {
               IdType = ID_DER_ASN1_DN;
           }
       }   
       else
       {
           //We didn't get the ID data from the user certificate.
           //Make sure that the type is set to not defined.
           IdType = ID_NOT_DEFINED;
       }
    }
    
    //If we didn't get the identity from the user certificate,
    //try to get it from the EAP plugin. 
    if ( IdType == ID_NOT_DEFINED && iEapPlugin )
    {
        __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
        //
        // Try to get Own identity data from EAP Plug-in
        //
        IdBfr = iEapPlugin->Identity();
        if ( IdBfr != NULL && IdBfr->Length() )
        {
            //
            // Identity data provided by EAP plug-in. Define IKE Id type
            // value according to Identity data content. If Id data
            // contains realm (format username@realm) Id type
            // ID_RFC822_ADDR  is used. If no realm in ID use type ID_KEY_ID
            //
            TInt offset = IdBfr->Find(_L8("@"));
            IdType = ( offset == KErrNotFound ) ? ID_KEY_ID : ID_RFC822_ADDR; 
        }   
        else
        {
            delete IdBfr;
            IdBfr = NULL;
            if ( !aEapIdResponse )
                return;   // Identity not yet available continue waiting             
        }   
    }
    
    //If we don't have identity so far, try to get it from the
    //policy:
    if ( IdType == ID_NOT_DEFINED && 
         iHdr.iIkeData->iIdType != ID_NOT_DEFINED &&
         iHdr.iIkeData->iFQDN.Length() > 0)
    {   
        __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
        IdBfr = HBufC8::NewL(iHdr.iIkeData->iFQDN.Length());
        IdBfr->Des().Copy(iHdr.iIkeData->iFQDN);
        IdType = iHdr.iIkeData->iIdType;            
    }
    
    
    //If we have not been able to get the identity so far, we are using the default
    //identity, which is our own IP address.
    if ( IdType == ID_NOT_DEFINED)
    {
        __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
        if ( (iHdr.iLocalAddr.Family()== KAfInet) || iHdr.iLocalAddr.IsV4Mapped() )
        {
            TUint32 num = ByteOrder::Swap32(iHdr.iLocalAddr.Address());//Put in network order
            IdBfr = HBufC8::NewL(sizeof(num));            
            IdBfr->Des().Append(reinterpret_cast<TUint8*>(&num), sizeof(num));
            IdType = ID_IPV4_ADDR;    
        }
        else   
        {
            IdBfr = HBufC8::NewL(16);  
            const TUint8* pnum = &iHdr.iLocalAddr.Ip6Address().u.iAddr8[0];  //Address in a bytestream
            IdBfr->Des().Append(pnum, 16);
            IdType = ID_IPV6_ADDR;                      
        }          
    }
    
    __ASSERT_DEBUG((IdType != ID_NOT_DEFINED && IdBfr != NULL), User::Invariant());
    CleanupStack::PushL(IdBfr);
    iLocalIdentity = CIkeV2Identity::NewL(IdType, *IdBfr);
    CleanupStack::PopAndDestroy(IdBfr); 
}


void CIkev2Negotiation::GenerateIkeKeysL(TIkev2SAData* aRekeydSaData)
{
	//
	//  Generate IKE keying material. Start by calculating
	//  Diffie-Hellman secret.
	//
	User::LeaveIfNull(iDHPublicPeer);		
	if ( !iDHKeys )
	{	
		iDHKeys = CDHKeys::CreateDHKeyL(iHdr.iDHGroup);
		iDHKeys->XValueL(); // Calculate own DH public value	   
	}
	HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
	CleanupStack::PushL(g_ir);
	delete iDHKeys;
	iDHKeys = NULL;

	HBufC8* Ni_Nr;
	HBufC8* SKEYSEED;
	TUint16 prfAlg(0);
	
	if ( aRekeydSaData )
	{
	    //
	    //  Calculate IKE keying material seed SKEYDSEED = prf(SK_d(old), [g^ir (new)] | Ni | Nr) 
        //
		Ni_Nr = HBufC8::NewL(g_ir->Length() + iNonce_I->Length() + iNonce_R->Length());
		CleanupStack::PushL(Ni_Nr);		
		Ni_Nr->Des().Copy(g_ir->Des());		
		Ni_Nr->Des().Append(iNonce_I->Des());
		Ni_Nr->Des().Append(iNonce_R->Des());	

		prfAlg = aRekeydSaData->iPRFAlg;
		SKEYSEED = IkeCrypto::PrfhmacL(*Ni_Nr, aRekeydSaData->iSK_d, prfAlg);
		CleanupStack::PushL(SKEYSEED);
	}
	else
	{	
	    //
	    //  Calculate IKE keying material seed SKEYDSEED = prf(Ni | Nr, g^ir)
	    //
		Ni_Nr = HBufC8::NewL(iNonce_I->Length() + iNonce_R->Length());
		CleanupStack::PushL(Ni_Nr);
		Ni_Nr->Des().Copy(iNonce_I->Des());
		Ni_Nr->Des().Append(iNonce_R->Des());	
		
		prfAlg = iHdr.iPRFAlg;
		SKEYSEED = IkeCrypto::PrfhmacL(*g_ir, *Ni_Nr, prfAlg);
		CleanupStack::PushL(SKEYSEED);		
	}  

	g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
	
	iHdr.GenerateIkeKeyDerivatesL(SKEYSEED->Des(),prfAlg, *iNonce_I, *iNonce_R);	
	SKEYSEED->Des().FillZ(); // Wipe out SKEYSEED value from buffer	
	
	CleanupStack::PopAndDestroy(3);  //g_ir , Ni_Nr and SKEYSEED
}


void CIkev2Negotiation::SaveSignedDataL(TBool aLocal,  const TDesC8& aIkeMsg)
{ 
	//
	//  Allocate buffer for signed octets needed for IKE SA
	//  authentication with AUTH payload.
	//  The signed octet contains the following data:
	//  Initiator:
	//  - IKE_SA_INIT message content (message number 1)
	//    concatenated with responder nonce data and value
	//    prf(SK_pi,IDi") where IDi" is initiator ID data without fixed
	//    payload header
	//
	//  Responder:
	//  - IKE_SA_INIT message content (message number 2)
	//    concatenated with initiator nonce data and value
	//    prf(SK_pr,IDr") where IDr" is responder ID data without fixed
	//    payload header
	//
	TInt SignedLth = aIkeMsg.Length(); // Initial value
	HBufC8*  Nonce;
	HBufC8** SignedBfrPtr;	
	if ( aLocal )
	{	
	   if ( iHdr.iInitiator )
	   {
		  SignedBfrPtr = &iAuthMsgInit;
	 	  Nonce = iNonce_R;
	   }	  
	   else {
		  SignedBfrPtr = &iAuthMsgResp;		   
		  Nonce = iNonce_I;
	   }		  
	}
	else
	{
	   if ( iHdr.iInitiator )
	   {
		  SignedBfrPtr = &iAuthMsgResp;		   
		  Nonce = iNonce_I;
	   }		
	   else
	   {
		  SignedBfrPtr = &iAuthMsgInit;		   
		  Nonce = iNonce_R;
	   }	  
	}

	SignedLth += Nonce->Length() + IkeCrypto::AlgorithmInfo(IKEV2_PRF, iHdr.iPRFAlg);
	HBufC8* Signed = HBufC8::NewL(SignedLth);
	Signed->Des().Copy(aIkeMsg);
	Signed->Des().Append(Nonce->Des());
	
	if ( aLocal && iLocalIdentity )
	{
	   //
	   // Add value prf(SK_px,IDx") into local signed data buffer end
	   //
	   AddIdToSignedDataL(ETrue, Signed, iLocalIdentity->PayloadData());
	}
	
	delete *SignedBfrPtr;
	*SignedBfrPtr = Signed;
}


void CIkev2Negotiation::AddIdToSignedDataL(TBool aLocal, HBufC8* aSigned, const TDesC8& aIdData)
{
    ASSERT(aSigned);
    //
    // Add value prf(SK_px,IDx") into signed data buffer end
    //

	HBufC8* signedIdData = NULL;;
	if ( iHdr.iInitiator )
	{
		if ( aLocal )
		    {
		    signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pi, iHdr.iPRFAlg);
		    }
		else 
		    {
		    signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pr, iHdr.iPRFAlg);
		    }
	}		
	else
	{
		if ( aLocal )
		    {
		    signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pr, iHdr.iPRFAlg);
		    }
		else 
		    {
		    signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pi, iHdr.iPRFAlg);
		    }
	}
	aSigned->Des().Append(*signedIdData);
	delete signedIdData;	
}	

HBufC8* CIkev2Negotiation::SignAuthDataL(const TDesC8& aAuthData, TUint8 aAuthMethod)
{
	//
	//  Sign aMsgData according to authentication method parameter
	//
	HBufC8* signedAuthData = NULL;
	
	if ( iPkiService && 
	     iPkiService->TrustedCaName().Length() > 0 &&
	     iPkiService->UserCertificateData().Length() > 0 )
	{		
	   //
	   // Message data <msg octets> is signed using private key
	   //		
		TPtrC8 TrustedCa(iPkiService->TrustedCaName());
		signedAuthData = HBufC8::NewLC(320); // reserved for sign (aware for 2048 bits signatures)
		TPtr8 signedAuthDataPtr(signedAuthData->Des()); 
		
		iPkiService->Ikev2SignatureL(TrustedCa, iHdr.iIkeData->iOwnCert, aAuthData, signedAuthDataPtr, aAuthMethod);
		CleanupStack::Pop(signedAuthData);
	}
	else		
	{
	   //
	   // Message data is signed using negotiated PRF function as
	   // follows:
	   // AUTH =
	   // prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>)
	   // If EAP method that creates a shared key as a side effect of
	   // authentication used, this shared key is used as Shared Secret
	   // Otherwise preshared key configured into policy is used as
	   // Shared secret.
	   //
	   if ( !iPresharedKey )
		  iPresharedKey = Ikev2Proposal::GetPSKFromPolicyL(iHdr.iIkeData);
	   //
	   // Calculate KEY = prf(Shared Secret,"Key Pad for IKEv2")
	   //   			
	   HBufC8* PskKey = IkeCrypto::PrfhmacL(KIkev2PSKData, *iPresharedKey, iHdr.iPRFAlg);
	   CleanupStack::PushL(PskKey);
	   //
	   // Calculate prf(KEY, <msg octets>)
	   //       	   
	   signedAuthData = IkeCrypto::PrfhmacL(aAuthData, *PskKey, iHdr.iPRFAlg);
 	   CleanupStack::PopAndDestroy(PskKey);
	}
	return signedAuthData;		
}

TBool CIkev2Negotiation::AddIdAndAuthenticatePeerL(CIkev2Payloads* aIkeMsg)
{
    ASSERT(aIkeMsg);
	//
	// Verify that authentication payload of peer is correct
	// To do this the signed data octets of peer must be filled with
	// value: prf(SK_px,IDx")
	// So the peer ID payload must be verified first.
	//
	HBufC8* Signed;
	TIDPayloadIkev2* Id;
	if ( iHdr.iInitiator )
	{
	   Signed = iAuthMsgResp;	
	   Id = (TIDPayloadIkev2*)aIkeMsg->iIdR;
	}   
	else
	{
	   Signed = iAuthMsgInit;			
	   Id = (TIDPayloadIkev2*)aIkeMsg->iIdI;
	}	
    if ( !Signed || !Id )
	   return EFalse;	

	if ( !iPeerIdInSignedData )
	{	
	   TUint16 IdLth = TPayloadIkev2::Cast(Id)->GetLength();
	   if ( IdLth < TIDPayloadIkev2::Size() ) 
	   {
		  DEBUG_LOG1(_L("Peer ID payload too short; Length %d"), IdLth);		  
		  return EFalse;
	   }
       //
	   // Add value prf(SK_px,IDx") into peer signed data buffer end
	   //
	   TPayloadIkev2* idPayload = TPayloadIkev2::Cast(Id);
	   TPtrC8 idPtr(idPayload->PayloadData(), (idPayload->GetLength() - TPayloadIkev2::Size()));
	   AddIdToSignedDataL(EFalse, Signed, idPtr);
	   iPeerIdInSignedData = ETrue;
	}
	
	return AuthenticatePeerL(aIkeMsg->iAuth); 

}

TBool CIkev2Negotiation::AuthenticatePeerL(TAuthPayloadIkev2* aAuth)
{
	//
	// Authenticate peer tication payload of peer is correct
	// To do this the signed data octets of peer must be filled with
	// value: prf(SK_px,IDx")
	// So the peer ID payload must be verified first.
	//
	HBufC8* Signed;	
	if ( iHdr.iInitiator )
		 Signed = iAuthMsgResp;	
	else Signed = iAuthMsgInit;
	
	if ( !Signed || !aAuth )
	   return EFalse;

	TUint16 AuthLth = TPayloadIkev2::Cast(aAuth)->GetLength();	
	if ( AuthLth < TAuthPayloadIkev2::Size() ) 
	{					
		DEBUG_LOG1(_L("Peer Auth payload too short; Length %d"), AuthLth);
		return EFalse;
	}
	AuthLth = (TUint16)(AuthLth - TAuthPayloadIkev2::Size());
	TBool Status = EFalse;
	
	if ( aAuth->GetAuthMethod() == PRESHARED_KEY )
	{
       DEBUG_LOG(_L("Authenticating SGW with PSK"));
	   //
	   // Pre shared key authentication is not accepted for peer if we
	   // have requested an certificate from peer (PKI authentication
	   // required) 
	   // 
		if ( !iPkiAuthRequired )
		{
			HBufC8* AuthRef = SignAuthDataL(*Signed, PRESHARED_KEY);
			CleanupStack::PushL(AuthRef);			
			if (  AuthRef->Length() == AuthLth )
			{
				Status = (Mem::Compare(AuthRef->Ptr(), AuthRef->Length(), aAuth->AuthData(), AuthLth ) == 0);		   
			}
			CleanupStack::PopAndDestroy();   // AuthRef			
		}	  
	}
	else
	{
	   //
	   // Authentication based on PKI (private key signature)
	   // 
		if ( iPkiService && iPeerCert )
		{
		    DEBUG_LOG(_L("Authenticating SGW with certs"));
		    
			TPtrC8 AuthData(Signed->Des());
			TPtrC8 Signature(aAuth->AuthData(), AuthLth);	   						
			Status = IkePkiUtils::VerifyIkev2SignatureL(Signature, AuthData, *iPeerCert);
			iPkiAuthRequired = EFalse;
		}			  
	}
	if (Status)
	    {
	    DEBUG_LOG(_L("SGW authentication success"));
	    }
	else
	    {
	    DEBUG_LOG(_L("SGW authentication failed"));
	    }
	
	return Status; 
}


TBool CIkev2Negotiation::VerifyPeerCertificateL(CArrayFixFlat<TCertPayloadIkev2*>* aCerts, TIDPayloadIkev2* aId )
{
	TBool Status        = EFalse;
	
	const CIkeCaList& trustedCaList = iPkiService->CaList();
	CX509Certificate* PeerCert = IkePkiUtils::VerifyCertificateL(*aCerts, trustedCaList);
	
	if ( PeerCert && aId )
	{
		CleanupStack::PushL(PeerCert);					 		
		TPtrC8 IdData(aId->IdData(), (TPayloadIkev2::Cast(aId)->GetLength() - TIDPayloadIkev2::Size()));	
		Status = IkePkiUtils::CertifyIdentityL(PeerCert, IdData, (TInt)aId->GetIdType());
		if ( Status )
		{
		    DEBUG_LOG(_L("IDr matches the SGW certificate"));
		    if (iRemoteIdentity && !iHdr.iIkeData->iSkipRemoteIdCheck ) //iRemoteIdentity if the REMOTE_IF from the policy
		        {
		        //TIDPayloadIkev2* peerIdentityPayload = TIDPayloadIkev2::Cast(iRemoteIdentity->Ptr());  
		        if (iRemoteIdentity->IdType() == aId->GetIdType())
		            {
		            TPtrC8 idPtr(aId->IdData(),
		                         TPayloadIkev2::Cast(aId)->GetLength() - TIDPayloadIkev2::Size());
		            TPtrC8 peerIdentityPtr(iRemoteIdentity->Identity());
		            
		            //Check if we accept partial remote id
		            if (iHdr.iIkeData->iAcceptPartialRemoteId && 
		                iRemoteIdentity->IdType() == ID_FQDN &&
		                peerIdentityPtr.Length() > idPtr.Length())
		                {
		                DEBUG_LOG(_L("Using PARTIAL_REMOTE_ID_CHECK"));
		                peerIdentityPtr.Set(peerIdentityPtr.Right(idPtr.Length()));
		                }
		            if (idPtr.Compare(peerIdentityPtr) == 0)
		                {
		                DEBUG_LOG(_L("IDr matches the REMOTE_ID"));
		                Status = ETrue;
		                }
		            else
		                {
		                DEBUG_LOG(_L("IDr does not match the REMOTE_ID"));
		                Status = EFalse;
		                }
		            }		        
		        else
		            {
		            DEBUG_LOG(_L("IDr payload ID does not match REMOTE_ID_TYPE"));
		            Status = EFalse;
		            }
		        }
		}	
	    else 
	    {
	        DEBUG_LOG(_L("IDr does not match the SGW certificate"));
	    }
		
		if ( Status )
		{
		   CleanupStack::Pop(PeerCert);		
		   delete iPeerCert;
		   iPeerCert = PeerCert;			
		}
		else CleanupStack::PopAndDestroy(PeerCert);
	}
	return Status;
}


TBool CIkev2Negotiation::ProcessKeyExchangeL(TKEPayloadIkev2* aKePayload, TUint16 aGroup)
{
	//
	//  Process key exchange payload received from peer
	//
	if ( !aKePayload )
	{
		DEBUG_LOG1(_L("Key Exchange payload not present, required Group %d"), aGroup);
		SetNotifyCode(INVALID_KE_PAYLOAD);
		StoreNotifyData16(aGroup);
		return EFalse;
	}	 
	TUint16 PlLth = TPayloadIkev2::Cast(aKePayload)->GetLength();
	if (( PlLth <= TKEPayloadIkev2::Size() ) || ( aKePayload->GetDHGroup() != aGroup ))
	{
		DEBUG_LOG1(_L("Peer Key Exchange DH group does not match, Group %d"), aKePayload->GetDHGroup());
		SetNotifyCode(INVALID_KE_PAYLOAD);
		StoreNotifyData16(aGroup);
	    return EFalse;
	}	
	if ( !iDHKeys )
		iDHKeys = CDHKeys::CreateDHKeyL(aGroup);
	PlLth = (TUint16)(PlLth - TKEPayloadIkev2::Size());
	if ( PlLth != iDHKeys->ModulusLength() )
	{
		DEBUG_LOG1(_L("Peer DH public value length does not match group, Length %d"), PlLth);
		SetNotifyCode(INVALID_KE_PAYLOAD);
        StoreNotifyData16(aGroup);
		return EFalse;
	}	
	delete iDHPublicPeer;
	iDHPublicPeer = NULL;
	iDHPublicPeer = HBufC8::NewL(PlLth);
	iDHPublicPeer->Des().Copy(aKePayload->DHPublic(), PlLth);

	return ETrue;
}

void CIkev2Negotiation::AppendKEPayloadL(CIkeV2Message& aIkeMsg, TUint16 aDHGroup)
{    
	if ( !iDHKeys )
       iDHKeys = CDHKeys::CreateDHKeyL(aDHGroup);

	iDHKeys->XValueL(); // Calculate own DH public value
	HBufC8* dHPublic = iDHKeys->GetPubKey();    //save the public key in a buffer to have easy access
	User::LeaveIfNull(dHPublic);
	CleanupStack::PushL(dHPublic);
	
	TInt modulusLength = iDHKeys->ModulusLength();	
	HBufC8* kePayloadData = HBufC8::NewLC(modulusLength);
	TPtr8 kePayloadDataPtr(kePayloadData->Des());
	
	__ASSERT_DEBUG(modulusLength == dHPublic->Length(), User::Invariant());	

	kePayloadDataPtr.Append(*dHPublic);	
	kePayloadDataPtr.SetLength(modulusLength); //adds zero padding, if needed

	aIkeMsg.AppendKePayloadL(aDHGroup, *kePayloadData);
	
	CleanupStack::PopAndDestroy(kePayloadData);  
	CleanupStack::PopAndDestroy(dHPublic);
}

     

TBool CIkev2Negotiation::CheckPayloadsOrder(CIkev2Payloads* aIkeMsg, TUint8 aExchange, TBool aResponse)
    {
	switch ( aExchange )
	    {
		case IKE_SA_INIT:
		    if(!aIkeMsg->iSa || !aIkeMsg->iKe || !aIkeMsg->iNonce) return EFalse;
            if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_KE) return EFalse;
            if(aIkeMsg->iKe->GetNextPayload() != IKEV2_PAYLOAD_NONCE) return EFalse;
			break;
			
		case IKE_AUTH:
		    if(!iEapPlugin)
		        {
		        if(!aIkeMsg->iEncr || !aIkeMsg->iAuth || !aIkeMsg->iSa || !aIkeMsg->iTsI || !aIkeMsg->iTsR)
		            {
           		    DEBUG_LOG(_L("1"));
		            return EFalse;
		            }
                if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_TS_I)
                    {
           		    DEBUG_LOG(_L("2"));                    
                    return EFalse;
                    }
                if(aIkeMsg->iTsI->GetNextPayload() != IKEV2_PAYLOAD_TS_R)
                    {
           		    DEBUG_LOG(_L("3"));      
                    return EFalse;
                    }

		        if(aResponse)
		            {
		            if(!aIkeMsg->iIdR)
		                {
           		        DEBUG_LOG(_L("4"));		                
		                return EFalse;
		                }
                    if(!aIkeMsg->iCerts || aIkeMsg->iCerts->Count() == 0)
                        {    
                        if(aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
                            {
                   		    DEBUG_LOG(_L("5"));                    
                            return EFalse;
                            }
                        }
		            else
		                {
                        if(aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_CERT)
                            {
                   		    DEBUG_LOG(_L("6"));                    
                            return EFalse;
                            }
                        TInt c = aIkeMsg->iCerts->Count();
                        if(aIkeMsg->iCerts->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
                            {
                   		    DEBUG_LOG(_L("7"));
                            return EFalse;
                            }
                        }
		            }
		        else
		            {
		            if(!aIkeMsg->iIdI)
		                {
               		    DEBUG_LOG(_L("8"));	                
		                return EFalse;
		                }
		            if(aIkeMsg->iCerts && aIkeMsg->iCerts->Count() != 0)
		                {
		                if(aIkeMsg->iIdI->GetNextPayload() != IKEV2_PAYLOAD_CERT)
		                    {
                   		    DEBUG_LOG(_L("9"));		                    
		                    return EFalse;
		                    }
		                }
                    if(aIkeMsg->iCertReqs && aIkeMsg->iCertReqs->Count() != 0)
                        {
                        TInt c = aIkeMsg->iCertReqs->Count();
                        if(aIkeMsg->iIdR && aIkeMsg->iCertReqs->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_ID_R)
                            {
                   		    DEBUG_LOG(_L("10"));                            
                            return EFalse;
                            }
                        if(!aIkeMsg->iIdR && aIkeMsg->iCertReqs->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
                            {
                   		    DEBUG_LOG(_L("11"));                            
                            return EFalse;
                            }
                        }
                    if(aIkeMsg->iIdR && aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
                        {
               		    DEBUG_LOG(_L("12"));                        
                        return EFalse;
                        }
		            }
		        }
			break;
			
		case CREATE_CHILD_SA:
            if(!aIkeMsg->iEncr || !aIkeMsg->iSa || !aIkeMsg->iNonce) return EFalse;
            if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_NONCE) return EFalse;
            if(aIkeMsg->iKe && aIkeMsg->iNonce->GetNextPayload() != IKEV2_PAYLOAD_KE) return EFalse;
            if(aIkeMsg->iTsI)
                {
                if(aIkeMsg->iKe && aIkeMsg->iKe->GetNextPayload() != IKEV2_PAYLOAD_TS_I) return EFalse;
                if(!aIkeMsg->iKe && aIkeMsg->iNonce->GetNextPayload() != IKEV2_PAYLOAD_TS_I) return EFalse;
                if(aIkeMsg->iTsI->GetNextPayload() != IKEV2_PAYLOAD_TS_R) return EFalse;
                }
			break;

		default:
			break;
	    }
    DEBUG_LOG(_L("13"));
	return ETrue;
    }


TBool CIkev2Negotiation::Stopped() 
    { 
    return iStopped; 
    }


TBool CIkev2Negotiation::ImplicitChildSa() 
    { 
    return (iState < KStateIkeSaCompleted); 
    }


HBufC8* CIkev2Negotiation::PeekProposedSa() 
    { 
    return iProposedSA; 
    }


HBufC8* CIkev2Negotiation::GetProposedSa()  
    { 
    HBufC8* Sa = iProposedSA; 
    iProposedSA = NULL; 
    return Sa; 
    }


void CIkev2Negotiation::SetProposedSa(HBufC8* aSaPl) 
    { 
    delete iProposedSA; 
    iProposedSA = aSaPl; 
    }


CIkev2Acquire** CIkev2Negotiation::GetAcquireQue() 
    { 
    return &iAcquireFirst; 
    }


CIkev2Expire** CIkev2Negotiation::GetExpireQue() 
    { 
    return &iExpireFirst; 
    }


TBool CIkev2Negotiation::RequestsPending() 
    { 
    return (iAcquireFirst || iExpireFirst); 
    }


void CIkev2Negotiation::SetNotifyCode(TInt aMsgType) 
    { 
    if (iNotifyCode == 0) 
        iNotifyCode = aMsgType; 
    }


TInt CIkev2Negotiation::GetNotifyCode() 
    { 
    return iNotifyCode; 
    }


void CIkev2Negotiation::StoreNotifyData32(TUint32 aData) 
    {
    PUT32(iNotifyData, aData); 
    iNotifyDataLth = 4;
    }


void CIkev2Negotiation::StoreNotifyData16(TUint16 aData) 
    {
    PUT16(iNotifyData, aData); 
    iNotifyDataLth = 2;
    }               


TUint8* CIkev2Negotiation::NotifyData(TInt& aDataLth)
    {
    aDataLth = iNotifyDataLth;
    if ( iNotifyDataLth )
        return iNotifyData;
    else return NULL;
    }


TInetAddr CIkev2Negotiation::GetLocalAddr() const
    {
    if ( iHdr.iVirtualAddr.IsUnspecified() )
        {
        return iHdr.iLocalAddr;
        }
    else
        {
         return iHdr.iVirtualAddr;
        }
    }