Blame src/commands.c

Packit Service aee942
/*
Packit Service aee942
    commands.c: Commands sent to the card
Packit Service aee942
    Copyright (C) 2003-2010   Ludovic Rousseau
Packit Service aee942
    Copyright (C) 2005 Martin Paljak
Packit Service aee942
Packit Service aee942
    This library is free software; you can redistribute it and/or
Packit Service aee942
    modify it under the terms of the GNU Lesser General Public
Packit Service aee942
    License as published by the Free Software Foundation; either
Packit Service aee942
    version 2.1 of the License, or (at your option) any later version.
Packit Service aee942
Packit Service aee942
    This library is distributed in the hope that it will be useful,
Packit Service aee942
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service aee942
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service aee942
    Lesser General Public License for more details.
Packit Service aee942
Packit Service aee942
	You should have received a copy of the GNU Lesser General Public License
Packit Service aee942
	along with this library; if not, write to the Free Software Foundation,
Packit Service aee942
	Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service aee942
*/
Packit Service aee942
Packit Service aee942
#include <config.h>
Packit Service aee942
Packit Service aee942
#ifdef HAVE_STRING_H
Packit Service aee942
#include <string.h>
Packit Service aee942
#endif
Packit Service aee942
#ifdef HAVE_STDLIB_H
Packit Service aee942
#include <stdlib.h>
Packit Service aee942
#endif
Packit Service aee942
#ifdef HAVE_ERRNO_H
Packit Service aee942
#include <errno.h>
Packit Service aee942
#endif
Packit Service aee942
#ifdef HAVE_UNISTD_H
Packit Service aee942
#include <unistd.h>
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
#include <pcsclite.h>
Packit Service aee942
#include <ifdhandler.h>
Packit Service aee942
#include <reader.h>
Packit Service aee942
Packit Service aee942
#include "misc.h"
Packit Service aee942
#include "commands.h"
Packit Service aee942
#include "openct/proto-t1.h"
Packit Service aee942
#include "ccid.h"
Packit Service aee942
#include "defs.h"
Packit Service aee942
#include "ccid_ifdhandler.h"
Packit Service aee942
#include "debug.h"
Packit Service aee942
#include "utils.h"
Packit Service aee942
Packit Service aee942
/* All the pinpad readers I used are more or less bogus
Packit Service aee942
 * I use code to change the user command and make the firmware happy */
Packit Service aee942
#define BOGUS_PINPAD_FIRMWARE
Packit Service aee942
Packit Service aee942
/* The firmware of SCM readers reports dwMaxCCIDMessageLength = 263
Packit Service aee942
 * instead of 270 so this prevents from sending a full length APDU
Packit Service aee942
 * of 260 bytes since the driver check this value */
Packit Service aee942
#define BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
Packit Service aee942
Packit Service aee942
#ifndef offsetof
Packit Service aee942
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
#ifndef BSWAP_16
Packit Service aee942
#define BSWAP_8(x)  ((x) & 0xff)
Packit Service aee942
#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
Packit Service aee942
#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
#define CHECK_STATUS(res) \
Packit Service aee942
	if (STATUS_NO_SUCH_DEVICE == res) \
Packit Service aee942
		return IFD_NO_SUCH_DEVICE; \
Packit Service aee942
	if (STATUS_SUCCESS != res) \
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
Packit Service aee942
/* internal functions */
Packit Service aee942
static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[]);
Packit Service aee942
Packit Service aee942
static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[]);
Packit Service aee942
Packit Service aee942
static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index, unsigned int
Packit Service aee942
	tx_length, unsigned char tx_buffer[], unsigned int *rx_length, unsigned
Packit Service aee942
	char rx_buffer[]);
Packit Service aee942
Packit Service aee942
static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[]);
Packit Service aee942
Packit Service aee942
static void i2dw(int value, unsigned char *buffer);
Packit Service aee942
static unsigned int bei2i(unsigned char *buffer);
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdPowerOn
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdPowerOn(unsigned int reader_index, unsigned int * nlength,
Packit Service aee942
	unsigned char buffer[], int voltage)
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[10];
Packit Service aee942
	status_t res;
Packit Service aee942
	int length, count = 1;
Packit Service aee942
	unsigned int atr_len;
Packit Service aee942
	int init_voltage;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
#ifndef TWIN_SERIAL
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit Service aee942
Packit Service aee942
		/* first power off to reset the ICC state machine */
Packit Service aee942
		r = CmdPowerOff(reader_index);
Packit Service aee942
		if (r != IFD_SUCCESS)
Packit Service aee942
			return r;
Packit Service aee942
Packit Service aee942
		/* wait for ready */
Packit Service aee942
		r = CmdGetSlotStatus(reader_index, pcbuffer);
Packit Service aee942
		if (r != IFD_SUCCESS)
Packit Service aee942
			return r;
Packit Service aee942
Packit Service aee942
		/* Power On */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x62, 0, buffer, *nlength);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		*nlength = r;
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char tmp[MAX_ATR_SIZE+1];
Packit Service aee942
Packit Service aee942
		/* first power off to reset the ICC state machine */
Packit Service aee942
		r = CmdPowerOff(reader_index);
Packit Service aee942
		if (r != IFD_SUCCESS)
Packit Service aee942
			return r;
Packit Service aee942
Packit Service aee942
		/* Power On */
Packit Service aee942
		r = ControlUSB(reader_index, 0x21, 0x62, 1, NULL, 0);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* Data Block */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x6F, 0, tmp, sizeof(tmp));
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if (tmp[0] != 0x00)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL2("bResponseType: 0x%02X", tmp[0]);
Packit Service aee942
Packit Service aee942
			/* Status Information? */
Packit Service aee942
			if (0x40 == tmp[0])
Packit Service aee942
				ccid_error(PCSC_LOG_ERROR, tmp[2], __FILE__, __LINE__, __FUNCTION__);
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		DEBUG_INFO_XXD("Data Block: ", tmp, r);
Packit Service aee942
		if ((int)*nlength > r-1)
Packit Service aee942
			*nlength = r-1;
Packit Service aee942
		memcpy(buffer, tmp+1, *nlength);
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* store length of buffer[] */
Packit Service aee942
	length = *nlength;
