Blame src/commands.c

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