947 lines
22 KiB
C
947 lines
22 KiB
C
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) SCM Microsystems, 1998 - 1999
|
|
//
|
|
// File: cbhndlr.c
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#if defined( SMCLIB_VXD )
|
|
#include "Driver98.h"
|
|
#else
|
|
#include "DriverNT.h"
|
|
#endif
|
|
|
|
#include "SerialIF.h"
|
|
#include "STCCmd.h"
|
|
#include "CBHndlr.h"
|
|
#include "T0Hndlr.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 ATRLength;
|
|
PREADER_EXTENSION ReaderExtension;
|
|
SERIAL_TIMEOUTS Timeouts;
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBCardPower Enter\n" ));
|
|
|
|
ReaderExtension = SmartcardExtension->ReaderExtension;
|
|
|
|
// discard old ATR
|
|
SmartcardExtension->CardCapabilities.ATR.Length = 0;
|
|
SmartcardExtension->CardCapabilities.Protocol.Selected =
|
|
SCARD_PROTOCOL_UNDEFINED;
|
|
|
|
// set standard timeouts for the worker thread
|
|
Timeouts.ReadIntervalTimeout = SR_READ_INTERVAL_TIMEOUT;
|
|
Timeouts.ReadTotalTimeoutConstant = SR_READ_TOTAL_TIMEOUT_CONSTANT;
|
|
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
Timeouts.WriteTotalTimeoutConstant = SR_WRITE_TOTAL_TIMEOUT_CONSTANT;
|
|
Timeouts.WriteTotalTimeoutMultiplier = 0;
|
|
|
|
NTStatus = IFSerialIoctl(
|
|
ReaderExtension,
|
|
IOCTL_SERIAL_SET_TIMEOUTS,
|
|
&Timeouts,
|
|
sizeof(Timeouts),
|
|
NULL,
|
|
0
|
|
);
|
|
ASSERT(NTStatus == STATUS_SUCCESS);
|
|
|
|
// set the ATR timeout in milli sec
|
|
ReaderExtension->ReadTimeout = 1500;
|
|
|
|
switch (SmartcardExtension->MinorIoControlCode)
|
|
{
|
|
case SCARD_WARM_RESET:
|
|
|
|
// if the card was not powerd, fall through to cold reset
|
|
if( SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_SWALLOWED )
|
|
{
|
|
// reset the card
|
|
ATRLength = ATR_SIZE;
|
|
NTStatus = STCReset(
|
|
ReaderExtension,
|
|
0, // not used: ReaderExtension->Device,
|
|
TRUE, // warm reset
|
|
ATRBuffer,
|
|
&ATRLength
|
|
);
|
|
|
|
break;
|
|
}
|
|
// 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;
|
|
STCPowerOff( ReaderExtension );
|
|
NTStatus = STATUS_SUCCESS;
|
|
CBUpdateCardState( SmartcardExtension, SCARD_PRESENT );
|
|
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 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 )
|
|
{
|
|
ULONG minWaitTime;
|
|
|
|
// set the stc registers
|
|
CBSynchronizeSTC( SmartcardExtension );
|
|
|
|
// now set the new - card specific - timeouts
|
|
if( SmartcardExtension->CardCapabilities.Protocol.Selected ==
|
|
SCARD_PROTOCOL_T1 )
|
|
{
|
|
ReaderExtension->ReadTimeout =
|
|
Timeouts.ReadTotalTimeoutConstant =
|
|
SmartcardExtension->CardCapabilities.T1.BWT / 1000;
|
|
|
|
Timeouts.ReadIntervalTimeout =
|
|
SmartcardExtension->CardCapabilities.T1.CWT / 1000;
|
|
}
|
|
else
|
|
{
|
|
ReaderExtension->ReadTimeout =
|
|
Timeouts.ReadIntervalTimeout =
|
|
Timeouts.ReadTotalTimeoutConstant =
|
|
SmartcardExtension->CardCapabilities.T0.WT / 1000 * 5;
|
|
}
|
|
minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
|
|
|
|
if (Timeouts.ReadTotalTimeoutConstant < minWaitTime) {
|
|
|
|
Timeouts.ReadTotalTimeoutConstant = minWaitTime;
|
|
}
|
|
|
|
if (Timeouts.ReadIntervalTimeout < minWaitTime) {
|
|
|
|
Timeouts.ReadIntervalTimeout = minWaitTime;
|
|
}
|
|
|
|
if (ReaderExtension->ReadTimeout < minWaitTime) {
|
|
|
|
ReaderExtension->ReadTimeout = minWaitTime;
|
|
}
|
|
|
|
// set standard timeouts for the worker thread
|
|
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
|
|
NTStatus = IFSerialIoctl(
|
|
ReaderExtension,
|
|
IOCTL_SERIAL_SET_TIMEOUTS,
|
|
&Timeouts,
|
|
sizeof(Timeouts),
|
|
NULL,
|
|
0
|
|
);
|
|
ASSERT(NTStatus == STATUS_SUCCESS);
|
|
}
|
|
}
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
( "SCMSTCS!CBCardPower Exit: %X\n",
|
|
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;
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBSetProtocol Enter\n" ));
|
|
|
|
ReaderExtension = SmartcardExtension->ReaderExtension;
|
|
NewProtocol = SmartcardExtension->MinorIoControlCode;
|
|
|
|
// check if the card is already in specific state
|
|
if( ( SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC ) &&
|
|
( SmartcardExtension->CardCapabilities.Protocol.Selected & NewProtocol ))
|
|
{
|
|
NTStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
// 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 )
|
|
{
|
|
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 = STCWriteICC1( ReaderExtension, PTSRequest, 4 );
|
|
|
|
// get response
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
ULONG BufferLength = sizeof(PTSReply);
|
|
NTStatus = STCReadICC1(
|
|
ReaderExtension,
|
|
PTSReply,
|
|
&BufferLength,
|
|
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
|
|
//
|
|
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 )
|
|
{
|
|
ULONG minWaitTime;
|
|
SERIAL_TIMEOUTS Timeouts;
|
|
|
|
if( SmartcardExtension->CardCapabilities.Protocol.Selected ==
|
|
SCARD_PROTOCOL_T1 )
|
|
{
|
|
ReaderExtension->ReadTimeout =
|
|
Timeouts.ReadTotalTimeoutConstant =
|
|
SmartcardExtension->CardCapabilities.T1.BWT / 1000;
|
|
|
|
Timeouts.ReadIntervalTimeout =
|
|
SmartcardExtension->CardCapabilities.T1.CWT / 1000;
|
|
}
|
|
else
|
|
{
|
|
ReaderExtension->ReadTimeout =
|
|
Timeouts.ReadIntervalTimeout =
|
|
Timeouts.ReadTotalTimeoutConstant =
|
|
SmartcardExtension->CardCapabilities.T0.WT / 1000 * 5;
|
|
}
|
|
|
|
minWaitTime = (KeQueryTimeIncrement() / 10000) * 5;
|
|
|
|
if (Timeouts.ReadTotalTimeoutConstant < minWaitTime) {
|
|
|
|
Timeouts.ReadTotalTimeoutConstant = minWaitTime;
|
|
}
|
|
|
|
if (Timeouts.ReadIntervalTimeout < minWaitTime) {
|
|
|
|
Timeouts.ReadIntervalTimeout = minWaitTime;
|
|
}
|
|
|
|
if (ReaderExtension->ReadTimeout < minWaitTime) {
|
|
|
|
ReaderExtension->ReadTimeout = minWaitTime;
|
|
}
|
|
|
|
Timeouts.WriteTotalTimeoutConstant = SR_WRITE_TOTAL_TIMEOUT_CONSTANT;
|
|
Timeouts.WriteTotalTimeoutMultiplier = 0;
|
|
Timeouts.ReadTotalTimeoutMultiplier = 0;
|
|
|
|
NTStatus = IFSerialIoctl(
|
|
ReaderExtension,
|
|
IOCTL_SERIAL_SET_TIMEOUTS,
|
|
&Timeouts,
|
|
sizeof(Timeouts),
|
|
NULL,
|
|
0
|
|
);
|
|
ASSERT(NTStatus == STATUS_SUCCESS);
|
|
|
|
// indicate that the card is in specific mode
|
|
SmartcardExtension->ReaderCapabilities.CurrentState =
|
|
SCARD_SPECIFIC;
|
|
|
|
// 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, ("SCMSTCS!CBSetProtocol: Exit %X\n", NTStatus ));
|
|
|
|
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, ("SCMSTCS!CBTransmit Enter\n" ));
|
|
|
|
// 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, ("SCMSTCS!CBTransmit Exit: %X\n", NTStatus ));
|
|
|
|
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, ("SCMSTCS!CBT0Transmit Enter\n" ));
|
|
|
|
SmartcardExtension->SmartcardRequest.BufferLength = 0;
|
|
SmartcardExtension->SmartcardReply.BufferLength =
|
|
SmartcardExtension->SmartcardReply.BufferSize;
|
|
|
|
// 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,("SCMSTCS!CBT0Transmit Exit: %X\n", 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;
|
|
ULONG BufferLength,AlreadyRead;
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBT1Transmit Enter\n" ));
|
|
|
|
//KJ
|
|
RtlZeroMemory( SmartcardExtension->SmartcardReply.Buffer,
|
|
sizeof(SmartcardExtension->SmartcardReply.Buffer));
|
|
|
|
// 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 )
|
|
{
|
|
// send command (don't calculate LRC because CRC may be used!)
|
|
NTStatus = STCWriteICC1(
|
|
SmartcardExtension->ReaderExtension,
|
|
SmartcardExtension->SmartcardRequest.Buffer,
|
|
SmartcardExtension->SmartcardRequest.BufferLength
|
|
);
|
|
|
|
//
|
|
// extend the timeout if a Wtx request was sent by the card. if the
|
|
// card responds before the waiting time extension expires, the data are
|
|
// buffered in the reader. A delay without polling the reader status
|
|
// slows down the performance of the driver, but wtx is an exeption,
|
|
// not the rule.
|
|
//
|
|
if (SmartcardExtension->T1.Wtx)
|
|
{
|
|
|
|
SysDelay(
|
|
(( SmartcardExtension->T1.Wtx *
|
|
SmartcardExtension->CardCapabilities.T1.BWT + 999L )/
|
|
1000L)
|
|
);
|
|
|
|
}
|
|
|
|
// get response
|
|
SmartcardExtension->SmartcardReply.BufferLength = 0;
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
BufferLength = SmartcardExtension->SmartcardReply.BufferSize;
|
|
NTStatus = STCReadICC1(
|
|
SmartcardExtension->ReaderExtension,
|
|
SmartcardExtension->SmartcardReply.Buffer,
|
|
&BufferLength,
|
|
3
|
|
);
|
|
// if we have read more then 3 bytes
|
|
if(BufferLength > 3)
|
|
{
|
|
AlreadyRead = BufferLength - 3;
|
|
}
|
|
else
|
|
{
|
|
AlreadyRead = 0;
|
|
}
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
ULONG Length;
|
|
|
|
Length = (ULONG)SmartcardExtension->SmartcardReply.Buffer[ LEN_IDX ] + 1;
|
|
|
|
if( Length + 3 < MIN_BUFFER_SIZE )
|
|
{
|
|
BufferLength =
|
|
SmartcardExtension->SmartcardReply.BufferSize -
|
|
Length;
|
|
|
|
NTStatus = STCReadICC1(
|
|
SmartcardExtension->ReaderExtension,
|
|
(&SmartcardExtension->SmartcardReply.Buffer[ DATA_IDX ]) + AlreadyRead,
|
|
&BufferLength,
|
|
Length-AlreadyRead
|
|
);
|
|
|
|
SmartcardExtension->SmartcardReply.BufferLength = Length + 3;
|
|
}
|
|
else
|
|
{
|
|
NTStatus = STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
//
|
|
// 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,( "SCMSTCS!CBT1Transmit Exit: %X\n", 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_SUCCESS
|
|
STATUS_NO_MEDIA
|
|
STATUS_TIMEOUT
|
|
STATUS_INVALID_DEVICE_REQUEST
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
NTStatus = STATUS_UNSUCCESSFUL;
|
|
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBRawTransmit Exit: %X\n", 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
|
|
|
|
--*/
|
|
{
|
|
SmartcardDebug( DEBUG_TRACE, ("SCMSTCS!CBCardTracking Enter\n" ));
|
|
|
|
#if defined( SMCLIB_VXD )
|
|
|
|
#else
|
|
|
|
{
|
|
KIRQL CurrentIrql;
|
|
|
|
// set cancel routine
|
|
IoAcquireCancelSpinLock( &CurrentIrql );
|
|
IoSetCancelRoutine(
|
|
SmartcardExtension->OsData->NotificationIrp,
|
|
DrvCancel
|
|
);
|
|
|
|
IoReleaseCancelSpinLock( CurrentIrql );
|
|
}
|
|
|
|
#endif
|
|
|
|
SmartcardDebug( DEBUG_TRACE, ( "SCMSTCS!CBCardTracking Exit\n" ));
|
|
|
|
return( STATUS_PENDING );
|
|
|
|
}
|
|
|
|
VOID
|
|
CBUpdateCardState(
|
|
PSMARTCARD_EXTENSION SmartcardExtension,
|
|
ULONG RequestedState
|
|
)
|
|
/*++
|
|
|
|
CBUpdateCardState:
|
|
updates the variable CurrentState in SmartcardExtension
|
|
|
|
Arguments:
|
|
SmartcardExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR Status;
|
|
KIRQL Irql;
|
|
BOOLEAN StateChanged = FALSE;
|
|
ULONG NewState = RequestedState;
|
|
|
|
if (RequestedState == SCARD_UNKNOWN) {
|
|
|
|
// read card state from reader
|
|
NTStatus = STCReadSTCRegister(
|
|
SmartcardExtension->ReaderExtension,
|
|
ADR_IO_CONFIG,
|
|
1,
|
|
&Status
|
|
);
|
|
|
|
ASSERT(NTStatus == STATUS_SUCCESS);
|
|
|
|
if (NTStatus == STATUS_SUCCESS) {
|
|
|
|
if ((Status & M_SD) == 0) {
|
|
|
|
NewState = SCARD_ABSENT;
|
|
|
|
} else {
|
|
|
|
NewState = SCARD_SWALLOWED;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_UNKNOWN ||
|
|
SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT &&
|
|
NewState <= SCARD_ABSENT ||
|
|
SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT &&
|
|
NewState > SCARD_ABSENT) {
|
|
|
|
StateChanged = TRUE;
|
|
}
|
|
|
|
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &Irql);
|
|
|
|
if(RequestedState != SCARD_UNKNOWN ||
|
|
NTStatus == STATUS_SUCCESS && StateChanged)
|
|
{
|
|
SmartcardExtension->ReaderCapabilities.CurrentState = NewState;
|
|
}
|
|
|
|
#if defined( SMCLIB_VXD )
|
|
//
|
|
// if a tracking request is pending, finish it (even if an error occured!)
|
|
// to prevent a hangup of an application
|
|
//
|
|
if( SmartcardExtension->OsData->NotificationOverlappedData != NULL )
|
|
{
|
|
SmartcardCompleteCardTracking( SmartcardExtension );
|
|
}
|
|
|
|
#else
|
|
|
|
if(StateChanged && SmartcardExtension->OsData->NotificationIrp != NULL)
|
|
{
|
|
KIRQL CurrentIrql;
|
|
IoAcquireCancelSpinLock( &CurrentIrql );
|
|
|
|
IoSetCancelRoutine( SmartcardExtension->OsData->NotificationIrp, NULL );
|
|
IoReleaseCancelSpinLock( CurrentIrql );
|
|
|
|
SmartcardExtension->OsData->NotificationIrp->IoStatus.Status =
|
|
STATUS_SUCCESS;
|
|
SmartcardExtension->OsData->NotificationIrp->IoStatus.Information = 0;
|
|
|
|
IoCompleteRequest(
|
|
SmartcardExtension->OsData->NotificationIrp,
|
|
IO_NO_INCREMENT
|
|
);
|
|
|
|
SmartcardExtension->OsData->NotificationIrp = NULL;
|
|
}
|
|
|
|
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, Irql);
|
|
#endif
|
|
}
|
|
|
|
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;
|
|
break;
|
|
|
|
case SCARD_PROTOCOL_T1:
|
|
CWT = 1000 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.CWI );
|
|
BWT = 11 + ( 0x01 << SmartcardExtension->CardCapabilities.T1.BWI ) * 960;
|
|
|
|
CGT = 15 + N; // 12 + N; sicrypt error
|
|
|
|
NTStatus = STCSetBWT( ReaderExtension, BWT * ETU );
|
|
|
|
break;
|
|
|
|
default:
|
|
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 );
|
|
}
|
|
|