diff -r 000000000000 -r 33413c0669b9 vpnengine/ikev1lib/src/ikev1pluginsession.cpp --- /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 +#include +#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;iiSPIList != 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;iCancelRekey(); + } + + 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;iiHdr.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;iIsExpired()) ) + { + return sa; + } + } + return NULL; + } + +CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TCookie& aCookie_I, + const TCookie& aCookie_R ) + { + for ( TInt i=0;iiHdr.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;iiHdr.iSAId == aSaId) && + (!sa->IsExpired()) ) + { + return sa; + } + } + return NULL; + } + +CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TInetAddr& aAddr ) + { + for ( TInt i=0;iiHdr.iRemoteAddr.Match(aAddr) && + (!sa->IsExpired()) ) + { + return sa; + } + } + return NULL; + } + +CIkev1SA* CIkev1PluginSession::FindIkev1SA( const TInetAddr& aAddr, + TUint32 aInboundSpi ) + { + for ( TInt i=0;iiHdr.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 . + length += NON_ESP_MARKER_SIZE; + } + HBufC8* ikeMsg = HBufC8::NewL( length ); + TPtr8 ptr = ikeMsg->Des(); + if ( localPort == IkeSocket::KIkePort4500 ) + { + // Append 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;iIsExpired() ) + { + 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; + } + } +