--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wim/WimServer/src/WimApduImpl.cpp Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,645 @@
+/*
+* Copyright (c) 2003 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: Apdu handling between WimServer and Scard
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "WimApduImpl.h"
+#include "WimConsts.h" // Error codes
+#include "WimDefs.h"
+#include "ScardBase.h"
+#include "ScardConnectionRequirement.h"
+#include "ScardComm.h"
+#include "ScardReaderQuery.h"
+#include "WimUtilityFuncs.h"
+#include "WimTrace.h"
+
+//APDU for retrieving response from WIM-card.
+TUint8 iResponseAPDU[] = {0x80, 0xc0, 0x00, 0x00, 0x00};
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+CWimApdu::CWimApdu() : CActive( EPriorityStandard )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::CWimApdu | Begin"));
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CWimApdu* CWimApdu::NewL()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::NewL | Begin"));
+ CWimApdu* self = new( ELeave ) CWimApdu();
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CWimApdu::ConstructL()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::ConstructL | Begin"));
+ CActiveScheduler::Add( this );
+ iReaderComm = new( ELeave ) CArrayFixFlat<CScardComm*>( 1 );
+ //Reserve space for each possible reader.
+ iReaderComm->SetReserveL( KMaxReaderCount );
+ iReaderNames = new( ELeave ) CArrayFixFlat<TScardReaderName>( 1 );
+ //Reserve space for each possible reader.
+ iReaderNames->SetReserveL( KMaxReaderCount );
+ iServer = RScard::NewL();
+ iResponseBuffer = HBufC8::NewL( KMaxApduLen );
+ iWimScardListenerArray = new( ELeave ) CArrayPtrFlat<CWimScardListener>(1);
+ }
+
+// Destructor
+CWimApdu::~CWimApdu()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::~CWimApdu | Begin"));
+
+ Cancel();
+ delete iResponseBuffer;
+ delete iReaderNames;
+
+ if ( iReaderComm )
+ {
+ for ( TUint8 i( 0 ); i < iReaderComm->Count(); i++ )
+ {
+ delete (*iReaderComm)[i];
+ (*iReaderComm)[i] = 0;
+ }
+ delete iReaderComm;
+ }
+
+ delete iServer;
+
+ if ( iWimScardListenerArray )
+ {
+ iWimScardListenerArray->ResetAndDestroy();
+ delete iWimScardListenerArray;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::RequestList
+// List readers and get cababilities of each card
+// -----------------------------------------------------------------------------
+//
+TUint8 CWimApdu::RequestListL()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::RequestListL | Begin"));
+ CScardReaderQuery* query = NULL; //Class used to list resources
+ //owned by Smart Card Server.
+ CArrayFixFlat<TScardReaderName>* readerNames = NULL;
+ CArrayFixFlat<TScardReaderName>* groupNames = NULL;
+ TInt8 position = 0;
+ TInt error;
+
+ //Reset member data associated with query data.
+ iReaderStatusLength = 0;
+ iReaderStatusses.Delete( 0, KMaxReaderCount );
+ iReaderStatusses.Zero();
+
+ TUint8 i;
+ for ( i = 0; i < iReaderComm->Count(); i++ )
+ {
+ delete (*iReaderComm)[i];
+ (*iReaderComm)[i] = NULL;
+ }
+ iReaderComm->Delete( 0, iReaderComm->Count() );
+ iReaderNames->Delete( 0, iReaderNames->Count() );
+
+ TRAP(
+ error,
+ query = CScardReaderQuery::NewL();
+ readerNames =
+ new( ELeave ) CArrayFixFlat<TScardReaderName>( KMaxReaderCount );
+ groupNames =
+ new( ELeave ) CArrayFixFlat<TScardReaderName>( KMaxReaderCount );
+ query->ListGroupsL( groupNames )
+ );
+
+ if ( error )
+ {
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ iResponseStatus = KWimApduNoMemory;
+
+ //any return value <> 0 means error by WIMlib specs
+ return KWimStatusIOError;
+ }
+
+ // Get readers from all groups and add them to readerNames.
+ for ( i = 0; i < groupNames->Count(); i++ )
+ {
+ //Get reader names from this group.
+ TRAP( error, query->ListReadersL( readerNames, (*groupNames)[i] ) );
+
+ if ( error )
+ {
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ iResponseStatus = KWimApduNoMemory;
+
+ return KWimStatusIOError;
+ }
+
+ //Add all reader names found from this group to iReaderNames.
+ for ( TInt8 k = 0; k < readerNames->Count(); k++ )
+ {
+ //Should do something if maxreadernames == readerNames->Count()!
+ TRAP( error, iReaderNames->AppendL( (*readerNames)[k] ) );
+
+ if ( error )
+ {
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ iResponseStatus = KWimApduNoMemory;
+
+ return KWimStatusIOError;
+ }
+ position++;
+ }
+ }
+
+ //Create CScardComm object for each found reader.
+ for ( TUint8 j = 0; j < iReaderNames->Count(); j++ )
+ {
+ TBuf8<1> tempStatus; //Buffer used to hold 1 status byte.
+ TScardConnectionRequirement rest; //Connection requirements used in
+ //the creation of CScardComm object.
+ TScardReaderName name;
+
+ CScardComm* tempComm = NULL;
+ //Set rest to explicit value (name of the current reader) and
+ //create CScardComm according to these values. Also check that
+ //the found reader name (name) is really what we were looking for
+ //(is this needed?). If everything is ok, add created CScardComm
+ //to iReaderComm, else NULL.
+ iStatus = KRequestPending;
+ TRAP( error,
+ rest.SetExplicitL( (*iReaderNames)[j] );
+ tempComm = CScardComm::NewL( iServer, rest, name, iStatus )
+ );
+
+ SetActiveAndWait();
+
+ if ( error || iStatus.Int() != KErrNone || ( name != (*iReaderNames)[j] ) )
+ {
+ iReaderComm->AppendL( NULL );
+ _WIMTRACE2(_L("WIM | WIMServer | CWimApdu::RequestListL | CScardComm::NewL leaved with %d"), error);
+
+ delete tempComm;
+ tempComm = NULL;
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ User::Leave ( KErrHardwareNotAvailable );
+ }
+ else //all ok.
+ {
+ TRAP( error,
+ iReaderComm->AppendL( tempComm )
+ );
+
+ if ( error )
+ {
+ delete tempComm;
+ tempComm = NULL;
+ iReaderComm->AppendL( NULL );
+ }
+ else //all ok.
+ {
+ //Get capabilities of the card. With this value GetCapabilities
+ //puts status to tempStatus.
+ TRAP( error,
+ (*iReaderComm)[j]->GetCapabilitiesL( KCardStatus,
+ tempStatus ) );
+ _WIMTRACE3(_L("WIM | WIMServer | CWimApdu::RequestListL | GetCapabilitiesL error = %d, Card status = %d"), error, (TUint8)*tempStatus.Ptr());
+ _WIMTRACE2(_L("WIM|WIMServer|CWimApdu::RequestListL|tempStatus.Size() = %d"), tempStatus.Size());
+
+ if ( error == KErrNoMemory )
+ {
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ iResponseStatus = KWimApduNoMemory;
+ return ( TUint8 )KErrCouldNotConnect;
+ }
+
+ else if ( error == KErrNone && tempStatus.Size() && *tempStatus.Ptr() )
+ {
+ iReaderStatusLength++;
+ iReaderStatusses.Append( tempStatus );
+ _WIMTRACE(_L("WIM|WIMServer|CWimApdu::RequestListL|Reader status appended"));
+ } //else if
+ else
+ {
+ _WIMTRACE2(_L("WIM|WIMServer|CWimApdu::RequestListL|Leave with error %d"), error);
+ User::Leave( error );
+ }
+ } //else
+ } //else
+ } //for
+
+ //Add Listeners to readers
+ for ( TInt y = 0; y < iReaderNames->Count(); y++ )
+ {
+ CWimScardListener* wimScardListener;
+ TRAP( error, wimScardListener = CWimScardListener::NewL( iServer,
+ ( TUint8 )y, iReaderNames->At( y ) ) );
+ iWimScardListenerArray->AppendL( wimScardListener );
+ }
+
+ iResponseStatus = KWimApduOk;
+
+ delete query;
+ readerNames->Reset();
+ delete readerNames;
+ groupNames->Reset();
+ delete groupNames;
+
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::Open
+// Open connection to Scard
+// -----------------------------------------------------------------------------
+//
+TUint8 CWimApdu::Open( TUint8 aUiReaderId )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::Open | Begin"));
+
+ if ( !iServer ) //No Scard
+ {
+ TRAPD( error, iServer = RScard::NewL() );
+
+ if ( error != KErrNone )
+ {
+ iResponseStatus = KWimApduTransmiossionError;
+ return KWimStatusIOError;
+ }
+ }
+
+ //If aUiReaderId is valid and connection to reader is not opened...
+ if ( ( aUiReaderId < iReaderComm->Count() ) &&
+ ( (*iReaderComm)[aUiReaderId] == 0 ) )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::Open | Reader not opened"));
+ //...open connection, try to find the reader with name
+ //specified in iReaderNames.
+ TScardConnectionRequirement rest;
+ TScardReaderName name;
+ iStatus = KRequestPending;
+
+ TRAPD( error,
+ rest.SetExplicitL( (*iReaderNames)[aUiReaderId] );
+ (*iReaderComm)[aUiReaderId] =
+ CScardComm::NewL( iServer, rest, name, iStatus ) );
+
+ SetActiveAndWait();
+
+ _WIMTRACE3(_L("WIM | WIMServer | CWimApdu::Open | Error=%d, iStatus=%d"),
+ error, iStatus.Int());
+
+ if ( error == KErrNone && iStatus.Int() == KErrNone )
+ {//Add listener to opened reader and append it to array.
+ CWimScardListener* wimScardListener;
+ TRAP( error,
+ wimScardListener = CWimScardListener::NewL( iServer,
+ aUiReaderId,
+ name );
+ iWimScardListenerArray->AppendL( wimScardListener );
+ );
+ }
+
+ if ( error == KErrNoMemory || iStatus.Int() == KErrNoMemory )
+ {
+ iResponseStatus = KWimApduNoMemory;
+ return ( TUint8 )KWimCardDriverInitError;
+ }
+ else if ( error || name != (*iReaderNames)[aUiReaderId]
+ || iStatus.Int() != KErrNone )
+ {
+ iResponseStatus = KWimApduTransmiossionError;
+ return KWimStatusIOError;
+ }
+ else
+ {
+ iResponseStatus = KWimApduOk;
+ return KWimStatusOK; //WIMSTA_OK;
+ }
+ }
+ else
+ {
+ iResponseStatus = KWimApduOk;
+ return KWimStatusOK; //WIMSTA_OK;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::Close
+// Close connection to card
+// -----------------------------------------------------------------------------
+//
+TUint8 CWimApdu::Close( TUint8 aUiReaderId )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::Close | Begin"));
+
+ if ( ( aUiReaderId < iReaderComm->Count() ) &&
+ ( (*iReaderComm)[aUiReaderId] != 0 ) )
+ {
+ delete (*iReaderComm)[aUiReaderId];
+ (*iReaderComm)[aUiReaderId] = 0;
+ }
+
+ if ( iWimScardListenerArray->Count() > aUiReaderId )
+ {
+ delete iWimScardListenerArray->At( aUiReaderId );
+ iWimScardListenerArray->Delete( aUiReaderId );
+ }
+ iResponseStatus = KWimApduOk;
+ return KWimStatusOK; //WIMSTA_OK;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::SendAPDU
+// Send APDU to card
+// -----------------------------------------------------------------------------
+//
+TUint8 CWimApdu::SendAPDU(
+ TUint8 aUiReaderId,
+ TUint8* aApdu,
+ TUint16 aUiApduLength )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SendAPDU | Begin"));
+ //clean SW
+ iResponseSW = 0;
+ TPtr8 responsePtr = iResponseBuffer->Des();
+ //clean buffer
+ responsePtr.Zero();
+ if ( ( aUiReaderId < iReaderComm->Count() ) &&
+ ( (*iReaderComm)[ aUiReaderId ] != 0 ) )
+ {
+ iUiReaderId = aUiReaderId;
+
+ iStatus = KRequestPending;
+ //If apdu to be sent was ManageChannel,
+ //use CScardComms ManageChannel function.
+ if ( ( aUiApduLength >= 4 ) && ( aApdu[1] == KManageChannelIns ) )
+ {
+ switch ( aApdu[2] )
+ {
+ case KManageChannelParamOpen:
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SendAPDU | OPEN CHANNEL"));
+ //Last parameter is timeout. No timeout used.
+ (*iReaderComm)[aUiReaderId]->ManageChannel(
+ EOpenAnyChannel, aApdu[3], responsePtr, iStatus, 0 );
+ break;
+ }
+ case KManageChannelParamClose:
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SendAPDU | CLOSE CHANNEL"));
+ // Check whether state of the SIM/SWIM is OK
+ if ( CWimUtilityFuncs::SimState() != KErrNone )
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SendAPDU | SIM not ready"));
+ // SIM/SWIM not OK, just return KWimStatusOK to WimLib
+ // so WimLib can continue properly
+ return KWimStatusOK;
+ }
+ else // Card OK, close the opened channel
+ {
+ // Close channel with 5 second timeout
+ (*iReaderComm)[aUiReaderId]->ManageChannel(
+ ECloseChannel,
+ aApdu[3],
+ responsePtr,
+ iStatus,
+ KDefaulCloseChannelTimeout );
+ }
+ break;
+ }
+ default: // APDU is not valid.
+ {
+ iResponseStatus = KWimApduFormatError;
+ return KWimStatusOK; //WIMSTA_OK;
+ //break; //unreachable
+ }
+ }
+ }
+ else
+ {
+ TPtrC8 commandAPDU( aApdu, aUiApduLength );
+
+ //Transmit APDU to card.
+ (*iReaderComm)[aUiReaderId]->TransmitToCard( commandAPDU,
+ responsePtr, iStatus, 0, (TUint8)( aApdu[0] & 0x0f ) );
+
+ }
+ SetActiveAndWait(); // Wait APDU response
+
+ if ( iStatus != KErrNone )
+ {
+ iResponseStatus = KWimApduTransmiossionError;
+ responsePtr.SetLength( 0 );
+ return KWimStatusIOError;
+ }
+
+ if ( responsePtr.Size() >= 2 ) //At least SW-bytes are needed (2 of'em).
+ {
+ //Response has to be retrieved.
+ if ( responsePtr[responsePtr.Size() - 2] == 0x61 )
+ {
+ iStatus = KRequestPending;
+ iResponseAPDU[0] = aApdu[0];
+ iResponseAPDU[4] = responsePtr[responsePtr.Size() - 1];
+ TPtrC8 commandAPDU( iResponseAPDU, 5 );
+
+ //Transmit APDU to card. Timeout not used.
+ (*iReaderComm)[aUiReaderId]->TransmitToCard( commandAPDU,
+ responsePtr, iStatus, 0, (TUint8)( aApdu[0] & 0x0f ) );
+
+ SetActiveAndWait(); // Wait APDU response
+
+ if ( iStatus != KErrNone )
+ {
+ iResponseStatus = KWimApduTransmiossionError;
+ responsePtr.SetLength( 0 );
+ return KWimStatusIOError;
+ }
+
+ //At least SW-bytes are needed (2 of them).
+ else if ( responsePtr.Size() < 2 )
+ {
+ iResponseStatus = KWimApduFormatError;
+ responsePtr.SetLength( 0 );
+ return KWimStatusOK;
+ }
+ }
+ iResponseStatus = KWimApduOk;
+ iResponseSW =
+ ( TUint16 )( ( responsePtr[responsePtr.Size() - 2] << 8 )
+ | ( responsePtr[responsePtr.Size() - 1] ) );
+
+ responsePtr.SetLength( responsePtr.Size() - 2 );//All but SW-bytes.
+ return KWimStatusOK;
+ }
+ else
+ {
+ iResponseStatus = KWimApduFormatError;
+ responsePtr.SetLength( 0 );
+ return KWimStatusOK; //WIMSTA_OK;
+ }
+ }
+ else
+ {
+ //Not valid card.
+ iResponseStatus = KWimApduReaderNotValid;
+ responsePtr.SetLength( 0 );
+ return KWimStatusOK; //WIMSTA_OK;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::ResponseApdu
+// Return response APDU
+// -----------------------------------------------------------------------------
+//
+TPtrC8 CWimApdu::ResponseApdu() const
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::ResponseApdu | Begin"));
+ return iResponseBuffer->Des();
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::ResponseSW
+// Return Response SW
+// -----------------------------------------------------------------------------
+//
+TUint16 CWimApdu::ResponseSW() const
+ {
+ _WIMTRACE2(_L("WIM | WIMServer | CWimApdu::ResponseSW | iResponse = %04x"),
+ iResponseSW );
+ return iResponseSW;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::StatusList
+// Return reader statusses
+// -----------------------------------------------------------------------------
+//
+const TBuf8<KMaxReaderCount>& CWimApdu::StatusList() const
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::StatusList | Begin"));
+ return iReaderStatusses;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::StatusListLength
+// Return status list length
+// -----------------------------------------------------------------------------
+//
+TUint8 CWimApdu::StatusListLength() const
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::StatusListLength | Begin"));
+ return iReaderStatusLength;
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::RunL
+// Stop ActiveSchedulerWait after APDU response
+// -----------------------------------------------------------------------------
+//
+void CWimApdu::RunL()
+ {
+ _WIMTRACE2(_L("WIM | WIMServer | CWimApdu::RunL, status: %d"), iStatus.Int());
+ iWait.AsyncStop();
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::DoCancel
+// Cancel asyncronous request
+// -----------------------------------------------------------------------------
+//
+void CWimApdu::DoCancel()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::DoCancel | Begin"));
+ (*iReaderComm)[iUiReaderId]->CancelTransmit();
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::DoCancel | End"));
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::SetActiveAndWait
+// Wait until asynchronous call is completed
+// -----------------------------------------------------------------------------
+//
+void CWimApdu::SetActiveAndWait()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SetActiveAndWait | Begin"));
+ SetActive();
+ iWait.Start();
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::SetActiveAndWait | End"));
+ }
+
+// -----------------------------------------------------------------------------
+// CWimApdu::CancelApduSending
+// -----------------------------------------------------------------------------
+//
+void CWimApdu::CancelApduSending()
+ {
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::CancelApduSending | Begin"));
+ if( IsActive() )
+ {
+ Cancel();
+ }
+ _WIMTRACE(_L("WIM | WIMServer | CWimApdu::CancelApduSending | End"));
+ }
+
+// End of File