2
* This wraps the dynamic ifdhandler functions.
4
* MUSCLE SmartCard Development ( http://www.linuxnet.com )
6
* Copyright (C) 1999-2004
7
* David Corcoran <corcoran@linuxnet.com>
8
* Damien Sauveron <damien.sauveron@labri.fr>
9
* Ludovic Rousseau <ludovic.rousseau@free.fr>
11
* $Id: ifdwrapper.c,v 1.29 2005/02/22 14:40:26 rousseau Exp $
16
#include "ifdhandler.h"
18
#include "readerfactory.h"
19
#include "ifdwrapper.h"
20
#include "atrhandler.h"
21
#include "dyn_generic.h"
22
#include "sys_generic.h"
24
#undef PCSCLITE_STATIC_DRIVER
27
* Function: IFDSetPTS Purpose : To set the protocol type selection (PTS).
28
* This function sets the appropriate protocol to be used on the card.
31
LONG IFDSetPTS(PREADER_CONTEXT rContext, DWORD dwProtocol, UCHAR ucFlags,
32
UCHAR ucPTS1, UCHAR ucPTS2, UCHAR ucPTS3)
37
#ifndef PCSCLITE_STATIC_DRIVER
38
RESPONSECODE(*IFD_set_protocol_parameters) (DWORD, UCHAR, UCHAR,
40
RESPONSECODE(*IFDH_set_protocol_parameters) (DWORD, DWORD, UCHAR,
41
UCHAR, UCHAR, UCHAR) = NULL;
43
if (rContext->dwVersion == IFD_HVERSION_1_0)
45
IFD_set_protocol_parameters = (RESPONSECODE(*)(DWORD, UCHAR, UCHAR,
46
UCHAR, UCHAR)) rContext->psFunctions.psFunctions_v1.pvfSetProtocolParameters;
48
if (NULL == IFD_set_protocol_parameters)
49
return SCARD_E_UNSUPPORTED_FEATURE;
53
IFDH_set_protocol_parameters = (RESPONSECODE(*)(DWORD, DWORD, UCHAR,
55
rContext->psFunctions.psFunctions_v2.pvfSetProtocolParameters;
57
if (NULL == IFDH_set_protocol_parameters)
58
return SCARD_E_UNSUPPORTED_FEATURE;
63
* LOCK THIS CODE REGION
65
SYS_MutexLock(rContext->mMutex);
67
ucValue[0] = rContext->dwSlot;
69
#ifndef PCSCLITE_STATIC_DRIVER
70
if (rContext->dwVersion == IFD_HVERSION_1_0)
72
ucValue[0] = rContext->dwSlot;
73
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
74
rv = (*IFD_set_protocol_parameters) (dwProtocol,
75
ucFlags, ucPTS1, ucPTS2, ucPTS3);
79
rv = (*IFDH_set_protocol_parameters) (rContext->dwSlot,
85
if (rContext->dwVersion == IFD_HVERSION_1_0)
87
ucValue[0] = rContext->dwSlot;
88
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
89
rv = IFD_Set_Protocol_Parameters(dwProtocol, ucFlags, ucPTS1,
94
rv = IFDHSetProtocolParameters(rContext->dwSlot, dwProtocol,
95
ucFlags, ucPTS1, ucPTS2, ucPTS3);
99
SYS_MutexUnLock(rContext->mMutex);
101
* END OF LOCKED REGION
108
* Function: IFDOpenIFD Purpose : This function opens a communication
109
* channel to the IFD.
112
LONG IFDOpenIFD(PREADER_CONTEXT rContext)
116
#ifndef PCSCLITE_STATIC_DRIVER
117
RESPONSECODE(*IO_create_channel) (DWORD) = NULL;
118
RESPONSECODE(*IFDH_create_channel) (DWORD, DWORD) = NULL;
119
RESPONSECODE(*IFDH_create_channel_by_name) (DWORD, LPTSTR) = NULL;
121
if (rContext->dwVersion == IFD_HVERSION_1_0)
123
rContext->psFunctions.psFunctions_v1.pvfCreateChannel;
125
if (rContext->dwVersion == IFD_HVERSION_2_0)
126
IFDH_create_channel =
127
rContext->psFunctions.psFunctions_v2.pvfCreateChannel;
130
IFDH_create_channel =
131
rContext->psFunctions.psFunctions_v3.pvfCreateChannel;
132
IFDH_create_channel_by_name =
133
rContext->psFunctions.psFunctions_v3.pvfCreateChannelByName;
138
* LOCK THIS CODE REGION
141
SYS_MutexLock(rContext->mMutex);
142
#ifndef PCSCLITE_STATIC_DRIVER
143
if (rContext->dwVersion == IFD_HVERSION_1_0)
145
rv = (*IO_create_channel) (rContext->dwPort);
146
} else if (rContext->dwVersion == IFD_HVERSION_2_0)
148
rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
151
/* use device name only if defined */
152
if (rContext->lpcDevice[0] != '\0')
153
rv = (*IFDH_create_channel_by_name) (rContext->dwSlot, rContext->lpcDevice);
155
rv = (*IFDH_create_channel) (rContext->dwSlot, rContext->dwPort);
158
if (rContext->dwVersion == IFD_HVERSION_1_0)
160
rv = IO_Create_Channel(rContext->dwPort);
161
} else if (rContext->dwVersion == IFD_HVERSION_2_0)
163
rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
166
/* Use device name only if defined */
167
if (rContext->lpcDevice[0] != '\0')
168
rv = IFDHCreateChannelByName(rContext->dwSlot, rContext->lpcDevice);
170
rv = IFDHCreateChannel(rContext->dwSlot, rContext->dwPort);
173
SYS_MutexUnLock(rContext->mMutex);
176
* END OF LOCKED REGION
183
* Function: IFDCloseIFD Purpose : This function closes a communication
184
* channel to the IFD.
187
LONG IFDCloseIFD(PREADER_CONTEXT rContext)
191
#ifndef PCSCLITE_STATIC_DRIVER
192
RESPONSECODE(*IO_close_channel) () = NULL;
193
RESPONSECODE(*IFDH_close_channel) (DWORD) = NULL;
195
if (rContext->dwVersion == IFD_HVERSION_1_0)
196
IO_close_channel = rContext->psFunctions.psFunctions_v1.pvfCloseChannel;
198
IFDH_close_channel = rContext->psFunctions.psFunctions_v2.pvfCloseChannel;
202
* LOCK THIS CODE REGION
205
SYS_MutexLock(rContext->mMutex);
206
#ifndef PCSCLITE_STATIC_DRIVER
207
if (rContext->dwVersion == IFD_HVERSION_1_0)
209
rv = (*IO_close_channel) ();
211
rv = (*IFDH_close_channel) (rContext->dwSlot);
213
if (rContext->dwVersion == IFD_HVERSION_1_0)
214
rv = IO_Close_Channel();
216
rv = IFDHCloseChannel(rContext->dwSlot);
218
SYS_MutexUnLock(rContext->mMutex);
221
* END OF LOCKED REGION
228
* Function: IFDSetCapabilites Purpose : This function set's capabilities
232
LONG IFDSetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
233
DWORD dwLength, PUCHAR pucValue)
237
#ifndef PCSCLITE_STATIC_DRIVER
238
RESPONSECODE(*IFD_set_capabilities) (DWORD, PUCHAR) = NULL;
239
RESPONSECODE(*IFDH_set_capabilities) (DWORD, DWORD, DWORD, PUCHAR) = NULL;
241
if (rContext->dwVersion == IFD_HVERSION_1_0)
242
IFD_set_capabilities = rContext->psFunctions.psFunctions_v1.pvfSetCapabilities;
244
IFDH_set_capabilities = rContext->psFunctions.psFunctions_v2.pvfSetCapabilities;
248
* Let the calling function lock this otherwise a deadlock will
252
#ifndef PCSCLITE_STATIC_DRIVER
253
if (rContext->dwVersion == IFD_HVERSION_1_0)
254
rv = (*IFD_set_capabilities) (dwTag, pucValue);
256
rv = (*IFDH_set_capabilities) (rContext->dwSlot, dwTag,
259
if (rContext->dwVersion == IFD_HVERSION_1_0)
260
rv = IFD_Set_Capabilities(dwTag, pucValue);
262
rv = IFDHSetCapabilities(rContext->dwSlot, dwTag, dwLength,
270
* Function: IFDGetCapabilites Purpose : This function get's capabilities
271
* in the reader. Other functions int this file will call the driver
272
* directly to not cause a deadlock.
275
LONG IFDGetCapabilities(PREADER_CONTEXT rContext, DWORD dwTag,
276
PDWORD pdwLength, PUCHAR pucValue)
280
#ifndef PCSCLITE_STATIC_DRIVER
281
RESPONSECODE(*IFD_get_capabilities) (DWORD, PUCHAR) = NULL;
282
RESPONSECODE(*IFDH_get_capabilities) (DWORD, DWORD, PDWORD, PUCHAR) = NULL;
284
if (rContext->dwVersion == IFD_HVERSION_1_0)
285
IFD_get_capabilities =
286
rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
288
IFDH_get_capabilities =
289
rContext->psFunctions.psFunctions_v2.pvfGetCapabilities;
293
* LOCK THIS CODE REGION
296
SYS_MutexLock(rContext->mMutex);
298
#ifndef PCSCLITE_STATIC_DRIVER
299
if (rContext->dwVersion == IFD_HVERSION_1_0)
300
rv = (*IFD_get_capabilities) (dwTag, pucValue);
302
rv = (*IFDH_get_capabilities) (rContext->dwSlot, dwTag,
303
pdwLength, pucValue);
305
if (rContext->dwVersion == IFD_HVERSION_1_0)
306
rv = IFD_Get_Capabilities(dwTag, pucValue);
308
rv = IFDHGetCapabilities(rContext->dwSlot, dwTag, pdwLength,
312
SYS_MutexUnLock(rContext->mMutex);
315
* END OF LOCKED REGION
322
* Function: IFDPowerICC Purpose : This function powers up/down or reset's
323
* an ICC located in the IFD.
326
LONG IFDPowerICC(PREADER_CONTEXT rContext, DWORD dwAction,
327
PUCHAR pucAtr, PDWORD pdwAtrLen)
329
RESPONSECODE rv, ret;
330
SMARTCARD_EXTENSION sSmartCard;
334
#ifndef PCSCLITE_STATIC_DRIVER
335
RESPONSECODE(*IFD_power_icc) (DWORD) = NULL;
336
RESPONSECODE(*IFDH_power_icc) (DWORD, DWORD, PUCHAR, PDWORD) = NULL;
340
* Zero out everything
347
* Check that the card is inserted first
349
IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
351
if (dwStatus & SCARD_ABSENT)
352
return SCARD_W_REMOVED_CARD;
353
#ifndef PCSCLITE_STATIC_DRIVER
354
if (rContext->dwVersion == IFD_HVERSION_1_0)
355
IFD_power_icc = rContext->psFunctions.psFunctions_v1.pvfPowerICC;
357
IFDH_power_icc = rContext->psFunctions.psFunctions_v2.pvfPowerICC;
361
* LOCK THIS CODE REGION
364
SYS_MutexLock(rContext->mMutex);
366
#ifndef PCSCLITE_STATIC_DRIVER
367
if (rContext->dwVersion == IFD_HVERSION_1_0)
369
ucValue[0] = rContext->dwSlot;
370
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
371
rv = (*IFD_power_icc) (dwAction);
375
rv = (*IFDH_power_icc) (rContext->dwSlot, dwAction,
378
ret = ATRDecodeAtr(&sSmartCard, pucAtr, *pdwAtrLen);
381
if (rContext->dwVersion == IFD_HVERSION_1_0)
383
ucValue[0] = rContext->dwSlot;
384
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
385
rv = IFD_Power_ICC(dwAction);
388
rv = IFDHPowerICC(rContext->dwSlot, dwAction, pucAtr, pdwAtrLen);
390
SYS_MutexUnLock(rContext->mMutex);
393
* END OF LOCKED REGION
396
/* use clean values in case of error */
397
if (rv != IFD_SUCCESS)
404
* Get the ATR and it's length
406
if (rContext->dwVersion == IFD_HVERSION_1_0)
407
IFDStatusICC(rContext, &dwStatus, pucAtr, pdwAtrLen);
413
* Function: IFDStatusICC Purpose : This function provides statistical
414
* information about the IFD and ICC including insertions, atr, powering
418
LONG IFDStatusICC(PREADER_CONTEXT rContext, PDWORD pdwStatus,
419
PUCHAR pucAtr, PDWORD pdwAtrLen)
422
DWORD dwTag = 0, dwCardStatus = 0;
423
SMARTCARD_EXTENSION sSmartCard;
424
UCHAR ucValue[1] = "\x00";
426
#ifndef PCSCLITE_STATIC_DRIVER
427
RESPONSECODE(*IFD_is_icc_present) () = NULL;
428
RESPONSECODE(*IFDH_icc_presence) (DWORD) = NULL;
429
RESPONSECODE(*IFD_get_capabilities) (DWORD, PUCHAR) = NULL;
431
if (rContext->dwVersion == IFD_HVERSION_1_0)
434
rContext->psFunctions.psFunctions_v1.pvfICCPresence;
435
IFD_get_capabilities =
436
rContext->psFunctions.psFunctions_v1.pvfGetCapabilities;
439
IFDH_icc_presence = rContext->psFunctions.psFunctions_v2.pvfICCPresence;
443
* LOCK THIS CODE REGION
446
SYS_MutexLock(rContext->mMutex);
448
#ifndef PCSCLITE_STATIC_DRIVER
449
if (rContext->dwVersion == IFD_HVERSION_1_0)
451
ucValue[0] = rContext->dwSlot;
452
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
453
rv = (*IFD_is_icc_present) ();
456
rv = (*IFDH_icc_presence) (rContext->dwSlot);
458
if (rContext->dwVersion == IFD_HVERSION_1_0)
460
ucValue[0] = rContext->dwSlot;
461
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
462
rv = IFD_Is_ICC_Present();
465
rv = IFDHICCPresence(rContext->dwSlot);
467
SYS_MutexUnLock(rContext->mMutex);
470
* END OF LOCKED REGION
473
if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
474
dwCardStatus |= SCARD_PRESENT;
476
if (rv == IFD_ICC_NOT_PRESENT)
477
dwCardStatus |= SCARD_ABSENT;
480
Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
481
return SCARD_E_NOT_TRANSACTED;
485
* Now lets get the ATR and process it if IFD Handler version 1.0.
486
* IFD Handler version 2.0 does this immediately after reset/power up
487
* to conserve resources
490
if (rContext->dwVersion == IFD_HVERSION_1_0)
492
if (rv == IFD_SUCCESS || rv == IFD_ICC_PRESENT)
497
* LOCK THIS CODE REGION
500
SYS_MutexLock(rContext->mMutex);
502
ucValue[0] = rContext->dwSlot;
503
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
505
#ifndef PCSCLITE_STATIC_DRIVER
506
rv = (*IFD_get_capabilities) (dwTag, pucAtr);
508
rv = IFD_Get_Capabilities(dwTag, pucAtr);
510
SYS_MutexUnLock(rContext->mMutex);
513
* END OF LOCKED REGION
517
* FIX :: This is a temporary way to return the correct size
518
* of the ATR since most of the drivers return MAX_ATR_SIZE
521
rv = ATRDecodeAtr(&sSmartCard, pucAtr, MAX_ATR_SIZE);
524
* Might be a memory card without an ATR
529
*pdwAtrLen = sSmartCard.ATR.Length;
534
* No card is inserted - Atr length is 0
543
*pdwStatus = dwCardStatus;
545
return SCARD_S_SUCCESS;
549
* Function: IFDControl Purpose : This function provides a means for
550
* toggling a specific action on the reader such as swallow, eject,
555
* Valid only for IFDHandler version 2.0
558
LONG IFDControl_v2(PREADER_CONTEXT rContext, PUCHAR TxBuffer,
559
DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
563
#ifndef PCSCLITE_STATIC_DRIVER
564
RESPONSECODE(*IFDH_control_v2) (DWORD, PUCHAR, DWORD, PUCHAR, PDWORD);
567
if (rContext->dwVersion != IFD_HVERSION_2_0)
568
return SCARD_E_UNSUPPORTED_FEATURE;
570
#ifndef PCSCLITE_STATIC_DRIVER
571
IFDH_control_v2 = rContext->psFunctions.psFunctions_v2.pvfControl;
575
* LOCK THIS CODE REGION
577
SYS_MutexLock(rContext->mMutex);
579
#ifndef PCSCLITE_STATIC_DRIVER
580
rv = (*IFDH_control_v2) (rContext->dwSlot, TxBuffer, TxLength,
583
rv = IFDHControl_v2(rContext->dwSlot, TxBuffer, TxLength,
586
SYS_MutexUnLock(rContext->mMutex);
588
* END OF LOCKED REGION
591
if (rv == IFD_SUCCESS)
592
return SCARD_S_SUCCESS;
595
Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
596
return SCARD_E_NOT_TRANSACTED;
601
* Function: IFDControl Purpose : This function provides a means for
602
* toggling a specific action on the reader such as swallow, eject,
607
* Valid only for IFDHandler version 3.0 and up
610
LONG IFDControl(PREADER_CONTEXT rContext, DWORD ControlCode,
611
LPCVOID TxBuffer, DWORD TxLength, LPVOID RxBuffer, DWORD RxLength,
612
LPDWORD BytesReturned)
616
#ifndef PCSCLITE_STATIC_DRIVER
617
RESPONSECODE(*IFDH_control) (DWORD, DWORD, LPCVOID, DWORD, LPVOID, DWORD, LPDWORD);
620
if (rContext->dwVersion < IFD_HVERSION_3_0)
621
return SCARD_E_UNSUPPORTED_FEATURE;
623
#ifndef PCSCLITE_STATIC_DRIVER
624
IFDH_control = rContext->psFunctions.psFunctions_v3.pvfControl;
628
* LOCK THIS CODE REGION
631
SYS_MutexLock(rContext->mMutex);
633
#ifndef PCSCLITE_STATIC_DRIVER
634
rv = (*IFDH_control) (rContext->dwSlot, ControlCode, TxBuffer,
635
TxLength, RxBuffer, RxLength, BytesReturned);
637
rv = IFDHControl(rContext->dwSlot, ControlCode, TxBuffer,
638
TxLength, RxBuffer, RxLength, BytesReturned);
640
SYS_MutexUnLock(rContext->mMutex);
643
* END OF LOCKED REGION
646
if (rv == IFD_SUCCESS)
647
return SCARD_S_SUCCESS;
650
Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
651
return SCARD_E_NOT_TRANSACTED;
656
* Function: IFDTransmit Purpose : This function transmits an APDU to the
660
LONG IFDTransmit(PREADER_CONTEXT rContext, SCARD_IO_HEADER pioTxPci,
661
PUCHAR pucTxBuffer, DWORD dwTxLength, PUCHAR pucRxBuffer,
662
PDWORD pdwRxLength, PSCARD_IO_HEADER pioRxPci)
665
UCHAR ucValue[1] = "\x00";
667
#ifndef PCSCLITE_STATIC_DRIVER
668
RESPONSECODE(*IFD_transmit_to_icc) (SCARD_IO_HEADER, PUCHAR, DWORD,
669
PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
670
RESPONSECODE(*IFDH_transmit_to_icc) (DWORD, SCARD_IO_HEADER, PUCHAR,
671
DWORD, PUCHAR, PDWORD, PSCARD_IO_HEADER) = NULL;
675
DebugLogCategory(DEBUG_CATEGORY_APDU, pucTxBuffer, dwTxLength);
677
#ifndef PCSCLITE_STATIC_DRIVER
678
if (rContext->dwVersion == IFD_HVERSION_1_0)
679
IFD_transmit_to_icc =
680
rContext->psFunctions.psFunctions_v1.pvfTransmitToICC;
682
IFDH_transmit_to_icc =
683
rContext->psFunctions.psFunctions_v2.pvfTransmitToICC;
687
* LOCK THIS CODE REGION
690
SYS_MutexLock(rContext->mMutex);
693
#ifndef PCSCLITE_STATIC_DRIVER
694
if (rContext->dwVersion == IFD_HVERSION_1_0)
696
ucValue[0] = rContext->dwSlot;
697
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
698
rv = (*IFD_transmit_to_icc) (pioTxPci, (LPBYTE) pucTxBuffer,
699
dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
702
rv = (*IFDH_transmit_to_icc) (rContext->dwSlot, pioTxPci,
703
(LPBYTE) pucTxBuffer, dwTxLength,
704
pucRxBuffer, pdwRxLength, pioRxPci);
706
if (rContext->dwVersion == IFD_HVERSION_1_0)
708
ucValue[0] = rContext->dwSlot;
709
IFDSetCapabilities(rContext, TAG_IFD_SLOTNUM, 1, ucValue);
710
rv = IFD_Transmit_to_ICC(pioTxPci, (LPBYTE) pucTxBuffer,
711
dwTxLength, pucRxBuffer, pdwRxLength, pioRxPci);
714
rv = IFDHTransmitToICC(rContext->dwSlot, pioTxPci,
715
(LPBYTE) pucTxBuffer, dwTxLength,
716
pucRxBuffer, pdwRxLength, pioRxPci);
718
SYS_MutexUnLock(rContext->mMutex);
721
* END OF LOCKED REGION
724
/* log the returned status word */
725
DebugLogCategory(DEBUG_CATEGORY_SW, pucRxBuffer, *pdwRxLength);
727
if (rv == IFD_SUCCESS)
728
return SCARD_S_SUCCESS;
731
Log2(PCSC_LOG_ERROR, "Card not transacted: %ld", rv);
732
return SCARD_E_NOT_TRANSACTED;