/*++ Copyright (c) 1998 SCM Microsystems, Inc. Module Name: StcCb.c Abstract: Declaration of callback functions - WDM Version Revision History: PP 1.01 01/19/1998 PP 1.00 12/18/1998 Initial Version --*/ // Include #include "common.h" #include "stccmd.h" #include "stccb.h" #include "stcusbnt.h" #include "usbcom.h" NTSTATUS CBCardPower( PSMARTCARD_EXTENSION SmartcardExtension) /*++ CBCardPower: callback handler for SMCLIB RDF_CARD_POWER Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_BUFFER_TOO_SMALL --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; UCHAR ATRBuffer[ ATR_SIZE ]; ULONG Command, ATRLength; PREADER_EXTENSION ReaderExtension; KIRQL irql; SmartcardDebug( DEBUG_TRACE, ("%s!CBCardPower Enter\n",DRIVER_NAME )); ReaderExtension = SmartcardExtension->ReaderExtension; // discard old ATR SysFillMemory( SmartcardExtension->CardCapabilities.ATR.Buffer, 0x00, 0x40 ); SmartcardExtension->CardCapabilities.ATR.Length = 0; SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; Command = SmartcardExtension->MinorIoControlCode; switch ( Command ) { case SCARD_WARM_RESET: // if the card was not powerd, fall through to cold reset KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); if( SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_SWALLOWED ) { KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); // reset the card ATRLength = ATR_SIZE; NTStatus = STCReset( ReaderExtension, 0, // not used: ReaderExtension->Device, TRUE, // warm reset ATRBuffer, &ATRLength); break; } else { KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); } // warm reset not possible because card was not powerd case SCARD_COLD_RESET: // reset the card ATRLength = ATR_SIZE; NTStatus = STCReset( ReaderExtension, 0, // not used: ReaderExtension->Device, FALSE, // cold reset ATRBuffer, &ATRLength); break; case SCARD_POWER_DOWN: // discard old card status ATRLength = 0; NTStatus = STCPowerOff( ReaderExtension ); if(NTStatus == STATUS_SUCCESS) { KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_PRESENT; KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); } break; } // finish the request if( NTStatus == STATUS_SUCCESS ) { // update all neccessary data if an ATR was received if( ATRLength >= 2 ) { // copy ATR to user buffer if( ATRLength <= SmartcardExtension->IoRequest.ReplyBufferLength ) { SysCopyMemory( SmartcardExtension->IoRequest.ReplyBuffer, ATRBuffer, ATRLength); *SmartcardExtension->IoRequest.Information = ATRLength; } else { NTStatus = STATUS_BUFFER_TOO_SMALL; } // copy ATR to card capability buffer if( ATRLength <= MAXIMUM_ATR_LENGTH ) { SysCopyMemory( SmartcardExtension->CardCapabilities.ATR.Buffer, ATRBuffer, ATRLength); SmartcardExtension->CardCapabilities.ATR.Length = ( UCHAR )ATRLength; // let the lib update the card capabilities NTStatus = SmartcardUpdateCardCapabilities( SmartcardExtension ); } else { NTStatus = STATUS_BUFFER_TOO_SMALL; } if( NTStatus == STATUS_SUCCESS ) { // set the stc registers CBSynchronizeSTC( SmartcardExtension ); // set read timeout if( SmartcardExtension->CardCapabilities.Protocol.Selected == SCARD_PROTOCOL_T1 ) { ReaderExtension->ReadTimeout = (ULONG) (SmartcardExtension->CardCapabilities.T1.BWT / 1000); } else { ReaderExtension->ReadTimeout = (ULONG) (SmartcardExtension->CardCapabilities.T0.WT / 1000); if(ReaderExtension->ReadTimeout < 50) { ReaderExtension->ReadTimeout = 50; // 50 ms minimum timeout } } } } } SmartcardDebug( DEBUG_TRACE,( "%s!CBCardPower Exit: %X\n", DRIVER_NAME,NTStatus )); return( NTStatus ); } NTSTATUS CBSetProtocol( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBSetProtocol: callback handler for SMCLIB RDF_SET_PROTOCOL Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_BUFFER_TOO_SMALL STATUS_INVALID_DEVICE_STATE STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_PENDING; UCHAR PTSRequest[5], PTSReply[5]; ULONG NewProtocol; PREADER_EXTENSION ReaderExtension; KIRQL irql; SmartcardDebug( DEBUG_TRACE, ("%s!CBSetProtocol Enter\n",DRIVER_NAME )); ReaderExtension = SmartcardExtension->ReaderExtension; NewProtocol = SmartcardExtension->MinorIoControlCode; // check if the card is already in specific state KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); if( ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC ) && ( SmartcardExtension->CardCapabilities.Protocol.Selected & NewProtocol )) { NTStatus = STATUS_SUCCESS; } KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); // protocol supported? if( !( SmartcardExtension->CardCapabilities.Protocol.Supported & NewProtocol ) || !( SmartcardExtension->ReaderCapabilities.SupportedProtocols & NewProtocol )) { NTStatus = STATUS_INVALID_DEVICE_REQUEST; } // send PTS while( NTStatus == STATUS_PENDING ) { // set initial character of PTS PTSRequest[0] = 0xFF; // set the format character if(( NewProtocol & SCARD_PROTOCOL_T1 )&& (SmartcardExtension->CardCapabilities.Protocol.Supported & SCARD_PROTOCOL_T1 )) { PTSRequest[1] = 0x11; SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T1; } else { PTSRequest[1] = 0x10; SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0; } // PTS1 codes Fl and Dl PTSRequest[2] = SmartcardExtension->CardCapabilities.PtsData.Fl << 4 | SmartcardExtension->CardCapabilities.PtsData.Dl; // check character PTSRequest[3] = PTSRequest[0] ^ PTSRequest[1] ^ PTSRequest[2]; // write PTSRequest NTStatus = IFWriteSTCData( ReaderExtension, PTSRequest, 4 ); // get response if( NTStatus == STATUS_SUCCESS ) { NTStatus = IFReadSTCData( ReaderExtension, PTSReply, 4 ); if(( NTStatus == STATUS_SUCCESS ) && !SysCompareMemory( PTSRequest, PTSReply, 4)) { // set the stc registers SmartcardExtension->CardCapabilities.Dl = SmartcardExtension->CardCapabilities.PtsData.Dl; SmartcardExtension->CardCapabilities.Fl = SmartcardExtension->CardCapabilities.PtsData.Fl; CBSynchronizeSTC( SmartcardExtension ); // the card replied correctly to the PTS-request break; } } // // The card did either NOT reply or it replied incorrectly // so try default values // if( SmartcardExtension->CardCapabilities.PtsData.Type != PTS_TYPE_DEFAULT ) { SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT; SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET; NTStatus = CBCardPower( SmartcardExtension ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = STATUS_PENDING; } else { NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; } } } if( NTStatus == STATUS_TIMEOUT ) { NTStatus = STATUS_IO_TIMEOUT; } if( NTStatus == STATUS_SUCCESS ) { // card replied correctly to the PTS request if( SmartcardExtension->CardCapabilities.Protocol.Selected & SCARD_PROTOCOL_T1 ) { ReaderExtension->ReadTimeout = SmartcardExtension->CardCapabilities.T1.BWT / 1000; } else { ULONG ClockRateFactor = SmartcardExtension->CardCapabilities.ClockRateConversion[SmartcardExtension->CardCapabilities.PtsData.Fl].F; // check for RFU value, and replace by default value if( !ClockRateFactor ) ClockRateFactor = 372; ReaderExtension->ReadTimeout = 960 * SmartcardExtension->CardCapabilities.T0.WI * ClockRateFactor / SmartcardExtension->CardCapabilities.PtsData.CLKFrequency; // We need to have a minimum timeout anyway if(ReaderExtension->ReadTimeout <50) { ReaderExtension->ReadTimeout =50; // 50 ms minimum timeout } } // indicate that the card is in specific mode KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC; KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); // return the selected protocol to the caller *(PULONG) SmartcardExtension->IoRequest.ReplyBuffer = SmartcardExtension->CardCapabilities.Protocol.Selected; *SmartcardExtension->IoRequest.Information = sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected); } else { SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED; *(PULONG) SmartcardExtension->IoRequest.ReplyBuffer = 0; *SmartcardExtension->IoRequest.Information = 0; } SmartcardDebug( DEBUG_TRACE, ("%d!CBSetProtocol: Exit %X\n",DRIVER_NAME, NTStatus )); return( NTStatus ); } NTSTATUS CBGenericIOCTL( PSMARTCARD_EXTENSION SmartcardExtension) /*++ Description: Performs generic callbacks to the reader Arguments: SmartcardExtension context of the call Return Value: STATUS_SUCCESS --*/ { NTSTATUS NTStatus; SmartcardDebug( DEBUG_TRACE, ( "%s!CBGenericIOCTL: Enter\n", DRIVER_NAME)); // // get pointer to current IRP stack location // // // assume error // NTStatus = STATUS_INVALID_DEVICE_REQUEST; // // dispatch IOCTL // switch( SmartcardExtension->MajorIoControlCode ) { case IOCTL_WRITE_STC_REGISTER: NTStatus = IFWriteSTCRegister( SmartcardExtension->ReaderExtension, *(SmartcardExtension->IoRequest.RequestBuffer), // Address (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1)), // Size SmartcardExtension->IoRequest.RequestBuffer + 2); // Data *SmartcardExtension->IoRequest.Information = 1; if(NTStatus == STATUS_SUCCESS) { *(SmartcardExtension->IoRequest.ReplyBuffer) = 0; } else { *(SmartcardExtension->IoRequest.ReplyBuffer) = 1; } break; case IOCTL_READ_STC_REGISTER: NTStatus = IFReadSTCRegister( SmartcardExtension->ReaderExtension, *(SmartcardExtension->IoRequest.RequestBuffer), // Address (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1)), // Size SmartcardExtension->IoRequest.ReplyBuffer); // Data if(NTStatus ==STATUS_SUCCESS) { *SmartcardExtension->IoRequest.Information = (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer + 1)); } else { SmartcardExtension->IoRequest.Information = 0; } break; case IOCTL_WRITE_STC_DATA: NTStatus = IFWriteSTCData( SmartcardExtension->ReaderExtension, SmartcardExtension->IoRequest.RequestBuffer + 1, // Data (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer))); // Size *SmartcardExtension->IoRequest.Information = 1; if(NTStatus == STATUS_SUCCESS) { *(SmartcardExtension->IoRequest.ReplyBuffer) = 0; } else { *(SmartcardExtension->IoRequest.ReplyBuffer) = 1; } break; case IOCTL_READ_STC_DATA: NTStatus = IFReadSTCData( SmartcardExtension->ReaderExtension, SmartcardExtension->IoRequest.ReplyBuffer, // Data (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer))); // Size if(NTStatus ==STATUS_SUCCESS) { *SmartcardExtension->IoRequest.Information = (ULONG)(*(SmartcardExtension->IoRequest.RequestBuffer)); } else { SmartcardExtension->IoRequest.Information = 0; } break; default: break; } SmartcardDebug( DEBUG_TRACE, ( "%s!CBGenericIOCTL: Exit\n", DRIVER_NAME)); return( NTStatus ); } NTSTATUS CBTransmit( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBTransmit: callback handler for SMCLIB RDF_TRANSMIT Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; SmartcardDebug( DEBUG_TRACE, ("%s!CBTransmit Enter\n",DRIVER_NAME )); // dispatch on the selected protocol switch( SmartcardExtension->CardCapabilities.Protocol.Selected ) { case SCARD_PROTOCOL_T0: NTStatus = CBT0Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_T1: NTStatus = CBT1Transmit( SmartcardExtension ); break; case SCARD_PROTOCOL_RAW: NTStatus = CBRawTransmit( SmartcardExtension ); break; default: NTStatus = STATUS_INVALID_DEVICE_REQUEST; break; } SmartcardDebug( DEBUG_TRACE, ("%s!CBTransmit Exit: %X\n",DRIVER_NAME, NTStatus )); return( NTStatus ); } NTSTATUS T0_ExchangeData( PREADER_EXTENSION ReaderExtension, PUCHAR pRequest, ULONG RequestLen, PUCHAR pReply, PULONG pReplyLen) /*++ Routine Description: T=0 management Arguments: ReaderExtension Context of the call pRequest Request buffer RequestLen Request buffer length pReply Reply buffer pReplyLen Reply buffer length Return Value: STATUS_SUCCESS Status returned by IFReadSTCData or IFWriteSTCData --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; BOOLEAN Direction; UCHAR Ins, Pcb = 0; ULONG Len, DataIdx; KPRIORITY PreviousPriority; BOOLEAN PriorityBoost = FALSE; if (ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) { SmartcardDebug( DEBUG_TRACE, ( "%s!T0_ExchangeData: Setting priority: 0x%x\n", DRIVER_NAME, ReaderExtension->Chosen_Priority)); PriorityBoost = TRUE; PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), ReaderExtension->Chosen_Priority); } // get direction Ins = pRequest[ INS_IDX ] & 0xFE; Len = pRequest[ P3_IDX ]; if( RequestLen == 5 ) { Direction = ISO_OUT; DataIdx = 0; // For an ISO OUT command Len=0 means that the host expect an // 256 byte answer if( !Len ) { Len = 0x100; } // Add 2 for SW1 SW2 Len+=2; } else { Direction = ISO_IN; DataIdx = 5; } // send header CLASS,INS,P1,P2,P3 NTStatus = IFWriteSTCData( ReaderExtension, pRequest, 5 ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = STATUS_MORE_PROCESSING_REQUIRED; } while( NTStatus == STATUS_MORE_PROCESSING_REQUIRED ) { // PCB reading NTStatus = IFReadSTCData( ReaderExtension, &Pcb, 1 ); if( NTStatus == STATUS_SUCCESS ) { if( Pcb == 0x60 ) { // null byte? NTStatus = STATUS_MORE_PROCESSING_REQUIRED; continue; } else if( ( Pcb & 0xFE ) == Ins ) { // transfer all if( Direction == ISO_IN ) { // write remaining data NTStatus = IFWriteSTCData( ReaderExtension, pRequest + DataIdx, Len ); if( NTStatus == STATUS_SUCCESS ) { // if all data successful written the status word is expected NTStatus = STATUS_MORE_PROCESSING_REQUIRED; Direction = ISO_OUT; DataIdx = 0; Len = 2; } } else { // read remaining data NTStatus = IFReadSTCData( ReaderExtension, pReply + DataIdx, Len ); DataIdx += Len; } } else if( (( Pcb & 0xFE ) ^ Ins ) == 0xFE ) { // transfer next if( Direction == ISO_IN ) { // write next NTStatus = IFWriteSTCData( ReaderExtension, pRequest + DataIdx, 1 ); if( NTStatus == STATUS_SUCCESS ) { DataIdx++; // if all data successful written the status word is expected if( --Len == 0 ) { Direction = ISO_OUT; DataIdx = 0; Len = 2; } NTStatus = STATUS_MORE_PROCESSING_REQUIRED; } } else { // read next NTStatus = IFReadSTCData( ReaderExtension, pReply + DataIdx, 1 ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = STATUS_MORE_PROCESSING_REQUIRED; if (Len == 0) { // we should have be done reading by now. NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; break; } Len--; DataIdx++; } } } else if( (( Pcb & 0x60 ) == 0x60 ) || (( Pcb & 0x90 ) == 0x90 ) ) { if( Direction == ISO_IN ) { Direction = ISO_OUT; DataIdx = 0; } // SW1 *pReply = Pcb; // read SW2 and leave NTStatus = IFReadSTCData( ReaderExtension, &Pcb, 1 ); *(pReply + 1) = Pcb; DataIdx += 2; } else { NTStatus = STATUS_UNSUCCESSFUL; } } } if(( NTStatus == STATUS_SUCCESS ) && ( pReplyLen != NULL )) { *pReplyLen = DataIdx; } if (PriorityBoost) { SmartcardDebug( DEBUG_TRACE, ( "%s!T0_ExchangeData: Setting priority: 0x%x\n", DRIVER_NAME, PreviousPriority)); PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), PreviousPriority); } return( NTStatus ); } NTSTATUS CBT0Transmit( PSMARTCARD_EXTENSION SmartcardExtension) /*++ CBT0Transmit: finishes the callback RDF_TRANSMIT for the T0 protocol Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; SmartcardDebug( DEBUG_TRACE, ("%s!CBT0Transmit Enter\n",DRIVER_NAME )); SmartcardExtension->SmartcardRequest.BufferLength = 0; // let the lib setup the T=1 APDU & check for errors NTStatus = SmartcardT0Request( SmartcardExtension ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = T0_ExchangeData( SmartcardExtension->ReaderExtension, SmartcardExtension->SmartcardRequest.Buffer, SmartcardExtension->SmartcardRequest.BufferLength, SmartcardExtension->SmartcardReply.Buffer, &SmartcardExtension->SmartcardReply.BufferLength); if( NTStatus == STATUS_SUCCESS ) { // let the lib evaluate the result & tansfer the data NTStatus = SmartcardT0Reply( SmartcardExtension ); } } SmartcardDebug( DEBUG_TRACE,("%s!CBT0Transmit Exit: %X\n",DRIVER_NAME, NTStatus )); return( NTStatus ); } NTSTATUS CBT1Transmit( PSMARTCARD_EXTENSION SmartcardExtension) /*++ CBT1Transmit: finishes the callback RDF_TRANSMIT for the T1 protocol Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS STATUS_NO_MEDIA STATUS_TIMEOUT STATUS_INVALID_DEVICE_REQUEST --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; KPRIORITY PreviousPriority; BOOLEAN PriorityBoost = FALSE; SmartcardDebug( DEBUG_TRACE, ("%s!CBT1Transmit Enter\n",DRIVER_NAME )); // smclib workaround *(PULONG)&SmartcardExtension->IoRequest.ReplyBuffer[0] = 0x02; *(PULONG)&SmartcardExtension->IoRequest.ReplyBuffer[4] = sizeof( SCARD_IO_REQUEST ); // use the lib support to construct the T=1 packets do { // no header for the T=1 protocol SmartcardExtension->SmartcardRequest.BufferLength = 0; SmartcardExtension->T1.NAD = 0; // let the lib setup the T=1 APDU & check for errors NTStatus = SmartcardT1Request( SmartcardExtension ); if( NTStatus == STATUS_SUCCESS ) { if (SmartcardExtension->ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) { SmartcardDebug( DEBUG_TRACE, ( "%s!CBT1Transmit: Setting priority: 0x%x\n", DRIVER_NAME, SmartcardExtension->ReaderExtension->Chosen_Priority)); PriorityBoost = TRUE; PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), SmartcardExtension->ReaderExtension->Chosen_Priority); } // send command (don't calculate LRC because CRC may be used!) NTStatus = IFWriteSTCData( SmartcardExtension->ReaderExtension, SmartcardExtension->SmartcardRequest.Buffer, SmartcardExtension->SmartcardRequest.BufferLength); if (PriorityBoost) { SmartcardDebug( DEBUG_TRACE, ( "%s!CBT1Transmit: Setting priority: 0x%x\n", DRIVER_NAME, PreviousPriority)); PriorityBoost = FALSE; PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), PreviousPriority); } // extend read timeout if the card issued a WTX request if (SmartcardExtension->T1.Wtx) { SmartcardExtension->ReaderExtension->ReadTimeout = ( SmartcardExtension->T1.Wtx * SmartcardExtension->CardCapabilities.T1.BWT + 999L )/ 1000L; } else { // restore timeout SmartcardExtension->ReaderExtension->ReadTimeout = (ULONG) (SmartcardExtension->CardCapabilities.T1.BWT / 1000); } // get response SmartcardExtension->SmartcardReply.BufferLength = 0; if( NTStatus == STATUS_SUCCESS ) { if (SmartcardExtension->ReaderExtension->Chosen_Priority > KeQueryPriorityThread(KeGetCurrentThread())) { SmartcardDebug( DEBUG_TRACE, ( "%s!CBT1Transmit: Setting priority: 0x%x\n", DRIVER_NAME, SmartcardExtension->ReaderExtension->Chosen_Priority)); PriorityBoost = TRUE; PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), SmartcardExtension->ReaderExtension->Chosen_Priority); } NTStatus = IFReadSTCData( SmartcardExtension->ReaderExtension, SmartcardExtension->SmartcardReply.Buffer, 3); if( NTStatus == STATUS_SUCCESS ) { ULONG Length; Length = (ULONG)SmartcardExtension->SmartcardReply.Buffer[ LEN_IDX ] + 1; if( Length + 3 < MIN_BUFFER_SIZE ) { NTStatus = IFReadSTCData( SmartcardExtension->ReaderExtension, &SmartcardExtension->SmartcardReply.Buffer[ DATA_IDX ], Length); SmartcardExtension->SmartcardReply.BufferLength = Length + 3; } else { NTStatus = STATUS_BUFFER_TOO_SMALL; } } if (PriorityBoost) { SmartcardDebug( DEBUG_TRACE, ( "%s!CBT1Transmit: Setting priority: 0x%x\n", DRIVER_NAME, PreviousPriority)); PriorityBoost = FALSE; PreviousPriority = KeSetPriorityThread(KeGetCurrentThread(), PreviousPriority); } // // if STCRead detects an LRC error, ignore it (maybe CRC used). Timeouts will // be detected by the lib if len=0 // if(( NTStatus == STATUS_CRC_ERROR ) || ( NTStatus == STATUS_IO_TIMEOUT )) { NTStatus = STATUS_SUCCESS; } if( NTStatus == STATUS_SUCCESS ) { // let the lib evaluate the result & setup the next APDU NTStatus = SmartcardT1Reply( SmartcardExtension ); } } } // continue if the lib wants to send the next packet } while( NTStatus == STATUS_MORE_PROCESSING_REQUIRED ); if( NTStatus == STATUS_IO_TIMEOUT ) { NTStatus = STATUS_DEVICE_PROTOCOL_ERROR; } SmartcardDebug( DEBUG_TRACE,( "%s!CBT1Transmit Exit: %X\n",DRIVER_NAME, NTStatus )); return ( NTStatus ); } NTSTATUS CBRawTransmit( PSMARTCARD_EXTENSION SmartcardExtension) /*++ CBRawTransmit: finishes the callback RDF_TRANSMIT for the RAW protocol Arguments: SmartcardExtension context of call Return Value: STATUS_UNSUCCESSFUL --*/ { NTSTATUS NTStatus = STATUS_UNSUCCESSFUL; SmartcardDebug( DEBUG_TRACE, ("%s!CBRawTransmit Exit: %X\n",DRIVER_NAME, NTStatus )); return ( NTStatus ); } NTSTATUS CBCardTracking( PSMARTCARD_EXTENSION SmartcardExtension) /*++ CBCardTracking: callback handler for SMCLIB RDF_CARD_TRACKING. the requested event was validated by the smclib (i.e. a card removal request will only be passed if a card is present). for a win95 build STATUS_PENDING will be returned without any other action. for NT the cancel routine for the irp will be set to the drivers cancel routine. Arguments: SmartcardExtension context of call Return Value: STATUS_PENDING --*/ { KIRQL CurrentIrql; SmartcardDebug( DEBUG_TRACE, ("%s!CBCardTracking Enter\n", DRIVER_NAME)); // set cancel routine IoAcquireCancelSpinLock( &CurrentIrql ); IoSetCancelRoutine( SmartcardExtension->OsData->NotificationIrp, StcUsbCancel); IoReleaseCancelSpinLock( CurrentIrql ); SmartcardDebug( DEBUG_TRACE, ("%s!CBCardTracking Exit\n", DRIVER_NAME)); return( STATUS_PENDING ); } NTSTATUS CBUpdateCardState( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBUpdateCardState: updates the variable CurrentState in SmartcardExtension Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS --*/ { NTSTATUS status = STATUS_SUCCESS; UCHAR cardStatus = 0; KIRQL irql; BOOLEAN stateChanged = FALSE; ULONG oldState; // read card state status = IFReadSTCRegister( SmartcardExtension->ReaderExtension, ADR_IO_CONFIG, 1, &cardStatus ); KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql); oldState = SmartcardExtension->ReaderCapabilities.CurrentState; switch(status) { case STATUS_NO_MEDIA: SmartcardExtension->ReaderExtension->ErrorCounter = 0; SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT; break; case STATUS_MEDIA_CHANGED: SmartcardExtension->ReaderExtension->ErrorCounter = 0; SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_PRESENT; break; case STATUS_SUCCESS: SmartcardExtension->ReaderExtension->ErrorCounter = 0; cardStatus &= M_SD; if( cardStatus == 0 ) { SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT; } else if( SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT ) { SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_PRESENT; } break; default: if( ++SmartcardExtension->ReaderExtension->ErrorCounter < ERROR_COUNTER_TRESHOLD ) { // a unknown status was reported from the reader, so use the previous state SmartcardExtension->ReaderCapabilities.CurrentState = oldState; } else { SmartcardLogError( SmartcardExtension->OsData->DeviceObject, STCUSB_TOO_MANY_ERRORS, NULL, 0); // a report of SCARD_UNKNOWN will force the resource manager to // disconnect the reader SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN; } break; } // // we need to update the card state if there was a card before hibernate // stand / by or when the current state has changed. // if (SmartcardExtension->ReaderExtension->CardPresent || oldState <= SCARD_ABSENT && SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT || oldState > SCARD_ABSENT && SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT) { stateChanged = TRUE; SmartcardExtension->ReaderExtension->CardPresent = FALSE; } if (stateChanged && SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) { PoSetSystemState (ES_USER_PRESENT); } if(stateChanged && SmartcardExtension->OsData->NotificationIrp != NULL) { KIRQL CurrentIrql; PIRP pIrp; IoAcquireCancelSpinLock( &CurrentIrql ); IoSetCancelRoutine( SmartcardExtension->OsData->NotificationIrp, NULL ); IoReleaseCancelSpinLock( CurrentIrql ); SmartcardExtension->OsData->NotificationIrp->IoStatus.Status = STATUS_SUCCESS; SmartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0; SmartcardDebug( DEBUG_DRIVER, ("%s!CBUpdateCardState: Completing notification irp %lx\n", DRIVER_NAME, SmartcardExtension->OsData->NotificationIrp)); pIrp = SmartcardExtension->OsData->NotificationIrp; SmartcardExtension->OsData->NotificationIrp = NULL; KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); IoCompleteRequest(pIrp, IO_NO_INCREMENT); } else { KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql); } return status; } NTSTATUS CBSynchronizeSTC( PSMARTCARD_EXTENSION SmartcardExtension ) /*++ CBSynchronizeSTC: updates the card dependend data of the stc (wait times, ETU...) Arguments: SmartcardExtension context of call Return Value: STATUS_SUCCESS --*/ { NTSTATUS NTStatus = STATUS_SUCCESS; PREADER_EXTENSION ReaderExtension; ULONG CWT, BWT, CGT, ETU; UCHAR Dl, Fl, N; PCLOCK_RATE_CONVERSION ClockRateConversion; PBIT_RATE_ADJUSTMENT BitRateAdjustment; ReaderExtension = SmartcardExtension->ReaderExtension; ClockRateConversion = SmartcardExtension->CardCapabilities.ClockRateConversion; BitRateAdjustment = SmartcardExtension->CardCapabilities.BitRateAdjustment; // cycle length Dl = SmartcardExtension->CardCapabilities.Dl; Fl = SmartcardExtension->CardCapabilities.Fl; ETU = ClockRateConversion[Fl & 0x0F].F; ETU /= BitRateAdjustment[ Dl & 0x0F ].DNumerator; ETU *= BitRateAdjustment[ Dl & 0x0F ].DDivisor; // ETU += (ETU % 2 == 0) ? 0 : 1; // a extra guard time of 0xFF means minimum delay in both directions N = SmartcardExtension->CardCapabilities.N; if( N == 0xFF ) { N = 0; } // set character waiting & guard time switch ( SmartcardExtension->CardCapabilities.Protocol.Selected ) { case SCARD_PROTOCOL_T0: CWT = 960 * SmartcardExtension->CardCapabilities.T0.WI; CGT = 14 + N; // 13 + N; cryptoflex error break; case SCARD_PROTOCOL_T1: CWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.CWI ); BWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.BWI ) * 960; CGT = 15 + N ;//13 + N; // 12 + N; sicrypt error NTStatus = STCSetBWT( ReaderExtension, BWT * ETU ); break; default: // restore default CGT CGT=13; STCSetCGT( ReaderExtension, CGT); NTStatus = STATUS_UNSUCCESSFUL; break; } if(( NTStatus == STATUS_SUCCESS ) && ETU ) { NTStatus = STCSetETU( ReaderExtension, ETU ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = STCSetCGT( ReaderExtension, CGT ); if( NTStatus == STATUS_SUCCESS ) { NTStatus = STCSetCWT( ReaderExtension, CWT * ETU ); } } } return( NTStatus ); }