diff -r 000000000000 -r 164170e6151a wim/WimServer/src/WimApduImpl.cpp --- /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( 1 ); + //Reserve space for each possible reader. + iReaderComm->SetReserveL( KMaxReaderCount ); + iReaderNames = new( ELeave ) CArrayFixFlat( 1 ); + //Reserve space for each possible reader. + iReaderNames->SetReserveL( KMaxReaderCount ); + iServer = RScard::NewL(); + iResponseBuffer = HBufC8::NewL( KMaxApduLen ); + iWimScardListenerArray = new( ELeave ) CArrayPtrFlat(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* readerNames = NULL; + CArrayFixFlat* 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( KMaxReaderCount ); + groupNames = + new( ELeave ) CArrayFixFlat( 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& 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