/*
ifdhandler.c
Mapping if CT-API / CT-BCS interface to the IFD Hanlder 2.0.
Getting/Setting IFD/Protocol/ICC parameters other than the ATR is not
supported. IFDH_MAX_READERS simultaneous readers are supported.
This file is part of the Unix driver for Towitoko smartcard readers
Copyright (C) 1998 1999 2000 2001 Carlos Prados <cprados@yahoo.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "pcscdefines.h"
#include "ifdhandler.h"
#include <ctapi.h>
#include <ctbcs.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_PTHREAD_H
#include <pthread.h>
#endif
#ifdef DEBUG_IFDH
#include <syslog.h>
#endif
/*
* Not exported constants definition
*/
/* Maximum number of readers handled */
#define IFDH_MAX_READERS 4
/* Maximum number of slots per reader handled */
#define IFDH_MAX_SLOTS 1
/*
* Not exported data types definition
*/
typedef struct
{
DEVICE_CAPABILITIES device_capabilities;
ICC_STATE icc_state;
PROTOCOL_OPTIONS protocol_options;
}
IFDH_Context;
/*
* Not exported variables definition
*/
/* Matrix that stores conext information of all slots and readers */
static IFDH_Context *ifdh_context[IFDH_MAX_READERS][IFDH_MAX_SLOTS] = {
{NULL},{NULL},{NULL},{NULL},
};
/* Mutexes for all readers */
#ifdef HAVE_PTHREAD_H
static pthread_mutex_t ifdh_context_mutex[IFDH_MAX_READERS] = {
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER,
PTHREAD_MUTEX_INITIALIZER
};
#endif
/*
* Exported functions definition
*/
RESPONSECODE IFDHCreateChannel (DWORD Lun, DWORD Channel)
{
char ret;
unsigned short ctn, pn, slot;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
if (ifdh_context[ctn][slot] == NULL)
{
/* Handle USB CHANNELID numbers */
if (Channel >= 0x200000)
/* USB ports on this CT-API starts at 0x8000 */
#ifndef CTAPI_WIN32_COM
pn = (unsigned short) (Channel & 0x1FFFFF) + 0x8000;
#else
pn = (unsigned short) (Channel & 0x1FFFFF) + 0x8001;
#endif
/* Conversion of old-style ifd-hanler 1.0 CHANNELID */
#ifndef CTAPI_WIN32_COM
else if (Channel == 0x0103F8)
pn = PORT_COM1;
else if (Channel == 0x0102F8)
pn = PORT_COM2;
else if (Channel == 0x0103E8)
pn = PORT_COM3;
else if (Channel == 0x0102E8)
pn = PORT_COM4;
#else
else if (Channel == 0x0103F8)
pn = 1;
else if (Channel == 0x0102F8)
pn = 2;
else if (Channel == 0x0103E8)
pn = 3;
else if (Channel == 0x0102E8)
pn = 4;
#endif
/* IFD Handler 2.0 CHANNELID*/
else
#ifndef CTAPI_WIN32_COM
pn = (unsigned short) Channel - 1;
#else
pn = (unsigned short) Channel;
#endif
ret = CT_init (ctn, pn);
if (ret == OK)
{
/* Initialize context of the all slots in this reader */
for (slot = 0; slot < IFDH_MAX_SLOTS; slot++)
{
ifdh_context[ctn][slot] =
(IFDH_Context *) malloc (sizeof (IFDH_Context));
if (ifdh_context[ctn][slot] != NULL)
memset (ifdh_context[ctn][slot], 0, sizeof (IFDH_Context));
}
rv = IFD_SUCCESS;
}
else
rv = IFD_COMMUNICATION_ERROR;
}
else
{
/* Assume that IFDHCreateChannel is being called for another
already initialized slot in this same reader, and return Success */
rv = IFD_SUCCESS;
}
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHCreateChannel(Lun=0x%X, Channel=0x%X)=%d",Lun,
Channel, rv);
#endif
return rv;
}
RESPONSECODE
IFDHCloseChannel (DWORD Lun)
{
char ret;
unsigned short ctn, slot;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
ret = CT_close (ctn);
if (ret == OK)
{
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
/* Free context of the all slots in this reader */
for (slot = 0; slot < IFDH_MAX_SLOTS; slot++)
{
if (ifdh_context[ctn][slot] != NULL)
{
free (ifdh_context[ctn][slot]);
ifdh_context[ctn][slot] = NULL;
}
}
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
rv = IFD_SUCCESS;
}
else
rv = IFD_COMMUNICATION_ERROR;
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHCloseChannel(Lun=0x%X)=%d", Lun, rv);
#endif
return rv;
}
RESPONSECODE
IFDHGetCapabilities (DWORD Lun, DWORD Tag, PDWORD Length, PUCHAR Value)
{
unsigned short ctn, slot;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
switch (Tag)
{
case TAG_IFD_ATR:
(*Length) = ifdh_context[ctn][slot]->icc_state.ATR_Length;
memcpy (Value, ifdh_context[ctn][slot]->icc_state.ATR, (*Length));
rv = IFD_SUCCESS;
break;
case TAG_IFD_SLOTS_NUMBER:
(*Length) = 1;
(*Value) = IFDH_MAX_SLOTS;
rv = IFD_SUCCESS;
break;
case TAG_IFD_SIMULTANEOUS_ACCESS:
(*Length) = 1;
(*Value) = IFDH_MAX_READERS;
rv = IFD_SUCCESS;
break;
default:
(*Length) = 0;
rv = IFD_ERROR_TAG;
}
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHGetCapabilities (Lun=0x%X, Tag=0x%X)=%d",Lun, Tag, rv);
#endif
return rv;
}
RESPONSECODE
IFDHSetCapabilities (DWORD Lun, DWORD Tag, DWORD Length, PUCHAR Value)
{
#ifdef DEBUG_IFDH
/* syslog (LOG_INFO, "IFDH: IFDHSetCapabilities (Lun=%X, Tag=%X)=%d",Lun, Tag,
IFD_NOT_SUPPORTED ); */
#endif
return IFD_NOT_SUPPORTED;
}
RESPONSECODE
IFDHSetProtocolParameters (DWORD Lun, DWORD Protocol,
UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
{
char ret;
unsigned short ctn, slot, lc, lr;
UCHAR cmd[10], rsp[256], sad, dad;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
if (ifdh_context[ctn][slot] != NULL)
{
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_RESET;
cmd[2] = (UCHAR) (slot + 1);
cmd[3] = CTBCS_P2_RESET_GET_ATR;
cmd[4] = 0x06;
cmd[5] = 0xFF;
cmd[6] = (Flags << 4) | (0x0F & Protocol);
lc=7;
if ((Flags & 0x10) == 0x10)
cmd[lc++] = PTS1;
if ((Flags & 0x20) == 0x20)
cmd[lc++] = PTS2;
if ((Flags & 0x40) == 0x40)
cmd[lc++] = PTS3;
dad = 0x01;
sad = 0x02;
lr = 256;
ret = CT_data (ctn, &dad, &sad, lc, cmd, &lr, rsp);
if ((ret == OK) && (lr >= 2))
{
ifdh_context[ctn][slot]->icc_state.ATR_Length = (DWORD) lr - 2;
memcpy (ifdh_context[ctn][slot]->icc_state.ATR, rsp, lr - 2);
rv = IFD_SUCCESS;
}
else
rv = IFD_ERROR_PTS_FAILURE;
}
else
rv = IFD_ICC_NOT_PRESENT;
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHSetProtocolParameters (Lun=0x%X, Protocol=%d, Flags=0x%02X, PTS1=0x%02X, PTS2=0x%02X, PTS3=0x%02X)=%d",
Lun, Protocol, Flags, PTS1, PTS2, PTS3, rv);
#endif
return rv;
}
RESPONSECODE
IFDHPowerICC (DWORD Lun, DWORD Action, PUCHAR Atr, PDWORD AtrLength)
{
char ret;
unsigned short ctn, slot, lc, lr;
UCHAR cmd[5], rsp[256], sad, dad;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
if (ifdh_context[ctn][slot] != NULL)
{
if (Action == IFD_POWER_UP)
{
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_REQUEST;
cmd[2] = (UCHAR) (slot + 1);
cmd[3] = CTBCS_P2_REQUEST_GET_ATR;
cmd[4] = 0x00;
dad = 0x01;
sad = 0x02;
lr = 256;
lc = 5;
ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, rsp);
if ((ret == OK) && (lr >= 2))
{
ifdh_context[ctn][slot]->icc_state.ATR_Length = (DWORD) lr - 2;
memcpy (ifdh_context[ctn][slot]->icc_state.ATR, rsp, lr - 2);
(*AtrLength) = (DWORD) lr - 2;
memcpy (Atr, rsp, lr - 2);
rv = IFD_SUCCESS;
}
else
rv = IFD_COMMUNICATION_ERROR;
}
else if (Action == IFD_POWER_DOWN)
{
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_EJECT;
cmd[2] = (UCHAR) (slot + 1);
cmd[3] = 0x00;
cmd[4] = 0x00;
dad = 0x01;
sad = 0x02;
lr = 256;
lc = 5;
ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, rsp);
if (ret == OK)
{
ifdh_context[ctn][slot]->icc_state.ATR_Length = 0;
memset (ifdh_context[ctn][slot]->icc_state.ATR, 0, MAX_ATR_SIZE);
(*AtrLength) = 0;
rv = IFD_SUCCESS;
}
else
rv = IFD_COMMUNICATION_ERROR;
}
else if (Action == IFD_RESET)
{
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_RESET;
cmd[2] = (UCHAR) (slot + 1);
cmd[3] = CTBCS_P2_RESET_GET_ATR;
cmd[4] = 0x00;
dad = 0x01;
sad = 0x02;
lr = 256;
lc = 5;
ret = CT_data (ctn, &dad, &sad, 5, cmd, &lr, rsp);
if ((ret == OK) && (lr >= 2))
{
ifdh_context[ctn][slot]->icc_state.ATR_Length = (DWORD) lr - 2;
memcpy (ifdh_context[ctn][slot]->icc_state.ATR, rsp, lr - 2);
(*AtrLength) = (DWORD) lr - 2;
memcpy (Atr, rsp, lr - 2);
rv = IFD_SUCCESS;
}
else
rv = IFD_ERROR_POWER_ACTION;
}
else
rv = IFD_NOT_SUPPORTED;
}
else
rv = IFD_ICC_NOT_PRESENT;
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHPowerICC (Lun=0x%X, Action=0x%X)=%d", Lun, Action, rv);
#endif
return rv;
}
RESPONSECODE
IFDHTransmitToICC (DWORD Lun, SCARD_IO_HEADER SendPci,
PUCHAR TxBuffer, DWORD TxLength,
PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci)
{
char ret;
unsigned short ctn, slot, lc, lr;
UCHAR sad, dad;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
if (ifdh_context[ctn][slot] != NULL)
{
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
dad = (UCHAR) ((slot == 0) ? 0x00 : slot + 1);
sad = 0x02;
lr = (unsigned short) (*RxLength);
lc = (unsigned short) TxLength;
ret = CT_data (ctn, &dad, &sad, lc, TxBuffer, &lr, RxBuffer);
if (ret == OK)
{
(*RxLength) = lr;
rv = IFD_SUCCESS;
}
else
{
(*RxLength) = 0;
rv = IFD_COMMUNICATION_ERROR;
}
}
else
{
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
rv = IFD_ICC_NOT_PRESENT;
}
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHTransmitToICC (Lun=0x%X, Tx=%u, Rx=%u)=%d", Lun, TxLength, (*RxLength), rv);
#endif
return rv;
}
RESPONSECODE
IFDHControl (DWORD Lun, PUCHAR TxBuffer,
DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
{
char ret;
unsigned short ctn, slot, lc, lr;
UCHAR sad, dad;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
#ifdef HAVE_PTHREAD_H
pthread_mutex_lock (&ifdh_context_mutex[ctn]);
#endif
if (ifdh_context[ctn][slot] != NULL)
{
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
dad = 0x01;
sad = 0x02;
lr = (unsigned short) (*RxLength);
lc = (unsigned short) TxLength;
ret = CT_data (ctn, &dad, &sad, lc, TxBuffer, &lr, RxBuffer);
if (ret == OK)
{
(*RxLength) = lr;
rv = IFD_SUCCESS;
}
else
{
(*RxLength) = 0;
rv = IFD_COMMUNICATION_ERROR;
}
}
else
{
#ifdef HAVE_PTHREAD_H
pthread_mutex_unlock (&ifdh_context_mutex[ctn]);
#endif
rv = IFD_ICC_NOT_PRESENT;
}
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHControl (Lun=0x%X, Tx=%u, Rx=%u)=%d", Lun, TxLength, (*RxLength), rv);
#endif
return rv;
}
RESPONSECODE
IFDHICCPresence (DWORD Lun)
{
char ret;
unsigned short ctn, slot, lc, lr;
UCHAR cmd[5], rsp[256], sad, dad;
RESPONSECODE rv;
ctn = ((unsigned short) (Lun >> 16)) % IFDH_MAX_READERS;
slot = ((unsigned short) (Lun & 0x0000FFFF)) % IFDH_MAX_SLOTS;
cmd[0] = CTBCS_CLA;
cmd[1] = CTBCS_INS_STATUS;
cmd[2] = CTBCS_P1_CT_KERNEL;
cmd[3] = CTBCS_P2_STATUS_ICC;
cmd[4] = 0x00;
dad = 0x01;
sad = 0x02;
lc = 5;
lr = 256;
ret = CT_data (ctn, &dad, &sad, lc, cmd, &lr, rsp);
if (ret == OK)
{
if (slot < lr - 2)
{
if (rsp[slot] == CTBCS_DATA_STATUS_NOCARD)
rv = IFD_ICC_NOT_PRESENT;
else
rv = IFD_ICC_PRESENT;
}
else
rv = IFD_ICC_NOT_PRESENT;
}
else
rv = IFD_COMMUNICATION_ERROR;
#ifdef DEBUG_IFDH
syslog (LOG_INFO, "IFDH: IFDHICCPresence (Lun=0x%X)=%d", Lun, rv);
#endif
return rv;
}
syntax highlighted by Code2HTML, v. 0.9.1