Windows2003-3790/drivers/smartcrd/smclib/smcutil.c
2020-09-30 16:53:55 +02:00

1041 lines
28 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
smcutil.c
Abstract:
This module contains some utility fucntions
Environment:
Kernel mode only.
Notes:
Revision History:
- Created December 1996 by Klaus Schutz
- Nov 97: Released Version 1.0
- Jan 98: Calc. of GT changed. (Now set to 0 if N = 0 or N = 255)
Rules for setting card status to SCARD_SPECIFIC changed
Default clock freq. is now used for initial etu calculation
--*/
#define _ISO_TABLES_
#ifdef SMCLIB_VXD
#define try
#define leave goto __label
#define finally __label:
#else
#if !defined(SMCLIB_CE)
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <ntddk.h>
#endif
#endif
#ifdef SMCLIB_TEST
#define DbgPrint printf
#define DbgBreakPoint()
#define RtlAssert
#endif
#define _SMCUTIL_
#include "smclib.h"
#define IS_VENDOR(a) (memcmp(SmartcardExtension->VendorAttr.VendorName.Buffer, a, SmartcardExtension->VendorAttr.VendorName.Length) == 0)
#define IS_IFDTYPE(a) (memcmp(SmartcardExtension->VendorAttr.IfdType.Buffer, a, SmartcardExtension->VendorAttr.IfdType.Length) == 0)
void
DumpData(
const ULONG DebugLevel,
PUCHAR Data,
ULONG DataLen
);
//
// This is the time resolution.
// We calculate all times not in seconds, but in micro seconds
//
#define TR ((ULONG)(1000l * 1000l))
static ULONG
Pow2(
UCHAR Exponent
)
{
ULONG result = 1;
while(Exponent--)
result *= 2;
return result;
}
#ifdef _X86_
#pragma optimize("", off)
#endif
#if (DEBUG && DEBUG_VERBOSE)
#pragma message("Debug Verbose is turned on")
ULONG DebugLevel = DEBUG_PERF | DEBUG_ATR;
#else
ULONG DebugLevel = 0;
#endif
ULONG
#ifdef SMCLIB_VXD
SMCLIB_SmartcardGetDebugLevel(
#else
SmartcardGetDebugLevel(
#endif
void
)
{
return DebugLevel;
}
void
#ifdef SMCLIB_VXD
SMCLIB_SmartcardSetDebugLevel(
#else
SmartcardSetDebugLevel(
#endif
ULONG Level
)
{
DebugLevel = Level;
}
#ifdef _X86_
#pragma optimize("", on)
#endif
#if DEBUG
void
DumpData(
const ULONG DebugLevel,
PUCHAR Data,
ULONG DataLen
)
{
ULONG i, line = 0;
TCHAR buffer[72], *pbuffer;
while(DataLen) {
pbuffer = buffer;
sprintf(pbuffer, "%*s", sizeof(buffer) - 1, "");
if (line > 0) {
pbuffer += 8;
}
for (i = 0; i < 8 && DataLen; i++, DataLen--, Data++) {
sprintf(pbuffer + i * 3, "%02X ", *Data);
sprintf(pbuffer + i + 26, "%c", (isprint(*Data) ? *Data : '.'));
}
pbuffer[i * 3] = ' ';
pbuffer[i + 26] = '\n';
pbuffer[i + 27] = '\0';
SmartcardDebug(DebugLevel, (buffer));
line += 1;
}
}
#endif
VOID
SmartcardInitializeCardCapabilities(
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine initializes all fields in the CardCapabilities structure,
which can be calculated by the SmartcardUpdateCardCapabilities function.
Arguments:
SmartcardExtension
Return Value:
None
--*/
{
//
// Save the pointers to the two tables
//
PCLOCK_RATE_CONVERSION clockRateConversion = SmartcardExtension->CardCapabilities.ClockRateConversion;
PBIT_RATE_ADJUSTMENT bitRateAdjustment = SmartcardExtension->CardCapabilities.BitRateAdjustment;
//
// Right now it is fine to zero the whole struct
//
RtlZeroMemory(
&SmartcardExtension->CardCapabilities,
sizeof(SmartcardExtension->CardCapabilities)
);
// Restore the pointers
SmartcardExtension->CardCapabilities.ClockRateConversion = clockRateConversion;
SmartcardExtension->CardCapabilities.BitRateAdjustment = bitRateAdjustment;
//
// Every card has to support the 'raw' protocol
// It enables the usage of cards that have their own protocol defined
//
SmartcardExtension->CardCapabilities.Protocol.Supported =
SCARD_PROTOCOL_RAW;
//
// Reset T=1 specific data
//
// force the T=1 protocol to start with an ifsd request
SmartcardExtension->T1.State = T1_INIT;
//
// Initialize the send sequence number and
// the 'receive sequence number'
//
SmartcardExtension->T1.SSN = 0;
SmartcardExtension->T1.RSN = 0;
SmartcardExtension->T1.IFSC = 0;
ASSERT(SmartcardExtension->ReaderCapabilities.MaxIFSD != 0);
// Initialize the interface information field size
if (SmartcardExtension->ReaderCapabilities.MaxIFSD != 0 &&
SmartcardExtension->ReaderCapabilities.MaxIFSD <= T1_IFSD) {
SmartcardExtension->T1.IFSD =
(UCHAR) SmartcardExtension->ReaderCapabilities.MaxIFSD;
} else {
SmartcardExtension->T1.IFSD = T1_IFSD_DEFAULT;
}
}
VOID
SmartcardInvertData(
PUCHAR Buffer,
ULONG Length
)
/*++
Routine Description:
This routine converts the passed buffer from inverse to direct or the other way
Arguments:
Return Value:
None
--*/
{
ULONG i;
for (i = 0; i < Length; i++) {
UCHAR j, inv = 0;
for (j = 0; j < 8; j++) {
if (Buffer[i] & (1 << j)) {
inv |= 1 << (7 - j);
}
}
Buffer[i] = (inv ^ 0xFF);
}
}
NTSTATUS
#ifdef SMCLIB_VXD
SMCLIB_SmartcardUpdateCardCapabilities(
#else
SmartcardUpdateCardCapabilities(
#endif
PSMARTCARD_EXTENSION SmartcardExtension
)
/*++
Routine Description:
This routine updates the CardCapabilities structure, which holds information about
the smartcard that has just been reset and is currently in use. It reads the
ATR string and retrieves all the relevent information.
Please refer to ISO 7816-3 ,section 6.1.4 for the format of the ATR string
Arguments:
SmartcardExtension
Return Value:
NTSTATUS
--*/
{
PSCARD_CARD_CAPABILITIES cardCapabilities = &SmartcardExtension->CardCapabilities;
PSCARD_READER_CAPABILITIES readerCapabilities = &SmartcardExtension->ReaderCapabilities;
PUCHAR atrString = cardCapabilities->ATR.Buffer;
ULONG atrLength = (ULONG) cardCapabilities->ATR.Length;
UCHAR Y, Tck, TA[MAXIMUM_ATR_CODES], TB[MAXIMUM_ATR_CODES];
UCHAR TC[MAXIMUM_ATR_CODES], TD[MAXIMUM_ATR_CODES];
ULONG i, fs, numProtocols = 0, protocolTypes = 0;
NTSTATUS status = STATUS_SUCCESS;
BOOLEAN TA2Present = FALSE;
#if DEBUG
TCHAR *ptsType[] = {TEXT("PTS_TYPE_DEFAULT"), TEXT("PTS_TYPE_OPTIMAL"), TEXT("PTS_TYPE_USER")};
#endif
#if defined (SMCLIB_NT)
KIRQL irql;
#endif
SmartcardDebug(
DEBUG_ATR,
(TEXT("%s!SmartcardUpdateCardCapabilities:\n"),
DRIVER_NAME)
);
if (atrLength < 2) {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" ATR is too short (Min. length is 2) \n"))
);
return STATUS_UNRECOGNIZED_MEDIA;
}
#if DEBUG
SmartcardDebug(
DEBUG_ATR,
(TEXT(" ATR: "))
);
DumpData(
DEBUG_ATR,
atrString,
atrLength
);
#endif
if (atrString[0] != 0x3b && atrString[0] != 0x3f && atrString[0] != 0x03) {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Initial character %02xh of ATR is invalid\n"),
atrString[0])
);
return STATUS_UNRECOGNIZED_MEDIA;
}
// Test for invers convention
if (*atrString == 0x03) {
cardCapabilities->InversConvention = TRUE;
//
// When the ATR starts with 0x03 then it
// has not been inverted already
//
SmartcardInvertData(
cardCapabilities->ATR.Buffer,
cardCapabilities->ATR.Length
);
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Card uses Inverse Convention\n"))
);
}
__try {
//
// The caller might be calling this function repeatedly in order to
// test if the ATR is valid. If the ATR we currently have here is
// not valid then we need to be able re-invert an inverted ATR.
//
atrString += 1;
atrLength -= 1;
//
// Calculate check char, but do not test now since if only T=0
// is present the ATR doesn't contain a check char
//
for (i = 0, Tck = 0; i < atrLength; i++) {
Tck ^= atrString[i];
}
// Initialize various data
cardCapabilities->Protocol.Supported = 0;
RtlZeroMemory(TA, sizeof(TA));
RtlZeroMemory(TB, sizeof(TB));
RtlZeroMemory(TC, sizeof(TC));
RtlZeroMemory(TD, sizeof(TD));
//
// Set default values as described in ISO 7816-3
//
// TA1 codes Fl in high-byte and Dl in low-byte;
TA[0] = 0x11;
// TB1 codes II in bits b7/b6 and Pl1 in b5-b1. b8 has to be 0
TB[0] = 0x25;
// TC2 codes T=0 WI
TC[1] = 10;
// Translate ATR string to TA to TD values (See ISO)
cardCapabilities->HistoricalChars.Length = *atrString & 0x0f;
Y = *atrString++ & 0xf0;
atrLength -= 1;
for (i = 0; i < MAXIMUM_ATR_CODES; i++) {
if (Y & 0x10) {
if (i == 1) {
TA2Present = TRUE;
}
TA[i] = *atrString++;
atrLength -= 1;
}
if (Y & 0x20) {
TB[i] = *atrString++;
atrLength -= 1;
}
if (Y & 0x40) {
TC[i] = *atrString++;
atrLength -= 1;
}
if (Y & 0x80) {
Y = *atrString & 0xf0;
TD[i] = *atrString++ & 0x0f;
atrLength -= 1;
// Check if the next parameters are for a new protocol.
if (((1 << TD[i]) & protocolTypes) == 0) {
// Count the number of protocols that the card supports
numProtocols++;
}
protocolTypes |= 1 << TD[i];
} else {
break;
}
}
// Check if the card supports a protocol other than T=0
if (protocolTypes & ~1) {
//
// The atr contains a checksum byte.
// Exclude that from the historical byte length check
//
atrLength -=1;
//
// This card supports more than one protocol or a protocol
// other than T=0, so test if the checksum is correct
//
if (Tck != 0) {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" ATR Checksum is invalid\n"))
);
status = STATUS_UNRECOGNIZED_MEDIA;
__leave;
}
}
if (/* atrLength < 0 || */
atrLength != cardCapabilities->HistoricalChars.Length) {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" ATR length is inconsistent\n"))
);
status = STATUS_UNRECOGNIZED_MEDIA;
__leave;
}
}
__finally {
if (status != STATUS_SUCCESS) {
if (cardCapabilities->InversConvention == TRUE) {
SmartcardInvertData(
cardCapabilities->ATR.Buffer,
cardCapabilities->ATR.Length
);
cardCapabilities->InversConvention = FALSE;
}
}
}
if (status != STATUS_SUCCESS)
return status;
// store historical characters
RtlCopyMemory(
cardCapabilities->HistoricalChars.Buffer,
atrString,
cardCapabilities->HistoricalChars.Length
);
//
// Now convert TA - TD values to global interface bytes
//
// Clock rate conversion
cardCapabilities->Fl = (TA[0] & 0xf0) >> 4;
// bit rate adjustment
cardCapabilities->Dl = (TA[0] & 0x0f);
// Maximum programming current factor
cardCapabilities->II = (TB[0] & 0xc0) >> 6;
// Programming voltage in 0.1 Volts
cardCapabilities->P = (TB[1] ? TB[1] : (TB[0] & 0x1f) * 10);
// Extra guard time
cardCapabilities->N = TC[0];
//
// Check if the Dl and Fl values are valid
//
if (BitRateAdjustment[cardCapabilities->Dl].DNumerator == 0 ||
ClockRateConversion[cardCapabilities->Fl].F == 0) {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Dl = %02x or Fl = %02x invalid\n"),
cardCapabilities->Dl,
cardCapabilities->Fl)
);
return STATUS_UNRECOGNIZED_MEDIA;
}
ASSERT(readerCapabilities->CLKFrequency.Max != 0);
ASSERT(readerCapabilities->CLKFrequency.Default != 0);
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Card parameters from ATR:\n Fl = %02x (%ld KHz), Dl = %02x, I = %02x, P = %02x, N = %02x\n"),
cardCapabilities->Fl,
ClockRateConversion[cardCapabilities->Fl].fs / 1000,
cardCapabilities->Dl,
cardCapabilities->II,
cardCapabilities->P,
cardCapabilities->N)
);
//
// assume default clock frequency
//
fs = readerCapabilities->CLKFrequency.Default * 1000l;
if (fs == 0) {
fs = 372 * 9600l;
}
if (cardCapabilities->PtsData.Type == PTS_TYPE_DEFAULT) {
//
// Assume default parameters
//
cardCapabilities->PtsData.Fl = 1;
cardCapabilities->PtsData.Dl = 1;
cardCapabilities->PtsData.DataRate =
readerCapabilities->DataRate.Default;
cardCapabilities->PtsData.CLKFrequency =
readerCapabilities->CLKFrequency.Default;
}
if (cardCapabilities->PtsData.Type != PTS_TYPE_DEFAULT) {
//
// Try to find optimal parameters:
// Highest possible clock frequency of the card
// combined with fastes data rate
//
//
// We now try to find a working Fl and Dl combination
//
if (cardCapabilities->PtsData.Type == PTS_TYPE_OPTIMAL) {
cardCapabilities->PtsData.Fl = cardCapabilities->Fl;
}
ASSERT(cardCapabilities->PtsData.Fl < 16);
ASSERT(ClockRateConversion[cardCapabilities->PtsData.Fl].F);
if (cardCapabilities->PtsData.Fl > 15 ||
ClockRateConversion[cardCapabilities->PtsData.Fl].F == 0) {
return STATUS_INVALID_PARAMETER;
}
do {
ULONG cardFreq, maxFreq;
if (readerCapabilities->CLKFrequenciesSupported.Entries == 0 ||
readerCapabilities->CLKFrequenciesSupported.List == NULL) {
//
// The clock freq. list supplied by the reader is empty
// We take the standard values supplied by the reader
//
readerCapabilities->CLKFrequenciesSupported.List =
&readerCapabilities->CLKFrequency.Default;
readerCapabilities->CLKFrequenciesSupported.Entries = 2;
}
//
// Find the highest possible clock freq. supported
// by the card and the reader
//
cardFreq =
ClockRateConversion[cardCapabilities->PtsData.Fl].fs /
1000;
cardCapabilities->PtsData.CLKFrequency = 0;
for (i = 0; i < readerCapabilities->CLKFrequenciesSupported.Entries; i++) {
// look for highest possible reader frequency
if (readerCapabilities->CLKFrequenciesSupported.List[i] >
cardCapabilities->PtsData.CLKFrequency &&
readerCapabilities->CLKFrequenciesSupported.List[i] <=
cardFreq) {
cardCapabilities->PtsData.CLKFrequency =
readerCapabilities->CLKFrequenciesSupported.List[i];
}
}
fs = cardCapabilities->PtsData.CLKFrequency * 1000;
cardCapabilities->PtsData.DataRate = 0;
ASSERT(fs != 0);
if (fs == 0) {
return STATUS_INVALID_PARAMETER;
}
if (cardCapabilities->PtsData.Type == PTS_TYPE_OPTIMAL) {
cardCapabilities->PtsData.Dl = cardCapabilities->Dl;
}
ASSERT(cardCapabilities->PtsData.Dl < 16);
ASSERT(BitRateAdjustment[cardCapabilities->PtsData.Dl].DNumerator);
if (cardCapabilities->PtsData.Dl > 15 ||
BitRateAdjustment[cardCapabilities->PtsData.Dl].DNumerator == 0) {
return STATUS_INVALID_PARAMETER;
}
if (readerCapabilities->DataRatesSupported.Entries == 0 ||
readerCapabilities->DataRatesSupported.List == NULL) {
//
// The data rate list supplied by the reader is empty.
// We take the standard min/max values of the reader
//
readerCapabilities->DataRatesSupported.List =
&readerCapabilities->DataRate.Default;
readerCapabilities->DataRatesSupported.Entries = 2;
}
//
// Now try to find the highest possible matching data rate
// (A matching data rate is one that VERY close
// to one supplied by the reader)
//
while(cardCapabilities->PtsData.Dl > 1) {
ULONG dataRate;
//
// Calculate the data rate using the current values
//
dataRate =
(BitRateAdjustment[cardCapabilities->PtsData.Dl].DNumerator *
fs) /
(BitRateAdjustment[cardCapabilities->PtsData.Dl].DDivisor *
ClockRateConversion[cardCapabilities->PtsData.Fl].F);
//
// Try to find a matching data rate
//
for (i = 0; i < readerCapabilities->DataRatesSupported.Entries; i++) {
if (readerCapabilities->DataRatesSupported.List[i] * 101 > dataRate * 100 &&
readerCapabilities->DataRatesSupported.List[i] * 99 < dataRate * 100) {
cardCapabilities->PtsData.DataRate =
readerCapabilities->DataRatesSupported.List[i];
break;
}
}
if (cardCapabilities->PtsData.DataRate) {
break;
}
//
// Select the next valid lower D value
//
while (BitRateAdjustment[--cardCapabilities->PtsData.Dl].DNumerator == 0)
;
}
if (cardCapabilities->PtsData.Fl == 1 &&
cardCapabilities->PtsData.Dl == 1) {
cardCapabilities->PtsData.DataRate =
readerCapabilities->DataRate.Default;
cardCapabilities->PtsData.CLKFrequency =
readerCapabilities->CLKFrequency.Default;
break;
}
if (cardCapabilities->PtsData.DataRate) {
break;
}
//
// Select the next valid lower F value
//
maxFreq = ClockRateConversion[cardCapabilities->Fl].fs;
do {
cardCapabilities->PtsData.Fl -= 1;
} while (ClockRateConversion[cardCapabilities->PtsData.Fl].F == 0 ||
ClockRateConversion[cardCapabilities->PtsData.Fl].fs >
maxFreq);
} while(cardCapabilities->PtsData.DataRate == 0);
}
ASSERT(fs != 0);
ASSERT(cardCapabilities->PtsData.Dl < 16);
ASSERT(BitRateAdjustment[cardCapabilities->PtsData.Dl].DNumerator != 0);
//
// We calculate the ETU on basis of the timing supplied by the
// clk-frequency of the reader
//
//
// Work etu in units of time resolution(TR) (NOT in seconds)
//
cardCapabilities->etu =
1 + // required to round up
(TR *
BitRateAdjustment[cardCapabilities->PtsData.Dl].DDivisor *
ClockRateConversion[cardCapabilities->PtsData.Fl].F) /
(BitRateAdjustment[cardCapabilities->PtsData.Dl].DNumerator *
fs);
//
// guard time in micro seconds
// the guard time is the gap between the end of the
// current character and the beginning of the next character
//
cardCapabilities->GT = 0;
cardCapabilities->PtsData.StopBits = 2;
if (cardCapabilities->N == 255) {
cardCapabilities->PtsData.StopBits = 1;
} else if (cardCapabilities->N > 0) {
cardCapabilities->GT = cardCapabilities->N * cardCapabilities->etu;
}
SmartcardDebug(
DEBUG_ATR,
(TEXT(" PTS parameters (%s):\n Fl = %02x (%ld KHz), Dl = %02x (%ld Bps, %d Stop Bits)\n"),
ptsType[cardCapabilities->PtsData.Type],
cardCapabilities->PtsData.Fl,
cardCapabilities->PtsData.CLKFrequency,
cardCapabilities->PtsData.Dl,
cardCapabilities->PtsData.DataRate,
cardCapabilities->PtsData.StopBits)
);
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Calculated timing values:\n Work etu = %ld micro sec, Guard time = %ld micro sec\n"),
cardCapabilities->etu,
cardCapabilities->GT)
);
#if defined (SMCLIB_NT) && !defined(SMCLIB_TEST)
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &irql);
#endif
if(SmartcardExtension->ReaderCapabilities.CurrentState >= SCARD_PRESENT) {
if (TA2Present || numProtocols <= 1 &&
cardCapabilities->Fl == 1 &&
cardCapabilities->Dl == 1) {
//
// If the card supports only one protocol (or T=0 as default)
// and only standard paramters then PTS selection is not available
//
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_SPECIFIC;
} else {
SmartcardExtension->ReaderCapabilities.CurrentState =
SCARD_NEGOTIABLE;
}
}
#if defined (SMCLIB_NT) && !defined(SMCLIB_TEST)
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, irql);
#endif
//
// Now find protocol specific data
//
if (TD[0] == 0) {
cardCapabilities->Protocol.Supported |=
SCARD_PROTOCOL_T0;
cardCapabilities->T0.WI = TC[1];
if (cardCapabilities->PtsData.Dl > 0 &&
cardCapabilities->PtsData.Dl < 6) {
cardCapabilities->T0.WT = 1 +
cardCapabilities->T0.WI *
960 * cardCapabilities->etu *
Pow2((UCHAR) (cardCapabilities->PtsData.Dl - 1));
} else {
cardCapabilities->T0.WT = 1+
cardCapabilities->T0.WI *
960 * cardCapabilities->etu /
Pow2((UCHAR) (cardCapabilities->PtsData.Dl - 1));
}
SmartcardDebug(
DEBUG_ATR,
(TEXT(" T=0 Values from ATR:\n WI = %ld\n"),
cardCapabilities->T0.WI)
);
SmartcardDebug(
DEBUG_ATR,
(TEXT(" T=0 Timing from ATR:\n WT = %ld ms\n"),
cardCapabilities->T0.WT / 1000)
);
}
if (protocolTypes & SCARD_PROTOCOL_T1) {
for (i = 0; TD[i] != 1 && i < MAXIMUM_ATR_CODES; i++)
;
for (; TD[i] == 1 && i < MAXIMUM_ATR_CODES; i++)
;
if (i == MAXIMUM_ATR_CODES) {
return STATUS_UNRECOGNIZED_MEDIA;
}
cardCapabilities->Protocol.Supported |=
SCARD_PROTOCOL_T1;
cardCapabilities->T1.IFSC =
(TA[i] ? TA[i] : 32);
cardCapabilities->T1.CWI =
((TB[i] & 0x0f) ? (TB[i] & 0x0f) : T1_CWI_DEFAULT);
cardCapabilities->T1.BWI =
((TB[i] & 0xf0) >> 4 ? (TB[i] & 0xf0) >> 4 : T1_BWI_DEFAULT);
cardCapabilities->T1.EDC =
(TC[i] & 0x01);
cardCapabilities->T1.CWT = 1 +
(Pow2(cardCapabilities->T1.CWI) + 11) * cardCapabilities->etu;
cardCapabilities->T1.BWT = 1 +
(((Pow2(cardCapabilities->T1.BWI) * 960l * 372l) /
cardCapabilities->PtsData.CLKFrequency) +
(11 * cardCapabilities->etu)) * 1000;
SmartcardDebug(
DEBUG_ATR,
(TEXT(" T=1 Values from ATR:\n IFSC = %ld, CWI = %ld, BWI = %ld, EDC = %02x\n"),
cardCapabilities->T1.IFSC,
cardCapabilities->T1.CWI,
cardCapabilities->T1.BWI,
cardCapabilities->T1.EDC)
);
SmartcardDebug(
DEBUG_ATR,
(TEXT(" T=1 Timing from ATR:\n CWT = %ld ms, BWT = %ld ms\n"),
cardCapabilities->T1.CWT / 1000,
cardCapabilities->T1.BWT / 1000)
);
}
if (SmartcardExtension->ReaderCapabilities.CurrentState == SCARD_SPECIFIC) {
if (TA2Present) {
//
// TA2 is present in the ATR, so use
// the protocol indicated in the ATR
//
cardCapabilities->Protocol.Selected = 1 << (TA[1] & 0xf);
} else {
//
// The card only supports one protocol
// So make that one protocol the current one to use
//
cardCapabilities->Protocol.Selected =
cardCapabilities->Protocol.Supported;
}
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Mode: Specific %s\n\n"),
TA2Present ? TEXT("set by TA(2)") : TEXT(""))
);
} else {
SmartcardDebug(
DEBUG_ATR,
(TEXT(" Mode: Negotiable\n\n"))
);
}
//
// Every card has to support the 'raw' protocol
// It enables the usage of cards that have their own protocol defined
//
SmartcardExtension->CardCapabilities.Protocol.Supported |=
SCARD_PROTOCOL_RAW;
return STATUS_SUCCESS;
}
#ifdef SMCLIB_TEST
__cdecl
main()
{
SMARTCARD_EXTENSION SmartcardExtension;
static ULONG dataRatesSupported[] = { 9909 };
memset(&SmartcardExtension, 0, sizeof(SmartcardExtension));
// Gemplus T=0 card
// memcpy(SmartcardExtension.CardCapabilities.ATR.Buffer, "\x3b\x2a\x00\x80\x65\xa2\x01\x02\x01\x31\x72\xd6\x43", 13);
// SmartcardExtension.CardCapabilities.ATR.Length = 13;
// MS card with TA2 set - card won't work due to incorrect parameters
memcpy(SmartcardExtension.CardCapabilities.ATR.Buffer, "\x3b\x98\x13\x91\x81\x31\x20\x55\x00\x57\x69\x6e\x43\x61\x72\x64\xbb", 17);
SmartcardExtension.CardCapabilities.ATR.Length = 17;
SmartcardExtension.ReaderCapabilities.CLKFrequency.Default = 3686;
SmartcardExtension.ReaderCapabilities.CLKFrequency.Max = 3686;
SmartcardExtension.ReaderCapabilities.DataRate.Default =
SmartcardExtension.ReaderCapabilities.DataRate.Max = 9909;
SmartcardExtension.ReaderCapabilities.DataRatesSupported.List =
dataRatesSupported;
SmartcardExtension.ReaderCapabilities.DataRatesSupported.Entries =
sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
SmartcardExtension.ReaderCapabilities.CurrentState = SCARD_PRESENT;
SmartcardSetDebugLevel(DEBUG_ALL);
SmartcardUpdateCardCapabilities(&SmartcardExtension);
}
#define DbgPrint printf
#endif