vpnengine/ikev1lib/src/ikev1pluginsession.cpp
changeset 0 33413c0669b9
child 10 68dc8923de26
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev1lib/src/ikev1pluginsession.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1924 @@
+/*
+* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  IKEv1 plugin session
+*
+*/
+
+
+#include <random.h>
+#include <vpnlogmessages.rsg>
+#include "ikev1plugin.h"
+#include "ikedebug.h"
+#include "ikev1negotiation.h"
+#include "ikev1isakmpstream.h"
+#include "pfkeymsg.h"
+#include "ikepolparser.h"
+#include "kmdapi.h"
+#include "ikev1crack.h"
+#include "ikev1infonegotiation.h"
+#include "ikev1SA.h"
+#include "ikev1sender.h"
+#include "ikesocketdefs.h"
+#include "ikedatainterface.h"
+#include "vpnaddrinfo.h"
+#include "ipsecsaspiretriever.h"
+
+// CLASS HEADER
+#include "ikev1pluginsession.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CIkev1PluginSession* CIkev1PluginSession::NewL( TUint32 aVpnIapId,
+                                                TUint32 aVpnNetId,
+                                                TUint32 aVpnInterfaceIndex,
+                                                MIkeDataInterface& aDataInterface,
+                                                CIkev1Plugin& aPlugin,
+                                                CPFKeySocketIf& aPFKeySocketIf,
+                                                MIkeDebug& aDebug )
+    {
+    CIkev1PluginSession* self = new ( ELeave ) CIkev1PluginSession( aVpnIapId,
+                                                                    aVpnNetId,
+                                                                    aVpnInterfaceIndex,
+                                                                    aDataInterface,
+                                                                    aPlugin,
+                                                                    aPFKeySocketIf,
+                                                                    aDebug );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+    
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CIkev1PluginSession::~CIkev1PluginSession()
+    {
+    // Cancel client's requests.
+    DoCompleteNegotiateWithHost( KErrCancel );
+    DoCompleteDeleteSession( KErrCancel );
+    DoCompleteNotifyError( KErrCancel );
+    DoCompleteInternalAddressChanged( KErrCancel );    
+    
+    if ( iDialogWaitQueue )
+        {
+        CIkev1Dialog::PurgeDialogQueue( iDialogWaitQueue );
+        }   
+
+    CIkev1Negotiation* negotiation;    
+    while ( iFirstNegotiation )
+        {
+        negotiation = iFirstNegotiation;
+        delete negotiation; // destructor removes object from queue, too
+        }
+    
+    DoEmptySendQueue();
+    iSendQueue.Close();
+    
+    while ( iIkev1SAs.Count() )
+        {
+        CIkev1SA* ikev1SA = iIkev1SAs[0];
+        iIkev1SAs.Remove(0);
+        delete ikev1SA;
+        }
+    iIkev1SAs.Close();
+    
+    delete iReceiver;
+    delete iSender;
+    delete iIkeData;
+    delete iInternalAddress;
+    
+    iPlugin.IkePluginSessionDeleted( this );
+    }
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+CIkev1PluginSession::CIkev1PluginSession( TUint32 aVpnIapId,
+                                          TUint32 aVpnNetId,
+                                          TUint32 aVpnInterfaceIndex,
+                                          MIkeDataInterface& aDataInterface,
+                                          CIkev1Plugin& aPlugin,
+                                          CPFKeySocketIf& aPFKeySocketIf,
+                                          MIkeDebug& aDebug )
+: iVpnIapId( aVpnIapId ),
+  iVpnNetId( aVpnNetId ),
+  iVpnInterfaceIndex( aVpnInterfaceIndex ),
+  iDataInterface( aDataInterface ),
+  iPlugin( aPlugin ),
+  iPFKeySocketIf( aPFKeySocketIf ),
+  iDebug( aDebug )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// Second phase construction.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::ConstructL()
+    {
+    TPtr8 ptr( (TUint8*)&iSAIdSeed, sizeof(iSAIdSeed) );
+    ptr.SetLength( sizeof(iSAIdSeed) );
+    TRandom::RandomL( ptr );  
+    iSAIdSeed &= 0x7fffffff;  // Reset the most significant bit    
+
+    iReceiver = CIkev1Receiver::NewL( iDataInterface,
+                                      *this );   
+    iSender = CIkev1Sender::NewL( iDataInterface,
+                                  *this,
+                                  iDebug );    
+    
+    DEBUG_LOG1( _L("CIkev1PluginSession::ConstructL, SAId seed: %d"),
+            iSAIdSeed );
+    }    
+
+// ---------------------------------------------------------------------------
+// Handles IKE SA deletion request.
+// ---------------------------------------------------------------------------
+//
+TBool CIkev1PluginSession::DeleteIkeSA( TIkev1SAData* aIkev1SaData,
+                                        TBool aSilentClose )
+    {
+    //
+    // An IKE SA delete request received
+    // Check first does there exists an ongoing negotiation on this IKE
+    // SA deleted and delete this block. 
+    // Allocate a new negotiation with TIkev1SAData and initiate IKE SA
+    // deletion request
+    //
+    DEBUG_LOG1( _L("Deleting IKEv1 SA SAID =  %d"),
+            aIkev1SaData->iSAId );
+    
+    CIkev1Negotiation* negotiation = FindNegotiation( aIkev1SaData->iSAId );
+    while ( negotiation )
+        {
+        delete negotiation; // destructor removes object from queue, too
+        negotiation = FindNegotiation( aIkev1SaData->iSAId );         
+        }
+
+    TBool started( EFalse );
+
+    if ( !aSilentClose )
+        {
+        DeleteIpsecSAs( aIkev1SaData->iSAId );
+        
+        TRAPD( err, 
+                {
+                // Trap the SendDeleteL -- it can fail, but the failure won't be fatal 
+                // (delete payload just won't be sent)
+                negotiation = CIkev1Negotiation::NewL( this,
+                                                       iPFKeySocketIf,
+                                                       iDebug,
+                                                       aIkev1SaData,
+                                                       RESPONDER ); // Nevermind INITIATOR or RESPONDER
+                negotiation->SendDeleteL( PROTO_ISAKMP );
+                } );
+                
+        delete negotiation;
+        negotiation = NULL;
+        
+        if ( err == KErrNone ) 
+            {
+            // DELETE payload sent succesfully.
+            DEBUG_LOG( _L("CIkev1PluginSession::DeleteIkeSAL() IKEv1 delete send OK") );            
+            started = ETrue;
+            }
+        else 
+            {
+            DEBUG_LOG1( _L("CIkev1PluginSession::DeleteIkeSAL() IKEv1 delete send failed, err=%d"), err );
+            }
+        }
+#ifdef _DEBUG
+    else
+        {
+        DEBUG_LOG( _L("Forced close, no delete payload(s) sent"));
+        }
+#endif    
+    ExpireIkev1SA( aIkev1SaData->iSAId );  // Set expired to delete IKE SA
+    
+    if ( FindIkev1SA() == NULL &&
+         FirstNegotiation() == NULL )
+        {
+        // Set error status, when expired IKE SA was the only IKE SA and there
+        // is no ongoing negotiation.        
+        iErrorStatus = KKmdIkeNegotFailed;
+        }
+
+    return started;
+    }
+
+// ---------------------------------------------------------------------------
+// Handles IKE SA rekeying request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::RekeyIkeSAL( TIkev1SAData* aIkev1SaData,
+                                       CSARekeyInfo* aSaRekeyInfo )
+    {
+    CIkev1Negotiation* negotiation = CIkev1Negotiation::NewL( this,
+                                                              iPFKeySocketIf,
+                                                              iDebug,
+                                                              aIkev1SaData->iRemoteAddr,
+                                                              EFalse );
+    CleanupStack::PushL( negotiation );
+    negotiation->SetRekeyInfo( aSaRekeyInfo );                
+    negotiation->InitNegotiationL();
+    if ( negotiation->Finished() )
+        {
+        CleanupStack::PopAndDestroy( negotiation );
+        }
+    else 
+        {
+        CleanupStack::Pop( negotiation );  
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Handles IKE SA keepalive request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::KeepAliveIkeSAL( TIkev1SAData* aIkev1SaData )
+    {
+    CIkev1Negotiation* negotiation = CIkev1Negotiation::NewL( this,
+                                                              iPFKeySocketIf,
+                                                              iDebug,
+                                                              aIkev1SaData,
+                                                              RESPONDER );
+    CleanupStack::PushL( negotiation );
+    negotiation->SendKeepAliveMsgL( aIkev1SaData );
+    if ( negotiation->Finished() )
+        {
+        CleanupStack::PopAndDestroy( negotiation );
+        }
+    else
+        {
+        CleanupStack::Pop( negotiation );  
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Creates IKE SA.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::CreateIkev1SAL( TIkev1SAData& aIkev1SaData,
+                                          CSARekeyInfo* aSaRekey )
+    {
+    CIkev1SA* ikev1SA = CIkev1SA::NewL( *this,
+                                        aIkev1SaData,
+                                        aSaRekey,
+                                        iDebug );
+    
+    if ( !aIkev1SaData.iInitiator )
+        {
+        // Move SPI list from previous IKE SA to new IKE SA
+        for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+            {
+            CIkev1SA* previousSA = iIkev1SAs[i];
+            if ( previousSA->iSPIList != NULL )
+                {
+                DEBUG_LOG(_L("Move SPI list to new IKE SA"));
+                delete ikev1SA->iSPIList;
+                ikev1SA->iSPIList = previousSA->iSPIList;
+                previousSA->iSPIList = new (ELeave) CIpsecSPIList(1);  // Dummy;
+                break;
+                }
+            }        
+        }        
+    
+    // Cancel IKE SA rekeying from other IKE SAs.
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* cancelSA = iIkev1SAs[i];
+        cancelSA->CancelRekey();
+        }
+    
+    CleanupStack::PushL( ikev1SA );
+    iIkev1SAs.AppendL( ikev1SA );
+    CleanupStack::Pop( ikev1SA );    
+    }
+
+// ---------------------------------------------------------------------------
+// Updates IKE SA.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::UpdateIkev1SAL( TUint32 aSaId,
+                                          TBool aExpired,
+                                          TIkev1SAData* aIkev1SaData )
+    {
+    if ( !aExpired )
+        {
+        CIkev1SA* Ikev1SA = FindIkev1SAWithId( aSaId );
+        if ( Ikev1SA )
+            {
+            Ikev1SA->UpdateSAL( aExpired, aIkev1SaData );
+            }
+        }
+    else
+        {
+        ExpireIkev1SA( aSaId );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Expires IKE SA.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::ExpireIkev1SA( TUint32 aSaId )
+    {
+    CIkev1SA* ikev1SA = FindIkev1SAWithId( aSaId );
+    if ( ikev1SA )
+        {
+        ikev1SA->ExpireSA();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Removes IKE SA.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::RemoveIkeSA( CIkev1SA* aIkev1Sa,
+                                       TInt aStatus )
+    {        
+    TInt dpdRetryCount( 0 );
+    
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if ( aIkev1Sa == sa )
+            {
+            // Remove IKE SA from array.
+            dpdRetryCount = sa->iHdr.iDPDRetry;
+            iIkev1SAs.Remove(i);
+            delete sa;
+            break;
+            }   
+        }
+    
+    if ( (iErrorStatus == KErrNone) &&
+         (dpdRetryCount > KMaxDpdRetryCount) &&
+         (FindIkev1SA() == NULL) )
+        {
+        // If DPD retry count was reached for only IKE SA, set error status.
+        iErrorStatus = KKmdIkeNoResponseErr;        
+        }
+        
+    // If session deletion has been requested, complete session deletion
+    // request.        
+    DoCompleteDeleteSession( aStatus );
+        
+    // If fatal error has occured, complete error notification.    
+    if ( iErrorStatus != KErrNone )
+        {
+        DoHandleError( iErrorStatus );
+        }
+    }
+
+// IKE SA find methods.
+
+CIkev1SA* CIkev1PluginSession::FindIkev1SA()
+    {
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if ( (!sa->IsExpired()) )
+            {
+            return sa;
+            }   
+        }
+    return NULL;
+    }
+
+CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TCookie& aCookie_I,
+                                            const TCookie& aCookie_R )
+    {
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if ( (sa->iHdr.iCookie_I ==  aCookie_I) &&
+             (sa->iHdr.iCookie_R ==  aCookie_R) &&
+             (!sa->IsExpired()) )
+            {
+            return sa;
+            }   
+        }
+    return NULL;
+    }
+
+CIkev1SA* CIkev1PluginSession::FindIkev1SAWithId( TUint32 aSaId )
+    {
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if ( (sa->iHdr.iSAId == aSaId) &&
+             (!sa->IsExpired()) )
+            {
+            return sa;
+            }   
+        }
+    return NULL;
+    }
+
+CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TInetAddr& aAddr )
+    {
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if (  sa->iHdr.iRemoteAddr.Match(aAddr) &&
+              (!sa->IsExpired()) ) 
+            {
+            return sa;
+            }   
+        }
+    return NULL;
+    }
+
+CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TInetAddr& aAddr,
+                                            TUint32 aInboundSpi )
+    {
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if (  sa->iHdr.iRemoteAddr.Match(aAddr) &&
+              (!sa->IsExpired()) ) 
+            {
+            if ( sa->FindIpsecSPI(aInboundSpi, ETrue) )
+                {
+                return sa;
+                }
+            }   
+        }
+    return NULL;
+    }
+
+TIkev1SAData* CIkev1PluginSession::FindIkev1SAData()
+    {
+    TIkev1SAData* saData = NULL;        
+    CIkev1SA* ikev1SA = FindIkev1SA();
+    if ( ikev1SA )
+        {
+        saData = (TIkev1SAData*)&ikev1SA->iHdr;
+        }
+    return saData;
+    }
+
+TIkev1SAData* CIkev1PluginSession::FindIkev1SAData( const TCookie& aCookie_I,
+                                                    const TCookie& aCookie_R )
+    {
+    TIkev1SAData* saData = NULL;        
+    CIkev1SA* ikev1SA = FindIkev1SA( aCookie_I, aCookie_R );
+    if ( ikev1SA )
+        {
+        saData = (TIkev1SAData*)&ikev1SA->iHdr;
+        }
+    return saData;
+    }
+
+TIkev1SAData* CIkev1PluginSession::FindIkev1SAData( TUint32 aSaId )
+    {
+    TIkev1SAData* saData = NULL;        
+    CIkev1SA* ikev1SA = FindIkev1SAWithId( aSaId );
+    if ( ikev1SA )
+        {
+        saData = (TIkev1SAData*)&ikev1SA->iHdr;
+        }
+    return saData;
+    }
+
+TIkev1SAData* CIkev1PluginSession::FindIkev1SAData( const TInetAddr& aAddr,
+                                                    TUint32 aInboundSpi )
+    {
+    TIkev1SAData* saData = NULL;        
+    CIkev1SA* ikev1SA = FindIkev1SA( aAddr, aInboundSpi );
+    if ( ikev1SA )
+        {
+        saData = (TIkev1SAData*)&ikev1SA->iHdr;
+        }
+    return saData;
+    }    
+
+TIkev1SAData* CIkev1PluginSession::FindIkev1SADataWithAddr( const TInetAddr& aAddr )
+    {
+    TIkev1SAData* saData = NULL;        
+    CIkev1SA* ikev1SA = FindIkev1SA( aAddr );
+    if ( ikev1SA )
+        {
+        saData = (TIkev1SAData*)&ikev1SA->iHdr;
+        }
+    return saData;
+    }    
+
+// ---------------------------------------------------------------------------
+// Handles IPsec SA deletion request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DeleteIpsecSAL( TIkev1SAData* aIkev1SaData,
+                                          TIpsecSPI* aIpsecSpi )
+    {
+    //
+    // Send a delete payload for specified IPSec SA 
+    //
+    CIkev1Negotiation* negotiation = CIkev1Negotiation::NewL( this,
+                                                              iPFKeySocketIf,
+                                                              iDebug,                                                              
+                                                              aIkev1SaData,
+                                                              RESPONDER );
+    CleanupStack::PushL( negotiation );
+    negotiation->SendDeleteL( aIpsecSpi->iProtocol,
+                              aIpsecSpi->iSPI );
+    CleanupStack::PopAndDestroy( negotiation );
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes IPsec SAs.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DeleteIpsecSAs( TUint32 aSaId )
+    {
+    CIkev1SA* ikev1SA = FindIkev1SAWithId( aSaId );
+    if ( ikev1SA )
+        {
+        ikev1SA->DeleteIpsecSAs(); 
+        }   
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes IPsec SPI.
+// ---------------------------------------------------------------------------
+//
+TBool CIkev1PluginSession::DeleteIpsecSpi( TUint32 aSaId,
+                                           TUint32 aSpi,
+                                           TBool aInbound )
+    {
+    TBool status = EFalse;
+    CIkev1SA* ikev1SA = FindIkev1SAWithId( aSaId );
+    if ( ikev1SA )
+        {
+        status = ikev1SA->DeleteIpsecSPI( aSpi, aInbound );
+        }
+    return status;
+    }
+
+// ---------------------------------------------------------------------------
+// Adds IPsec SPI to IKE SA.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::AddIpsecSPIToSAL( TUint32 aSaId,
+                                            TIpsecSPI& aIpsecSpi )
+    {
+    CIkev1SA* ikev1SA = FindIkev1SAWithId( aSaId );
+    if ( ikev1SA )
+        {
+        ikev1SA->AddIpsecSPIL( aIpsecSpi );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Returns dialog anchor.
+// ---------------------------------------------------------------------------
+//
+CIkev1Dialog** CIkev1PluginSession::DialogAnchor()
+    {
+    return &iDialogWaitQueue;
+    }
+
+// ---------------------------------------------------------------------------
+// Returns debug trace interface.
+// ---------------------------------------------------------------------------
+//
+MIkeDebug& CIkev1PluginSession::Debug()
+    {
+    return iDebug;
+    }
+
+// ---------------------------------------------------------------------------
+// Gets SA id.
+// ---------------------------------------------------------------------------
+//
+TUint32 CIkev1PluginSession::GetSAId()
+    {
+    iSAIdSeed++;
+    return iSAIdSeed;
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes ISAKMP SAs.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DeleteISAKMPSAsL( TDeleteISAKMP* aDeletePayload,
+                                            const CIkev1Negotiation& aInfoNegotiation )
+    {
+    TCookie cookie_I, cookie_R;
+
+    // It should always be only one.
+    for ( TInt i=0; i < aDeletePayload->NumSPI(); i++ )
+        {
+        if ( aDeletePayload->SPISize() < 2 * ISAKMP_COOKIE_SIZE ) //The ISAKMPSA SPI is the union of both cookies
+            {
+            DEBUG_LOG( _L("Bad SPI Size for a ISAKMP SA. (SA Not deleted)") );
+            return;
+            }
+        cookie_I.Copy( aDeletePayload->SPI(i), ISAKMP_COOKIE_SIZE );
+        cookie_R.Copy( aDeletePayload->SPI(i) + ISAKMP_COOKIE_SIZE,
+                       ISAKMP_COOKIE_SIZE);
+
+        CIkev1Negotiation* neg = iFirstNegotiation;
+        while ( neg )
+            {
+            CIkev1Negotiation* current = neg;
+            neg = neg->iNext;
+
+            // Delete any active negotiations with the same cookies.
+            // Currently used negotiation is not deleted.
+            if ( ( current != &aInfoNegotiation ) &&
+                 ( current->iCookie_I == cookie_I ) &&
+                 ( current->iCookie_R == cookie_R ) )
+                {
+                DEBUG_LOG( _L("Active negotiation deleted.") );
+                delete current;
+                current = NULL;
+                }
+            }
+        
+        // Expire IKE SA.
+        TIkev1SAData* sa = FindIkev1SAData( cookie_I, cookie_R );
+        if ( sa )
+            {
+            UpdateIkev1SAL( sa->iSAId, ETrue );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Gets local IP address.
+// ---------------------------------------------------------------------------
+//
+TInt CIkev1PluginSession::GetLocalAddress( TInetAddr& aAddr )
+    {
+    TInt err( KErrNone );
+    if ( iLocalAddr.IsUnspecified() )
+        {
+        err = iDataInterface.GetLocalAddress( iLocalAddr );
+        }
+    
+    aAddr = iLocalAddr;
+    return err;
+    }
+
+// ---------------------------------------------------------------------------
+// Sends IKE message.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::SendIkeMsgL( const TDesC8& aIkeMsg,
+                                       TInetAddr& aDestAddr,
+                                       TBool aUseNatPort )
+    {
+    // Construct buffer for storing IKE message data.
+    TInt localPort = ( aUseNatPort ?
+                       IkeSocket::KIkePort4500 :
+                       IkeSocket::KIkePort500 );    
+    TInt length = aIkeMsg.Length();    
+    if ( localPort == IkeSocket::KIkePort4500 )
+        {
+        // Reserve space for <non-ESP marker>.
+        length += NON_ESP_MARKER_SIZE;
+        }    
+    HBufC8* ikeMsg = HBufC8::NewL( length );    
+    TPtr8 ptr = ikeMsg->Des();    
+    if ( localPort == IkeSocket::KIkePort4500 )
+        {    
+        // Append <non-ESP marker> to the beginning of IKE message.
+        TUint32 nonEspMarker = NON_ESP_MARKER;        
+        TUint8* nonEspPtr = (TUint8*)&nonEspMarker;
+        ptr.Append( nonEspPtr, NON_ESP_MARKER_SIZE );
+        } 
+    // Append IKE message data to descriptor.
+    ptr.Append( aIkeMsg );    
+    
+    DoSendUdpDataL( ikeMsg, // Ownership transferred.
+                    aDestAddr,
+                    localPort,
+                    0 );
+    }
+
+// ---------------------------------------------------------------------------
+// Sends NAT keep-alive packet.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::SendNatKeepAliveL( TInetAddr& aDestAddr,
+                                             const TDesC8& aData,
+                                             TUint8 aDscp )
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::SendNatKeepAliveL"));
+    HBufC8* udpData = HBufC8::NewL( aData.Length() );
+    *udpData = aData;
+    TInt localPort = aDestAddr.Port();
+    DoSendUdpDataL( udpData, // Ownership transferred.
+                    aDestAddr,
+                    localPort,
+                    aDscp );
+    }
+
+// ---------------------------------------------------------------------------
+// Sends Nokia NAT keep-alive packet.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::SendNokiaNatKeepAliveL( TInetAddr& aDestAddr,
+                                                  const TDesC8& aData,
+                                                  TUint8 aDscp )    
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::SendNokiaNatKeepAliveL"));
+    SendNatKeepAliveL( aDestAddr,
+                       aData,
+                       aDscp );
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of IKE SA establishment.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::IkeSaCompleted( TInt aStatus,
+                                          CInternalAddress* aInternalAddress )
+    {
+    delete iInternalAddress;
+    iInternalAddress = aInternalAddress;
+    
+    DoCompleteNegotiateWithHost( aStatus );
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes negotiation object.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::DeleteNegotiation( CIkev1Negotiation* aNegotiation )
+    {
+    TInt err = ErrorStatus();
+    delete aNegotiation;        
+    
+    if ( err == KErrNone &&
+         (iClientStatusNegotiate != NULL ||
+          iClientStatusDelete != NULL) &&
+         (FindIkev1SA() == NULL) )
+        {
+        // If negotiate or delete session request has been issued, and
+        // there are no IKE SAs, client is completed with error.
+        err = KKmdIkeNegotFailed;
+        }
+
+    DEBUG_LOG1(_L("IKEv1 negotiation deleted, status=%d"),
+            err );
+    
+    if ( err != KErrNone )
+        {
+        //
+        // IKE negotiation failed.
+        //
+        DoHandleError( err );
+        }        
+    }
+
+// Negotiation linking and find methods.
+
+void CIkev1PluginSession::LinkNegotiation( CIkev1Negotiation* aNegotiation )
+    {  
+    aNegotiation->iNext = iFirstNegotiation;  
+    iFirstNegotiation = aNegotiation; 
+    }    
+    
+CIkev1Negotiation* CIkev1PluginSession::FirstNegotiation()
+    {
+    return iFirstNegotiation;
+    }
+
+CIkev1Negotiation* CIkev1PluginSession::FindNegotiation( TCookie aInit,
+                                                         TCookie aResp,
+                                                         TUint8 aExchange,
+                                                         TUint32 aMsgId )
+    {
+    CIkev1Negotiation* negotiation;
+    TCookie NULL_COOKIE;
+    NULL_COOKIE.FillZ(ISAKMP_COOKIE_SIZE);
+
+    if ( aExchange == ISAKMP_EXCHANGE_INFO )
+        {
+        for ( negotiation = iFirstNegotiation;
+              negotiation;
+              negotiation = negotiation->iNext )
+            {
+            if ( (negotiation->iCookie_I.Compare(aInit) == 0 ) &&
+                 ((negotiation->iCookie_R.Compare(aResp) == 0 ) ||
+                   (negotiation->iCookie_R.Compare(NULL_COOKIE) == 0)) )
+                {   
+                return negotiation;
+                }   
+            }
+        
+        }   
+    else
+        {
+        for ( negotiation = iFirstNegotiation;
+              negotiation;
+              negotiation = negotiation->iNext )
+            {            
+            if ( negotiation->iCookie_I.Compare(aInit) == 0 )
+                {
+                if ( (negotiation->iMessageId == aMsgId) ||
+                     (negotiation->iMessageId == 0) )
+                    {
+                    if ( (negotiation->iCookie_R.Compare(aResp) == 0 ) ||
+                         (negotiation->iCookie_R.Compare(NULL_COOKIE) == 0) ||
+                         (aResp.Compare(NULL_COOKIE) == 0) )
+                        {
+                        return negotiation;
+                        }
+                    }
+                }
+            }           
+        }   
+
+    return NULL; // Not found
+    }
+
+CIkev1Negotiation* CIkev1PluginSession::FindNegotiation( TUint32 aSaId )
+    {
+    //
+    // Find IKEv1 negotiation object using SA id as search argument 
+    //
+    CIkev1Negotiation* negotiation = iFirstNegotiation;
+    while ( negotiation )
+        {
+        if ( negotiation->SAId() == aSaId )
+            {   
+            break;
+            }   
+
+        negotiation = negotiation->iNext;
+        }   
+    return negotiation;     
+    }
+
+void CIkev1PluginSession::RemoveNegotiation( CIkev1Negotiation* aNegotiation )
+    {
+    CIkev1Negotiation* prev = NULL;
+    CIkev1Negotiation* negotiation  = iFirstNegotiation;
+    
+    while ( negotiation )
+        {
+        if ( negotiation == aNegotiation )
+            {
+            if ( prev )
+                {
+                prev->iNext = negotiation->iNext;
+               }
+           else 
+               {
+               iFirstNegotiation = negotiation->iNext;
+               }
+            break;  
+            }
+        prev = negotiation;
+        negotiation = negotiation->iNext;
+        }   
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of authentication dialog processing.
+// ---------------------------------------------------------------------------
+//    
+TInt CIkev1PluginSession::AuthDialogCompletedL( CAuthDialogInfo* aUserInfo )
+    {
+    CIkev1Negotiation* negotiation = FindNegotiation( aUserInfo->SAId() );
+    if ( negotiation )
+        {
+        DEBUG_LOG1( _L("Dialog completed for SAID: %d"),
+                aUserInfo->SAId() );
+        
+        negotiation->AuthDialogCompletedL(aUserInfo);
+        if ( negotiation->Finished() )
+            {
+            DeleteNegotiation( negotiation );
+            }   
+        return KErrNone;
+        }   
+    DEBUG_LOG1( _L("Dialog completed, no negotiation found for SAID: %d"),
+            aUserInfo->SAId() );
+    return KErrNotFound;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Handles change of internal address.
+// ---------------------------------------------------------------------------
+//    
+TBool CIkev1PluginSession::InternalAddressChangedL( const CInternalAddress& aInternalAddr )
+    {
+    TBool internalAddressChanged( ETrue );
+    
+    if ( iInternalAddress )
+        {
+        if ( iInternalAddress->iClientIntAddr.Match(aInternalAddr.iClientIntAddr) )                    
+            {
+            internalAddressChanged = EFalse;
+            }
+        }        
+    
+    delete iInternalAddress;
+    iInternalAddress = NULL;
+    iInternalAddress = CInternalAddress::NewL( aInternalAddr );
+    
+    if ( internalAddressChanged )
+        {
+        DoCompleteInternalAddressChanged( KErrNone );
+        }
+    
+    return internalAddressChanged;
+    }
+
+// ---------------------------------------------------------------------------
+// Gets acceptable IPsec policies for specified selectors.
+// ---------------------------------------------------------------------------
+//
+CIpsecSaSpecList* CIkev1PluginSession::GetIpseSaSpecListLC( const TInetAddr& aLocalAddr, const TInetAddr& aLocalMask, 
+                                                            const TInetAddr& aRemoteAddr, const TInetAddr& aRemoteMask,
+                                                            TInt aProtocol )
+
+    {
+    return iPlugin.GetIpseSaSpecListLC( aLocalAddr, aLocalMask, 
+                                        aRemoteAddr, aRemoteMask,
+                                        aProtocol, iVpnNetId );
+    }
+
+// ---------------------------------------------------------------------------
+// Matches destination address to remote address in IKE policy data.
+// ---------------------------------------------------------------------------
+//
+TBool CIkev1PluginSession::MatchDestinationAddress( const TInetAddr& aDestAddr )
+    {
+    TBool match( EFalse );
+    
+    if ( iIkeData )
+        {
+        match = iIkeData->iAddr.Match( aDestAddr );
+        }    
+    return match;
+    }
+
+// ---------------------------------------------------------------------------
+// Handles fatal error.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::HandleError( TInt aStatus )
+    {
+    DoHandleError( aStatus );
+    }
+
+// ---------------------------------------------------------------------------
+// Returns error status.
+// ---------------------------------------------------------------------------
+//
+TInt CIkev1PluginSession::ErrorStatus()
+    {
+    return iErrorStatus;
+    }
+
+// ---------------------------------------------------------------------------
+// Sets error status.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::SetErrorStatus( TInt aStatus )
+    {
+    if ( iErrorStatus == KErrNone )
+        {
+        iErrorStatus = aStatus;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Returns VPN IAP id.
+// ---------------------------------------------------------------------------
+//
+TUint32 CIkev1PluginSession::VpnIapId()
+    {
+    return iVpnIapId;
+    }
+
+// ---------------------------------------------------------------------------
+// Returns VPN interface index.
+// ---------------------------------------------------------------------------
+//
+TUint32 CIkev1PluginSession::VpnInterfaceIndex()
+    {
+    return iVpnInterfaceIndex;
+    }
+
+// ---------------------------------------------------------------------------
+// Returns IKE policy data.
+// ---------------------------------------------------------------------------
+//
+CIkeData& CIkev1PluginSession::IkeData()
+    {
+    __ASSERT_DEBUG( iIkeData != NULL,
+                    User::Invariant() );
+    return *iIkeData;
+    }
+
+// ---------------------------------------------------------------------------
+// Returns UID.
+// ---------------------------------------------------------------------------
+//
+TUint32 CIkev1PluginSession::Uid()
+    {
+    return iPlugin.Uid();
+    }
+
+// ---------------------------------------------------------------------------
+// Returns event logger interface.
+// ---------------------------------------------------------------------------
+//
+MKmdEventLoggerIf& CIkev1PluginSession::EventLogger()
+    {
+    return iPlugin.EventLogger();
+    }      
+
+// ---------------------------------------------------------------------------
+// Returns internal address (NULL if does not exist). 
+// ---------------------------------------------------------------------------
+//
+CInternalAddress* CIkev1PluginSession::InternalAddressL()
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::InternalAddressL"));
+    
+    CInternalAddress* internalAddress = NULL;
+    if ( iInternalAddress != NULL )
+        {
+        internalAddress = CInternalAddress::NewL( *iInternalAddress );    
+        }
+    return internalAddress;            
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkev1SenderCallback
+// Handles completion of sending.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::SendUdpDataCompleted( TInt aStatus )
+    {    
+    if ( iSendQueue.Count() != 0 )
+        {
+        // Send queue is not empty.
+        // Send next item from queue.
+        TIkeSendQueueItem item = iSendQueue[0];
+        HBufC8* udpData = item.UdpData();
+        TInetAddr destAddr = item.DestAddr();
+        TInt localPort = item.LocalPort();
+        TUint8 dscp = item.Dscp();
+        iSendQueue.Remove(0);
+        DoSendUdpData( udpData,
+                       destAddr,
+                       localPort,
+                       dscp );
+        
+        }
+    else
+        {
+        // IKE message send queue is empty.
+        // If session deletion has been requested, complete request.
+        DoCompleteDeleteSession( aStatus );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Handles PFKEY message.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::PfkeyMessageReceived( const TPfkeyMessage& aPfkeyMessage )
+    {
+    TRAPD( err, DoPfkeyMessageReceivedL( aPfkeyMessage) );
+    err = err;
+    DEBUG_LOG1(_L("CIkev1PluginSession::PfkeyMessageReceivedL, err=%d"), err);
+    }
+
+// Methods to build and send PFKEY API primitives to IPsec
+
+void CIkev1PluginSession::AcquireSAError( TIpsecSAData& aSAData,
+                                          TInt aError )
+    {
+    iPlugin.AcquireSAError( aSAData, aError );
+    }
+
+void CIkev1PluginSession::UpdateSAL( TIpsecSAData& aSaData )
+    {
+    iPlugin.UpdateSAL( aSaData );
+    }
+
+void CIkev1PluginSession::AddSAL( TIpsecSAData& aSaData )
+    {
+    iPlugin.AddSAL( aSaData );
+    }
+
+void CIkev1PluginSession::DeleteIpsecSA( TIpsecSPI& aIpsecSpi )
+    {
+    iPlugin.DeleteIpsecSA( aIpsecSpi );
+    }
+
+void CIkev1PluginSession::DeleteIpsecSA( TUint32 aSPI,
+                                         TInetAddr& aSrc, 
+                                         TInetAddr& aDst,
+                                         TUint8 aProtocol )
+    {
+    iPlugin.DeleteIpsecSA( aSPI, aSrc, aDst, aProtocol );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Starts negotiation with a peer. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::NegotiateWithHost( const CIkeData& aIkeData,
+                                             TVPNAddress& aInternalAddress,
+                                             TRequestStatus& aStatus )
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::NegotiateWithHost"));    
+    __ASSERT_DEBUG( iClientStatusNegotiate == NULL,
+                    User::Invariant() );
+    
+    // Store client's request status and internal address.
+    iClientStatusNegotiate = &aStatus;
+    *iClientStatusNegotiate = KRequestPending;
+    iClientIaNegotiate = &aInternalAddress;
+    
+    TRAPD( err, DoNegotiateWithHostL( aIkeData ) );
+    
+    if ( err != KErrNone )
+        {
+        DoCompleteNegotiateWithHost( err );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Cancels negotiate request. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::CancelNegotiateWithHost()
+    {    
+    DEBUG_LOG(_L("CIkev1PluginSession::CancelNegotiateWithHost"));
+    
+    if ( iClientStatusNegotiate != NULL )
+        {
+        // Completion is enough as deletion of session is requested after
+        // cancellation.
+        DoCompleteNegotiateWithHost( KErrCancel );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Deletes session. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DeleteSession( const TBool aSilentClose,
+                                         TRequestStatus& aStatus )
+    {
+    DEBUG_LOG1(_L("CIkev1PluginSession::DeleteSession, silent=%d"),
+            aSilentClose);
+    
+    iClientStatusDelete = &aStatus;
+    *iClientStatusDelete = KRequestPending;
+    
+    TBool deactivatingStarted = DeleteSAsWithHost( aSilentClose );    
+    if ( !deactivatingStarted )
+        {
+        DoCompleteDeleteSession( KErrNone );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Cancels deletion requests. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::CancelDeleteSession()
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::CancelDeleteSession"));
+
+    if ( iClientStatusDelete != NULL )
+        {
+        // Delete SAs silently.
+        DeleteSAsWithHost( ETrue );
+        
+        DoCancelDataTransfer();
+        
+        User::RequestComplete( iClientStatusDelete, KErrCancel );
+        iClientStatusDelete = NULL;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Requests notification about error condition. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::NotifyError( TRequestStatus& aStatus )
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::NotifyError"));
+    
+    iClientStatusNotifyError = &aStatus;
+    *iClientStatusNotifyError = KRequestPending;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Cancels error notification request. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::CancelNotifyError()
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::CancelNotifyError"));
+    
+    if ( iClientStatusNotifyError != NULL )
+        {
+        User::RequestComplete( iClientStatusNotifyError, KErrCancel );
+        iClientStatusNotifyError = NULL;
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Requests notification about change of internal address. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::NotifyInternalAddressChanged( TVPNAddress& aInternalAddress,
+                                                        TRequestStatus& aStatus )
+    {
+    DEBUG_LOG(_L("CIkev1PluginSession::NotifyInternalAddressChanged"));
+    __ASSERT_DEBUG( iClientStatusNotifyIaChange == NULL,
+                    User::Invariant() );
+    
+    iClientStatusNotifyIaChange = &aStatus;
+    *iClientStatusNotifyIaChange = KRequestPending;
+    iClientIaNotify = &aInternalAddress;    
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkePluginSessionIf
+// Cancels internal address change notification request. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::CancelNotifyInternalAddressChanged()
+    {    
+    DEBUG_LOG(_L("CIkev1PluginSession::CancelNotifyInternalAddressChanged"));
+    
+    if ( iClientStatusNotifyIaChange != NULL )
+        {
+        DoCompleteInternalAddressChanged( KErrCancel );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkev1ReceiverCallback
+// Handles notification about received IKE message. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::IkeMsgReceivedL( const ThdrISAKMP& aIkeMsg,
+                                           const TInetAddr& aSrcAddr,
+                                           TInt aLocalPort )
+    {
+    CIkev1Negotiation* negotiation = NULL;
+    TIkev1SAData* sa = NULL;
+    
+    TUint8 exchange = aIkeMsg.GetExchange();
+    negotiation = FindNegotiation( aIkeMsg.GetCookieI(),
+                                   aIkeMsg.GetCookieR(),
+                                   exchange,
+                                   aIkeMsg.GetMessageId() );
+    
+    if ( exchange == ISAKMP_EXCHANGE_INFO || exchange == ISAKMP_EXCHANGE_TRANSACT )
+        {
+#ifdef _DEBUG
+        if ( exchange == ISAKMP_EXCHANGE_INFO )
+            {
+            DEBUG_LOG( _L("---ISAKMP_EXCHANGE_INFO message received---") );
+            }
+        else 
+            {
+            DEBUG_LOG( _L("---ISAKMP_EXCHANGE_TRANSACTION message received---") );
+            }                
+#endif
+        TBool inactive = EFalse;                 
+        if ( !negotiation ) 
+            {
+            if ( exchange == ISAKMP_EXCHANGE_INFO )
+                {
+                sa = FindIkev1SAData( aIkeMsg.GetCookieI(),
+                                      aIkeMsg.GetCookieR() );
+                if ( sa )
+                    {
+                    negotiation = CIkev1Negotiation::NewL( this,
+                                                           iPFKeySocketIf,
+                                                           iDebug,
+                                                           sa,
+                                                           RESPONDER );
+                    }       
+                }       
+            if ( !negotiation )
+                {
+                DEBUG_LOG( _L("Cannot find a matching negotiation") );
+#ifdef _DEBUG                    
+                const TPtrC8 ikeMsgPtr( (TUint8 *)&aIkeMsg, (TUint16)aIkeMsg.GetLength() );
+                TInetAddr dstAddr;
+                GetLocalAddress( dstAddr );
+                dstAddr.SetPort( aLocalPort );
+                TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, dstAddr );
+#endif // _DEBUG                    
+                return; //Not found
+                }
+            CleanupStack::PushL( negotiation );
+            inactive = ETrue;   //Not enqueued because not active. Only used to process the packet
+            }
+
+        if ( exchange == ISAKMP_EXCHANGE_INFO )
+            {                   
+            CIkev1InfoNegotiation* info_neg = new (ELeave) CIkev1InfoNegotiation( *this,
+                                                                                  *negotiation,
+                                                                                  iDebug );
+            CleanupStack::PushL( info_neg );            
+            // Update the negotiation state
+            info_neg->ExecuteL( aIkeMsg,
+                                aSrcAddr,
+                                aLocalPort  );
+            CleanupStack::PopAndDestroy( info_neg );
+            
+            if ( inactive )
+                {   
+                CleanupStack::PopAndDestroy( negotiation );
+                }
+            else
+                {
+                if ( negotiation->Finished() )
+                    {
+                    DeleteNegotiation( negotiation );
+                    }
+                }   
+            }
+        else
+            { 
+            //
+            // An ISAKMP transaction exchange message received
+            // The handling of this requires that there exists a
+            // CTransNegotiation object pointer linked into current
+            // CIkev1Negotiation object 
+            //
+            if ( negotiation )
+                {
+                if ( negotiation->ExecuteTransactionL( aIkeMsg,
+                                                       aSrcAddr,
+                                                       aLocalPort ) )
+                    {
+                    if ( negotiation->Finished() )
+                        {
+                        DeleteNegotiation( negotiation );
+                        }
+                    }
+                else
+                    {
+                    DEBUG_LOG( _L("Unexpected Transaction excange message") );
+#ifdef _DEBUG   
+                    const TPtrC8 ikeMsgPtr( (TUint8 *)&aIkeMsg, (TUint16)aIkeMsg.GetLength() );
+                    TInetAddr dstAddr;
+                    GetLocalAddress( dstAddr );
+                    dstAddr.SetPort( aLocalPort );
+                    TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, dstAddr );                        
+#endif // _DEBUG                        
+                    }     
+                }      
+            }   
+        return;
+        }
+
+    //
+    // IKE Main, Aggressive and Quick mode exchanges
+    //
+    if ( negotiation )
+        {
+        negotiation->ExecuteL( aIkeMsg, aSrcAddr, aLocalPort );
+        if ( negotiation->Finished() )
+            {
+            DeleteNegotiation( negotiation );
+            }
+        return;
+        }   
+    DEBUG_LOG( _L("No active negotiation found...Searching existing PHASE_II") );
+
+    TBool status;
+    sa = FindIkev1SAData( aIkeMsg.GetCookieI(),
+                          aIkeMsg.GetCookieR() );
+    if ( sa )
+        {
+        DEBUG_LOG( _L("Creating a NEW IKE Phase 2 Negotiation") );           
+        
+        TRAPD( err, negotiation = CIkev1Negotiation::NewL( this,
+                                                           iPFKeySocketIf,
+                                                           iDebug,
+                                                           sa,
+                                                           RESPONDER ) );
+        if ( err == KErrNone )
+            {
+            CleanupStack::PushL( negotiation );
+            status = negotiation->ExecutePhase2L( aIkeMsg, aSrcAddr, aLocalPort ); 
+            if ( status && !negotiation->Finished() )
+               {
+               //Negotiation OK
+               CleanupStack::Pop();    //negotiation safe
+               return;
+               }
+            CleanupStack::PopAndDestroy();
+            }            
+        return;
+        }
+    else
+        {
+        TCookie NULL_COOKIE;
+        NULL_COOKIE.FillZ(ISAKMP_COOKIE_SIZE);
+        if ( aIkeMsg.GetCookieR() == NULL_COOKIE )
+            {
+            //
+            // This is the initial opening message from a remote host
+            // Start a new negotiation
+            //
+            DEBUG_LOG( _L("Creating a NEW IKE Phase 1 Negotiation") );
+            TRAPD( err, negotiation = CIkev1Negotiation::NewL( this,
+                                                               iPFKeySocketIf,
+                                                               iDebug,
+                                                               aSrcAddr,
+                                                               aIkeMsg.GetCookieI(),
+                                                               EFalse ) );
+            
+            if ( err == KErrNone )
+                {
+                CleanupStack::PushL( negotiation );
+                status = negotiation->ExecuteL( aIkeMsg, aSrcAddr, aLocalPort );                   
+                if ( status && !negotiation->Finished() )
+                    {
+                    //Negotiation OK
+                    CleanupStack::Pop();    //negotiation safe
+                    return;
+                    }
+                CleanupStack::PopAndDestroy( negotiation );
+                }                
+            return;
+            }
+        }
+
+    if ( !negotiation )
+        {
+        DEBUG_LOG( _L("Cannot find a matching negotiation") );
+#ifdef _DEBUG
+        const TPtrC8 ikeMsgPtr((TUint8 *)&aIkeMsg, (TUint16)aIkeMsg.GetLength());
+        TInetAddr dstAddr;
+        GetLocalAddress( dstAddr );
+        dstAddr.SetPort( aLocalPort );
+        TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, dstAddr );
+#endif // _DEBUG            
+        return;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIkev1ReceiverCallback
+// Handles notification about receive error. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::ReceiveError( TInt aError )
+    {
+    HandleError( aError );
+    }
+
+// ---------------------------------------------------------------------------
+// Requests sending of UDP data.
+// ---------------------------------------------------------------------------
+//    
+void CIkev1PluginSession::DoSendUdpDataL( HBufC8* aUdpData,
+                                          const TInetAddr& aDestAddr,
+                                          TInt aLocalPort,
+                                          TUint8 aDscp )
+    {
+    if ( !iSender->IsActive() &&
+         iSendQueue.Count() == 0 )
+        {
+        // Sending is not in progress and send queue is empty.
+        // Start sending UDP data.
+        DoSendUdpData( aUdpData,
+                       aDestAddr,
+                       aLocalPort,
+                       aDscp );
+        }
+    else
+        {
+        // Store buffer into send queue for later sending.
+        TIkeSendQueueItem item = TIkeSendQueueItem( aUdpData,
+                                                    aDestAddr,
+                                                    aLocalPort,
+                                                    aDscp );
+        iSendQueue.Append( item );                
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// Sends UDP data. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoSendUdpData( HBufC8* aUdpData,
+                                         const TInetAddr& aDestAddr,
+                                         TInt aLocalPort,
+                                         TUint8 aDscp )
+    {
+    __ASSERT_DEBUG( aUdpData != NULL,
+                    User::Invariant() );
+    
+    iSender->SendUdpData( aUdpData, aDestAddr, aLocalPort, aDscp );
+    }
+
+// ---------------------------------------------------------------------------
+// Handles PFKEY message.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoPfkeyMessageReceivedL( const TPfkeyMessage& aPfkeyMessage )
+    {
+    //
+    //  Process received PFKEY message according to message type
+    //
+#ifdef _DEBUG    
+    TBuf<40> txt_addr;
+#endif        
+            
+    TIkev1SAData* ikev1SAdata = NULL;
+    CIkev1Negotiation* negotiation = NULL;   
+    
+    switch ( aPfkeyMessage.iBase.iMsg->sadb_msg_type )
+        {
+        case SADB_ACQUIRE:
+             //
+             // A request to negotiate an IPSEC SA received
+             // Try to find an existing IKE SA with remote address 
+             //
+#ifdef _DEBUG
+            aPfkeyMessage.iDstAddr.Address().OutputWithScope( txt_addr );
+#endif                
+            ikev1SAdata = FindIkev1SADataWithAddr( aPfkeyMessage.iDstAddr.Address() );
+            if ( ikev1SAdata )
+                {
+                //
+                // An IKE SA found for Acquire. Get a negotiation
+                // object for IKE Quick mode SA exchange 
+                //
+                negotiation = CIkev1Negotiation::NewL( this,
+                                                       iPFKeySocketIf,
+                                                       iDebug,
+                                                       ikev1SAdata,
+                                                       INITIATOR,
+                                                       &aPfkeyMessage );                     
+                CleanupStack::PushL( negotiation );                   
+                negotiation->InitPhase2L();    //Because is initiator
+                DEBUG_LOG1( _L("IKEv1 SA found for Acquire IP: %S"), &txt_addr );
+                CleanupStack::Pop();                                                
+                }
+            else
+                {
+                //
+                // No IKE SA found for Acquire.
+                //
+                // If rekeying is in progress, IKE Quick mode SA exchange
+                // is started after Phase I has completed.
+                //
+                CIkev1Negotiation* negotiation = iFirstNegotiation;
+                while ( negotiation != NULL )
+                    {
+                    if ( negotiation->IsRekeyingIkeSa() )
+                        {                        
+                        break;
+                        }
+                    negotiation = negotiation->iNext;
+                    }                
+                if ( negotiation != NULL )
+                    {
+                    negotiation->PreparePhase2L( aPfkeyMessage );                    
+                    DEBUG_LOG1( _L("Negotiation found for Acquire IP: %S"), &txt_addr );
+                    break;
+                    }                    
+                
+                //
+                // Otherwise we shall start a new IKE SA negotiation to
+                // defined destination address.
+                //
+                negotiation = CIkev1Negotiation::NewL( this,
+                                                       iPFKeySocketIf,
+                                                       iDebug,
+                                                       (TInetAddr&)aPfkeyMessage.iDstAddr.Address(),
+                                                       aPfkeyMessage );
+                CleanupStack::PushL( negotiation );
+                negotiation->InitNegotiationL();
+                if ( negotiation->Finished() )
+                    {
+                    CleanupStack::PopAndDestroy();
+                    }
+                else 
+                    {
+                    CleanupStack::Pop();                                              
+                    }
+                DEBUG_LOG1( _L("Negotiate a new IKE SA for Acquire IP: %S"), &txt_addr );
+                }
+            break;
+
+        case SADB_EXPIRE:
+            //
+            // An IPSEC SA has been expired.
+            // Try to find an existing IKE SA with source address
+            // (= inbound SA destination address)
+            //
+#ifdef _DEBUG                
+            aPfkeyMessage.iDstAddr.Address().OutputWithScope( txt_addr );
+#endif                  
+            ikev1SAdata = FindIkev1SAData( aPfkeyMessage.iSrcAddr.Address(),
+                                           aPfkeyMessage.iSa.iExt->sadb_sa_spi );
+            if ( ikev1SAdata )
+                {
+                //
+                // An IKE SA found for Expire. Get a negotiation
+                // object for IKE Informational exchange 
+                //
+                if ( DeleteIpsecSpi(ikev1SAdata->iSAId,
+                                    aPfkeyMessage.iSa.iExt->sadb_sa_spi,
+                                    ETrue) )
+                    {
+                    negotiation = CIkev1Negotiation::NewL( this,
+                                                           iPFKeySocketIf,
+                                                           iDebug,
+                                                           ikev1SAdata,
+                                                           RESPONDER );
+                    CleanupStack::PushL( negotiation );
+                    negotiation->SendDeleteL( aPfkeyMessage.iBase.iMsg->sadb_msg_satype,
+                                              aPfkeyMessage.iSa.iExt->sadb_sa_spi );
+                    CleanupStack::PopAndDestroy();
+                    DEBUG_LOG3(_L("Notifying SGW, IPsec SA Expiration (addr = %S, spi = %x , proto = %d)"), &txt_addr,
+                            ByteOrder::Swap32(aPfkeyMessage.iSa.iExt->sadb_sa_spi), aPfkeyMessage.iDstAddr.iExt->sadb_address_proto);
+                    }       
+                }
+            else
+                {                       
+                DEBUG_LOG1( _L("No IKE SA found Expire IP: %S"), &txt_addr );
+                }                       
+            break;
+             
+        default:
+            break;
+            
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Deletes IKE SAs. 
+// ---------------------------------------------------------------------------
+//
+TBool CIkev1PluginSession::DeleteSAsWithHost( TBool aSilentClose )
+    {        
+    DEBUG_LOG( _L("Deactivating IKEv1 SA:s") );
+    
+    //
+    // For sure check if there is any ongoing negotiations for this
+    // and delete these negotiations immediatelly.
+    //
+    while ( iFirstNegotiation )
+        {
+        CIkev1Negotiation* negotiation = iFirstNegotiation;
+        iFirstNegotiation = negotiation->iNext;             
+        delete negotiation;
+        }
+    
+    TInt deactivatingStarted( EFalse );
+    for ( TInt i=0;i<iIkev1SAs.Count();i++ )
+        {
+        CIkev1SA* sa = iIkev1SAs[i]; 
+        if ( !sa->IsExpired() )
+            {
+            TIkev1SAData& ikeSaData = sa->iHdr;
+            deactivatingStarted = DeleteIkeSA( &ikeSaData, aSilentClose );
+            }   
+        }
+
+    return deactivatingStarted;
+    }    
+
+// ---------------------------------------------------------------------------
+// Handles starting of negotiation with a peer. 
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoNegotiateWithHostL( const CIkeData& aIkeData )
+    {
+    __ASSERT_DEBUG( iIkeData == NULL,
+                    User::Invariant() );    
+    
+    iIkeData = CIkeData::NewL( &aIkeData ); 
+
+    // Start ISAKMP Phase 1 negotiation to the specified gateway immediately
+    // if the Internal VPN address feature is enabled in policy (= IA payload
+    // or CONFIG-MODE). Otherwise postpone negotiation.    
+    if ( !aIkeData.iUseInternalAddr &&
+         !aIkeData.iUseCfgMode )
+        {
+        DEBUG_LOG(_L("Negotiation postponed."));
+        User::RequestComplete( iClientStatusNegotiate, KErrNone );
+        iClientStatusNegotiate = NULL;
+        return;
+        }   
+    
+    CIkev1Negotiation* negotiation = CIkev1Negotiation::NewL( this,
+                                                              iPFKeySocketIf,
+                                                              iDebug,
+                                                              iIkeData->iAddr,
+                                                              ETrue );
+    CleanupStack::PushL( negotiation );
+    negotiation->InitNegotiationL();        
+    if ( negotiation->Finished() )
+        {
+        CleanupStack::PopAndDestroy( negotiation );
+        User::Leave( KKmdIkeNegotFailed );            
+        }
+    else
+        {           
+        CleanupStack::Pop( negotiation );
+        }   
+    }  
+
+// ---------------------------------------------------------------------------
+// Handles fatal error.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoHandleError( TInt aError )
+    {
+    DEBUG_LOG1(_L("CIkev1PluginSession::DoHandleError, err=%d"), aError);
+    
+    while ( iFirstNegotiation )
+        {
+        CIkev1Negotiation* negotiation = iFirstNegotiation;
+        iFirstNegotiation = negotiation->iNext;             
+        delete negotiation;
+        }
+    
+    while ( iIkev1SAs.Count() )
+        {
+        CIkev1SA* ikev1SA = iIkev1SAs[0];
+        iIkev1SAs.Remove(0);
+        delete ikev1SA;
+        }
+    
+    // Complete client's requests.
+    DoCompleteNegotiateWithHost( aError );
+    DoCompleteDeleteSession( aError );
+    DoCompleteNotifyError( aError );
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of client's negotiate request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoCompleteNegotiateWithHost( TInt aStatus )
+    {         
+    if ( iClientStatusNegotiate != NULL )
+        {
+        if ( aStatus == KErrNone )
+            {
+            if ( iInternalAddress != NULL )
+                {
+                __ASSERT_DEBUG( iIkeData != NULL,
+                                User::Invariant() );
+                // Build internal address for client.       
+                VPNAddrInfo::BuildVPNAddrInfo( iInternalAddress,
+                                               iIkeData->iDnsServer,
+                                               *iClientIaNegotiate,
+                                               iDebug );
+                }
+            }
+
+        // Complete client's request.
+        DEBUG_LOG1(_L("CIkev1PluginSession::DoCompleteNegotiateWithHost, aStatus=%d"),
+                aStatus);        
+        User::RequestComplete( iClientStatusNegotiate, aStatus );
+        iClientStatusNegotiate = NULL;
+        iClientIaNegotiate = NULL;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of client's delete session request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoCompleteDeleteSession( TInt aStatus )
+    {       
+    if ( iClientStatusDelete != NULL )
+        {
+        DoCancelDataTransfer();
+        
+        DEBUG_LOG1(_L("CIkev1PluginSession::DoCompleteDeleteSession, aStatus=%d"),
+                aStatus);
+        User::RequestComplete( iClientStatusDelete, aStatus );
+        iClientStatusDelete = NULL;
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of client's notify error request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoCompleteNotifyError( TInt aStatus )
+    {   
+    if ( iClientStatusNotifyError != NULL )
+        {
+        DoCancelDataTransfer();
+
+        DEBUG_LOG1(_L("CIkev1PluginSession::DoCompleteNotifyError, aStatus=%d"),
+                aStatus);
+        User::RequestComplete( iClientStatusNotifyError, aStatus );
+        iClientStatusNotifyError = NULL;
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// Handles completion of client's notify internal address change request.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoCompleteInternalAddressChanged( TInt aStatus )
+    {
+    if ( iClientStatusNotifyIaChange != NULL )
+        {       
+        DEBUG_LOG1(_L("CIkev1PluginSession::DoCompleteInternalAddressChange, aStatus=%d"),
+                aStatus);
+
+        if ( aStatus == KErrNone )
+            {
+            if ( iInternalAddress != NULL )
+                {
+                // Build internal address for client.       
+                VPNAddrInfo::BuildVPNAddrInfo( iInternalAddress,
+                                               iIkeData->iDnsServer,
+                                               *iClientIaNotify,
+                                               iDebug );            
+                }
+            }
+        
+        if ( aStatus != KErrNone &&
+             aStatus != KErrCancel )
+            {
+            HandleError( aStatus);
+            return;
+            }
+        
+        User::RequestComplete( iClientStatusNotifyIaChange, aStatus );
+        iClientStatusNotifyIaChange = NULL;
+        iClientIaNotify = NULL;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// Cancels data transfer.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoCancelDataTransfer()
+    {
+    iReceiver->Cancel();
+    iDataInterface.StopReceive();
+    DoEmptySendQueue();
+    iSender->Cancel();
+    }
+
+// ---------------------------------------------------------------------------
+// Empties send queue.
+// ---------------------------------------------------------------------------
+//
+void CIkev1PluginSession::DoEmptySendQueue()
+    {
+    while ( iSendQueue.Count() )
+        {
+        TIkeSendQueueItem item = iSendQueue[0];
+        HBufC8* udpData = item.UdpData();
+        iSendQueue.Remove(0);
+        delete udpData;
+        udpData = NULL;
+        }    
+    }
+