vpnengine/ikeutils/src/pfkeysocketif.cpp
changeset 0 33413c0669b9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikeutils/src/pfkeysocketif.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,423 @@
+/*
+* 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:  Implementation of VPN PFKEY socket interface
+*
+*/
+
+
+#include <es_sock.h>
+#include <in_sock.h>
+#include <eikenv.h>
+#include <pfkey_send.h>
+#include <random.h>
+#include "pfkeysocketif.h"
+#include "pfkeymsg.h"
+#include "ipsecsadata.h"
+#include "ipsecsalifetime.h"
+#include "ikedebug.h"
+
+const TInt KDefaultPID( 0x2001E609 ); // UID3 of ikeutils.dll
+
+// ======== MEMBER FUNCTIONS ========
+
+EXPORT_C CPFKeySocketIf* CPFKeySocketIf::NewL( MPFKeyMessageListener* aListener,
+                                               MIkeDebug& aDebug )
+    {
+    CPFKeySocketIf* reader = new ( ELeave ) CPFKeySocketIf( aListener, aDebug );
+    CleanupStack::PushL( reader );
+    reader->ConstructL();
+    CleanupStack::Pop( reader );        
+    return reader;
+    }
+
+//
+// CPFKeySocketIf::~CPFKeySocketIf
+//
+CPFKeySocketIf::~CPFKeySocketIf()
+    {
+    Cancel();
+    iPendingSpiRequests.Close();
+    iSadb.Close();
+    iSocketServer.Close();
+    }
+
+//
+// CPFKeySocketIf::CPFKeySocketIf
+//
+CPFKeySocketIf::CPFKeySocketIf( MPFKeyMessageListener* aListener,
+                                MIkeDebug& aDebug )
+: CActive( EPriorityNormal ),
+  iListener( aListener ),
+  iSeq( 0 ),
+  iDebug( aDebug )
+    {
+    CActiveScheduler::Add( this );
+    }
+    
+//
+// CPFKeySocketIf::ConstructL()
+// Open and activate the socket input
+//
+void CPFKeySocketIf::ConstructL()
+    {   
+    TPtr8 ptr( (TUint8*)&iSpiBase, sizeof( iSpiBase ) );
+    ptr.SetLength( sizeof( iSpiBase ) );
+    TRandom::RandomL( ptr );
+    iSpiBase &= 0x7fffffff;
+    
+    User::LeaveIfError( iSocketServer.Connect() ); 
+    User::LeaveIfError( iSadb.Open( iSocketServer ) );
+
+    //
+    // Register for ACQUIRE messages
+    //
+    TPfkeySendMsg reg( SADB_REGISTER, SADB_SATYPE_ESP, ++iSeq, KDefaultPID );
+    TRequestStatus status;
+	iSadb.FinalizeAndSend( reg, status );
+    User::WaitForRequest( status );
+    DEBUG_LOG1( _L("Register for ESP, status=%d"), iStatus.Int() );
+    
+    iMsg.Reset();
+    iSadb.ReadRequest( iMsg, iStatus );
+    SetActive();
+    }
+    
+    
+void CPFKeySocketIf::GetSpi( const TUint8 aType,
+                             const TUint32 aSeq,
+                             const TInetAddr& aSrc,
+                             const TInetAddr& aDst,
+                             TUint32& aSpi,
+                             TRequestStatus& aClientStatus)
+    {
+    /*Params:
+            aType:SADB_SATYPE_AH,SADB_SATYPE_ESP from prop_II
+            aSeq: Seq number for the message
+            aSrc,aDst: Src & dst addresses
+    */
+    TRequestStatus status;
+    TUint32 start = NewSpi();
+
+	TPfkeySendMsg msg( SADB_GETSPI, aType, aSeq, (TUint32)&aClientStatus );
+    msg.Add( Int2Type<SADB_EXT_ADDRESS_SRC>(), aSrc );
+    msg.Add( Int2Type<SADB_EXT_ADDRESS_DST>(), aDst );
+    msg.Add( Int2Type<SADB_EXT_SPIRANGE>(), start );
+    
+    aClientStatus = KRequestPending;
+    TPendingSpiRequest pendingSpiRequest(aSpi, aClientStatus);
+    TInt err = iPendingSpiRequests.Append(pendingSpiRequest);
+    
+    if (err == KErrNone)
+        {
+        iSadb.FinalizeAndSend( msg, status );
+        User::WaitForRequest( status );
+        }
+    else
+        {
+        TRequestStatus* status = &aClientStatus;
+        User::RequestComplete(status, err);
+        }
+    }
+
+
+void CPFKeySocketIf::CancelGetSpi(TRequestStatus& aClientStatus)
+    {
+    for (TInt i = 0; i < iPendingSpiRequests.Count(); ++i)
+        {
+        TPendingSpiRequest& pendingSpiRequest = iPendingSpiRequests[i];
+        if (&pendingSpiRequest.iClientStatus == &aClientStatus)
+            {
+            pendingSpiRequest.iSpi = 0;
+            TRequestStatus* status = &pendingSpiRequest.iClientStatus;
+            iPendingSpiRequests.Remove(i);
+            User::RequestComplete(status, KErrCancel);
+            break;
+            }
+        }
+    }
+
+
+// Sends Acquire with errno informing about key management failure.
+EXPORT_C void CPFKeySocketIf::AcquireSAError( const TIpsecSAData& aSAData,
+                                              const TInt aError )
+ 	 {
+     TRequestStatus status;
+     TInt err = -aError;
+     TPfkeySendMsg msg( SADB_ACQUIRE,
+                        aSAData.iSAType,
+                        aSAData.iSeq,
+                        aSAData.iPid );
+
+     struct sadb_msg& msgHdr = msg.MsgHdr();
+     msgHdr.sadb_msg_errno = (TUint8) err;
+     msgHdr.sadb_msg_reserved = (TUint16) ( err>>8 );
+     
+     msg.Add( Int2Type<SADB_EXT_SA>(), aSAData.iSPI );
+     msg.Add( Int2Type<SADB_EXT_ADDRESS_DST>(), aSAData.iDst );     
+     iSadb.FinalizeAndSend( msg, status );
+     User::WaitForRequest( status );
+ 	 }
+
+EXPORT_C void CPFKeySocketIf::UpdateSAL( const TIpsecSAData& aSAData )
+    {
+    AddUpdateSAL( SADB_UPDATE, aSAData );
+    }
+
+EXPORT_C void CPFKeySocketIf::AddSAL( const TIpsecSAData& aSAData )
+    {
+    AddUpdateSAL( SADB_ADD, aSAData );
+    }
+
+EXPORT_C void CPFKeySocketIf::DeleteSA( const TUint32 aSPI,
+                                        const TInetAddr& aSrc,
+                                        const TInetAddr& aDst,
+                                        const TUint8 aProtocol )
+    {
+    TRequestStatus status;
+	TPfkeySendMsg msg( SADB_DELETE,
+	                   aProtocol );
+	msg.Add( Int2Type<SADB_EXT_SA>(), aSPI );
+	msg.Add( Int2Type<SADB_EXT_ADDRESS_SRC>(), aSrc );
+	msg.Add( Int2Type<SADB_EXT_ADDRESS_DST>(), aDst );
+	iSadb.FinalizeAndSend( msg, status );
+	User::WaitForRequest( status );
+    }
+
+EXPORT_C void CPFKeySocketIf::FlushSAs()
+    {
+    TRequestStatus status;
+	TPfkeySendMsg msg( SADB_FLUSH,
+	                   SADB_SATYPE_UNSPEC,
+	                   ++iSeq,
+	                   KDefaultPID );
+	iSadb.FinalizeAndSend( msg, status );
+    User::WaitForRequest( status );
+	DEBUG_LOG1( _L("Request FLUSH, iStatus=%d"), iStatus.Int() );	    
+    }
+
+//Updates an SA from the SA database.
+//SPI in Net order.
+void CPFKeySocketIf::AddUpdateSAL( const TUint8 aType,
+                                   const TIpsecSAData &aSAData )
+    {
+    TRequestStatus status;
+    TPfkeySendMsg* msg = new( ELeave ) TPfkeySendMsg( aType,
+                                                      aSAData.iSAType,
+                                                      aSAData.iSeq,
+                                                      aSAData.iPid );
+    msg->Add( Int2Type<SADB_EXT_SA>(),
+              aSAData.iSPI,
+              aSAData.iAuthAlg,
+              aSAData.iEncrAlg,
+              SADB_SASTATE_MATURE,
+              aSAData.iReplayWindowLength,
+              aSAData.iFlags );
+    
+    if( aSAData.iHard )
+        {
+        msg->Add( Int2Type<SADB_EXT_LIFETIME_HARD>(), 
+                  aSAData.iHard->iAllocations, 
+                  aSAData.iHard->iBytes, 
+                  aSAData.iHard->iAddtime, 
+                  aSAData.iHard->iUsetime);
+        }
+    if( aSAData.iSoft )
+        {
+        msg->Add( Int2Type<SADB_EXT_LIFETIME_SOFT>(),
+                  aSAData.iSoft->iAllocations, 
+                  aSAData.iSoft->iBytes, 
+                  aSAData.iSoft->iAddtime,
+                  aSAData.iSoft->iUsetime);
+        }
+    msg->Add( Int2Type<SADB_EXT_ADDRESS_SRC>(),
+              aSAData.iSrc,
+              aSAData.iProtocol );
+    msg->Add( Int2Type<SADB_EXT_ADDRESS_DST>(),
+              aSAData.iDst,
+              aSAData.iProtocol );
+    
+    // Deliver internal address for IPSEC4 
+    if ( aSAData.iFlags & SADB_SAFLAGS_INT_ADDR )
+       msg->Add( Int2Type<SADB_EXT_ADDRESS_PROXY>(),
+                 aSAData.iInternalAddress );
+    
+    if ( aSAData.iAuthKey.Length() > 0 )
+        {
+        msg->Add( Int2Type<SADB_EXT_KEY_AUTH>(),
+                  aSAData.iAuthKey );
+        }
+    if ( aSAData.iEncrKey.Length() > 0 )
+        {
+        msg->Add( Int2Type<SADB_EXT_KEY_ENCRYPT>(),
+                  aSAData.iEncrKey );
+        }
+    if ( aSAData.iSrcIdent.Length() > 0 )
+        {
+        msg->Add( Int2Type<SADB_EXT_IDENTITY_SRC>(),
+                  aSAData.iSrcIdent,
+                  aSAData.iSrcIdType );
+        }
+    if ( aSAData.iDstIdent.Length() > 0 )
+        {
+        msg->Add( Int2Type<SADB_EXT_IDENTITY_DST>(),
+                  aSAData.iDstIdent,
+                  aSAData.iDstIdType );
+        }
+
+    // Deliver generic private PFKEY API extension, if exist.
+    // In this phase extension can consists NAT traversal information for ESP UDP encapsulation (done by IPSEC)
+    if ( aSAData.iGenericExtension.Length() )
+        {
+        msg->Add( Int2Type<SADB_PRIV_GENERIC_EXT>(),
+                  aSAData.iGenericExtension );
+        }
+    
+    iSadb.FinalizeAndSend( *msg, status );
+    User::WaitForRequest( status );
+    delete msg;
+    }
+
+TUint32 CPFKeySocketIf::NewSpi()
+    {
+    iSpiBase++;
+    return iSpiBase;
+    }
+
+//
+// SocketReader::ShowMessage
+//  Output actual "payload" messages (e.g. PFKEY)
+//
+#ifdef _DEBUG       
+void CPFKeySocketIf::ShowMessageL( TPfkeyRecvMsg &aMsg )
+    {
+    HBufC* buffer = HBufC::NewL( 1000 );
+    TPtr str( buffer->Des() );
+    TPfkeyMessage msg( aMsg );
+
+    if ( msg.iError )
+        {
+        str.Format( _L("Received malformed PFKEY msg of %d bytes: %d\n"),
+                aMsg.Length(), msg.iError );
+        }   
+    else
+        {
+        msg.iBase.String( str, _L(" ") );
+        msg.iSa.String( str, _L(" ") );
+        msg.iCurrent.String( str, _L(" C=") );
+        msg.iHard.String( str, _L(" H=") );
+        msg.iSoft.String( str, _L(" S=") );
+        msg.iSrcAddr.String( str, _L(" SRC=") );
+        msg.iDstAddr.String( str, _L(" DST=") );
+        msg.iProxyAddr.String( str, _L(" PROXY=") );
+        msg.iAuthKey.String( str, _L(" AUTHKEY=") );
+        msg.iEncryptKey.String( str, _L(" ENCRYPTKEY=") );
+        msg.iSrcIdent.String( str, _L(" SRCI=") );
+        msg.iDstIdent.String( str, _L(" DSTI=") );
+        msg.iSensitivity.String( str, _L(" SENS=") );
+        msg.iProposal.String( str, _L(" PROP=") );
+        msg.iAuthAlgs.String( str, _L(" AUTH=") );
+        msg.iEncryptAlgs.String( str, _L(" ENCR=") );
+        msg.iSpirange.String( str, _L(" SPIR=") );
+        msg.iTs.String( str, _L(" TS=") );
+        msg.iPrivateExtension.String( str, _L(" GEN_EXT=") );
+        }
+    DEBUG_LOG( str );
+    
+    delete buffer;
+    buffer = NULL;
+    }
+#endif    
+
+//
+// CPFKeySocketIf::RunL
+//  Called when request completed
+//
+void CPFKeySocketIf::RunL()
+    {
+    if ( iStatus.Int() != KErrNone )
+        {
+        DEBUG_LOG1( _L("Socket read, iStatus=%d"), iStatus.Int() );    
+        }
+
+#ifdef _DEBUG    
+    TRAP_IGNORE( ShowMessageL( iMsg ) );
+#endif    
+            
+    TPfkeyMessage msg(iMsg);
+    if ( ( msg.iError == KErrNone ) &&
+         ( msg.iBase.iMsg->sadb_msg_errno == KErrNone ) ) // No error
+        {
+        switch ( msg.iBase.iMsg->sadb_msg_type )
+            {
+            case SADB_GETSPI:
+                for (TInt i = 0; i < iPendingSpiRequests.Count(); ++i)
+                    {
+                    TPendingSpiRequest& pendingSpiRequest = iPendingSpiRequests[i];
+                    if ((TUint32)&pendingSpiRequest.iClientStatus == msg.iBase.iMsg->sadb_msg_pid)
+                        {
+                        pendingSpiRequest.iSpi = msg.iSa.iExt->sadb_sa_spi;
+                        TRequestStatus* status = &pendingSpiRequest.iClientStatus;
+                        iPendingSpiRequests.Remove(i);
+                        User::RequestComplete(status, KErrNone);
+                        break;
+                        }
+                    }
+                break;
+            case SADB_ADD:     // Fall through
+            case SADB_UPDATE:  // Fall through
+            case SADB_ACQUIRE: // Fall through
+            case SADB_EXPIRE:  // Fall through               
+                iListener->PfkeyMessageReceived( msg );
+                break;
+
+            default:
+                break;
+            }       
+        }
+    else
+        {   
+        DEBUG_LOG2( _L("Error in Pfkey message, iError=%d, sadb_msg_errno=%d"),
+                iStatus.Int(), msg.iBase.iMsg->sadb_msg_errno );
+        }
+    iMsg.Reset();
+    iSadb.ReadRequest( iMsg, iStatus ); // Start a new read
+    SetActive();
+    }
+
+//
+// CPFKeySocketIf::DoCancel
+//  Called when a pending request should be cancelled
+//
+void CPFKeySocketIf::DoCancel()
+    {
+    iSadb.CancelRecv();
+    }
+
+//
+// CPFKeySocketIf::RunError
+// Called when RunL() leaves 
+//
+TInt CPFKeySocketIf::RunError( TInt aError )
+    {
+    DEBUG_LOG1( _L("CPFKeySocketIf::RunError() aError=%d, PFKEY message lost"),
+            aError );
+    aError = aError;
+
+    iMsg.Reset();
+    iSadb.ReadRequest( iMsg, iStatus ); // Start a new read. 
+    SetActive();
+    
+    return KErrNone; // Active scheduler Error() method NOT called              
+    }
+