Packit Service aee942
Packit Service aee942
	if ((ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
Packit Service aee942
		|| (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_ACTIVATION))
Packit Service aee942
		voltage = 0;	/* automatic voltage selection */
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		int bVoltageSupport = ccid_descriptor->bVoltageSupport;
Packit Service aee942
Packit Service aee942
check_again:
Packit Service aee942
		if ((1 == voltage) && !(bVoltageSupport & 1))
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO1("5V requested but not support by reader");
Packit Service aee942
			voltage = 2;	/* 3V */
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if ((2 == voltage) && !(bVoltageSupport & 2))
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO1("3V requested but not support by reader");
Packit Service aee942
			voltage = 3;	/* 1.8V */
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if ((3 == voltage) && !(bVoltageSupport & 4))
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO1("1.8V requested but not support by reader");
Packit Service aee942
			voltage = 1;	/* 5V */
Packit Service aee942
			goto check_again;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
	init_voltage = voltage;
Packit Service aee942
Packit Service aee942
again:
Packit Service aee942
	cmd[0] = 0x62; /* IccPowerOn */
Packit Service aee942
	cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0;	/* dwLength */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = voltage;
Packit Service aee942
	cmd[8] = cmd[9] = 0; /* RFU */
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, sizeof(cmd), cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	/* reset available buffer size */
Packit Service aee942
	/* needed if we go back after a switch to ISO mode */
Packit Service aee942
	*nlength = length;
Packit Service aee942
Packit Service aee942
	res = ReadPort(reader_index, nlength, buffer);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	if (*nlength < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", *nlength);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
	{
Packit Service aee942
		ccid_error(PCSC_LOG_ERROR, buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
Packit Service aee942
		if (0xBB == buffer[ERROR_OFFSET] &&	/* Protocol error in EMV mode */
Packit Service aee942
			((GEMPC433 == ccid_descriptor->readerID)
Packit Service aee942
			|| (CHERRYXX33 == ccid_descriptor->readerID)))
Packit Service aee942
		{
Packit Service aee942
			unsigned char cmd_tmp[] = {0x1F, 0x01};
Packit Service aee942
			unsigned char res_tmp[1];
Packit Service aee942
			unsigned int res_length = sizeof(res_tmp);
Packit Service aee942
Packit Service aee942
			if ((return_value = CmdEscape(reader_index, cmd_tmp,
Packit Service aee942
				sizeof(cmd_tmp), res_tmp, &res_length, 0)) != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			/* avoid looping if we can't switch mode */
Packit Service aee942
			if (count--)
Packit Service aee942
				goto again;
Packit Service aee942
			else
Packit Service aee942
				DEBUG_CRITICAL("Can't set reader in ISO mode");
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* continue with other voltage values */
Packit Service aee942
		if (voltage)
Packit Service aee942
		{
Packit Service aee942
#ifndef NO_LOG
Packit Service aee942
			const char *voltage_code[] = { "auto", "5V", "3V", "1.8V" };
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
			DEBUG_INFO3("Power up with %s failed. Try with %s.",
Packit Service aee942
				voltage_code[voltage], voltage_code[voltage-1]);
Packit Service aee942
			voltage--;
Packit Service aee942
Packit Service aee942
			/* loop from 5V to 1.8V */
Packit Service aee942
			if (0 == voltage)
Packit Service aee942
				voltage = 3;
Packit Service aee942
Packit Service aee942
			/* continue until we tried every values */
Packit Service aee942
			if (voltage != init_voltage)
Packit Service aee942
				goto again;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* extract the ATR */
Packit Service aee942
	atr_len = dw2i(buffer, 1);	/* ATR length */
Packit Service aee942
	if (atr_len > *nlength)
Packit Service aee942
		atr_len = *nlength;
Packit Service aee942
	else
Packit Service aee942
		*nlength = atr_len;
Packit Service aee942
Packit Service aee942
	memmove(buffer, buffer+10, atr_len);
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdPowerOn */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					SecurePINVerify
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE SecurePINVerify(unsigned int reader_index,
Packit Service aee942
	unsigned char TxBuffer[], unsigned int TxLength,
Packit Service aee942
	unsigned char RxBuffer[], unsigned int *RxLength)
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[11+14+TxLength];
Packit Service aee942
	unsigned int a, b;
Packit Service aee942
	PIN_VERIFY_STRUCTURE *pvs;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	int old_read_timeout;
Packit Service aee942
	RESPONSECODE ret;
Packit Service aee942
	status_t res;
Packit Service aee942
Packit Service aee942
	pvs = (PIN_VERIFY_STRUCTURE *)TxBuffer;
Packit Service aee942
	cmd[0] = 0x69;	/* Secure */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = 0;		/* bBWI */
Packit Service aee942
	cmd[8] = 0;		/* wLevelParameter */
Packit Service aee942
	cmd[9] = 0;
Packit Service aee942
	cmd[10] = 0;	/* bPINOperation: PIN Verification */
Packit Service aee942
Packit Service aee942
	if (TxLength < 19+4 /* 4 = APDU size */)	/* command too short? */
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO3("Command too short: %d < %d", TxLength, 19+4);
Packit Service aee942
		return IFD_NOT_SUPPORTED;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* On little endian machines we are all set. */
Packit Service aee942
	/* If on big endian machine and caller is using host byte order */
Packit Service aee942
	if ((pvs->ulDataLength + 19  == TxLength) &&
Packit Service aee942
		(bei2i((unsigned char*)(&pvs->ulDataLength)) == pvs->ulDataLength))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO1("Reversing order from big to little endian");
Packit Service aee942
		/* If ulDataLength is big endian, assume others are too */
Packit Service aee942
		/* reverse the byte order for 3 fields */
Packit Service aee942
		pvs->wPINMaxExtraDigit = BSWAP_16(pvs->wPINMaxExtraDigit);
Packit Service aee942
		pvs->wLangId = BSWAP_16(pvs->wLangId);
Packit Service aee942
		pvs->ulDataLength = BSWAP_32(pvs->ulDataLength);
Packit Service aee942
	}
Packit Service aee942
	/* At this point we now have the above 3 variables in little endian */
Packit Service aee942
Packit Service aee942
	if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field coherency */
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 15) + 19, TxLength);
Packit Service aee942
		return IFD_NOT_SUPPORTED;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* make sure bEntryValidationCondition is valid
Packit Service aee942
	 * The Cherry XX44 reader crashes with a wrong value */
Packit Service aee942
	if ((0x00 == TxBuffer[7]) || (TxBuffer[7] > 0x07))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
Packit Service aee942
			TxBuffer[7]);
Packit Service aee942
		TxBuffer[7] = 0x02;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#ifdef BOGUS_PINPAD_FIRMWARE
Packit Service aee942
	/* bug circumvention for the GemPC Pinpad */
Packit Service aee942
	if ((GEMPCPINPAD == ccid_descriptor->readerID)
Packit Service aee942
		|| (VEGAALPHA == ccid_descriptor->readerID))
Packit Service aee942
	{
Packit Service aee942
		/* the firmware reject the cases: 00h No string and FFh default
Packit Service aee942
		 * CCID message. The only value supported is 01h (display 1 message) */
Packit Service aee942
		if (0x01 != TxBuffer[8])
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
Packit Service aee942
				TxBuffer[8]);
Packit Service aee942
			TxBuffer[8] = 0x01;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* The reader does not support, and actively reject, "max size reached"
Packit Service aee942
		 * and "timeout occured" validation conditions */
Packit Service aee942
		if (0x02 != TxBuffer[7])
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
Packit Service aee942
				TxBuffer[7]);
Packit Service aee942
			TxBuffer[7] = 0x02;	/* validation key pressed */
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if ((DELLSCRK == ccid_descriptor->readerID)
Packit Service aee942
		|| (DELLSK == ccid_descriptor->readerID))
Packit Service aee942
	{
Packit Service aee942
		/* the firmware rejects the cases: 01h-FEh and FFh default
Packit Service aee942
		 * CCID message. The only value supported is 00h (no message) */
Packit Service aee942
		if (0x00 != TxBuffer[8])
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Correct bNumberMessage for Dell keyboard (was %d)",
Packit Service aee942
				TxBuffer[8]);
Packit Service aee942
			TxBuffer[8] = 0x00;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* avoid the command rejection because the Enter key is still
Packit Service aee942
		 * pressed. Wait a bit for the key to be released */
Packit Service aee942
		(void)usleep(250*1000);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (DELLSK == ccid_descriptor->readerID)
Packit Service aee942
	{
Packit Service aee942
		/* the 2 bytes of wPINMaxExtraDigit are reversed */
Packit Service aee942
		int tmp;
Packit Service aee942
Packit Service aee942
		tmp = TxBuffer[6];
Packit Service aee942
		TxBuffer[6] = TxBuffer[5];
Packit Service aee942
		TxBuffer[5] = tmp;
Packit Service aee942
		DEBUG_INFO1("Correcting wPINMaxExtraDigit for Dell keyboard");
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* T=1 Protocol Management for a TPDU reader */
Packit Service aee942
	if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
Packit Service aee942
		&& (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
Packit Service aee942
	{
Packit Service aee942
		ct_buf_t sbuf;
Packit Service aee942
		unsigned char sdata[T1_BUFFER_SIZE];
Packit Service aee942
Packit Service aee942
		/* Initialize send buffer with the APDU */
Packit Service aee942
		ct_buf_set(&sbuf,
Packit Service aee942
			(void *)(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, abData)),
Packit Service aee942
			TxLength - offsetof(PIN_VERIFY_STRUCTURE, abData));
Packit Service aee942
Packit Service aee942
		/* Create T=1 block */
Packit Service aee942
		(void)t1_build(&((get_ccid_slot(reader_index))->t1),
Packit Service aee942
			sdata, 0, T1_I_BLOCK, &sbuf, NULL);
Packit Service aee942
Packit Service aee942
		/* Increment the sequence numbers  */
Packit Service aee942
		get_ccid_slot(reader_index)->t1.ns ^= 1;
Packit Service aee942
		get_ccid_slot(reader_index)->t1.nr ^= 1;
Packit Service aee942
Packit Service aee942
		/* Copy the generated T=1 block prologue into the teoprologue
Packit Service aee942
		 * of the CCID command */
Packit Service aee942
		memcpy(TxBuffer + offsetof(PIN_VERIFY_STRUCTURE, bTeoPrologue),
Packit Service aee942
			sdata, 3);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
Packit Service aee942
	for (a = 11, b = 0; b < TxLength; b++)
Packit Service aee942
	{
Packit Service aee942
		if (1 == b) /* bTimeOut2 field */
Packit Service aee942
			/* Ignore the second timeout as there's nothing we can do with
Packit Service aee942
			 * it currently */
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		if ((b >= 15) && (b <= 18)) /* ulDataLength field (4 bytes) */
Packit Service aee942
			/* the ulDataLength field is not present in the CCID frame
Packit Service aee942
			 * so do not copy */
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		/* copy the CCID block 'verbatim' */
Packit Service aee942
		cmd[a] = TxBuffer[b];
Packit Service aee942
		a++;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* SPR532 and Case 1 APDU */
Packit Service aee942
	if ((SPR532 == ccid_descriptor->readerID)
Packit Service aee942
		/* bmPINBlockString = 0 => PIN length not inserted in APDU */
Packit Service aee942
		&& (0 == TxBuffer[3])
Packit Service aee942
		/* case 1 APDU */
Packit Service aee942
		&& (4 == TxBuffer[15]))
Packit Service aee942
	{
Packit Service aee942
		RESPONSECODE return_value;
Packit Service aee942
		unsigned char cmd_tmp[] = { 0x80, 0x02, 0x00 };
Packit Service aee942
		unsigned char res_tmp[1];
Packit Service aee942
		unsigned int res_length = sizeof(res_tmp);
Packit Service aee942
Packit Service aee942
		/* the SPR532 will append the PIN code without any padding */
Packit Service aee942
		return_value = CmdEscape(reader_index, cmd_tmp, sizeof(cmd_tmp),
Packit Service aee942
			res_tmp, &res_length, 0);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		/* we need to set bSeq again to avoid a "Duplicate frame detected"
Packit Service aee942
		 * error since the bSeq of CmdEscape is now greater than bSeq set at
Packit Service aee942
		 * the beginning of this function */
Packit Service aee942
		cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	i2dw(a - 10, cmd + 1);  /* CCID message length */
Packit Service aee942
Packit Service aee942
	old_read_timeout = ccid_descriptor -> readTimeout;
Packit Service aee942
	ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000;	/* at least 90 seconds */
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, a, cmd);
Packit Service aee942
	if (STATUS_SUCCESS != res)
Packit Service aee942
	{
Packit Service aee942
		if (STATUS_NO_SUCH_DEVICE == res)
Packit Service aee942
			ret = IFD_NO_SUCH_DEVICE;
Packit Service aee942
		else
Packit Service aee942
			ret = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
Packit Service aee942
Packit Service aee942
	/* T=1 Protocol Management for a TPDU reader */
Packit Service aee942
	if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
Packit Service aee942
		&& (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
Packit Service aee942
	{
Packit Service aee942
		/* timeout and cancel cases are faked by CCID_Receive() */
Packit Service aee942
		if ((2 == *RxLength)
Packit Service aee942
			/* the CCID command is rejected or failed */
Packit Service aee942
		   || (IFD_SUCCESS != ret))
Packit Service aee942
		{
Packit Service aee942
			/* Decrement the sequence numbers since no TPDU was sent */
Packit Service aee942
			get_ccid_slot(reader_index)->t1.ns ^= 1;
Packit Service aee942
			get_ccid_slot(reader_index)->t1.nr ^= 1;
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
		{
Packit Service aee942
			/* FIXME: manage T=1 error blocks */
Packit Service aee942
Packit Service aee942
			/* defines from openct/proto-t1.c */
Packit Service aee942
			#define PCB 1
Packit Service aee942
			#define DATA 3
Packit Service aee942
			#define T1_S_BLOCK		0xC0
Packit Service aee942
			#define T1_S_RESPONSE		0x20
Packit Service aee942
			#define T1_S_TYPE(pcb)		((pcb) & 0x0F)
Packit Service aee942
			#define T1_S_WTX		0x03
Packit Service aee942
Packit Service aee942
			/* WTX S-block */
Packit Service aee942
			if ((T1_S_BLOCK | T1_S_WTX) == RxBuffer[PCB])
Packit Service aee942
			{
Packit Service aee942
/*
Packit Service aee942
 * The Swiss health care card sends a WTX request before returning the
Packit Service aee942
 * SW code. If the reader is in TPDU the driver must manage the request
Packit Service aee942
 * itself.
Packit Service aee942
 *
Packit Service aee942
 * received: 00 C3 01 09 CB
Packit Service aee942
 * openct/proto-t1.c:432:t1_transceive() S-Block request received
Packit Service aee942
 * openct/proto-t1.c:489:t1_transceive() CT sent S-block with wtx=9
Packit Service aee942
 * sending: 00 E3 01 09 EB
Packit Service aee942
 * openct/proto-t1.c:667:t1_xcv() New timeout at WTX request: 23643 sec
Packit Service aee942
 * received: 00 40 02 90 00 D2
Packit Service aee942
*/
Packit Service aee942
				ct_buf_t tbuf;
Packit Service aee942
				unsigned char sblk[1]; /* we only need 1 byte of data */
Packit Service aee942
				t1_state_t *t1 = &get_ccid_slot(reader_index)->t1;
Packit Service aee942
				unsigned int slen;
Packit Service aee942
				int oldReadTimeout;
Packit Service aee942
Packit Service aee942
				DEBUG_COMM2("CT sent S-block with wtx=%u", RxBuffer[DATA]);
Packit Service aee942
				t1->wtx = RxBuffer[DATA];
Packit Service aee942
Packit Service aee942
				oldReadTimeout = ccid_descriptor->readTimeout;
Packit Service aee942
				if (t1->wtx > 1)
Packit Service aee942
				{
Packit Service aee942
					/* set the new temporary timeout at WTX card request */
Packit Service aee942
					ccid_descriptor->readTimeout *= t1->wtx;
Packit Service aee942
					DEBUG_INFO2("New timeout at WTX request: %d sec",
Packit Service aee942
							ccid_descriptor->readTimeout);
Packit Service aee942
				}
Packit Service aee942
Packit Service aee942
				ct_buf_init(&tbuf, sblk, sizeof(sblk));
Packit Service aee942
				t1->wtx = RxBuffer[DATA];
Packit Service aee942
				ct_buf_putc(&tbuf, RxBuffer[DATA]);
Packit Service aee942
Packit Service aee942
				slen = t1_build(t1, RxBuffer, 0,
Packit Service aee942
					T1_S_BLOCK | T1_S_RESPONSE | T1_S_TYPE(RxBuffer[PCB]),
Packit Service aee942
					&tbuf, NULL);
Packit Service aee942
Packit Service aee942
				ret = CCID_Transmit(t1 -> lun, slen, RxBuffer, 0, t1->wtx);
Packit Service aee942
				if (ret != IFD_SUCCESS)
Packit Service aee942
					return ret;
Packit Service aee942
Packit Service aee942
				/* I guess we have at least 6 bytes in RxBuffer */
Packit Service aee942
				*RxLength = 6;
Packit Service aee942
				ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
Packit Service aee942
				if (ret != IFD_SUCCESS)
Packit Service aee942
					return ret;
Packit Service aee942
Packit Service aee942
				/* Restore initial timeout */
Packit Service aee942
				ccid_descriptor->readTimeout = oldReadTimeout;
Packit Service aee942
			}
Packit Service aee942
Packit Service aee942
			/* get only the T=1 data */
Packit Service aee942
			memmove(RxBuffer, RxBuffer+3, *RxLength -4);
Packit Service aee942
			*RxLength -= 4;	/* remove NAD, PCB, LEN and CRC */
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
end:
Packit Service aee942
	ccid_descriptor -> readTimeout = old_read_timeout;
Packit Service aee942
	return ret;
Packit Service aee942
} /* SecurePINVerify */
Packit Service aee942
Packit Service aee942
Packit Service aee942
#ifdef BOGUS_PINPAD_FIRMWARE
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					has_gemalto_modify_pin_bug
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static int has_gemalto_modify_pin_bug(_ccid_descriptor *ccid_descriptor)
Packit Service aee942
{
Packit Service aee942
	/* Bug not present by default */
Packit Service aee942
	int has_bug = 0;
Packit Service aee942
Packit Service aee942
	/* Covadis Véga-Alpha reader */
Packit Service aee942
	if (VEGAALPHA == ccid_descriptor->readerID)
Packit Service aee942
	{
Packit Service aee942
		/* This reader has the bug (uses a Gemalto firmware) */
Packit Service aee942
		has_bug = 1;
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		/* Gemalto reader */
Packit Service aee942
		if ((GET_VENDOR(ccid_descriptor->readerID) == VENDOR_GEMALTO))
Packit Service aee942
		{
Packit Service aee942
			has_bug = 1; /* assume it has the bug */
Packit Service aee942
Packit Service aee942
			if (ccid_descriptor->gemalto_firmware_features &&
Packit Service aee942
				ccid_descriptor->gemalto_firmware_features->bNumberMessageFix)
Packit Service aee942
			{
Packit Service aee942
				/* A Gemalto reader has the ModifyPIN structure bug */
Packit Service aee942
				/* unless it explicitly reports it has been fixed */
Packit Service aee942
				has_bug = 0;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return has_bug;
Packit Service aee942
} /* has_gemalto_modify_pin_bug */
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					SecurePINModify
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE SecurePINModify(unsigned int reader_index,
Packit Service aee942
	unsigned char TxBuffer[], unsigned int TxLength,
Packit Service aee942
	unsigned char RxBuffer[], unsigned int *RxLength)
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[11+19+TxLength];
Packit Service aee942
	unsigned int a, b;
Packit Service aee942
	PIN_MODIFY_STRUCTURE *pms;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	int old_read_timeout;
Packit Service aee942
	RESPONSECODE ret;
Packit Service aee942
	status_t res;
Packit Service aee942
#ifdef BOGUS_PINPAD_FIRMWARE
Packit Service aee942
	int bNumberMessage = 0; /* for GemPC Pinpad */
Packit Service aee942
	int gemalto_modify_pin_bug;
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	pms = (PIN_MODIFY_STRUCTURE *)TxBuffer;
Packit Service aee942
	cmd[0] = 0x69;	/* Secure */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = 0;		/* bBWI */
Packit Service aee942
	cmd[8] = 0;		/* wLevelParameter */
Packit Service aee942
	cmd[9] = 0;
Packit Service aee942
	cmd[10] = 1;	/* bPINOperation: PIN Modification */
Packit Service aee942
Packit Service aee942
	if (TxLength < 24+4 /* 4 = APDU size */) /* command too short? */
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO3("Command too short: %d < %d", TxLength, 24+4);
Packit Service aee942
		return IFD_NOT_SUPPORTED;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* On little endian machines we are all set. */
Packit Service aee942
	/* If on big endian machine and caller is using host byte order */
Packit Service aee942
	if ((pms->ulDataLength + 24  == TxLength) &&
Packit Service aee942
		(bei2i((unsigned char*)(&pms->ulDataLength)) == pms->ulDataLength))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO1("Reversing order from big to little endian");
Packit Service aee942
		/* If ulDataLength is big endian, assume others are too */
Packit Service aee942
		/* reverse the byte order for 3 fields */
Packit Service aee942
		pms->wPINMaxExtraDigit = BSWAP_16(pms->wPINMaxExtraDigit);
Packit Service aee942
		pms->wLangId = BSWAP_16(pms->wLangId);
Packit Service aee942
		pms->ulDataLength = BSWAP_32(pms->ulDataLength);
Packit Service aee942
	}
Packit Service aee942
	/* At this point we now have the above 3 variables in little endian */
Packit Service aee942
Packit Service aee942
Packit Service aee942
	if (dw2i(TxBuffer, 20) + 24 != TxLength) /* ulDataLength field coherency */
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 20) + 24, TxLength);
Packit Service aee942
		return IFD_NOT_SUPPORTED;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Make sure in the beginning if bNumberMessage is valid or not.
Packit Service aee942
	 * 0xFF is the default value. */
Packit Service aee942
	if ((TxBuffer[11] > 3) && (TxBuffer[11] != 0xFF))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO2("Wrong bNumberMessage: %d", TxBuffer[11]);
Packit Service aee942
		return IFD_NOT_SUPPORTED;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Make sure bEntryValidationCondition is valid
Packit Service aee942
	 * The Cherry XX44 reader crashes with a wrong value */
Packit Service aee942
	if ((0x00 == TxBuffer[10]) || (TxBuffer[10] > 0x07))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO2("Correct bEntryValidationCondition (was 0x%02X)",
Packit Service aee942
			TxBuffer[10]);
Packit Service aee942
		TxBuffer[10] = 0x02;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#ifdef BOGUS_PINPAD_FIRMWARE
Packit Service aee942
	/* some firmwares are buggy so we try to "correct" the frame */
Packit Service aee942
	/*
Packit Service aee942
	 * SPR 532 and Cherry ST 2000C has no display but requires _all_
Packit Service aee942
	 * bMsgIndex fields with bNumberMessage set to 0.
Packit Service aee942
	 */
Packit Service aee942
	if ((SPR532 == ccid_descriptor->readerID)
Packit Service aee942
		|| (CHERRYST2000 == ccid_descriptor->readerID))
Packit Service aee942
	{
Packit Service aee942
		TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
Packit Service aee942
								all bMsgIndex123 are filled */
Packit Service aee942
		TxBuffer[14] = TxBuffer[15] = TxBuffer[16] = 0;	/* bMsgIndex123 */
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* the bug is a bit different than for the Cherry ST 2000C
Packit Service aee942
	 * with bNumberMessage < 3 the command seems to be accepted
Packit Service aee942
	 * and the card sends 6B 80 */
Packit Service aee942
	if (CHERRYXX44 == ccid_descriptor->readerID)
Packit Service aee942
	{
Packit Service aee942
		TxBuffer[11] = 0x03; /* set bNumberMessage to 3 so that
Packit Service aee942
								all bMsgIndex123 are filled */
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* bug circumvention for the GemPC Pinpad */
Packit Service aee942
	if ((GEMPCPINPAD == ccid_descriptor->readerID)
Packit Service aee942
		|| (VEGAALPHA == ccid_descriptor->readerID))
Packit Service aee942
	{
Packit Service aee942
		/* The reader does not support, and actively reject, "max size reached"
Packit Service aee942
		 * and "timeout occured" validation conditions */
Packit Service aee942
		if (0x02 != TxBuffer[10])
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Correct bEntryValidationCondition for GemPC Pinpad (was %d)",
Packit Service aee942
				TxBuffer[10]);
Packit Service aee942
			TxBuffer[10] = 0x02;	/* validation key pressed */
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	gemalto_modify_pin_bug = has_gemalto_modify_pin_bug(ccid_descriptor);
Packit Service aee942
	if (gemalto_modify_pin_bug)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_INFO1("Gemalto CCID Modify Pin Bug");
Packit Service aee942
Packit Service aee942
		/* The reader requests a value for bMsgIndex2 and bMsgIndex3
Packit Service aee942
		 * even if they should not be present. So we fake
Packit Service aee942
		 * bNumberMessage=3.  The real number of messages will be
Packit Service aee942
		 * corrected later in the code */
Packit Service aee942
		bNumberMessage = TxBuffer[11];
Packit Service aee942
		if (0x03 != TxBuffer[11])
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Correct bNumberMessage for GemPC Pinpad (was %d)",
Packit Service aee942
				TxBuffer[11]);
Packit Service aee942
			TxBuffer[11] = 0x03; /* 3 messages */
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* T=1 Protocol Management for a TPDU reader */
Packit Service aee942
	if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
Packit Service aee942
		&& (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
Packit Service aee942
	{
Packit Service aee942
		ct_buf_t sbuf;
Packit Service aee942
		unsigned char sdata[T1_BUFFER_SIZE];
Packit Service aee942
Packit Service aee942
		/* Initialize send buffer with the APDU */
Packit Service aee942
		ct_buf_set(&sbuf,
Packit Service aee942
			(void *)(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, abData)),
Packit Service aee942
			TxLength - offsetof(PIN_MODIFY_STRUCTURE, abData));
Packit Service aee942
Packit Service aee942
		/* Create T=1 block */
Packit Service aee942
		(void)t1_build(&((get_ccid_slot(reader_index))->t1),
Packit Service aee942
			sdata, 0, T1_I_BLOCK, &sbuf, NULL);
Packit Service aee942
Packit Service aee942
		/* Increment the sequence numbers  */
Packit Service aee942
		get_ccid_slot(reader_index)->t1.ns ^= 1;
Packit Service aee942
		get_ccid_slot(reader_index)->t1.nr ^= 1;
Packit Service aee942
Packit Service aee942
		/* Copy the generated T=1 block prologue into the teoprologue
Packit Service aee942
		 * of the CCID command */
Packit Service aee942
		memcpy(TxBuffer + offsetof(PIN_MODIFY_STRUCTURE, bTeoPrologue),
Packit Service aee942
			sdata, 3);
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Build a CCID block from a PC/SC V2.02.05 Part 10 block */
Packit Service aee942
Packit Service aee942
	/* Do adjustments as needed - CCID spec is not exact with some
Packit Service aee942
	 * details in the format of the structure, per-reader adaptions
Packit Service aee942
	 * might be needed.
Packit Service aee942
	 */
Packit Service aee942
	for (a = 11, b = 0; b < TxLength; b++)
Packit Service aee942
	{
Packit Service aee942
		if (1 == b) /* bTimeOut2 */
Packit Service aee942
			/* Ignore the second timeout as there's nothing we can do with it
Packit Service aee942
			 * currently */
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		if (15 == b) /* bMsgIndex2 */
Packit Service aee942
		{
Packit Service aee942
			/* in CCID the bMsgIndex2 is present only if bNumberMessage != 0 */
Packit Service aee942
			if (0 == TxBuffer[11])
Packit Service aee942
				continue;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if (16 == b) /* bMsgIndex3 */
Packit Service aee942
		{
Packit Service aee942
			/* in CCID the bMsgIndex3 is present only if bNumberMessage == 3 */
Packit Service aee942
			if (TxBuffer[11] < 3)
Packit Service aee942
				continue;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		if ((b >= 20) && (b <= 23)) /* ulDataLength field (4 bytes) */
Packit Service aee942
			/* the ulDataLength field is not present in the CCID frame
Packit Service aee942
			 * so do not copy */
Packit Service aee942
			continue;
Packit Service aee942
Packit Service aee942
		/* copy to the CCID block 'verbatim' */
Packit Service aee942
		cmd[a] = TxBuffer[b];
Packit Service aee942
		a++;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
#ifdef BOGUS_PINPAD_FIRMWARE
Packit Service aee942
	if ((SPR532 == ccid_descriptor->readerID)
Packit Service aee942
		|| (CHERRYST2000 == ccid_descriptor->readerID))
Packit Service aee942
	{
Packit Service aee942
		cmd[21] = 0x00; /* set bNumberMessage to 0 */
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (gemalto_modify_pin_bug)
Packit Service aee942
		cmd[21] = bNumberMessage;	/* restore the real value */
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* We know the size of the CCID message now */
Packit Service aee942
	i2dw(a - 10, cmd + 1);	/* command length (includes bPINOperation) */
Packit Service aee942
Packit Service aee942
	old_read_timeout = ccid_descriptor -> readTimeout;
Packit Service aee942
	ccid_descriptor -> readTimeout = max(90, TxBuffer[0]+10)*1000;	/* at least 90 seconds */
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, a, cmd);
Packit Service aee942
	if (STATUS_SUCCESS != res)
Packit Service aee942
	{
Packit Service aee942
		if (STATUS_NO_SUCH_DEVICE == res)
Packit Service aee942
			ret = IFD_NO_SUCH_DEVICE;
Packit Service aee942
		else
Packit Service aee942
			ret = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	ret = CCID_Receive(reader_index, RxLength, RxBuffer, NULL);
Packit Service aee942
Packit Service aee942
	/* T=1 Protocol Management for a TPDU reader */
Packit Service aee942
	if ((SCARD_PROTOCOL_T1 == ccid_descriptor->cardProtocol)
Packit Service aee942
		&& (CCID_CLASS_TPDU == (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)))
Packit Service aee942
	{
Packit Service aee942
		/* timeout and cancel cases are faked by CCID_Receive() */
Packit Service aee942
		if ((2 == *RxLength)
Packit Service aee942
			/* the CCID command is rejected or failed */
Packit Service aee942
			|| (IFD_SUCCESS != ret))
Packit Service aee942
		{
Packit Service aee942
			/* Decrement the sequence numbers since no TPDU was sent */
Packit Service aee942
			get_ccid_slot(reader_index)->t1.ns ^= 1;
Packit Service aee942
			get_ccid_slot(reader_index)->t1.nr ^= 1;
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
		{
Packit Service aee942
			/* get only the T=1 data */
Packit Service aee942
			/* FIXME: manage T=1 error blocks */
Packit Service aee942
			memmove(RxBuffer, RxBuffer+3, *RxLength -4);
Packit Service aee942
			*RxLength -= 4;	/* remove NAD, PCB, LEN and CRC */
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
end:
Packit Service aee942
	ccid_descriptor -> readTimeout = old_read_timeout;
Packit Service aee942
	return ret;
Packit Service aee942
} /* SecurePINModify */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Escape
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdEscape(unsigned int reader_index,
Packit Service aee942
	const unsigned char TxBuffer[], unsigned int TxLength,
Packit Service aee942
	unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout)
Packit Service aee942
{
Packit Service aee942
	return CmdEscapeCheck(reader_index, TxBuffer, TxLength, RxBuffer, RxLength,
Packit Service aee942
		timeout, FALSE);
Packit Service aee942
} /* CmdEscape */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					Escape (with check of gravity)
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdEscapeCheck(unsigned int reader_index,
Packit Service aee942
	const unsigned char TxBuffer[], unsigned int TxLength,
Packit Service aee942
	unsigned char RxBuffer[], unsigned int *RxLength, unsigned int timeout,
Packit Service aee942
	int mayfail)
Packit Service aee942
{
Packit Service aee942
	unsigned char *cmd_in, *cmd_out;
Packit Service aee942
	status_t res;
Packit Service aee942
	unsigned int length_in, length_out;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	int old_read_timeout;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
	/* a value of 0 do not change the default read timeout */
Packit Service aee942
	if (timeout > 0)
Packit Service aee942
	{
Packit Service aee942
		old_read_timeout = ccid_descriptor -> readTimeout;
Packit Service aee942
		ccid_descriptor -> readTimeout = timeout;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
again:
Packit Service aee942
	/* allocate buffers */
Packit Service aee942
	length_in = 10 + TxLength;
Packit Service aee942
	if (NULL == (cmd_in = malloc(length_in)))
Packit Service aee942
	{
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	length_out = 10 + *RxLength;
Packit Service aee942
	if (NULL == (cmd_out = malloc(length_out)))
Packit Service aee942
	{
Packit Service aee942
		free(cmd_in);
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	cmd_in[0] = 0x6B; /* PC_to_RDR_Escape */
Packit Service aee942
	i2dw(length_in - 10, cmd_in+1);	/* dwLength */
Packit Service aee942
	cmd_in[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd_in[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd_in[7] = cmd_in[8] = cmd_in[9] = 0; /* RFU */
Packit Service aee942
Packit Service aee942
	/* copy the command */
Packit Service aee942
	memcpy(&cmd_in[10], TxBuffer, TxLength);
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, length_in, cmd_in);
Packit Service aee942
	free(cmd_in);
Packit Service aee942
	if (res != STATUS_SUCCESS)
Packit Service aee942
	{
Packit Service aee942
		free(cmd_out);
Packit Service aee942
		if (STATUS_NO_SUCH_DEVICE == res)
Packit Service aee942
			return_value = IFD_NO_SUCH_DEVICE;
Packit Service aee942
		else
Packit Service aee942
			return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
time_request:
Packit Service aee942
	length_out = 10 + *RxLength;
Packit Service aee942
	res = ReadPort(reader_index, &length_out, cmd_out);
Packit Service aee942
Packit Service aee942
	/* replay the command if NAK
Packit Service aee942
	 * This (generally) happens only for the first command sent to the reader
Packit Service aee942
	 * with the serial protocol so it is not really needed for all the other
Packit Service aee942
	 * ReadPort() calls */
Packit Service aee942
	if (STATUS_COMM_NAK == res)
Packit Service aee942
	{
Packit Service aee942
		free(cmd_out);
Packit Service aee942
		goto again;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (res != STATUS_SUCCESS)
Packit Service aee942
	{
Packit Service aee942
		free(cmd_out);
Packit Service aee942
		if (STATUS_NO_SUCH_DEVICE == res)
Packit Service aee942
			return_value = IFD_NO_SUCH_DEVICE;
Packit Service aee942
		else
Packit Service aee942
			return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (length_out < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		free(cmd_out);
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", length_out);
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		goto end;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd_out[STATUS_OFFSET] & CCID_TIME_EXTENSION)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_COMM2("Time extension requested: 0x%02X", cmd_out[ERROR_OFFSET]);
Packit Service aee942
		goto time_request;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd_out[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
	{
Packit Service aee942
		/* mayfail: the error may be expected and not fatal */
Packit Service aee942
		ccid_error(mayfail ? PCSC_LOG_INFO : PCSC_LOG_ERROR,
Packit Service aee942
			cmd_out[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* copy the response */
Packit Service aee942
	length_out = dw2i(cmd_out, 1);
Packit Service aee942
	if (length_out > *RxLength)
Packit Service aee942
	{
Packit Service aee942
		length_out = *RxLength;
Packit Service aee942
		return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit Service aee942
	}
Packit Service aee942
	*RxLength = length_out;
Packit Service aee942
	memcpy(RxBuffer, &cmd_out[10], length_out);
Packit Service aee942
Packit Service aee942
	free(cmd_out);
Packit Service aee942
Packit Service aee942
end:
Packit Service aee942
	if (timeout > 0)
Packit Service aee942
		ccid_descriptor -> readTimeout = old_read_timeout;
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* EscapeCheck */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdPowerOff
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdPowerOff(unsigned int reader_index)
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[10];
Packit Service aee942
	status_t res;
Packit Service aee942
	unsigned int length;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
#ifndef TWIN_SERIAL
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
Packit Service aee942
		/* PowerOff */
Packit Service aee942
		r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char buffer[3];
Packit Service aee942
Packit Service aee942
		/* PowerOff */
Packit Service aee942
		r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* SlotStatus */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer, sizeof(buffer));
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC SlotStatus failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	cmd[0] = 0x63; /* IccPowerOff */
Packit Service aee942
	cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0;	/* dwLength */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, sizeof(cmd), cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	length = sizeof(cmd);
Packit Service aee942
	res = ReadPort(reader_index, &length, cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	if (length < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
	{
Packit Service aee942
		ccid_error(PCSC_LOG_ERROR, cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdPowerOff */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdGetSlotStatus
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[])
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[10];
Packit Service aee942
	status_t res;
Packit Service aee942
	unsigned int length;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
#ifndef TWIN_SERIAL
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char status[1];
Packit Service aee942
Packit Service aee942
again_status:
Packit Service aee942
		/* SlotStatus */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0xA0, 0, status, sizeof(status));
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
Packit Service aee942
			if (ENODEV == errno)
Packit Service aee942
				return IFD_NO_SUCH_DEVICE;
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* busy */
Packit Service aee942
		if (status[0] & 0x40)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("Busy: 0x%02X", status[0]);
Packit Service aee942
			(void)usleep(1000 * 10);
Packit Service aee942
			goto again_status;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* simulate a CCID bStatus */
Packit Service aee942
		/* present and active by default */
Packit Service aee942
		buffer[7] = CCID_ICC_PRESENT_ACTIVE;
Packit Service aee942
Packit Service aee942
		/* mute */
Packit Service aee942
		if (0x80 == status[0])
Packit Service aee942
			buffer[7] = CCID_ICC_ABSENT;
Packit Service aee942
Packit Service aee942
		/* store the status for CmdXfrBlockCHAR_T0() */
Packit Service aee942
		buffer[0] = status[0];
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char buffer_tmp[3];
Packit Service aee942
Packit Service aee942
		/* SlotStatus */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer_tmp,
Packit Service aee942
			sizeof(buffer_tmp));
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
Packit Service aee942
			if (ENODEV == errno)
Packit Service aee942
				return IFD_NO_SUCH_DEVICE;
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* simulate a CCID bStatus */
Packit Service aee942
		switch (buffer_tmp[1] & 0x03)
Packit Service aee942
		{
Packit Service aee942
			case 0:
Packit Service aee942
				buffer[7] = CCID_ICC_PRESENT_ACTIVE;
Packit Service aee942
				break;
Packit Service aee942
			case 1:
Packit Service aee942
				buffer[7] = CCID_ICC_PRESENT_INACTIVE;
Packit Service aee942
				break;
Packit Service aee942
			case 2:
Packit Service aee942
			case 3:
Packit Service aee942
				buffer[7] = CCID_ICC_ABSENT;
Packit Service aee942
		}
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
#ifdef __APPLE__
Packit Service aee942
	if (MICROCHIP_SEC1100 == ccid_descriptor->readerID)
Packit Service aee942
		InterruptRead(reader_index, 10);
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	cmd[0] = 0x65; /* GetSlotStatus */
Packit Service aee942
	cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0;	/* dwLength */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, sizeof(cmd), cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	length = SIZE_GET_SLOT_STATUS;
Packit Service aee942
	res = ReadPort(reader_index, &length, buffer);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	if (length < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if ((buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
		/* card absent or mute is not an communication error */
Packit Service aee942
		&& (buffer[ERROR_OFFSET] != 0xFE))
Packit Service aee942
	{
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		ccid_error(PCSC_LOG_ERROR, buffer[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdGetSlotStatus */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdXfrBlock
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CmdXfrBlock(unsigned int reader_index, unsigned int tx_length,
Packit Service aee942
	unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[], int protocol)
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
	/* APDU or TPDU? */
Packit Service aee942
	switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
Packit Service aee942
	{
Packit Service aee942
		case CCID_CLASS_TPDU:
Packit Service aee942
			if (protocol == T_0)
Packit Service aee942
				return_value = CmdXfrBlockTPDU_T0(reader_index,
Packit Service aee942
					tx_length, tx_buffer, rx_length, rx_buffer);
Packit Service aee942
			else
Packit Service aee942
				if (protocol == T_1)
Packit Service aee942
					return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
Packit Service aee942
						tx_buffer, rx_length, rx_buffer);
Packit Service aee942
				else
Packit Service aee942
					return_value = IFD_PROTOCOL_NOT_SUPPORTED;
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		case CCID_CLASS_SHORT_APDU:
Packit Service aee942
			return_value = CmdXfrBlockTPDU_T0(reader_index,
Packit Service aee942
				tx_length, tx_buffer, rx_length, rx_buffer);
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		case CCID_CLASS_EXTENDED_APDU:
Packit Service aee942
			return_value = CmdXfrBlockAPDU_extended(reader_index,
Packit Service aee942
				tx_length, tx_buffer, rx_length, rx_buffer);
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		case CCID_CLASS_CHARACTER:
Packit Service aee942
			if (protocol == T_0)
Packit Service aee942
				return_value = CmdXfrBlockCHAR_T0(reader_index, tx_length,
Packit Service aee942
					tx_buffer, rx_length, rx_buffer);
Packit Service aee942
			else
Packit Service aee942
				if (protocol == T_1)
Packit Service aee942
					return_value = CmdXfrBlockTPDU_T1(reader_index, tx_length,
Packit Service aee942
						tx_buffer, rx_length, rx_buffer);
Packit Service aee942
				else
Packit Service aee942
					return_value = IFD_PROTOCOL_NOT_SUPPORTED;
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		default:
Packit Service aee942
			return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdXfrBlock */
Packit Service aee942
Packit Service 3bd214
static RESPONSECODE omnikey_transmit_tpdu(unsigned int reader_index,
Packit Service 3bd214
        _ccid_descriptor *ccid_descriptor, unsigned int tx_length,
Packit Service 3bd214
        const unsigned char *tx_buffer)
Packit Service 3bd214
{
Packit Service 3bd214
	unsigned char cmd[11+CMD_BUF_SIZE];	 /* CCID + APDU buffer */
Packit Service 3bd214
	status_t ret;
Packit Service 3bd214
Packit Service 3bd214
	cmd[0] = 0x6B; 				/* 3121 escape */
Packit Service 3bd214
	i2dw(tx_length+1, cmd+1); 	/* APDU length */
Packit Service 3bd214
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service 3bd214
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service 3bd214
	cmd[7] = 0;
Packit Service 3bd214
	cmd[8] = 0;
Packit Service 3bd214
	cmd[9] = 0;
Packit Service 3bd214
	cmd[10] = 0x1A;
Packit Service 3bd214
Packit Service 3bd214
	/* check that the command is not too large */
Packit Service 3bd214
	if (tx_length > CMD_BUF_SIZE)
Packit Service 3bd214
	{
Packit Service 3bd214
		DEBUG_CRITICAL2("TX Length too big: %d", tx_length);
Packit Service 3bd214
		return IFD_NOT_SUPPORTED;
Packit Service 3bd214
	}
Packit Service 3bd214
Packit Service 3bd214
	memcpy(cmd+11, tx_buffer, tx_length);
Packit Service 3bd214
Packit Service 3bd214
	ret = WritePort(reader_index, 11+tx_length, cmd);
Packit Service 3bd214
	if (STATUS_NO_SUCH_DEVICE == ret)
Packit Service 3bd214
		return IFD_NO_SUCH_DEVICE;
Packit Service 3bd214
	if (ret != STATUS_SUCCESS)
Packit Service 3bd214
		return IFD_COMMUNICATION_ERROR;
Packit Service 3bd214
Packit Service 3bd214
	return IFD_SUCCESS;
Packit Service 3bd214
} /* omnikey_transmit_tpdu */
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CCID_Transmit
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CCID_Transmit(unsigned int reader_index, unsigned int tx_length,
Packit Service aee942
	const unsigned char tx_buffer[], unsigned short rx_length, unsigned char bBWI)
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[10+tx_length];	/* CCID + APDU buffer */
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	status_t ret;
Packit Service aee942
Packit Service aee942
#ifndef TWIN_SERIAL
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
Packit Service aee942
		/* Xfr Block */
Packit Service aee942
		r = ControlUSB(reader_index, 0x21, 0x65, 0,
Packit Service aee942
			(unsigned char *)tx_buffer, tx_length);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
Packit Service aee942
		/* nul block so we are chaining */
Packit Service aee942
		if (NULL == tx_buffer)
Packit Service aee942
			rx_length = 0x10;	/* bLevelParameter */
Packit Service aee942
Packit Service aee942
		/* Xfr Block */
Packit Service aee942
		DEBUG_COMM2("chain parameter: %d", rx_length);
Packit Service aee942
		r = ControlUSB(reader_index, 0x21, 0x65, rx_length << 8,
Packit Service aee942
			(unsigned char *)tx_buffer, tx_length);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service 3bd214
	/* hack for Onmikey 3121 */
Packit Service 3bd214
	if ((ccid_descriptor->dwNonStandardFlags & CCID_NON_STAND_OMK_3121_T1) &&
Packit Service 3bd214
		(ccid_descriptor->cardProtocol == SCARD_PROTOCOL_T1)) {
Packit Service 3bd214
		return omnikey_transmit_tpdu(reader_index, ccid_descriptor, tx_length, 
Packit Service 3bd214
				tx_buffer);
Packit Service 3bd214
	}
Packit Service 3bd214
Packit Service aee942
	cmd[0] = 0x6F; /* XfrBlock */
Packit Service aee942
	i2dw(tx_length, cmd+1);	/* APDU length */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = bBWI;	/* extend block waiting timeout */
Packit Service aee942
	cmd[8] = rx_length & 0xFF;	/* Expected length, in character mode only */
Packit Service aee942
	cmd[9] = (rx_length >> 8) & 0xFF;
Packit Service aee942
Packit Service aee942
	memcpy(cmd+10, tx_buffer, tx_length);
Packit Service aee942
Packit Service aee942
	ret = WritePort(reader_index, 10+tx_length, cmd);
Packit Service aee942
	CHECK_STATUS(ret)
Packit Service aee942
Packit Service aee942
	return IFD_SUCCESS;
Packit Service aee942
} /* CCID_Transmit */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CCID_Receive
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE CCID_Receive(unsigned int reader_index, unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[], unsigned char *chain_parameter)
Packit Service aee942
{
Packit Service 3bd214
	unsigned char cmd[11+CMD_BUF_SIZE];	/* CCID + APDU buffer */
Packit Service aee942
	unsigned int length;
Packit Service 3bd214
	unsigned char *rx_ptr = cmd+10;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	status_t ret;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	unsigned int old_timeout;
Packit Service aee942
Packit Service aee942
#ifndef TWIN_SERIAL
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit Service aee942
		int r;
Packit Service aee942
Packit Service aee942
		/* wait for ready */
Packit Service aee942
		r = CmdGetSlotStatus(reader_index, pcbuffer);
Packit Service aee942
		if (r != IFD_SUCCESS)
Packit Service aee942
			return r;
Packit Service aee942
Packit Service aee942
		/* Data Block */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* we need to store returned value */
Packit Service aee942
		*rx_length = r;
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		int r;
Packit Service aee942
		unsigned char rx_tmp[4];
Packit Service aee942
		unsigned char *old_rx_buffer = NULL;
Packit Service aee942
		int old_rx_length = 0;
Packit Service aee942
Packit Service aee942
		/* read a nul block. buffer need to be at least 4-bytes */
Packit Service aee942
		if (NULL == rx_buffer)
Packit Service aee942
		{
Packit Service aee942
			rx_buffer = rx_tmp;
Packit Service aee942
			*rx_length = sizeof(rx_tmp);
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* the buffer must be 4 bytes minimum for ICCD-B */
Packit Service aee942
		if (*rx_length < 4)
Packit Service aee942
		{
Packit Service aee942
			old_rx_buffer = rx_buffer;
Packit Service aee942
			old_rx_length = *rx_length;
Packit Service aee942
			rx_buffer = rx_tmp;
Packit Service aee942
			*rx_length = sizeof(rx_tmp);
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
time_request_ICCD_B:
Packit Service aee942
		/* Data Block */
Packit Service aee942
		r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
Packit Service aee942
Packit Service aee942
		/* we got an error? */
Packit Service aee942
		if (r < 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* copy from the 4 bytes buffer if used */
Packit Service aee942
		if (old_rx_buffer)
Packit Service aee942
		{
Packit Service aee942
			memcpy(old_rx_buffer, rx_buffer, min(r, old_rx_length));
Packit Service aee942
			rx_buffer = old_rx_buffer;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* bResponseType */
Packit Service aee942
		switch (rx_buffer[0])
Packit Service aee942
		{
Packit Service aee942
			case 0x00:
Packit Service aee942
				/* the abData field contains the information created by the
Packit Service aee942
				 * preceding request */
Packit Service aee942
				break;
Packit Service aee942
Packit Service aee942
			case 0x40:
Packit Service aee942
				/* Status Information */
Packit Service aee942
				ccid_error(PCSC_LOG_ERROR, rx_buffer[2], __FILE__, __LINE__, __FUNCTION__);
Packit Service aee942
				return IFD_COMMUNICATION_ERROR;
Packit Service aee942
Packit Service aee942
			case 0x80:
Packit Service aee942
				/* Polling */
Packit Service aee942
			{
Packit Service aee942
				int delay;
Packit Service aee942
Packit Service aee942
				delay = (rx_buffer[2] << 8) + rx_buffer[1];
Packit Service aee942
				DEBUG_COMM2("Pooling delay: %d", delay);
Packit Service aee942
Packit Service aee942
				if (0 == delay)
Packit Service aee942
					/* host select the delay */
Packit Service aee942
					delay = 1;
Packit Service aee942
				(void)usleep(delay * 1000 * 10);
Packit Service aee942
				goto time_request_ICCD_B;
Packit Service aee942
			}
Packit Service aee942
Packit Service aee942
			case 0x01:
Packit Service aee942
			case 0x02:
Packit Service aee942
			case 0x03:
Packit Service aee942
			case 0x10:
Packit Service aee942
				/* Extended case
Packit Service aee942
				 * Only valid for Data Block frames */
Packit Service aee942
				if (chain_parameter)
Packit Service aee942
					*chain_parameter = rx_buffer[0];
Packit Service aee942
				break;
Packit Service aee942
Packit Service aee942
			default:
Packit Service aee942
				DEBUG_CRITICAL2("Unknown bResponseType: 0x%02X", rx_buffer[0]);
Packit Service aee942
				return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		memmove(rx_buffer, rx_buffer+1, r-1);
Packit Service aee942
		*rx_length = r-1;
Packit Service aee942
Packit Service aee942
		return IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
#endif
Packit Service aee942
Packit Service aee942
	/* store the original value of read timeout*/
Packit Service aee942
	old_timeout = ccid_descriptor -> readTimeout;
Packit Service aee942
Packit Service aee942
time_request:
Packit Service aee942
	length = sizeof(cmd);
Packit Service aee942
	ret = ReadPort(reader_index, &length, cmd);
Packit Service aee942
Packit Service aee942
	/* restore the original value of read timeout */
Packit Service aee942
	ccid_descriptor -> readTimeout = old_timeout;
Packit Service aee942
	CHECK_STATUS(ret)
Packit Service aee942
Packit Service aee942
	if (length < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
	{
Packit Service aee942
		ccid_error(PCSC_LOG_ERROR, cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
		switch (cmd[ERROR_OFFSET])
Packit Service aee942
		{
Packit Service aee942
			case 0xEF:	/* cancel */
Packit Service aee942
				if (*rx_length < 2)
Packit Service aee942
					return IFD_ERROR_INSUFFICIENT_BUFFER;
Packit Service aee942
				rx_buffer[0]= 0x64;
Packit Service aee942
				rx_buffer[1]= 0x01;
Packit Service aee942
				*rx_length = 2;
Packit Service aee942
				return IFD_SUCCESS;
Packit Service aee942
Packit Service aee942
			case 0xF0:	/* timeout */
Packit Service aee942
				if (*rx_length < 2)
Packit Service aee942
					return IFD_ERROR_INSUFFICIENT_BUFFER;
Packit Service aee942
				rx_buffer[0]= 0x64;
Packit Service aee942
				rx_buffer[1]= 0x00;
Packit Service aee942
				*rx_length = 2;
Packit Service aee942
				return IFD_SUCCESS;
Packit Service aee942
Packit Service aee942
			case 0xFD:	/* Parity error during exchange */
Packit Service aee942
				return IFD_PARITY_ERROR;
Packit Service aee942
Packit Service aee942
			default:
Packit Service aee942
				return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_COMM2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
Packit Service aee942
Packit Service aee942
		/* compute the new value of read timeout */
Packit Service aee942
		if (cmd[ERROR_OFFSET] > 0)
Packit Service aee942
			ccid_descriptor -> readTimeout *= cmd[ERROR_OFFSET];
Packit Service aee942
Packit Service aee942
		DEBUG_COMM2("New timeout: %d ms", ccid_descriptor -> readTimeout);
Packit Service aee942
		goto time_request;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* we have read less (or more) data than the CCID frame says to contain */
Packit Service aee942
	if (length-10 != dw2i(cmd, 1))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL3("Can't read all data (%d out of %d expected)",
Packit Service aee942
			length-10, dw2i(cmd, 1));
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	length = dw2i(cmd, 1);
Packit Service 3bd214
Packit Service 3bd214
	if (length && 
Packit Service 3bd214
	  (ccid_descriptor->dwNonStandardFlags & CCID_NON_STAND_OMK_3121_T1) &&
Packit Service 3bd214
	  (ccid_descriptor->cardProtocol == SCARD_PROTOCOL_T1)) {
Packit Service 3bd214
		length--;
Packit Service 3bd214
		rx_ptr = cmd+11;
Packit Service 3bd214
	}
Packit Service 3bd214
Packit Service aee942
	if (length <= *rx_length)
Packit Service aee942
		*rx_length = length;
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("overrun by %d bytes", length - *rx_length);
Packit Service aee942
		length = *rx_length;
Packit Service aee942
		return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Kobil firmware bug. No support for chaining */
Packit Service aee942
	if (length && (NULL == rx_buffer))
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Nul block expected but got %d bytes", length);
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service 3bd214
		memcpy(rx_buffer, rx_ptr, length);
Packit Service aee942
Packit Service aee942
	/* Extended case?
Packit Service aee942
	 * Only valid for RDR_to_PC_DataBlock frames */
Packit Service aee942
	if (chain_parameter)
Packit Service aee942
		*chain_parameter = cmd[CHAIN_PARAMETER_OFFSET];
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CCID_Receive */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdXfrBlockAPDU_extended
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[])
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	unsigned char chain_parameter;
Packit Service aee942
	unsigned int local_tx_length, sent_length;
Packit Service aee942
	unsigned int local_rx_length = 0, received_length;
Packit Service aee942
	int buffer_overflow = 0;
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_B == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		/* length is on 16-bits only
Packit Service aee942
		 * if a size > 0x1000 is used then usb_control_msg() fails with
Packit Service aee942
		 * "Invalid argument" */
Packit Service aee942
		if (*rx_length > 0x1000)
Packit Service aee942
			*rx_length = 0x1000;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("T=0 (extended): %d bytes", tx_length);
Packit Service aee942
Packit Service aee942
	/* send the APDU */
Packit Service aee942
	sent_length = 0;
Packit Service aee942
Packit Service aee942
	/* we suppose one command is enough */
Packit Service aee942
	chain_parameter = 0x00;
Packit Service aee942
Packit Service aee942
	local_tx_length = tx_length - sent_length;
Packit Service aee942
	if (local_tx_length > CMD_BUF_SIZE)
Packit Service aee942
	{
Packit Service aee942
		local_tx_length = CMD_BUF_SIZE;
Packit Service aee942
		/* the command APDU begins with this command, and continue in the next
Packit Service aee942
		 * PC_to_RDR_XfrBlock */
Packit Service aee942
		chain_parameter = 0x01;
Packit Service aee942
	}
Packit Service aee942
	if (local_tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
Packit Service aee942
	{
Packit Service aee942
		local_tx_length = ccid_descriptor->dwMaxCCIDMessageLength-10;
Packit Service aee942
		chain_parameter = 0x01;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
send_next_block:
Packit Service aee942
	return_value = CCID_Transmit(reader_index, local_tx_length, tx_buffer,
Packit Service aee942
		chain_parameter, 0);
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
		return return_value;
Packit Service aee942
Packit Service aee942
	sent_length += local_tx_length;
Packit Service aee942
	tx_buffer += local_tx_length;
Packit Service aee942
Packit Service aee942
	/* we just sent the last block (0x02) or only one block was needded (0x00) */
Packit Service aee942
	if ((0x02 == chain_parameter) || (0x00 == chain_parameter))
Packit Service aee942
		goto receive_block;
Packit Service aee942
Packit Service aee942
	/* read a nul block */
Packit Service aee942
	return_value = CCID_Receive(reader_index, &local_rx_length, NULL, NULL);
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
		return return_value;
Packit Service aee942
Packit Service aee942
	/* size of the next block */
Packit Service aee942
	if (tx_length - sent_length > local_tx_length)
Packit Service aee942
	{
Packit Service aee942
		/* the abData field continues a command APDU and
Packit Service aee942
		 * another block is to follow */
Packit Service aee942
		chain_parameter = 0x03;
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		/* this abData field continues a command APDU and ends
Packit Service aee942
		 * the APDU command */
Packit Service aee942
		chain_parameter = 0x02;
Packit Service aee942
Packit Service aee942
		/* last (smaller) block */
Packit Service aee942
		local_tx_length = tx_length - sent_length;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	goto send_next_block;
Packit Service aee942
Packit Service aee942
receive_block:
Packit Service aee942
	/* receive the APDU */
Packit Service aee942
	received_length = 0;
Packit Service aee942
Packit Service aee942
receive_next_block:
Packit Service aee942
	local_rx_length = *rx_length - received_length;
Packit Service aee942
	return_value = CCID_Receive(reader_index, &local_rx_length, rx_buffer,
Packit Service aee942
		&chain_parameter);
Packit Service aee942
	if (IFD_ERROR_INSUFFICIENT_BUFFER == return_value)
Packit Service aee942
	{
Packit Service aee942
		buffer_overflow = 1;
Packit Service aee942
Packit Service aee942
		/* we continue to read all the response APDU */
Packit Service aee942
		return_value = IFD_SUCCESS;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
		return return_value;
Packit Service aee942
Packit Service aee942
	/* advance in the reiceiving buffer */
Packit Service aee942
	rx_buffer += local_rx_length;
Packit Service aee942
	received_length += local_rx_length;
Packit Service aee942
Packit Service aee942
	switch (chain_parameter)
Packit Service aee942
	{
Packit Service aee942
		/* the response APDU begins and ends in this command */
Packit Service aee942
		case 0x00:
Packit Service aee942
		/* this abData field continues the response APDU and ends the response
Packit Service aee942
		 * APDU */
Packit Service aee942
		case 0x02:
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		/* the response APDU begins with this command and is to continue */
Packit Service aee942
		case 0x01:
Packit Service aee942
		/* this abData field continues the response APDU and another block is
Packit Service aee942
		 * to follow */
Packit Service aee942
		case 0x03:
Packit Service aee942
		/* empty abData field, continuation of the command APDU is expected in
Packit Service aee942
		 * next PC_to_RDR_XfrBlock command */
Packit Service aee942
		case 0x10:
Packit Service aee942
			/* send a nul block */
Packit Service aee942
			/* set wLevelParameter to 0010h: empty abData field,
Packit Service aee942
			 * continuation of response APDU is
Packit Service aee942
			 * expected in the next RDR_to_PC_DataBlock. */
Packit Service aee942
			return_value = CCID_Transmit(reader_index, 0, NULL, 0x10, 0);
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			goto receive_next_block;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	*rx_length = received_length;
Packit Service aee942
Packit Service aee942
	/* generate an overflow detected by pcscd */
Packit Service aee942
	if (buffer_overflow)
Packit Service aee942
		(*rx_length)++;
Packit Service aee942
Packit Service aee942
	return IFD_SUCCESS;
Packit Service aee942
} /* CmdXfrBlockAPDU_extended */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdXfrBlockTPDU_T0
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE CmdXfrBlockTPDU_T0(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[])
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("T=0: %d bytes", tx_length);
Packit Service aee942
Packit Service aee942
	/* command length too big for CCID reader? */
Packit Service aee942
	if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength-10)
Packit Service aee942
	{
Packit Service aee942
#ifdef BOGUS_SCM_FIRMWARE_FOR_dwMaxCCIDMessageLength
Packit Service aee942
		if (263 == ccid_descriptor->dwMaxCCIDMessageLength)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_INFO3("Command too long (%d bytes) for max: %d bytes."
Packit Service aee942
				" SCM reader with bogus firmware?",
Packit Service aee942
				tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
#endif
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
Packit Service aee942
				tx_length, ccid_descriptor->dwMaxCCIDMessageLength-10);
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* command length too big for CCID driver? */
Packit Service aee942
	if (tx_length > CMD_BUF_SIZE)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
Packit Service aee942
				tx_length, CMD_BUF_SIZE);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return_value = CCID_Transmit(reader_index, tx_length, tx_buffer, 0, 0);
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
		return return_value;
Packit Service aee942
Packit Service aee942
	return CCID_Receive(reader_index, rx_length, rx_buffer, NULL);
Packit Service aee942
} /* CmdXfrBlockTPDU_T0 */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					T0CmdParsing
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE T0CmdParsing(unsigned char *cmd, unsigned int cmd_len,
Packit Service aee942
	/*@out@*/ unsigned int *exp_len)
Packit Service aee942
{
Packit Service aee942
	*exp_len = 0;
Packit Service aee942
Packit Service aee942
	/* Ref: 7816-4 Annex A */
Packit Service aee942
	switch (cmd_len)
Packit Service aee942
	{
Packit Service aee942
		case 4:	/* Case 1 */
Packit Service aee942
			*exp_len = 2; /* SW1 and SW2 only */
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		case 5: /* Case 2 */
Packit Service aee942
			if (cmd[4] != 0)
Packit Service aee942
				*exp_len = cmd[4] + 2;
Packit Service aee942
			else
Packit Service aee942
				*exp_len = 256 + 2;
Packit Service aee942
			break;
Packit Service aee942
Packit Service aee942
		default: /* Case 3 */
Packit Service aee942
			if (cmd_len > 5 && cmd_len == (unsigned int)(cmd[4] + 5))
Packit Service aee942
				*exp_len = 2; /* SW1 and SW2 only */
Packit Service aee942
			else
Packit Service aee942
				return IFD_COMMUNICATION_ERROR;	/* situation not supported */
Packit Service aee942
			break;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return IFD_SUCCESS;
Packit Service aee942
} /* T0CmdParsing */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					T0ProcACK
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE T0ProcACK(unsigned int reader_index,
Packit Service aee942
	unsigned char **snd_buf, unsigned int *snd_len,
Packit Service aee942
	unsigned char **rcv_buf, unsigned int *rcv_len,
Packit Service aee942
	unsigned char **in_buf, unsigned int *in_len,
Packit Service aee942
	unsigned int proc_len, int is_rcv)
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value;
Packit Service aee942
	unsigned int ret_len;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("Enter, is_rcv = %d", is_rcv);
Packit Service aee942
Packit Service aee942
	if (is_rcv == 1)
Packit Service aee942
	{	/* Receiving mode */
Packit Service aee942
		unsigned int remain_len;
Packit Service aee942
		unsigned char tmp_buf[512];
Packit Service aee942
Packit Service aee942
		if (*in_len > 0)
Packit Service aee942
		{	/* There are still available data in our buffer */
Packit Service aee942
			if (*in_len >= proc_len)
Packit Service aee942
			{
Packit Service aee942
				/* We only need to get the data from our buffer */
Packit Service aee942
				memcpy(*rcv_buf, *in_buf, proc_len);
Packit Service aee942
				*rcv_buf += proc_len;
Packit Service aee942
				*in_buf += proc_len;
Packit Service aee942
				*rcv_len += proc_len;
Packit Service aee942
				*in_len -= proc_len;
Packit Service aee942
Packit Service aee942
				return IFD_SUCCESS;
Packit Service aee942
			}
Packit Service aee942
			else
Packit Service aee942
			{
Packit Service aee942
				/* Move all data in the input buffer to the reply buffer */
Packit Service aee942
				remain_len = proc_len - *in_len;
Packit Service aee942
				memcpy(*rcv_buf, *in_buf, *in_len);
Packit Service aee942
				*rcv_buf += *in_len;
Packit Service aee942
				*in_buf += *in_len;
Packit Service aee942
				*rcv_len += *in_len;
Packit Service aee942
				*in_len = 0;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
			/* There is no data in our tmp_buf,
Packit Service aee942
			 * we have to read all data we needed */
Packit Service aee942
			remain_len = proc_len;
Packit Service aee942
Packit Service aee942
		/* Read the expected data from the smartcard */
Packit Service aee942
		if (*in_len != 0)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL("*in_len != 0");
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		memset(tmp_buf, 0, sizeof(tmp_buf));
Packit Service aee942
Packit Service aee942
#ifdef O2MICRO_OZ776_PATCH
Packit Service aee942
		if((0 != remain_len) && (0 == (remain_len + 10) % 64))
Packit Service aee942
        {
Packit Service aee942
			/* special hack to avoid a command of size modulo 64
Packit Service aee942
			 * we send two commands instead */
Packit Service aee942
            ret_len = 1;
Packit Service aee942
            return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
Packit Service aee942
            if (return_value != IFD_SUCCESS)
Packit Service aee942
                return return_value;
Packit Service aee942
            return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
Packit Service aee942
            if (return_value != IFD_SUCCESS)
Packit Service aee942
                return return_value;
Packit Service aee942
Packit Service aee942
            ret_len = remain_len - 1;
Packit Service aee942
            return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
Packit Service aee942
            if (return_value != IFD_SUCCESS)
Packit Service aee942
                return return_value;
Packit Service aee942
            return_value = CCID_Receive(reader_index, &ret_len, &tmp_buf[1],
Packit Service aee942
				NULL);
Packit Service aee942
            if (return_value != IFD_SUCCESS)
Packit Service aee942
                return return_value;
Packit Service aee942
Packit Service aee942
            ret_len += 1;
Packit Service aee942
        }
Packit Service aee942
        else
Packit Service aee942
#endif
Packit Service aee942
		{
Packit Service aee942
			ret_len = remain_len;
Packit Service aee942
			return_value = CCID_Transmit(reader_index, 0, *snd_buf, ret_len, 0);
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			return_value = CCID_Receive(reader_index, &ret_len, tmp_buf, NULL);
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
		}
Packit Service aee942
		memcpy(*rcv_buf, tmp_buf, remain_len);
Packit Service aee942
		*rcv_buf += remain_len, *rcv_len += remain_len;
Packit Service aee942
Packit Service aee942
		/* If ret_len != remain_len, our logic is erroneous */
Packit Service aee942
		if (ret_len != remain_len)
Packit Service aee942
		{
Packit Service aee942
			DEBUG_CRITICAL("ret_len != remain_len");
Packit Service aee942
			return IFD_COMMUNICATION_ERROR;
Packit Service aee942
		}
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
	{	/* Sending mode */
Packit Service aee942
Packit Service aee942
		return_value = CCID_Transmit(reader_index, proc_len, *snd_buf, 1, 0);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		*snd_len -= proc_len;
Packit Service aee942
		*snd_buf += proc_len;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	DEBUG_COMM("Exit");
Packit Service aee942
Packit Service aee942
	return IFD_SUCCESS;
Packit Service aee942
} /* T0ProcACK */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					T0ProcSW1
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE T0ProcSW1(unsigned int reader_index,
Packit Service aee942
	unsigned char *rcv_buf, unsigned int *rcv_len,
Packit Service aee942
	unsigned char *in_buf, unsigned int in_len)
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	UCHAR tmp_buf[512];
Packit Service aee942
	unsigned char sw1, sw2;
Packit Service aee942
Packit Service aee942
	/* store the SW1 */
Packit Service aee942
	sw1 = *rcv_buf = *in_buf;
Packit Service aee942
	rcv_buf++;
Packit Service aee942
	in_buf++;
Packit Service aee942
	in_len--;
Packit Service aee942
	(*rcv_len)++;
Packit Service aee942
Packit Service aee942
	/* store the SW2 */
Packit Service aee942
	if (0 == in_len)
Packit Service aee942
	{
Packit Service aee942
		return_value = CCID_Transmit(reader_index, 0, rcv_buf, 1, 0);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		in_len = 1;
Packit Service aee942
Packit Service aee942
		return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		in_buf = tmp_buf;
Packit Service aee942
	}
Packit Service aee942
	sw2 = *rcv_buf = *in_buf;
Packit Service aee942
	in_len--;
Packit Service aee942
	(*rcv_len)++;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM3("Exit: SW=%02X %02X", sw1, sw2);
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* T0ProcSW1 */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdXfrBlockCHAR_T0
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE CmdXfrBlockCHAR_T0(unsigned int reader_index,
Packit Service aee942
	unsigned int snd_len, unsigned char snd_buf[], unsigned int *rcv_len,
Packit Service aee942
	unsigned char rcv_buf[])
Packit Service aee942
{
Packit Service aee942
	int is_rcv;
Packit Service aee942
	unsigned char cmd[5];
Packit Service aee942
	unsigned char tmp_buf[512];
Packit Service aee942
	unsigned int exp_len, in_len;
Packit Service aee942
	unsigned char ins, *in_buf;
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("T=0: %d bytes", snd_len);
Packit Service aee942
Packit Service aee942
	if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol)
Packit Service aee942
	{
Packit Service aee942
		unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit Service aee942
		unsigned int backup_len;
Packit Service aee942
Packit Service aee942
		/* length is on 16-bits only
Packit Service aee942
		 * if a size > 0x1000 is used then usb_control_msg() fails with
Packit Service aee942
		 * "Invalid argument" */
Packit Service aee942
		if (*rcv_len > 0x1000)
Packit Service aee942
			*rcv_len = 0x1000;
Packit Service aee942
Packit Service aee942
		backup_len = *rcv_len;
Packit Service aee942
Packit Service aee942
		/* Command to send to the smart card (must be 5 bytes) */
Packit Service aee942
		memset(cmd, 0, sizeof(cmd));
Packit Service aee942
		if (snd_len == 4)
Packit Service aee942
		{
Packit Service aee942
			memcpy(cmd, snd_buf, 4);
Packit Service aee942
			snd_buf += 4;
Packit Service aee942
			snd_len -= 4;
Packit Service aee942
		}
Packit Service aee942
		else
Packit Service aee942
		{
Packit Service aee942
			memcpy(cmd, snd_buf, 5);
Packit Service aee942
			snd_buf += 5;
Packit Service aee942
			snd_len -= 5;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* at most 5 bytes */
Packit Service aee942
		return_value = CCID_Transmit(reader_index, 5, cmd, 0, 0);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		/* wait for ready */
Packit Service aee942
		pcbuffer[0] = 0;
Packit Service aee942
		return_value = CmdGetSlotStatus(reader_index, pcbuffer);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		if (0x10 == pcbuffer[0])
Packit Service aee942
		{
Packit Service aee942
			if (snd_len > 0)
Packit Service aee942
			{
Packit Service aee942
				/* continue sending the APDU */
Packit Service aee942
				return_value = CCID_Transmit(reader_index, snd_len, snd_buf,
Packit Service aee942
					0, 0);
Packit Service aee942
				if (return_value != IFD_SUCCESS)
Packit Service aee942
					return return_value;
Packit Service aee942
			}
Packit Service aee942
			else
Packit Service aee942
			{
Packit Service aee942
				/* read apdu data */
Packit Service aee942
				return_value = CCID_Receive(reader_index, rcv_len, rcv_buf,
Packit Service aee942
						NULL);
Packit Service aee942
				if (return_value != IFD_SUCCESS)
Packit Service aee942
					return return_value;
Packit Service aee942
			}
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		return_value = CmdGetSlotStatus(reader_index, pcbuffer);
Packit Service aee942
		if (return_value != IFD_SUCCESS)
Packit Service aee942
			return return_value;
Packit Service aee942
Packit Service aee942
		/* SW1-SW2 available */
Packit Service aee942
		if (0x20 == pcbuffer[0])
Packit Service aee942
		{
Packit Service aee942
			/* backup apdu data length */
Packit Service aee942
			/* if no data recieved before - backup length must be zero */
Packit Service aee942
			backup_len = (backup_len == *rcv_len) ? 0 : *rcv_len;
Packit Service aee942
Packit Service aee942
			/* wait for 2 bytes (SW1-SW2) */
Packit Service aee942
			*rcv_len = 2;
Packit Service aee942
Packit Service aee942
			return_value = CCID_Receive(reader_index, rcv_len,
Packit Service aee942
				rcv_buf + backup_len, NULL);
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				DEBUG_CRITICAL("CCID_Receive failed");
Packit Service aee942
Packit Service aee942
			/* restore recieved length */
Packit Service aee942
			*rcv_len += backup_len;
Packit Service aee942
		}
Packit Service aee942
		return return_value;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	in_buf = tmp_buf;
Packit Service aee942
	in_len = 0;
Packit Service aee942
	*rcv_len = 0;
Packit Service aee942
Packit Service aee942
	return_value = T0CmdParsing(snd_buf, snd_len, &exp_len);
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL("T0CmdParsing failed");
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (snd_len == 5 || snd_len == 4)
Packit Service aee942
		is_rcv = 1;
Packit Service aee942
	else
Packit Service aee942
		is_rcv = 0;
Packit Service aee942
Packit Service aee942
	/* Command to send to the smart card (must be 5 bytes, from 7816 p.15) */
Packit Service aee942
	memset(cmd, 0, sizeof(cmd));
Packit Service aee942
	if (snd_len == 4)
Packit Service aee942
	{
Packit Service aee942
		memcpy(cmd, snd_buf, 4);
Packit Service aee942
		snd_buf += 4;
Packit Service aee942
		snd_len -= 4;
Packit Service aee942
	}
Packit Service aee942
	else
Packit Service aee942
	{
Packit Service aee942
		memcpy(cmd, snd_buf, 5);
Packit Service aee942
		snd_buf += 5;
Packit Service aee942
		snd_len -= 5;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	/* Make sure this is a valid command by checking the INS field */
Packit Service aee942
	ins = cmd[1];
Packit Service aee942
	if ((ins & 0xF0) == 0x60 ||	/* 7816-3 8.3.2 */
Packit Service aee942
		(ins & 0xF0) == 0x90)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("fatal: INS (0x%02X) = 0x6X or 0x9X", ins);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return_value = CCID_Transmit(reader_index, 5, cmd, 1, 0);
Packit Service aee942
	if (return_value != IFD_SUCCESS)
Packit Service aee942
		return return_value;
Packit Service aee942
Packit Service aee942
	while (1)
Packit Service aee942
	{
Packit Service aee942
		if (in_len == 0)
Packit Service aee942
		{
Packit Service aee942
			in_len = 1;
Packit Service aee942
			return_value = CCID_Receive(reader_index, &in_len, tmp_buf, NULL);
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
			{
Packit Service aee942
				DEBUG_CRITICAL("CCID_Receive failed");
Packit Service aee942
				return return_value;
Packit Service aee942
			}
Packit Service aee942
			in_buf = tmp_buf;
Packit Service aee942
		}
Packit Service aee942
		if (in_len == 0)
Packit Service aee942
		{
Packit Service aee942
			/* Suppose we should be able to get data.
Packit Service aee942
			 * If not, error. Set the time-out error */
Packit Service aee942
			DEBUG_CRITICAL("error: in_len = 0");
Packit Service aee942
			return IFD_RESPONSE_TIMEOUT;
Packit Service aee942
		}
Packit Service aee942
Packit Service aee942
		/* Start to process the procedure bytes */
Packit Service aee942
		if (*in_buf == 0x60)
Packit Service aee942
		{
Packit Service aee942
			in_len = 0;
Packit Service aee942
			return_value = CCID_Transmit(reader_index, 0, cmd, 1, 0);
Packit Service aee942
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			continue;
Packit Service aee942
		}
Packit Service aee942
		else if (*in_buf == ins || *in_buf == (ins ^ 0x01))
Packit Service aee942
		{
Packit Service aee942
			/* ACK => To transfer all remaining data bytes */
Packit Service aee942
			in_buf++, in_len--;
Packit Service aee942
			if (is_rcv)
Packit Service aee942
				return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
Packit Service aee942
					&rcv_buf, rcv_len, &in_buf, &in_len, exp_len - *rcv_len, 1);
Packit Service aee942
			else
Packit Service aee942
				return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
Packit Service aee942
					&rcv_buf, rcv_len, &in_buf, &in_len, snd_len, 0);
Packit Service aee942
Packit Service aee942
			if (*rcv_len == exp_len)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			continue;
Packit Service aee942
		}
Packit Service aee942
		else if (*in_buf == (ins ^ 0xFF) || *in_buf == (ins ^ 0xFE))
Packit Service aee942
		{
Packit Service aee942
			/* ACK => To transfer 1 remaining bytes */
Packit Service aee942
			in_buf++, in_len--;
Packit Service aee942
			return_value = T0ProcACK(reader_index, &snd_buf, &snd_len,
Packit Service aee942
				&rcv_buf, rcv_len, &in_buf, &in_len, 1, is_rcv);
Packit Service aee942
Packit Service aee942
			if (return_value != IFD_SUCCESS)
Packit Service aee942
				return return_value;
Packit Service aee942
Packit Service aee942
			continue;
Packit Service aee942
		}
Packit Service aee942
		else if ((*in_buf & 0xF0) == 0x60 || (*in_buf & 0xF0) == 0x90)
Packit Service aee942
			/* SW1 */
Packit Service aee942
			return T0ProcSW1(reader_index, rcv_buf, rcv_len, in_buf, in_len);
Packit Service aee942
Packit Service aee942
		/* Error, unrecognized situation found */
Packit Service aee942
		DEBUG_CRITICAL2("Unrecognized Procedure byte (0x%02X) found!", *in_buf);
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
		return return_value;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdXfrBlockCHAR_T0 */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					CmdXfrBlockTPDU_T1
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static RESPONSECODE CmdXfrBlockTPDU_T1(unsigned int reader_index,
Packit Service aee942
	unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length,
Packit Service aee942
	unsigned char rx_buffer[])
Packit Service aee942
{
Packit Service aee942
	RESPONSECODE return_value = IFD_SUCCESS;
Packit Service aee942
	int ret;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM3("T=1: %d and %d bytes", tx_length, *rx_length);
Packit Service aee942
Packit Service aee942
	ret = t1_transceive(&((get_ccid_slot(reader_index)) -> t1), 0,
Packit Service aee942
		tx_buffer, tx_length, rx_buffer, *rx_length);
Packit Service aee942
Packit Service aee942
	if (ret < 0)
Packit Service aee942
		return_value = IFD_COMMUNICATION_ERROR;
Packit Service aee942
	else
Packit Service aee942
		*rx_length = ret;
Packit Service aee942
Packit Service aee942
	return return_value;
Packit Service aee942
} /* CmdXfrBlockTPDU_T1 */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					SetParameters
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
RESPONSECODE SetParameters(unsigned int reader_index, char protocol,
Packit Service aee942
	unsigned int length, unsigned char buffer[])
Packit Service aee942
{
Packit Service aee942
	unsigned char cmd[10+length];	/* CCID + APDU buffer */
Packit Service aee942
	_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit Service aee942
	status_t res;
Packit Service aee942
Packit Service aee942
	DEBUG_COMM2("length: %d bytes", length);
Packit Service aee942
Packit Service aee942
	cmd[0] = 0x61; /* SetParameters */
Packit Service aee942
	i2dw(length, cmd+1);	/* APDU length */
Packit Service aee942
	cmd[5] = ccid_descriptor->bCurrentSlotIndex;	/* slot number */
Packit Service aee942
	cmd[6] = (*ccid_descriptor->pbSeq)++;
Packit Service aee942
	cmd[7] = protocol;	/* bProtocolNum */
Packit Service aee942
	cmd[8] = cmd[9] = 0; /* RFU */
Packit Service aee942
Packit Service aee942
	memcpy(cmd+10, buffer, length);
Packit Service aee942
Packit Service aee942
	res = WritePort(reader_index, 10+length, cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	length = sizeof(cmd);
Packit Service aee942
	res = ReadPort(reader_index, &length, cmd);
Packit Service aee942
	CHECK_STATUS(res)
Packit Service aee942
Packit Service aee942
	if (length < STATUS_OFFSET+1)
Packit Service aee942
	{
Packit Service aee942
		DEBUG_CRITICAL2("Not enough data received: %d bytes", length);
Packit Service aee942
		return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
Packit Service aee942
	{
Packit Service aee942
		ccid_error(PCSC_LOG_ERROR, cmd[ERROR_OFFSET], __FILE__, __LINE__, __FUNCTION__);    /* bError */
Packit Service aee942
		if (0x00 == cmd[ERROR_OFFSET])	/* command not supported */
Packit Service aee942
			return IFD_NOT_SUPPORTED;
Packit Service aee942
		else
Packit Service aee942
			if ((cmd[ERROR_OFFSET] >= 1) && (cmd[ERROR_OFFSET] <= 127))
Packit Service aee942
				/* a parameter is not changeable */
Packit Service aee942
				return IFD_SUCCESS;
Packit Service aee942
			else
Packit Service aee942
				return IFD_COMMUNICATION_ERROR;
Packit Service aee942
	}
Packit Service aee942
Packit Service aee942
	return IFD_SUCCESS;
Packit Service aee942
} /* SetParameters */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					isCharLevel
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
int isCharLevel(int reader_index)
Packit Service aee942
{
Packit Service aee942
	return CCID_CLASS_CHARACTER == (get_ccid_descriptor(reader_index)->dwFeatures & CCID_CLASS_EXCHANGE_MASK);
Packit Service aee942
} /* isCharLevel */
Packit Service aee942
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
 *
Packit Service aee942
 *					i2dw
Packit Service aee942
 *
Packit Service aee942
 ****************************************************************************/
Packit Service aee942
static void i2dw(int value, unsigned char buffer[])
Packit Service aee942
{
Packit Service aee942
	buffer[0] = value & 0xFF;
Packit Service aee942
	buffer[1] = (value >> 8) & 0xFF;
Packit Service aee942
	buffer[2] = (value >> 16) & 0xFF;
Packit Service aee942
	buffer[3] = (value >> 24) & 0xFF;
Packit Service aee942
} /* i2dw */
Packit Service aee942
Packit Service aee942
/*****************************************************************************
Packit Service aee942
*
Packit Service aee942
*                  bei2i (big endian integer to host order interger)
Packit Service aee942
*
Packit Service aee942
****************************************************************************/
Packit Service aee942
Packit Service aee942
static unsigned int bei2i(unsigned char buffer[])
Packit Service aee942
{
Packit Service aee942
	return (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
Packit Service aee942
}