Blame src/ifdhandler.c

Packit 9f0df5
/*
Packit 9f0df5
    ifdhandler.c: IFDH API
Packit 9f0df5
    Copyright (C) 2003-2010   Ludovic Rousseau
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_STDIO_H
Packit 9f0df5
#include <stdio.h>
Packit 9f0df5
#endif
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_UNISTD_H
Packit 9f0df5
#include <unistd.h>
Packit 9f0df5
#endif
Packit 9f0df5
#ifdef HAVE_ARPA_INET_H
Packit 9f0df5
#include <arpa/inet.h>
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
#include "misc.h"
Packit 9f0df5
#include <pcsclite.h>
Packit 9f0df5
#include <ifdhandler.h>
Packit 9f0df5
#include <reader.h>
Packit 9f0df5
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
#include "commands.h"
Packit 9f0df5
#include "towitoko/atr.h"
Packit 9f0df5
#include "towitoko/pps.h"
Packit 9f0df5
#include "parser.h"
Packit 9f0df5
#include "strlcpycat.h"
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
#include <pthread.h>
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
/* Array of structures to hold the ATR and other state value of each slot */
Packit 9f0df5
static CcidDesc CcidSlots[CCID_DRIVER_MAX_READERS];
Packit 9f0df5
Packit 9f0df5
/* global mutex */
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
int LogLevel = DEBUG_LEVEL_CRITICAL | DEBUG_LEVEL_INFO;
Packit 9f0df5
int DriverOptions = 0;
Packit 9f0df5
int PowerOnVoltage = -1;
Packit 9f0df5
static int DebugInitialized = FALSE;
Packit 9f0df5
Packit 9f0df5
/* local functions */
Packit 9f0df5
static void init_driver(void);
Packit 9f0df5
static char find_baud_rate(unsigned int baudrate, unsigned int *list);
Packit 9f0df5
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
Packit 9f0df5
	int clock_frequency);
Packit 9f0df5
static unsigned int T1_card_timeout(double f, double d, int TC1, int BWI,
Packit 9f0df5
	int CWI, int clock_frequency);
Packit 9f0df5
static int get_IFSC(ATR_t *atr, int *i);
Packit 9f0df5
Packit 9f0df5
static void FreeChannel(int reader_index)
Packit 9f0df5
{
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
	(void)pthread_mutex_lock(&ifdh_context_mutex);
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
	(void)ClosePort(reader_index);
Packit 9f0df5
Packit 9f0df5
	free(CcidSlots[reader_index].readerName);
Packit 9f0df5
	memset(&CcidSlots[reader_index], 0, sizeof(CcidSlots[reader_index]));
Packit 9f0df5
Packit 9f0df5
	ReleaseReaderIndex(reader_index);
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
	(void)pthread_mutex_unlock(&ifdh_context_mutex);
Packit 9f0df5
#endif
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static RESPONSECODE CreateChannelByNameOrChannel(DWORD Lun,
Packit 9f0df5
	LPSTR lpcDevice, DWORD Channel)
Packit 9f0df5
{
Packit 9f0df5
	RESPONSECODE return_value = IFD_SUCCESS;
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	status_t ret;
Packit 9f0df5
Packit 9f0df5
	if (! DebugInitialized)
Packit 9f0df5
		init_driver();
Packit 9f0df5
Packit 9f0df5
	if (lpcDevice)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_INFO3("Lun: " DWORD_X ", device: %s", Lun, lpcDevice);
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_INFO3("Lun: " DWORD_X ", Channel: " DWORD_X, Lun, Channel);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
	(void)pthread_mutex_lock(&ifdh_context_mutex);
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
	reader_index = GetNewReaderIndex(Lun);
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
	(void)pthread_mutex_unlock(&ifdh_context_mutex);
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
	if (-1 == reader_index)
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	/* Reset ATR buffer */
Packit 9f0df5
	CcidSlots[reader_index].nATRLength = 0;
Packit 9f0df5
	*CcidSlots[reader_index].pcATRBuffer = '\0';
Packit 9f0df5
Packit 9f0df5
	/* Reset PowerFlags */
Packit 9f0df5
	CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
Packit 9f0df5
Packit 9f0df5
	/* reader name */
Packit 9f0df5
	if (lpcDevice)
Packit 9f0df5
		CcidSlots[reader_index].readerName = strdup(lpcDevice);
Packit 9f0df5
	else
Packit 9f0df5
		CcidSlots[reader_index].readerName = strdup("no name");
Packit 9f0df5
Packit 9f0df5
	if (lpcDevice)
Packit 9f0df5
		ret = OpenPortByName(reader_index, lpcDevice);
Packit 9f0df5
	else
Packit 9f0df5
		ret = OpenPort(reader_index, Channel);
Packit 9f0df5
Packit 9f0df5
	if (ret != STATUS_SUCCESS)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_CRITICAL("failed");
Packit 9f0df5
		if (STATUS_NO_SUCH_DEVICE == ret)
Packit 9f0df5
			return_value = IFD_NO_SUCH_DEVICE;
Packit 9f0df5
		else
Packit 9f0df5
			return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
		goto error;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit 9f0df5
		unsigned int oldReadTimeout;
Packit 9f0df5
		RESPONSECODE cmd_ret;
Packit 9f0df5
		_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
		/* Maybe we have a special treatment for this reader */
Packit 9f0df5
		(void)ccid_open_hack_pre(reader_index);
Packit 9f0df5
Packit 9f0df5
		/* Try to access the reader */
Packit 9f0df5
		/* This "warm up" sequence is sometimes needed when pcscd is
Packit 9f0df5
		 * restarted with the reader already connected. We get some
Packit 9f0df5
		 * "usb_bulk_read: Resource temporarily unavailable" on the first
Packit 9f0df5
		 * few tries. It is an empirical hack */
Packit 9f0df5
Packit 9f0df5
		/* The reader may have to start here so give it some time */
Packit 9f0df5
		cmd_ret = CmdGetSlotStatus(reader_index, pcbuffer);
Packit 9f0df5
		if (IFD_NO_SUCH_DEVICE == cmd_ret)
Packit 9f0df5
		{
Packit 9f0df5
			return_value = cmd_ret;
Packit 9f0df5
			goto error;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* save the current read timeout computed from card capabilities */
Packit 9f0df5
		oldReadTimeout = ccid_descriptor->readTimeout;
Packit 9f0df5
Packit 9f0df5
		/* 100 ms just to resync the USB toggle bits */
Packit 9f0df5
		/* Do not use a fixed 100 ms value but compute it from the
Packit 9f0df5
		 * default timeout. It is now possible to use a different value
Packit 9f0df5
		 * by changing readTimeout in ccid_open_hack_pre() */
Packit 9f0df5
		ccid_descriptor->readTimeout = ccid_descriptor->readTimeout * 100.0 / DEFAULT_COM_READ_TIMEOUT;
Packit 9f0df5
Packit 9f0df5
		if ((IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer))
Packit 9f0df5
			&& (IFD_COMMUNICATION_ERROR == CmdGetSlotStatus(reader_index, pcbuffer)))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_CRITICAL("failed");
Packit 9f0df5
			return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			/* Maybe we have a special treatment for this reader */
Packit 9f0df5
			return_value = ccid_open_hack_post(reader_index);
Packit 9f0df5
			if (return_value != IFD_SUCCESS)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_CRITICAL("failed");
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* set back the old timeout */
Packit 9f0df5
		ccid_descriptor->readTimeout = oldReadTimeout;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
error:
Packit 9f0df5
	if (return_value != IFD_SUCCESS)
Packit 9f0df5
	{
Packit 9f0df5
		/* release the allocated resources */
Packit 9f0df5
		FreeChannel(reader_index);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* CreateChannelByNameOrChannel */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHCreateChannelByName(DWORD Lun, LPSTR lpcDevice)
Packit 9f0df5
{
Packit 9f0df5
	return CreateChannelByNameOrChannel(Lun, lpcDevice, -1);
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * Lun - Logical Unit Number, use this for multiple card slots or
Packit 9f0df5
	 * multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
Packit 9f0df5
	 * slots. The resource manager will set these automatically.  By
Packit 9f0df5
	 * default the resource manager loads a new instance of the driver so
Packit 9f0df5
	 * if your reader does not have more than one smartcard slot then
Packit 9f0df5
	 * ignore the Lun in all the functions. Future versions of PC/SC might
Packit 9f0df5
	 * support loading multiple readers through one instance of the driver
Packit 9f0df5
	 * in which XXXX would be important to implement if you want this.
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * Channel - Channel ID.  This is denoted by the following: 0x000001 -
Packit 9f0df5
	 * /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
Packit 9f0df5
	 *
Packit 9f0df5
	 * USB readers may choose to ignore this parameter and query the bus
Packit 9f0df5
	 * for the particular reader.
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function is required to open a communications channel to the
Packit 9f0df5
	 * port listed by Channel.  For example, the first serial reader on
Packit 9f0df5
	 * COM1 would link to /dev/pcsc/1 which would be a sym link to
Packit 9f0df5
	 * /dev/ttyS0 on some machines This is used to help with intermachine
Packit 9f0df5
	 * independance.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Once the channel is opened the reader must be in a state in which
Packit 9f0df5
	 * it is possible to query IFDHICCPresence() for card status.
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
Packit 9f0df5
	 */
Packit 9f0df5
	return CreateChannelByNameOrChannel(Lun, NULL, Channel);
Packit 9f0df5
} /* IFDHCreateChannel */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHCloseChannel(DWORD Lun)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function should close the reader communication channel for the
Packit 9f0df5
	 * particular reader.  Prior to closing the communication channel the
Packit 9f0df5
	 * reader should make sure the card is powered down and the terminal
Packit 9f0df5
	 * is also powered down.
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
Packit 9f0df5
	 */
Packit 9f0df5
	int reader_index;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
Packit 9f0df5
		Lun);
Packit 9f0df5
Packit 9f0df5
	/* Restore the default timeout
Packit 9f0df5
	 * No need to wait too long if the reader disapeared */
Packit 9f0df5
	get_ccid_descriptor(reader_index)->readTimeout = DEFAULT_COM_READ_TIMEOUT;
Packit 9f0df5
Packit 9f0df5
	(void)CmdPowerOff(reader_index);
Packit 9f0df5
	/* No reader status check, if it failed, what can you do ? :) */
Packit 9f0df5
Packit 9f0df5
	FreeChannel(reader_index);
Packit 9f0df5
Packit 9f0df5
	return IFD_SUCCESS;
Packit 9f0df5
} /* IFDHCloseChannel */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
#if !defined(TWIN_SERIAL)
Packit 9f0df5
static RESPONSECODE IFDHPolling(DWORD Lun, int timeout)
Packit 9f0df5
{
Packit 9f0df5
	int reader_index;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	/* log only if DEBUG_LEVEL_PERIODIC is set */
Packit 9f0df5
	if (LogLevel & DEBUG_LEVEL_PERIODIC)
Packit 9f0df5
		DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
Packit 9f0df5
			CcidSlots[reader_index].readerName, Lun, timeout);
Packit 9f0df5
Packit 9f0df5
	return InterruptRead(reader_index, timeout);
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
/* on an ICCD device the card is always inserted
Packit 9f0df5
 * so no card movement will ever happen: just do nothing */
Packit 9f0df5
static RESPONSECODE IFDHSleep(DWORD Lun, int timeout)
Packit 9f0df5
{
Packit 9f0df5
	int reader_index;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("%s (lun: " DWORD_X ") %d ms",
Packit 9f0df5
		CcidSlots[reader_index].readerName, Lun, timeout);
Packit 9f0df5
Packit 9f0df5
	/* just sleep for 5 seconds since the polling thread is NOT killable
Packit 9f0df5
	 * so pcscd event thread must loop to exit cleanly
Packit 9f0df5
	 *
Packit 9f0df5
	 * Once the driver (libusb in fact) will support
Packit 9f0df5
	 * TAG_IFD_POLLING_THREAD_KILLABLE then we could use a much longer delay
Packit 9f0df5
	 * and be killed before pcscd exits
Packit 9f0df5
	 */
Packit 9f0df5
	(void)usleep(timeout * 1000);
Packit 9f0df5
	return IFD_SUCCESS;
Packit 9f0df5
}
Packit 9f0df5
Packit 9f0df5
static RESPONSECODE IFDHStopPolling(DWORD Lun)
Packit 9f0df5
{
Packit 9f0df5
	int reader_index;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO3("%s (lun: " DWORD_X ")",
Packit 9f0df5
		CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	(void)InterruptStop(reader_index);
Packit 9f0df5
	return IFD_SUCCESS;
Packit 9f0df5
}
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
Packit 9f0df5
	PDWORD Length, PUCHAR Value)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function should get the slot/card capabilities for a
Packit 9f0df5
	 * particular slot/card specified by Lun.  Again, if you have only 1
Packit 9f0df5
	 * card slot and don't mind loading a new driver for each reader then
Packit 9f0df5
	 * ignore Lun.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Tag - the tag for the information requested example: TAG_IFD_ATR -
Packit 9f0df5
	 * return the Atr and its size (required). these tags are defined in
Packit 9f0df5
	 * ifdhandler.h
Packit 9f0df5
	 *
Packit 9f0df5
	 * Length - the length of the returned data Value - the value of the
Packit 9f0df5
	 * data
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_ERROR_TAG
Packit 9f0df5
	 */
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	RESPONSECODE return_value = IFD_SUCCESS;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
Packit 9f0df5
		CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	switch (Tag)
Packit 9f0df5
	{
Packit 9f0df5
		case TAG_IFD_ATR:
Packit 9f0df5
		case SCARD_ATTR_ATR_STRING:
Packit 9f0df5
			/* If Length is not zero, powerICC has been performed.
Packit 9f0df5
			 * Otherwise, return NULL pointer
Packit 9f0df5
			 * Buffer size is stored in *Length */
Packit 9f0df5
			if ((int)*Length >= CcidSlots[reader_index].nATRLength)
Packit 9f0df5
			{
Packit 9f0df5
				*Length = CcidSlots[reader_index].nATRLength;
Packit 9f0df5
Packit 9f0df5
				memcpy(Value, CcidSlots[reader_index].pcATRBuffer, *Length);
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
				return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_ICC_INTERFACE_STATUS:
Packit 9f0df5
			*Length = 1;
Packit 9f0df5
			if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
Packit 9f0df5
				/* nonzero if contact is active */
Packit 9f0df5
				*Value = 1;
Packit 9f0df5
			else
Packit 9f0df5
				/* smart card electrical contact is not active */
Packit 9f0df5
				*Value = 0;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_ICC_PRESENCE:
Packit 9f0df5
			*Length = 1;
Packit 9f0df5
			/* Single byte indicating smart card presence:
Packit 9f0df5
			 * 0 = not present
Packit 9f0df5
			 * 1 = card present but not swallowed (applies only if
Packit 9f0df5
			 *     reader supports smart card swallowing)
Packit 9f0df5
			 * 2 = card present (and swallowed if reader supports smart
Packit 9f0df5
			 *     card swallowing)
Packit 9f0df5
			 * 4 = card confiscated. */
Packit 9f0df5
			if (IFD_ICC_PRESENT == IFDHICCPresence(Lun))
Packit 9f0df5
				/* Card present */
Packit 9f0df5
				*Value = 2;
Packit 9f0df5
			else
Packit 9f0df5
				/* Not present */
Packit 9f0df5
				*Value = 0;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
#ifdef HAVE_PTHREAD
Packit 9f0df5
		case TAG_IFD_SIMULTANEOUS_ACCESS:
Packit 9f0df5
			if (*Length >= 1)
Packit 9f0df5
			{
Packit 9f0df5
				*Length = 1;
Packit 9f0df5
				*Value = CCID_DRIVER_MAX_READERS;
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
				return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case TAG_IFD_THREAD_SAFE:
Packit 9f0df5
			if (*Length >= 1)
Packit 9f0df5
			{
Packit 9f0df5
				*Length = 1;
Packit 9f0df5
#ifdef __APPLE__
Packit 9f0df5
				*Value = 0; /* Apple pcscd is bogus (rdar://problem/5697388) */
Packit 9f0df5
#else
Packit 9f0df5
				*Value = 1; /* Can talk to multiple readers at the same time */
Packit 9f0df5
#endif
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
				return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
			break;
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
		case TAG_IFD_SLOTS_NUMBER:
Packit 9f0df5
			if (*Length >= 1)
Packit 9f0df5
			{
Packit 9f0df5
				*Length = 1;
Packit 9f0df5
				*Value = 1 + get_ccid_descriptor(reader_index) -> bMaxSlotIndex;
Packit 9f0df5
#ifdef USE_COMPOSITE_AS_MULTISLOT
Packit 9f0df5
				{
Packit 9f0df5
					/* On MacOS X or Linux+libusb we can simulate a
Packit 9f0df5
					 * composite device with 2 CCID interfaces by a
Packit 9f0df5
					 * multi-slot reader */
Packit 9f0df5
					int readerID =  get_ccid_descriptor(reader_index) -> readerID;
Packit 9f0df5
Packit 9f0df5
					/* 2 CCID interfaces */
Packit 9f0df5
					if ((GEMALTOPROXDU == readerID)
Packit 9f0df5
						|| (GEMALTOPROXSU == readerID)
Packit 9f0df5
						|| (HID_OMNIKEY_5422 == readerID))
Packit 9f0df5
						*Value = 2;
Packit 9f0df5
Packit 9f0df5
					/* 3 CCID interfaces */
Packit 9f0df5
					if (FEITIANR502DUAL == readerID)
Packit 9f0df5
						*Value = 3;
Packit 9f0df5
				}
Packit 9f0df5
#endif
Packit 9f0df5
				DEBUG_INFO2("Reader supports %d slot(s)", *Value);
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
				return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case TAG_IFD_SLOT_THREAD_SAFE:
Packit 9f0df5
			if (*Length >= 1)
Packit 9f0df5
			{
Packit 9f0df5
				*Length = 1;
Packit 9f0df5
				*Value = 0; /* Can NOT talk to multiple slots at the same time */
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
				return_value = IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_VENDOR_IFD_VERSION:
Packit 9f0df5
			{
Packit 9f0df5
				int IFD_bcdDevice = get_ccid_descriptor(reader_index)->IFD_bcdDevice;
Packit 9f0df5
Packit 9f0df5
				/* Vendor-supplied interface device version (DWORD in the form
Packit 9f0df5
				 * 0xMMmmbbbb where MM = major version, mm = minor version, and
Packit 9f0df5
				 * bbbb = build number). */
Packit 9f0df5
				*Length = 4;
Packit 9f0df5
				if (Value)
Packit 9f0df5
					*(uint32_t *)Value = IFD_bcdDevice << 16;
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_VENDOR_NAME:
Packit 9f0df5
			{
Packit 9f0df5
				const char *sIFD_iManufacturer = get_ccid_descriptor(reader_index) -> sIFD_iManufacturer;
Packit 9f0df5
Packit 9f0df5
				if (sIFD_iManufacturer)
Packit 9f0df5
				{
Packit 9f0df5
					strlcpy((char *)Value, sIFD_iManufacturer, *Length);
Packit 9f0df5
					*Length = strlen((char *)Value) +1;
Packit 9f0df5
				}
Packit 9f0df5
				else
Packit 9f0df5
				{
Packit 9f0df5
					/* not supported */
Packit 9f0df5
					*Length = 0;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_MAXINPUT:
Packit 9f0df5
			*Length = sizeof(uint32_t);
Packit 9f0df5
			if (Value)
Packit 9f0df5
				*(uint32_t *)Value = get_ccid_descriptor(reader_index) -> dwMaxCCIDMessageLength -10;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
#if !defined(TWIN_SERIAL)
Packit 9f0df5
		case TAG_IFD_POLLING_THREAD_WITH_TIMEOUT:
Packit 9f0df5
			{
Packit 9f0df5
				_ccid_descriptor *ccid_desc;
Packit 9f0df5
Packit 9f0df5
				/* default value: not supported */
Packit 9f0df5
				*Length = 0;
Packit 9f0df5
Packit 9f0df5
				ccid_desc = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
				/* CCID and not ICCD */
Packit 9f0df5
				if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
Packit 9f0df5
					/* 3 end points */
Packit 9f0df5
					&& (3 == ccid_desc -> bNumEndpoints))
Packit 9f0df5
				{
Packit 9f0df5
					*Length = sizeof(void *);
Packit 9f0df5
					if (Value)
Packit 9f0df5
						*(void **)Value = IFDHPolling;
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
Packit 9f0df5
					|| (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
Packit 9f0df5
				{
Packit 9f0df5
					*Length = sizeof(void *);
Packit 9f0df5
					if (Value)
Packit 9f0df5
						*(void **)Value = IFDHSleep;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case TAG_IFD_POLLING_THREAD_KILLABLE:
Packit 9f0df5
			{
Packit 9f0df5
				_ccid_descriptor *ccid_desc;
Packit 9f0df5
Packit 9f0df5
				/* default value: not supported */
Packit 9f0df5
				*Length = 0;
Packit 9f0df5
Packit 9f0df5
				ccid_desc = get_ccid_descriptor(reader_index);
Packit 9f0df5
				if ((PROTOCOL_ICCD_A == ccid_desc->bInterfaceProtocol)
Packit 9f0df5
					|| (PROTOCOL_ICCD_B == ccid_desc->bInterfaceProtocol))
Packit 9f0df5
				{
Packit 9f0df5
					*Length = 1;	/* 1 char */
Packit 9f0df5
					if (Value)
Packit 9f0df5
						*Value = 1;	/* TRUE */
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case TAG_IFD_STOP_POLLING_THREAD:
Packit 9f0df5
			{
Packit 9f0df5
				_ccid_descriptor *ccid_desc;
Packit 9f0df5
Packit 9f0df5
				/* default value: not supported */
Packit 9f0df5
				*Length = 0;
Packit 9f0df5
Packit 9f0df5
				ccid_desc = get_ccid_descriptor(reader_index);
Packit 9f0df5
				/* CCID and not ICCD */
Packit 9f0df5
				if ((PROTOCOL_CCID == ccid_desc -> bInterfaceProtocol)
Packit 9f0df5
					/* 3 end points */
Packit 9f0df5
					&& (3 == ccid_desc -> bNumEndpoints))
Packit 9f0df5
				{
Packit 9f0df5
					*Length = sizeof(void *);
Packit 9f0df5
					if (Value)
Packit 9f0df5
						*(void **)Value = IFDHStopPolling;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
		case SCARD_ATTR_VENDOR_IFD_SERIAL_NO:
Packit 9f0df5
			{
Packit 9f0df5
				_ccid_descriptor *ccid_desc;
Packit 9f0df5
Packit 9f0df5
				ccid_desc = get_ccid_descriptor(reader_index);
Packit 9f0df5
				if (ccid_desc->sIFD_serial_number)
Packit 9f0df5
				{
Packit 9f0df5
					strlcpy((char *)Value, ccid_desc->sIFD_serial_number, *Length);
Packit 9f0df5
					*Length = strlen((char *)Value)+1;
Packit 9f0df5
				}
Packit 9f0df5
				else
Packit 9f0df5
				{
Packit 9f0df5
					/* not supported */
Packit 9f0df5
					*Length = 0;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		default:
Packit 9f0df5
			return_value = IFD_ERROR_TAG;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* IFDHGetCapabilities */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
Packit 9f0df5
	/*@unused@*/ DWORD Length, /*@unused@*/ PUCHAR Value)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function should set the slot/card capabilities for a
Packit 9f0df5
	 * particular slot/card specified by Lun.  Again, if you have only 1
Packit 9f0df5
	 * card slot and don't mind loading a new driver for each reader then
Packit 9f0df5
	 * ignore Lun.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Tag - the tag for the information needing set
Packit 9f0df5
	 *
Packit 9f0df5
	 * Length - the length of the returned data Value - the value of the
Packit 9f0df5
	 * data
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
Packit 9f0df5
	 * IFD_ERROR_VALUE_READ_ONLY
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	(void)Length;
Packit 9f0df5
	(void)Value;
Packit 9f0df5
Packit 9f0df5
	int reader_index;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("tag: 0x" DWORD_X ", %s (lun: " DWORD_X ")", Tag,
Packit 9f0df5
		CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	return IFD_NOT_SUPPORTED;
Packit 9f0df5
} /* IFDHSetCapabilities */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
Packit 9f0df5
	UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function should set the PTS of a particular card/slot using
Packit 9f0df5
	 * the three PTS parameters sent
Packit 9f0df5
	 *
Packit 9f0df5
	 * Protocol - SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
Packit 9f0df5
	 * Flags - Logical OR of possible values:
Packit 9f0df5
	 *  IFD_NEGOTIATE_PTS1
Packit 9f0df5
	 *  IFD_NEGOTIATE_PTS2
Packit 9f0df5
	 *  IFD_NEGOTIATE_PTS3
Packit 9f0df5
	 * to determine which PTS values to negotiate.
Packit 9f0df5
	 * PTS1,PTS2,PTS3 - PTS Values.
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *  IFD_SUCCESS
Packit 9f0df5
	 *  IFD_ERROR_PTS_FAILURE
Packit 9f0df5
	 *  IFD_COMMUNICATION_ERROR
Packit 9f0df5
	 *  IFD_PROTOCOL_NOT_SUPPORTED
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	BYTE pps[PPS_MAX_LENGTH];
Packit 9f0df5
	ATR_t atr;
Packit 9f0df5
	unsigned int len;
Packit 9f0df5
	int convention;
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	int atr_ret;
Packit 9f0df5
Packit 9f0df5
	/* Set ccid desc params */
Packit 9f0df5
	CcidDesc *ccid_slot;
Packit 9f0df5
	_ccid_descriptor *ccid_desc;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("protocol T=" DWORD_D ", %s (lun: " DWORD_X ")",
Packit 9f0df5
		Protocol-SCARD_PROTOCOL_T0, CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	/* Set to zero buffer */
Packit 9f0df5
	memset(pps, 0, sizeof(pps));
Packit 9f0df5
	memset(&atr, 0, sizeof(atr));
Packit 9f0df5
Packit 9f0df5
	/* Get ccid params */
Packit 9f0df5
	ccid_slot = get_ccid_slot(reader_index);
Packit 9f0df5
	ccid_desc = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
	/* Do not send CCID command SetParameters or PPS to the CCID
Packit 9f0df5
	 * The CCID will do this himself */
Packit 9f0df5
	if (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_PROP)
Packit 9f0df5
	{
Packit 9f0df5
		DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
Packit 9f0df5
		goto end;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Get ATR of the card */
Packit 9f0df5
	atr_ret = ATR_InitFromArray(&atr, ccid_slot->pcATRBuffer,
Packit 9f0df5
		ccid_slot->nATRLength);
Packit 9f0df5
	if (ATR_MALFORMED == atr_ret)
Packit 9f0df5
		return IFD_PROTOCOL_NOT_SUPPORTED;
Packit 9f0df5
Packit 9f0df5
	if (SCARD_PROTOCOL_T0 == Protocol)
Packit 9f0df5
		pps[1] |= ATR_PROTOCOL_TYPE_T0;
Packit 9f0df5
	else
Packit 9f0df5
		if (SCARD_PROTOCOL_T1 == Protocol)
Packit 9f0df5
			pps[1] |= ATR_PROTOCOL_TYPE_T1;
Packit 9f0df5
		else
Packit 9f0df5
			return IFD_PROTOCOL_NOT_SUPPORTED;
Packit 9f0df5
Packit 9f0df5
	/* TA2 present -> specific mode */
Packit 9f0df5
	if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
Packit 9f0df5
	{
Packit 9f0df5
		if (pps[1] != (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F))
Packit 9f0df5
		{
Packit 9f0df5
			/* wrong protocol */
Packit 9f0df5
			DEBUG_COMM3("Specific mode in T=%d and T=%d requested",
Packit 9f0df5
				atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x0F, pps[1]);
Packit 9f0df5
Packit 9f0df5
			return IFD_PROTOCOL_NOT_SUPPORTED;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* TCi (i>2) indicates CRC instead of LRC */
Packit 9f0df5
	if (SCARD_PROTOCOL_T1 == Protocol)
Packit 9f0df5
	{
Packit 9f0df5
		t1_state_t *t1 = &(ccid_slot -> t1);
Packit 9f0df5
		int i;
Packit 9f0df5
Packit 9f0df5
		/* TCi (i>2) present? */
Packit 9f0df5
		for (i=2; i
Packit 9f0df5
			if (atr.ib[i][ATR_INTERFACE_BYTE_TC].present)
Packit 9f0df5
			{
Packit 9f0df5
				if (0 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM("Use LRC");
Packit 9f0df5
					(void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_LRC, 0);
Packit 9f0df5
				}
Packit 9f0df5
				else
Packit 9f0df5
					if (1 == atr.ib[i][ATR_INTERFACE_BYTE_TC].value)
Packit 9f0df5
					{
Packit 9f0df5
						DEBUG_COMM("Use CRC");
Packit 9f0df5
						(void)t1_set_param(t1, IFD_PROTOCOL_T1_CHECKSUM_CRC, 0);
Packit 9f0df5
					}
Packit 9f0df5
					else
Packit 9f0df5
						DEBUG_COMM2("Wrong value for TCi: %d",
Packit 9f0df5
							atr.ib[i][ATR_INTERFACE_BYTE_TC].value);
Packit 9f0df5
Packit 9f0df5
				/* only the first TCi (i>2) must be used */
Packit 9f0df5
				break;
Packit 9f0df5
			}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* PTS1? */
Packit 9f0df5
	if (Flags & IFD_NEGOTIATE_PTS1)
Packit 9f0df5
	{
Packit 9f0df5
		/* just use the value passed in argument */
Packit 9f0df5
		pps[1] |= 0x10; /* PTS1 presence */
Packit 9f0df5
		pps[2] = PTS1;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	{
Packit 9f0df5
		/* TA1 present */
Packit 9f0df5
		if (atr.ib[0][ATR_INTERFACE_BYTE_TA].present)
Packit 9f0df5
		{
Packit 9f0df5
			unsigned int card_baudrate;
Packit 9f0df5
			unsigned int default_baudrate;
Packit 9f0df5
			double f, d;
Packit 9f0df5
Packit 9f0df5
			(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
Packit 9f0df5
			(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
Packit 9f0df5
Packit 9f0df5
			/* may happen with non ISO cards */
Packit 9f0df5
			if ((0 == f) || (0 == d))
Packit 9f0df5
			{
Packit 9f0df5
				/* values for TA1=11 */
Packit 9f0df5
				f = 372;
Packit 9f0df5
				d = 1;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* Baudrate = f x D/F */
Packit 9f0df5
			card_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
Packit 9f0df5
				* d / f);
Packit 9f0df5
Packit 9f0df5
			default_baudrate = (unsigned int) (1000 * ccid_desc->dwDefaultClock
Packit 9f0df5
				* ATR_DEFAULT_D / ATR_DEFAULT_F);
Packit 9f0df5
Packit 9f0df5
			/* if the card does not try to lower the default speed */
Packit 9f0df5
			if ((card_baudrate > default_baudrate)
Packit 9f0df5
				/* and the reader is fast enough */
Packit 9f0df5
				&& (card_baudrate <= ccid_desc->dwMaxDataRate))
Packit 9f0df5
			{
Packit 9f0df5
				/* the reader has no baud rates table */
Packit 9f0df5
				if ((NULL == ccid_desc->arrayOfSupportedDataRates)
Packit 9f0df5
					/* or explicitely support it */
Packit 9f0df5
					|| find_baud_rate(card_baudrate,
Packit 9f0df5
						ccid_desc->arrayOfSupportedDataRates))
Packit 9f0df5
				{
Packit 9f0df5
					pps[1] |= 0x10; /* PTS1 presence */
Packit 9f0df5
					pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
Packit 9f0df5
Packit 9f0df5
					DEBUG_COMM2("Set speed to %d bauds", card_baudrate);
Packit 9f0df5
				}
Packit 9f0df5
				else
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_COMM2("Reader does not support %d bauds",
Packit 9f0df5
						card_baudrate);
Packit 9f0df5
Packit 9f0df5
					/* TA2 present -> specific mode: the card is supporting
Packit 9f0df5
					 * only the baud rate specified in TA1 but reader does not
Packit 9f0df5
					 * support this value. Reject the card. */
Packit 9f0df5
					if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present)
Packit 9f0df5
						return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				/* the card is too fast for the reader */
Packit 9f0df5
				if ((card_baudrate > ccid_desc->dwMaxDataRate +2)
Packit 9f0df5
					/* but TA1 <= 97 */
Packit 9f0df5
					&& (atr.ib[0][ATR_INTERFACE_BYTE_TA].value <= 0x97))
Packit 9f0df5
				{
Packit 9f0df5
					unsigned char old_TA1;
Packit 9f0df5
Packit 9f0df5
					old_TA1 = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
Packit 9f0df5
					while (atr.ib[0][ATR_INTERFACE_BYTE_TA].value > 0x94)
Packit 9f0df5
					{
Packit 9f0df5
						/* use a lower TA1 */
Packit 9f0df5
						atr.ib[0][ATR_INTERFACE_BYTE_TA].value--;
Packit 9f0df5
Packit 9f0df5
						(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
Packit 9f0df5
						(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
Packit 9f0df5
Packit 9f0df5
						/* Baudrate = f x D/F */
Packit 9f0df5
						card_baudrate = (unsigned int) (1000 *
Packit 9f0df5
							ccid_desc->dwDefaultClock * d / f);
Packit 9f0df5
Packit 9f0df5
						/* the reader has a baud rate table */
Packit 9f0df5
						if ((ccid_desc->arrayOfSupportedDataRates
Packit 9f0df5
							/* and the baud rate is supported */
Packit 9f0df5
							&& find_baud_rate(card_baudrate,
Packit 9f0df5
							ccid_desc->arrayOfSupportedDataRates))
Packit 9f0df5
							/* or the reader has NO baud rate table */
Packit 9f0df5
							|| ((NULL == ccid_desc->arrayOfSupportedDataRates)
Packit 9f0df5
							/* and the baud rate is bellow the limit */
Packit 9f0df5
							&& (card_baudrate <= ccid_desc->dwMaxDataRate)))
Packit 9f0df5
						{
Packit 9f0df5
							pps[1] |= 0x10; /* PTS1 presence */
Packit 9f0df5
							pps[2] = atr.ib[0][ATR_INTERFACE_BYTE_TA].value;
Packit 9f0df5
Packit 9f0df5
							DEBUG_COMM2("Set adapted speed to %d bauds",
Packit 9f0df5
								card_baudrate);
Packit 9f0df5
Packit 9f0df5
							break;
Packit 9f0df5
						}
Packit 9f0df5
					}
Packit 9f0df5
Packit 9f0df5
					/* restore original TA1 value */
Packit 9f0df5
					atr.ib[0][ATR_INTERFACE_BYTE_TA].value = old_TA1;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* PTS2? */
Packit 9f0df5
	if (Flags & IFD_NEGOTIATE_PTS2)
Packit 9f0df5
	{
Packit 9f0df5
		pps[1] |= 0x20; /* PTS2 presence */
Packit 9f0df5
		pps[3] = PTS2;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* PTS3? */
Packit 9f0df5
	if (Flags & IFD_NEGOTIATE_PTS3)
Packit 9f0df5
	{
Packit 9f0df5
		pps[1] |= 0x40; /* PTS3 presence */
Packit 9f0df5
		pps[4] = PTS3;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Generate PPS */
Packit 9f0df5
	pps[0] = 0xFF;
Packit 9f0df5
Packit 9f0df5
	/* Automatic PPS made by the ICC? */
Packit 9f0df5
	if ((! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_PPS_CUR))
Packit 9f0df5
		/* TA2 absent: negociable mode */
Packit 9f0df5
		&& (! atr.ib[1][ATR_INTERFACE_BYTE_TA].present))
Packit 9f0df5
	{
Packit 9f0df5
		int default_protocol;
Packit 9f0df5
Packit 9f0df5
		ATR_GetDefaultProtocol(&atr, &default_protocol, NULL);
Packit 9f0df5
Packit 9f0df5
		/* if the requested protocol is not the default one
Packit 9f0df5
		 * or a TA1/PPS1 is present */
Packit 9f0df5
		if (((pps[1] & 0x0F) != default_protocol) || (PPS_HAS_PPS1(pps)))
Packit 9f0df5
		{
Packit 9f0df5
#ifdef O2MICRO_OZ776_PATCH
Packit 9f0df5
			if ((OZ776 == ccid_desc->readerID)
Packit 9f0df5
				|| (OZ776_7772 == ccid_desc->readerID))
Packit 9f0df5
			{
Packit 9f0df5
				/* convert from ATR_PROTOCOL_TYPE_T? to SCARD_PROTOCOL_T? */
Packit 9f0df5
				Protocol = default_protocol +
Packit 9f0df5
					(SCARD_PROTOCOL_T0 - ATR_PROTOCOL_TYPE_T0);
Packit 9f0df5
				DEBUG_INFO2("PPS not supported on O2Micro readers. Using T=" DWORD_D,
Packit 9f0df5
					Protocol - SCARD_PROTOCOL_T0);
Packit 9f0df5
			}
Packit 9f0df5
			else
Packit 9f0df5
#endif
Packit 9f0df5
			if (PPS_Exchange(reader_index, pps, &len, &pps[2]) != PPS_OK)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_INFO1("PPS_Exchange Failed");
Packit 9f0df5
Packit 9f0df5
				return IFD_ERROR_PTS_FAILURE;
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Now we must set the reader parameters */
Packit 9f0df5
	(void)ATR_GetConvention(&atr, &convention);
Packit 9f0df5
Packit 9f0df5
	/* specific mode and implicit parameters? (b5 of TA2) */
Packit 9f0df5
	if (atr.ib[1][ATR_INTERFACE_BYTE_TA].present
Packit 9f0df5
		&& (atr.ib[1][ATR_INTERFACE_BYTE_TA].value & 0x10))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	/* T=1 */
Packit 9f0df5
	if (SCARD_PROTOCOL_T1 == Protocol)
Packit 9f0df5
	{
Packit 9f0df5
		BYTE param[] = {
Packit 9f0df5
			0x11,	/* Fi/Di		*/
Packit 9f0df5
			0x10,	/* TCCKS		*/
Packit 9f0df5
			0x00,	/* GuardTime	*/
Packit 9f0df5
			0x4D,	/* BWI/CWI		*/
Packit 9f0df5
			0x00,	/* ClockStop	*/
Packit 9f0df5
			0x20,	/* IFSC			*/
Packit 9f0df5
			0x00	/* NADValue		*/
Packit 9f0df5
		};
Packit 9f0df5
		int i;
Packit 9f0df5
		t1_state_t *t1 = &(ccid_slot -> t1);
Packit 9f0df5
		RESPONSECODE ret;
Packit 9f0df5
		double f, d;
Packit 9f0df5
		int ifsc;
Packit 9f0df5
Packit 9f0df5
		/* TA1 is not default */
Packit 9f0df5
		if (PPS_HAS_PPS1(pps))
Packit 9f0df5
			param[0] = pps[2];
Packit 9f0df5
Packit 9f0df5
		/* CRC checksum? */
Packit 9f0df5
		if (2 == t1->rc_bytes)
Packit 9f0df5
			param[1] |= 0x01;
Packit 9f0df5
Packit 9f0df5
		/* the CCID should ignore this bit */
Packit 9f0df5
		if (ATR_CONVENTION_INVERSE == convention)
Packit 9f0df5
			param[1] |= 0x02;
Packit 9f0df5
Packit 9f0df5
		/* get TC1 Extra guard time */
Packit 9f0df5
		if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
Packit 9f0df5
			param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
Packit 9f0df5
Packit 9f0df5
		/* TBi (i>2) present? BWI/CWI */
Packit 9f0df5
		for (i=2; i
Packit 9f0df5
			if (atr.ib[i][ATR_INTERFACE_BYTE_TB].present)
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_COMM3("BWI/CWI (TB%d) present: 0x%02X", i+1,
Packit 9f0df5
					atr.ib[i][ATR_INTERFACE_BYTE_TB].value);
Packit 9f0df5
				param[3] = atr.ib[i][ATR_INTERFACE_BYTE_TB].value;
Packit 9f0df5
Packit 9f0df5
				{
Packit 9f0df5
					/* Hack for OpenPGP card */
Packit 9f0df5
					unsigned char openpgp_atr[] = { 0x3B, 0xFA, 0x13,
Packit 9f0df5
						0x00, 0xFF, 0x81, 0x31, 0x80, 0x45, 0x00, 0x31,
Packit 9f0df5
						0xC1, 0x73, 0xC0, 0x01, 0x00, 0x00, 0x90, 0x00, 0xB1 };
Packit 9f0df5
Packit 9f0df5
					if (0 == memcmp(ccid_slot->pcATRBuffer, openpgp_atr,
Packit 9f0df5
						ccid_slot->nATRLength))
Packit 9f0df5
						/* change BWI from 4 to 7 to increase BWT from
Packit 9f0df5
						 * 1.4s to 11s and avoid a timeout during on
Packit 9f0df5
						 * board key generation (bogus card) */
Packit 9f0df5
					{
Packit 9f0df5
						param[3] = 0x75;
Packit 9f0df5
						DEBUG_COMM2("OpenPGP hack, using 0x%02X", param[3]);
Packit 9f0df5
					}
Packit 9f0df5
				}
Packit 9f0df5
Packit 9f0df5
				/* only the first TBi (i>2) must be used */
Packit 9f0df5
				break;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
		/* compute communication timeout */
Packit 9f0df5
		(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
Packit 9f0df5
		(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
Packit 9f0df5
		ccid_desc->readTimeout = T1_card_timeout(f, d, param[2],
Packit 9f0df5
			(param[3] & 0xF0) >> 4 /* BWI */, param[3] & 0x0F /* CWI */,
Packit 9f0df5
			ccid_desc->dwDefaultClock);
Packit 9f0df5
Packit 9f0df5
		ifsc = get_IFSC(&atr, &i);
Packit 9f0df5
		if (ifsc > 0)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
Packit 9f0df5
			param[5] = ifsc;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		DEBUG_COMM2("Timeout: %d ms", ccid_desc->readTimeout);
Packit 9f0df5
Packit 9f0df5
		ret = SetParameters(reader_index, 1, sizeof(param), param);
Packit 9f0df5
		if (IFD_SUCCESS != ret)
Packit 9f0df5
			return ret;
Packit 9f0df5
	}
Packit 9f0df5
	else
Packit 9f0df5
	/* T=0 */
Packit 9f0df5
	{
Packit 9f0df5
		BYTE param[] = {
Packit 9f0df5
			0x11,	/* Fi/Di			*/
Packit 9f0df5
			0x00,	/* TCCKS			*/
Packit 9f0df5
			0x00,	/* GuardTime		*/
Packit 9f0df5
			0x0A,	/* WaitingInteger	*/
Packit 9f0df5
			0x00	/* ClockStop		*/
Packit 9f0df5
		};
Packit 9f0df5
		RESPONSECODE ret;
Packit 9f0df5
		double f, d;
Packit 9f0df5
Packit 9f0df5
		/* TA1 is not default */
Packit 9f0df5
		if (PPS_HAS_PPS1(pps))
Packit 9f0df5
			param[0] = pps[2];
Packit 9f0df5
Packit 9f0df5
		if (ATR_CONVENTION_INVERSE == convention)
Packit 9f0df5
			param[1] |= 0x02;
Packit 9f0df5
Packit 9f0df5
		/* get TC1 Extra guard time */
Packit 9f0df5
		if (atr.ib[0][ATR_INTERFACE_BYTE_TC].present)
Packit 9f0df5
			param[2] = atr.ib[0][ATR_INTERFACE_BYTE_TC].value;
Packit 9f0df5
Packit 9f0df5
		/* TC2 WWT */
Packit 9f0df5
		if (atr.ib[1][ATR_INTERFACE_BYTE_TC].present)
Packit 9f0df5
			param[3] = atr.ib[1][ATR_INTERFACE_BYTE_TC].value;
Packit 9f0df5
Packit 9f0df5
		/* compute communication timeout */
Packit 9f0df5
		(void)ATR_GetParameter(&atr, ATR_PARAMETER_F, &f);
Packit 9f0df5
		(void)ATR_GetParameter(&atr, ATR_PARAMETER_D, &d);
Packit 9f0df5
Packit 9f0df5
		ccid_desc->readTimeout = T0_card_timeout(f, d, param[2] /* TC1 */,
Packit 9f0df5
			param[3] /* TC2 */, ccid_desc->dwDefaultClock);
Packit 9f0df5
Packit 9f0df5
		DEBUG_COMM2("Communication timeout: %d ms", ccid_desc->readTimeout);
Packit 9f0df5
Packit 9f0df5
		ret = SetParameters(reader_index, 0, sizeof(param), param);
Packit 9f0df5
		if (IFD_SUCCESS != ret)
Packit 9f0df5
			return ret;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* set IFSC & IFSD in T=1 */
Packit 9f0df5
	if (SCARD_PROTOCOL_T1 == Protocol)
Packit 9f0df5
	{
Packit 9f0df5
		t1_state_t *t1 = &(ccid_slot -> t1);
Packit 9f0df5
		int i, ifsc;
Packit 9f0df5
Packit 9f0df5
		ifsc = get_IFSC(&atr, &i);
Packit 9f0df5
		if (ifsc > 0)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM3("IFSC (TA%d) present: %d", i, ifsc);
Packit 9f0df5
			(void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSC, ifsc);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* IFSD not negociated by the reader? */
Packit 9f0df5
		if (! (ccid_desc->dwFeatures & CCID_CLASS_AUTO_IFSD))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_COMM2("Negotiate IFSD at %d", ccid_desc -> dwMaxIFSD);
Packit 9f0df5
			if (t1_negotiate_ifsd(t1, 0, ccid_desc -> dwMaxIFSD) < 0)
Packit 9f0df5
				return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
		}
Packit 9f0df5
		(void)t1_set_param(t1, IFD_PROTOCOL_T1_IFSD, ccid_desc -> dwMaxIFSD);
Packit 9f0df5
Packit 9f0df5
		DEBUG_COMM3("T=1: IFSC=%d, IFSD=%d", t1->ifsc, t1->ifsd);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
end:
Packit 9f0df5
	/* store used protocol for use by the secure commands (verify/change PIN) */
Packit 9f0df5
	ccid_desc->cardProtocol = Protocol;
Packit 9f0df5
Packit 9f0df5
	return IFD_SUCCESS;
Packit 9f0df5
} /* IFDHSetProtocolParameters */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
Packit 9f0df5
	PUCHAR Atr, PDWORD AtrLength)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function controls the power and reset signals of the smartcard
Packit 9f0df5
	 * reader at the particular reader/slot specified by Lun.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Action - Action to be taken on the card.
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_POWER_UP - Power and reset the card if not done so (store the
Packit 9f0df5
	 * ATR and return it and its length).
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_POWER_DOWN - Power down the card if not done already
Packit 9f0df5
	 * (Atr/AtrLength should be zero'd)
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_RESET - Perform a quick reset on the card.  If the card is not
Packit 9f0df5
	 * powered power up the card.  (Store and return the Atr/Length)
Packit 9f0df5
	 *
Packit 9f0df5
	 * Atr - Answer to Reset of the card.  The driver is responsible for
Packit 9f0df5
	 * caching this value in case IFDHGetCapabilities is called requesting
Packit 9f0df5
	 * the ATR and its length.  This should not exceed MAX_ATR_SIZE.
Packit 9f0df5
	 *
Packit 9f0df5
	 * AtrLength - Length of the Atr.  This should not exceed
Packit 9f0df5
	 * MAX_ATR_SIZE.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Notes:
Packit 9f0df5
	 *
Packit 9f0df5
	 * Memory cards without an ATR should return IFD_SUCCESS on reset but
Packit 9f0df5
	 * the Atr should be zero'd and the length should be zero
Packit 9f0df5
	 *
Packit 9f0df5
	 * Reset errors should return zero for the AtrLength and return
Packit 9f0df5
	 * IFD_ERROR_POWER_ACTION.
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
Packit 9f0df5
	 * IFD_NOT_SUPPORTED
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	unsigned int nlength;
Packit 9f0df5
	RESPONSECODE return_value = IFD_SUCCESS;
Packit 9f0df5
	unsigned char pcbuffer[10+MAX_ATR_SIZE];
Packit 9f0df5
	int reader_index;
Packit 9f0df5
#ifndef NO_LOG
Packit 9f0df5
	const char *actions[] = { "PowerUp", "PowerDown", "Reset" };
Packit 9f0df5
#endif
Packit 9f0df5
	unsigned int oldReadTimeout;
Packit 9f0df5
	_ccid_descriptor *ccid_descriptor;
Packit 9f0df5
Packit 9f0df5
	/* By default, assume it won't work :) */
Packit 9f0df5
	*AtrLength = 0;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("action: %s, %s (lun: " DWORD_X ")",
Packit 9f0df5
		actions[Action-IFD_POWER_UP], CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	switch (Action)
Packit 9f0df5
	{
Packit 9f0df5
		case IFD_POWER_DOWN:
Packit 9f0df5
			/* Clear ATR buffer */
Packit 9f0df5
			CcidSlots[reader_index].nATRLength = 0;
Packit 9f0df5
			*CcidSlots[reader_index].pcATRBuffer = '\0';
Packit 9f0df5
Packit 9f0df5
			/* Memorise the request */
Packit 9f0df5
			CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PDWN;
Packit 9f0df5
Packit 9f0df5
			/* send the command */
Packit 9f0df5
			if (IFD_SUCCESS != CmdPowerOff(reader_index))
Packit 9f0df5
			{
Packit 9f0df5
				DEBUG_CRITICAL("PowerDown failed");
Packit 9f0df5
				return_value = IFD_ERROR_POWER_ACTION;
Packit 9f0df5
				goto end;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* clear T=1 context */
Packit 9f0df5
			t1_release(&(get_ccid_slot(reader_index) -> t1));
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case IFD_POWER_UP:
Packit 9f0df5
		case IFD_RESET:
Packit 9f0df5
			/* save the current read timeout computed from card capabilities */
Packit 9f0df5
			ccid_descriptor = get_ccid_descriptor(reader_index);
Packit 9f0df5
			oldReadTimeout = ccid_descriptor->readTimeout;
Packit 9f0df5
Packit 9f0df5
			/* The German eID card is bogus and need to be powered off
Packit 9f0df5
			 * before a power on */
Packit 9f0df5
			if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
Packit 9f0df5
			{
Packit 9f0df5
				/* send the command */
Packit 9f0df5
				if (IFD_SUCCESS != CmdPowerOff(reader_index))
Packit 9f0df5
				{
Packit 9f0df5
					DEBUG_CRITICAL("PowerDown failed");
Packit 9f0df5
					return_value = IFD_ERROR_POWER_ACTION;
Packit 9f0df5
					goto end;
Packit 9f0df5
				}
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* use a very long timeout since the card can use up to
Packit 9f0df5
			 * (9600+12)*33 ETU in total
Packit 9f0df5
			 * 12 ETU per byte
Packit 9f0df5
			 * 9600 ETU max between each byte
Packit 9f0df5
			 * 33 bytes max for ATR
Packit 9f0df5
			 * 1 ETU = 372 cycles during ATR
Packit 9f0df5
			 * with a 4 MHz clock => 29 seconds
Packit 9f0df5
			 */
Packit 9f0df5
			ccid_descriptor->readTimeout = 60*1000;
Packit 9f0df5
Packit 9f0df5
			nlength = sizeof(pcbuffer);
Packit 9f0df5
			return_value = CmdPowerOn(reader_index, &nlength, pcbuffer,
Packit 9f0df5
				PowerOnVoltage);
Packit 9f0df5
Packit 9f0df5
			/* set back the old timeout */
Packit 9f0df5
			ccid_descriptor->readTimeout = oldReadTimeout;
Packit 9f0df5
Packit 9f0df5
			if (return_value != IFD_SUCCESS)
Packit 9f0df5
			{
Packit 9f0df5
				/* used by GemCore SIM PRO: no card is present */
Packit 9f0df5
				if (GEMCORESIMPRO == ccid_descriptor -> readerID)
Packit 9f0df5
					get_ccid_descriptor(reader_index)->dwSlotStatus
Packit 9f0df5
						= IFD_ICC_NOT_PRESENT;
Packit 9f0df5
Packit 9f0df5
				DEBUG_CRITICAL("PowerUp failed");
Packit 9f0df5
				return_value = IFD_ERROR_POWER_ACTION;
Packit 9f0df5
				goto end;
Packit 9f0df5
			}
Packit 9f0df5
Packit 9f0df5
			/* Power up successful, set state variable to memorise it */
Packit 9f0df5
			CcidSlots[reader_index].bPowerFlags |= MASK_POWERFLAGS_PUP;
Packit 9f0df5
			CcidSlots[reader_index].bPowerFlags &= ~MASK_POWERFLAGS_PDWN;
Packit 9f0df5
Packit 9f0df5
			/* Reset is returned, even if TCK is wrong */
Packit 9f0df5
			CcidSlots[reader_index].nATRLength = *AtrLength =
Packit 9f0df5
				(nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
Packit 9f0df5
			memcpy(Atr, pcbuffer, *AtrLength);
Packit 9f0df5
			memcpy(CcidSlots[reader_index].pcATRBuffer, pcbuffer, *AtrLength);
Packit 9f0df5
Packit 9f0df5
			/* initialise T=1 context */
Packit 9f0df5
			(void)t1_init(&(get_ccid_slot(reader_index) -> t1), reader_index);
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		default:
Packit 9f0df5
			DEBUG_CRITICAL("Action not supported");
Packit 9f0df5
			return_value = IFD_NOT_SUPPORTED;
Packit 9f0df5
	}
Packit 9f0df5
end:
Packit 9f0df5
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* IFDHPowerICC */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
Packit 9f0df5
	PUCHAR TxBuffer, DWORD TxLength,
Packit 9f0df5
	PUCHAR RxBuffer, PDWORD RxLength, /*@unused@*/ PSCARD_IO_HEADER RecvPci)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function performs an APDU exchange with the card/slot
Packit 9f0df5
	 * specified by Lun.  The driver is responsible for performing any
Packit 9f0df5
	 * protocol specific exchanges such as T=0/1 ... differences.  Calling
Packit 9f0df5
	 * this function will abstract all protocol differences.
Packit 9f0df5
	 *
Packit 9f0df5
	 * SendPci Protocol - 0, 1, .... 14 Length - Not used.
Packit 9f0df5
	 *
Packit 9f0df5
	 * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
Packit 9f0df5
	 * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
Packit 9f0df5
	 * example (0x61 0x14) RxLength - Length of the received APDU.  This
Packit 9f0df5
	 * function will be passed the size of the buffer of RxBuffer and this
Packit 9f0df5
	 * function is responsible for setting this to the length of the
Packit 9f0df5
	 * received APDU.  This should be ZERO on all errors.  The resource
Packit 9f0df5
	 * manager will take responsibility of zeroing out any temporary APDU
Packit 9f0df5
	 * buffers for security reasons.
Packit 9f0df5
	 *
Packit 9f0df5
	 * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Notes: The driver is responsible for knowing what type of card it
Packit 9f0df5
	 * has.  If the current slot/card contains a memory card then this
Packit 9f0df5
	 * command should ignore the Protocol and use the MCT style commands
Packit 9f0df5
	 * for support for these style cards and transmit them appropriately.
Packit 9f0df5
	 * If your reader does not support memory cards or you don't want to
Packit 9f0df5
	 * then ignore this.
Packit 9f0df5
	 *
Packit 9f0df5
	 * RxLength should be set to zero on error.
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns:
Packit 9f0df5
	 *
Packit 9f0df5
	 * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
Packit 9f0df5
	 * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	RESPONSECODE return_value;
Packit 9f0df5
	unsigned int rx_length;
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	int old_read_timeout;
Packit 9f0df5
	int restore_timeout = FALSE;
Packit 9f0df5
	_ccid_descriptor *ccid_descriptor;
Packit 9f0df5
Packit 9f0df5
	(void)RecvPci;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	ccid_descriptor = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName,
Packit 9f0df5
		Lun);
Packit 9f0df5
Packit 9f0df5
	/* special APDU for the Kobil IDToken (CLASS = 0xFF) */
Packit 9f0df5
	if (KOBIL_IDTOKEN == ccid_descriptor -> readerID)
Packit 9f0df5
	{
Packit 9f0df5
		char manufacturer[] = {0xFF, 0x9A, 0x01, 0x01, 0x00};
Packit 9f0df5
		char product_name[] = {0xFF, 0x9A, 0x01, 0x03, 0x00};
Packit 9f0df5
		char firmware_version[] = {0xFF, 0x9A, 0x01, 0x06, 0x00};
Packit 9f0df5
		char driver_version[] = {0xFF, 0x9A, 0x01, 0x07, 0x00};
Packit 9f0df5
Packit 9f0df5
		if ((sizeof manufacturer == TxLength)
Packit 9f0df5
			&& (memcmp(TxBuffer, manufacturer, sizeof manufacturer) == 0))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("IDToken: Manufacturer command");
Packit 9f0df5
			memcpy(RxBuffer, "KOBIL systems\220\0", 15);
Packit 9f0df5
			*RxLength = 15;
Packit 9f0df5
			return IFD_SUCCESS;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((sizeof product_name == TxLength)
Packit 9f0df5
			&& (memcmp(TxBuffer, product_name, sizeof product_name) == 0))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("IDToken: Product name command");
Packit 9f0df5
			memcpy(RxBuffer, "IDToken\220\0", 9);
Packit 9f0df5
			*RxLength = 9;
Packit 9f0df5
			return IFD_SUCCESS;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((sizeof firmware_version == TxLength)
Packit 9f0df5
			&& (memcmp(TxBuffer, firmware_version, sizeof firmware_version) == 0))
Packit 9f0df5
		{
Packit 9f0df5
			int IFD_bcdDevice = ccid_descriptor -> IFD_bcdDevice;
Packit 9f0df5
Packit 9f0df5
			DEBUG_INFO1("IDToken: Firmware version command");
Packit 9f0df5
			*RxLength = sprintf((char *)RxBuffer, "%X.%02X",
Packit 9f0df5
				IFD_bcdDevice >> 8, IFD_bcdDevice & 0xFF);
Packit 9f0df5
			RxBuffer[(*RxLength)++] = 0x90;
Packit 9f0df5
			RxBuffer[(*RxLength)++] = 0x00;
Packit 9f0df5
			return IFD_SUCCESS;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((sizeof driver_version == TxLength)
Packit 9f0df5
			&& (memcmp(TxBuffer, driver_version, sizeof driver_version) == 0))
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("IDToken: Driver version command");
Packit 9f0df5
#define DRIVER_VERSION "2012.2.7\220\0"
Packit 9f0df5
			memcpy(RxBuffer, DRIVER_VERSION, sizeof DRIVER_VERSION -1);
Packit 9f0df5
			*RxLength = sizeof DRIVER_VERSION -1;
Packit 9f0df5
			return IFD_SUCCESS;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Pseudo-APDU as defined in PC/SC v2 part 10 supplement document
Packit 9f0df5
	 * CLA=0xFF, INS=0xC2, P1=0x01 */
Packit 9f0df5
	if (0 == memcmp(TxBuffer, "\xFF\xC2\x01", 3))
Packit 9f0df5
	{
Packit 9f0df5
		/* Yes, use the same timeout as for SCardControl() */
Packit 9f0df5
		restore_timeout = TRUE;
Packit 9f0df5
		old_read_timeout = ccid_descriptor -> readTimeout;
Packit 9f0df5
		ccid_descriptor -> readTimeout = 90 * 1000;	/* 90 seconds */
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	rx_length = *RxLength;
Packit 9f0df5
	return_value = CmdXfrBlock(reader_index, TxLength, TxBuffer, &rx_length,
Packit 9f0df5
		RxBuffer, SendPci.Protocol);
Packit 9f0df5
	if (IFD_SUCCESS == return_value)
Packit 9f0df5
		*RxLength = rx_length;
Packit 9f0df5
	else
Packit 9f0df5
		*RxLength = 0;
Packit 9f0df5
Packit 9f0df5
	/* restore timeout */
Packit 9f0df5
	if (restore_timeout)
Packit 9f0df5
		ccid_descriptor -> readTimeout = old_read_timeout;
Packit 9f0df5
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* IFDHTransmitToICC */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHControl(DWORD Lun, DWORD dwControlCode,
Packit 9f0df5
	PUCHAR TxBuffer, DWORD TxLength, PUCHAR RxBuffer, DWORD RxLength,
Packit 9f0df5
	PDWORD pdwBytesReturned)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function performs a data exchange with the reader (not the
Packit 9f0df5
	 * card) specified by Lun.  Here XXXX will only be used. It is
Packit 9f0df5
	 * responsible for abstracting functionality such as PIN pads,
Packit 9f0df5
	 * biometrics, LCD panels, etc.  You should follow the MCT, CTBCS
Packit 9f0df5
	 * specifications for a list of accepted commands to implement.
Packit 9f0df5
	 *
Packit 9f0df5
	 * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
Packit 9f0df5
	 * - Receive data RxLength - Length of the received data.  This
Packit 9f0df5
	 * function will be passed the length of the buffer RxBuffer and it
Packit 9f0df5
	 * must set this to the length of the received data.
Packit 9f0df5
	 *
Packit 9f0df5
	 * Notes: RxLength should be zero on error.
Packit 9f0df5
	 */
Packit 9f0df5
	RESPONSECODE return_value = IFD_ERROR_NOT_SUPPORTED;
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	_ccid_descriptor *ccid_descriptor;
Packit 9f0df5
Packit 9f0df5
	reader_index = LunToReaderIndex(Lun);
Packit 9f0df5
	if ((-1 == reader_index) || (NULL == pdwBytesReturned))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	ccid_descriptor = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO4("ControlCode: 0x" DWORD_X ", %s (lun: " DWORD_X ")",
Packit 9f0df5
		dwControlCode, CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
	DEBUG_INFO_XXD("Control TxBuffer: ", TxBuffer, TxLength);
Packit 9f0df5
Packit 9f0df5
	/* Set the return length to 0 to avoid problems */
Packit 9f0df5
	*pdwBytesReturned = 0;
Packit 9f0df5
Packit 9f0df5
	if (IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		int allowed = (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED);
Packit 9f0df5
		int readerID = ccid_descriptor -> readerID;
Packit 9f0df5
Packit 9f0df5
		if (VENDOR_GEMALTO == GET_VENDOR(readerID))
Packit 9f0df5
		{
Packit 9f0df5
			unsigned char switch_interface[] = { 0x52, 0xF8, 0x04, 0x01, 0x00 };
Packit 9f0df5
Packit 9f0df5
			/* get firmware version escape command */
Packit 9f0df5
			if ((1 == TxLength) && (0x02 == TxBuffer[0]))
Packit 9f0df5
				allowed = TRUE;
Packit 9f0df5
Packit 9f0df5
			/* switch interface escape command on the GemProx DU
Packit 9f0df5
			 * the next byte in the command is the interface:
Packit 9f0df5
			 * 0x01 switch to contactless interface
Packit 9f0df5
			 * 0x02 switch to contact interface
Packit 9f0df5
			 */
Packit 9f0df5
			if ((GEMALTOPROXDU == readerID)
Packit 9f0df5
				&& (6 == TxLength)
Packit 9f0df5
				&& (0 == memcmp(TxBuffer, switch_interface, sizeof(switch_interface))))
Packit 9f0df5
				allowed = TRUE;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if (!allowed)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("ifd exchange (Escape command) not allowed");
Packit 9f0df5
			return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			unsigned int iBytesReturned;
Packit 9f0df5
Packit 9f0df5
			iBytesReturned = RxLength;
Packit 9f0df5
			/* 30 seconds timeout for long commands */
Packit 9f0df5
			return_value = CmdEscape(reader_index, TxBuffer, TxLength,
Packit 9f0df5
				RxBuffer, &iBytesReturned, 30*1000);
Packit 9f0df5
			*pdwBytesReturned = iBytesReturned;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Implement the PC/SC v2.02.07 Part 10 IOCTL mechanism */
Packit 9f0df5
Packit 9f0df5
	/* Query for features */
Packit 9f0df5
	/* 0x313520 is the Windows value for SCARD_CTL_CODE(3400)
Packit 9f0df5
	 * This hack is needed for RDP applications */
Packit 9f0df5
	if ((CM_IOCTL_GET_FEATURE_REQUEST == dwControlCode)
Packit 9f0df5
		|| (0x313520 == dwControlCode))
Packit 9f0df5
	{
Packit 9f0df5
		unsigned int iBytesReturned = 0;
Packit 9f0df5
		PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)RxBuffer;
Packit 9f0df5
		int readerID = ccid_descriptor -> readerID;
Packit 9f0df5
Packit 9f0df5
		/* we need room for up to six records */
Packit 9f0df5
		if (RxLength < 6 * sizeof(PCSC_TLV_STRUCTURE))
Packit 9f0df5
			return IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
Packit 9f0df5
		/* We can only support direct verify and/or modify currently */
Packit 9f0df5
		if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_VERIFY)
Packit 9f0df5
		{
Packit 9f0df5
			pcsc_tlv -> tag = FEATURE_VERIFY_PIN_DIRECT;
Packit 9f0df5
			pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
			pcsc_tlv -> value = htonl(IOCTL_FEATURE_VERIFY_PIN_DIRECT);
Packit 9f0df5
Packit 9f0df5
			pcsc_tlv++;
Packit 9f0df5
			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_MODIFY)
Packit 9f0df5
		{
Packit 9f0df5
			pcsc_tlv -> tag = FEATURE_MODIFY_PIN_DIRECT;
Packit 9f0df5
			pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
			pcsc_tlv -> value = htonl(IOCTL_FEATURE_MODIFY_PIN_DIRECT);
Packit 9f0df5
Packit 9f0df5
			pcsc_tlv++;
Packit 9f0df5
			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Provide IFD_PIN_PROPERTIES only for pinpad readers */
Packit 9f0df5
		if (ccid_descriptor -> bPINSupport)
Packit 9f0df5
		{
Packit 9f0df5
			pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES;
Packit 9f0df5
			pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
			pcsc_tlv -> value = htonl(IOCTL_FEATURE_IFD_PIN_PROPERTIES);
Packit 9f0df5
Packit 9f0df5
			pcsc_tlv++;
Packit 9f0df5
			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if ((KOBIL_TRIBANK == readerID)
Packit 9f0df5
			|| (KOBIL_MIDENTITY_VISUAL == readerID))
Packit 9f0df5
		{
Packit 9f0df5
			pcsc_tlv -> tag = FEATURE_MCT_READER_DIRECT;
Packit 9f0df5
			pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
			pcsc_tlv -> value = htonl(IOCTL_FEATURE_MCT_READER_DIRECT);
Packit 9f0df5
Packit 9f0df5
			pcsc_tlv++;
Packit 9f0df5
			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		pcsc_tlv -> tag = FEATURE_GET_TLV_PROPERTIES;
Packit 9f0df5
		pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
		pcsc_tlv -> value = htonl(IOCTL_FEATURE_GET_TLV_PROPERTIES);
Packit 9f0df5
		pcsc_tlv++;
Packit 9f0df5
		iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
Packit 9f0df5
		/* IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE */
Packit 9f0df5
		if (DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED)
Packit 9f0df5
		{
Packit 9f0df5
			pcsc_tlv -> tag = FEATURE_CCID_ESC_COMMAND;
Packit 9f0df5
			pcsc_tlv -> length = 0x04; /* always 0x04 */
Packit 9f0df5
			pcsc_tlv -> value = htonl(IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE);
Packit 9f0df5
Packit 9f0df5
			pcsc_tlv++;
Packit 9f0df5
			iBytesReturned += sizeof(PCSC_TLV_STRUCTURE);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		*pdwBytesReturned = iBytesReturned;
Packit 9f0df5
		return_value = IFD_SUCCESS;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Get PIN handling capabilities */
Packit 9f0df5
	if (IOCTL_FEATURE_IFD_PIN_PROPERTIES == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *)RxBuffer;
Packit 9f0df5
		int validation;
Packit 9f0df5
Packit 9f0df5
		if (RxLength < sizeof(PIN_PROPERTIES_STRUCTURE))
Packit 9f0df5
			return IFD_ERROR_INSUFFICIENT_BUFFER;
Packit 9f0df5
Packit 9f0df5
		/* Only give the LCD size for now */
Packit 9f0df5
		caps -> wLcdLayout = ccid_descriptor -> wLcdLayout;
Packit 9f0df5
Packit 9f0df5
		/* Hardcoded special reader cases */
Packit 9f0df5
		switch (ccid_descriptor->readerID)
Packit 9f0df5
		{
Packit 9f0df5
			case GEMPCPINPAD:
Packit 9f0df5
			case VEGAALPHA:
Packit 9f0df5
			case CHERRYST2000:
Packit 9f0df5
				validation = 0x02; /* Validation key pressed */
Packit 9f0df5
				break;
Packit 9f0df5
			default:
Packit 9f0df5
				validation = 0x07; /* Default */
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Gemalto readers providing firmware features */
Packit 9f0df5
		if (ccid_descriptor -> gemalto_firmware_features)
Packit 9f0df5
			validation = ccid_descriptor -> gemalto_firmware_features -> bEntryValidationCondition;
Packit 9f0df5
Packit 9f0df5
		caps -> bEntryValidationCondition = validation;
Packit 9f0df5
		caps -> bTimeOut2 = 0x00; /* We do not distinguish bTimeOut from TimeOut2 */
Packit 9f0df5
Packit 9f0df5
		*pdwBytesReturned = sizeof(*caps);
Packit 9f0df5
		return_value = IFD_SUCCESS;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Reader features */
Packit 9f0df5
	if (IOCTL_FEATURE_GET_TLV_PROPERTIES == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		int p = 0;
Packit 9f0df5
		int tmp;
Packit 9f0df5
Packit 9f0df5
		/* wLcdLayout */
Packit 9f0df5
		RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdLayout;	/* tag */
Packit 9f0df5
		RxBuffer[p++] = 2;	/* length */
Packit 9f0df5
		tmp = ccid_descriptor -> wLcdLayout;
Packit 9f0df5
		RxBuffer[p++] = tmp & 0xFF;	/* value in little endian order */
Packit 9f0df5
		RxBuffer[p++] = (tmp >> 8) & 0xFF;
Packit 9f0df5
Packit 9f0df5
		/* only if the reader has a display */
Packit 9f0df5
		if (ccid_descriptor -> wLcdLayout)
Packit 9f0df5
		{
Packit 9f0df5
			/* wLcdMaxCharacters */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxCharacters;	/* tag */
Packit 9f0df5
			RxBuffer[p++] = 2;	/* length */
Packit 9f0df5
			tmp = ccid_descriptor -> wLcdLayout & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = tmp & 0xFF;	/* value in little endian order */
Packit 9f0df5
			RxBuffer[p++] = (tmp >> 8) & 0xFF;
Packit 9f0df5
Packit 9f0df5
			/* wLcdMaxLines */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wLcdMaxLines;	/* tag */
Packit 9f0df5
			RxBuffer[p++] = 2;	/* length */
Packit 9f0df5
			tmp = ccid_descriptor -> wLcdLayout >> 8;
Packit 9f0df5
			RxBuffer[p++] = tmp & 0xFF;	/* value in little endian order */
Packit 9f0df5
			RxBuffer[p++] = (tmp >> 8) & 0xFF;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* bTimeOut2 */
Packit 9f0df5
		RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bTimeOut2;
Packit 9f0df5
		RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
		/* IFD does not distinguish bTimeOut from bTimeOut2 */
Packit 9f0df5
		RxBuffer[p++] = 0x00;
Packit 9f0df5
Packit 9f0df5
		/* sFirmwareID */
Packit 9f0df5
		if (VENDOR_GEMALTO == GET_VENDOR(ccid_descriptor -> readerID))
Packit 9f0df5
		{
Packit 9f0df5
			unsigned char firmware[256];
Packit 9f0df5
			const unsigned char cmd[] = { 0x02 };
Packit 9f0df5
			RESPONSECODE ret;
Packit 9f0df5
			unsigned int len;
Packit 9f0df5
Packit 9f0df5
			len = sizeof(firmware);
Packit 9f0df5
			ret = CmdEscape(reader_index, cmd, sizeof(cmd), firmware, &len, 0);
Packit 9f0df5
Packit 9f0df5
			if (IFD_SUCCESS == ret)
Packit 9f0df5
			{
Packit 9f0df5
				RxBuffer[p++] = PCSCv2_PART10_PROPERTY_sFirmwareID;
Packit 9f0df5
				RxBuffer[p++] = len;
Packit 9f0df5
				memcpy(&RxBuffer[p], firmware, len);
Packit 9f0df5
				p += len;
Packit 9f0df5
			}
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Gemalto PC Pinpad V1 */
Packit 9f0df5
		if (((GEMPCPINPAD == ccid_descriptor -> readerID)
Packit 9f0df5
			&& (0x0100 == ccid_descriptor -> IFD_bcdDevice))
Packit 9f0df5
			/* Covadis VĂ©ga-Alpha */
Packit 9f0df5
			|| (VEGAALPHA == ccid_descriptor->readerID))
Packit 9f0df5
		{
Packit 9f0df5
			/* bMinPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 4;	/* min PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bMaxPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 8;	/* max PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bEntryValidationCondition */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 0x02;	/* validation key pressed */
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Cherry GmbH SmartTerminal ST-2xxx */
Packit 9f0df5
		if (CHERRYST2000 == ccid_descriptor -> readerID)
Packit 9f0df5
		{
Packit 9f0df5
			/* bMinPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 0;	/* min PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bMaxPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 25;	/* max PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bEntryValidationCondition */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = 0x02;	/* validation key pressed */
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Gemalto readers providing firmware features */
Packit 9f0df5
		if (ccid_descriptor -> gemalto_firmware_features)
Packit 9f0df5
		{
Packit 9f0df5
			struct GEMALTO_FIRMWARE_FEATURES *features = ccid_descriptor -> gemalto_firmware_features;
Packit 9f0df5
Packit 9f0df5
			/* bMinPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMinPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = features -> MinimumPINSize;	/* min PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bMaxPINSize */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bMaxPINSize;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = features -> MaximumPINSize;	/* max PIN size */
Packit 9f0df5
Packit 9f0df5
			/* bEntryValidationCondition */
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bEntryValidationCondition;
Packit 9f0df5
			RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
			RxBuffer[p++] = features -> bEntryValidationCondition;	/* validation key pressed */
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* bPPDUSupport */
Packit 9f0df5
		RxBuffer[p++] = PCSCv2_PART10_PROPERTY_bPPDUSupport;
Packit 9f0df5
		RxBuffer[p++] = 1;	/* length */
Packit 9f0df5
		RxBuffer[p++] =
Packit 9f0df5
			(DriverOptions & DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED) ? 1 : 0;
Packit 9f0df5
			/* bit0: PPDU is supported over SCardControl using
Packit 9f0df5
			 * FEATURE_CCID_ESC_COMMAND */
Packit 9f0df5
Packit 9f0df5
		/* wIdVendor */
Packit 9f0df5
		{
Packit 9f0df5
			int idVendor = ccid_descriptor -> readerID >> 16;
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdVendor;
Packit 9f0df5
			RxBuffer[p++] = 2;	/* length */
Packit 9f0df5
			RxBuffer[p++] = idVendor & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = idVendor >> 8;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* wIdProduct */
Packit 9f0df5
		{
Packit 9f0df5
			int idProduct = ccid_descriptor -> readerID & 0xFFFF;
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_wIdProduct;
Packit 9f0df5
			RxBuffer[p++] = 2;	/* length */
Packit 9f0df5
			RxBuffer[p++] = idProduct & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = idProduct >> 8;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* dwMaxAPDUDataSize */
Packit 9f0df5
		{
Packit 9f0df5
			int MaxAPDUDataSize = 0; /* short APDU only by default */
Packit 9f0df5
Packit 9f0df5
			/* reader is TPDU or extended APDU */
Packit 9f0df5
			if ((ccid_descriptor -> dwFeatures & CCID_CLASS_EXTENDED_APDU)
Packit 9f0df5
				|| (ccid_descriptor -> dwFeatures & CCID_CLASS_TPDU))
Packit 9f0df5
				MaxAPDUDataSize = 0x10000;
Packit 9f0df5
Packit 9f0df5
			RxBuffer[p++] = PCSCv2_PART10_PROPERTY_dwMaxAPDUDataSize;
Packit 9f0df5
			RxBuffer[p++] = 4;	/* length */
Packit 9f0df5
			RxBuffer[p++] = MaxAPDUDataSize & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = (MaxAPDUDataSize >> 8) & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = (MaxAPDUDataSize >> 16) & 0xFF;
Packit 9f0df5
			RxBuffer[p++] = (MaxAPDUDataSize >> 24) & 0xFF;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		*pdwBytesReturned = p;
Packit 9f0df5
		return_value = IFD_SUCCESS;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Verify a PIN, plain CCID */
Packit 9f0df5
	if (IOCTL_FEATURE_VERIFY_PIN_DIRECT == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		unsigned int iBytesReturned;
Packit 9f0df5
Packit 9f0df5
		iBytesReturned = RxLength;
Packit 9f0df5
		return_value = SecurePINVerify(reader_index, TxBuffer, TxLength,
Packit 9f0df5
			RxBuffer, &iBytesReturned);
Packit 9f0df5
		*pdwBytesReturned = iBytesReturned;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* Modify a PIN, plain CCID */
Packit 9f0df5
	if (IOCTL_FEATURE_MODIFY_PIN_DIRECT == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		unsigned int iBytesReturned;
Packit 9f0df5
Packit 9f0df5
		iBytesReturned = RxLength;
Packit 9f0df5
		return_value = SecurePINModify(reader_index, TxBuffer, TxLength,
Packit 9f0df5
			RxBuffer, &iBytesReturned);
Packit 9f0df5
		*pdwBytesReturned = iBytesReturned;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* MCT: Multifunctional Card Terminal */
Packit 9f0df5
	if (IOCTL_FEATURE_MCT_READER_DIRECT == dwControlCode)
Packit 9f0df5
	{
Packit 9f0df5
		if ( (TxBuffer[0] != 0x20)	/* CLA */
Packit 9f0df5
			|| ((TxBuffer[1] & 0xF0) != 0x70)	/* INS */
Packit 9f0df5
			/* valid INS are
Packit 9f0df5
			 * 0x70: SECODER INFO
Packit 9f0df5
			 * 0x71: SECODER SELECT APPLICATION
Packit 9f0df5
			 * 0x72: SECODER APPLICATION ACTIVE
Packit 9f0df5
			 * 0x73: SECODER DATA CONFIRMATION
Packit 9f0df5
			 * 0x74: SECODER PROCESS AUTHENTICATION TOKEN */
Packit 9f0df5
			|| ((TxBuffer[1] & 0x0F) > 4)
Packit 9f0df5
			|| (TxBuffer[2] != 0x00)	/* P1 */
Packit 9f0df5
			|| (TxBuffer[3] != 0x00)	/* P2 */
Packit 9f0df5
			|| (TxBuffer[4] != 0x00)	/* Lind */
Packit 9f0df5
		   )
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("MCT Command refused by driver");
Packit 9f0df5
			return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
		}
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			unsigned int iBytesReturned;
Packit 9f0df5
Packit 9f0df5
			/* we just transmit the buffer as a CCID Escape command */
Packit 9f0df5
			iBytesReturned = RxLength;
Packit 9f0df5
			return_value = CmdEscape(reader_index, TxBuffer, TxLength,
Packit 9f0df5
				RxBuffer, &iBytesReturned, 0);
Packit 9f0df5
			*pdwBytesReturned = iBytesReturned;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if (IFD_SUCCESS != return_value)
Packit 9f0df5
		*pdwBytesReturned = 0;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO_XXD("Control RxBuffer: ", RxBuffer, *pdwBytesReturned);
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* IFDHControl */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
EXTERNAL RESPONSECODE IFDHICCPresence(DWORD Lun)
Packit 9f0df5
{
Packit 9f0df5
	/*
Packit 9f0df5
	 * This function returns the status of the card inserted in the
Packit 9f0df5
	 * reader/slot specified by Lun.  It will return either:
Packit 9f0df5
	 *
Packit 9f0df5
	 * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
Packit 9f0df5
	 * IFD_COMMUNICATION_ERROR
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
Packit 9f0df5
	RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
	int oldLogLevel;
Packit 9f0df5
	int reader_index;
Packit 9f0df5
	_ccid_descriptor *ccid_descriptor;
Packit 9f0df5
	unsigned int oldReadTimeout;
Packit 9f0df5
Packit 9f0df5
	if (-1 == (reader_index = LunToReaderIndex(Lun)))
Packit 9f0df5
		return IFD_COMMUNICATION_ERROR;
Packit 9f0df5
Packit 9f0df5
	DEBUG_PERIODIC3("%s (lun: " DWORD_X ")", CcidSlots[reader_index].readerName, Lun);
Packit 9f0df5
Packit 9f0df5
	ccid_descriptor = get_ccid_descriptor(reader_index);
Packit 9f0df5
Packit 9f0df5
	if ((GEMCORESIMPRO == ccid_descriptor->readerID)
Packit 9f0df5
	     && (ccid_descriptor->IFD_bcdDevice < 0x0200))
Packit 9f0df5
	{
Packit 9f0df5
		/* GemCore SIM Pro firmware 2.00 and up features
Packit 9f0df5
		 * a full independant second slot */
Packit 9f0df5
		return_value = ccid_descriptor->dwSlotStatus;
Packit 9f0df5
		goto end;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* save the current read timeout computed from card capabilities */
Packit 9f0df5
	oldReadTimeout = ccid_descriptor->readTimeout;
Packit 9f0df5
Packit 9f0df5
	/* use default timeout since the reader may not be present anymore */
Packit 9f0df5
	ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT;
Packit 9f0df5
Packit 9f0df5
	/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
Packit 9f0df5
	oldLogLevel = LogLevel;
Packit 9f0df5
	if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
Packit 9f0df5
		LogLevel &= ~DEBUG_LEVEL_COMM;
Packit 9f0df5
Packit 9f0df5
	return_value = CmdGetSlotStatus(reader_index, pcbuffer);
Packit 9f0df5
Packit 9f0df5
	/* set back the old timeout */
Packit 9f0df5
	ccid_descriptor->readTimeout = oldReadTimeout;
Packit 9f0df5
Packit 9f0df5
	/* set back the old LogLevel */
Packit 9f0df5
	LogLevel = oldLogLevel;
Packit 9f0df5
Packit 9f0df5
	if (return_value != IFD_SUCCESS)
Packit 9f0df5
		return return_value;
Packit 9f0df5
Packit 9f0df5
	return_value = IFD_COMMUNICATION_ERROR;
Packit 9f0df5
	switch (pcbuffer[7] & CCID_ICC_STATUS_MASK)	/* bStatus */
Packit 9f0df5
	{
Packit 9f0df5
		case CCID_ICC_PRESENT_ACTIVE:
Packit 9f0df5
			return_value = IFD_ICC_PRESENT;
Packit 9f0df5
			/* use default slot */
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case CCID_ICC_PRESENT_INACTIVE:
Packit 9f0df5
			if ((CcidSlots[reader_index].bPowerFlags == POWERFLAGS_RAZ)
Packit 9f0df5
				|| (CcidSlots[reader_index].bPowerFlags & MASK_POWERFLAGS_PDWN))
Packit 9f0df5
				/* the card was previously absent */
Packit 9f0df5
				return_value = IFD_ICC_PRESENT;
Packit 9f0df5
			else
Packit 9f0df5
			{
Packit 9f0df5
				/* the card was previously present but has been
Packit 9f0df5
				 * removed and inserted between two consecutive
Packit 9f0df5
				 * IFDHICCPresence() calls */
Packit 9f0df5
				CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
Packit 9f0df5
				return_value = IFD_ICC_NOT_PRESENT;
Packit 9f0df5
			}
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case CCID_ICC_ABSENT:
Packit 9f0df5
			/* Reset ATR buffer */
Packit 9f0df5
			CcidSlots[reader_index].nATRLength = 0;
Packit 9f0df5
			*CcidSlots[reader_index].pcATRBuffer = '\0';
Packit 9f0df5
Packit 9f0df5
			/* Reset PowerFlags */
Packit 9f0df5
			CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
Packit 9f0df5
Packit 9f0df5
			return_value = IFD_ICC_NOT_PRESENT;
Packit 9f0df5
			break;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
#if 0
Packit 9f0df5
	/* SCR331-DI contactless reader */
Packit 9f0df5
	if (((SCR331DI == ccid_descriptor->readerID)
Packit 9f0df5
		|| (SDI010 == ccid_descriptor->readerID)
Packit 9f0df5
		|| (SCR331DINTTCOM == ccid_descriptor->readerID))
Packit 9f0df5
		&& (ccid_descriptor->bCurrentSlotIndex > 0))
Packit 9f0df5
	{
Packit 9f0df5
		unsigned char cmd[] = { 0x11 };
Packit 9f0df5
		/*  command: 11 ??
Packit 9f0df5
		 * response: 00 11 01 ?? no card
Packit 9f0df5
		 *           01 04 00 ?? card present */
Packit 9f0df5
Packit 9f0df5
		unsigned char res[10];
Packit 9f0df5
		unsigned int length_res = sizeof(res);
Packit 9f0df5
		RESPONSECODE ret;
Packit 9f0df5
Packit 9f0df5
		/* if DEBUG_LEVEL_PERIODIC is not set we remove DEBUG_LEVEL_COMM */
Packit 9f0df5
		oldLogLevel = LogLevel;
Packit 9f0df5
		if (! (LogLevel & DEBUG_LEVEL_PERIODIC))
Packit 9f0df5
			LogLevel &= ~DEBUG_LEVEL_COMM;
Packit 9f0df5
Packit 9f0df5
		ret = CmdEscape(reader_index, cmd, sizeof(cmd), res, &length_res, 0);
Packit 9f0df5
Packit 9f0df5
		/* set back the old LogLevel */
Packit 9f0df5
		LogLevel = oldLogLevel;
Packit 9f0df5
Packit 9f0df5
		if (ret != IFD_SUCCESS)
Packit 9f0df5
		{
Packit 9f0df5
			DEBUG_INFO1("CmdEscape failed");
Packit 9f0df5
			/* simulate a card absent */
Packit 9f0df5
			res[0] = 0;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		if (0x01 == res[0])
Packit 9f0df5
			return_value = IFD_ICC_PRESENT;
Packit 9f0df5
		else
Packit 9f0df5
		{
Packit 9f0df5
			/* Reset ATR buffer */
Packit 9f0df5
			CcidSlots[reader_index].nATRLength = 0;
Packit 9f0df5
			*CcidSlots[reader_index].pcATRBuffer = '\0';
Packit 9f0df5
Packit 9f0df5
			/* Reset PowerFlags */
Packit 9f0df5
			CcidSlots[reader_index].bPowerFlags = POWERFLAGS_RAZ;
Packit 9f0df5
Packit 9f0df5
			return_value = IFD_ICC_NOT_PRESENT;
Packit 9f0df5
		}
Packit 9f0df5
	}
Packit 9f0df5
#endif
Packit 9f0df5
Packit 9f0df5
end:
Packit 9f0df5
	DEBUG_PERIODIC2("Card %s",
Packit 9f0df5
		IFD_ICC_PRESENT == return_value ? "present" : "absent");
Packit 9f0df5
Packit 9f0df5
	return return_value;
Packit 9f0df5
} /* IFDHICCPresence */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
CcidDesc *get_ccid_slot(unsigned int reader_index)
Packit 9f0df5
{
Packit 9f0df5
	return &CcidSlots[reader_index];
Packit 9f0df5
} /* get_ccid_slot */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
void init_driver(void)
Packit 9f0df5
{
Packit 9f0df5
	char infofile[FILENAME_MAX];
Packit 9f0df5
	char *e;
Packit 9f0df5
	int rv;
Packit 9f0df5
	list_t plist, *values;
Packit 9f0df5
Packit 9f0df5
	DEBUG_INFO1("Driver version: " VERSION);
Packit 9f0df5
Packit 9f0df5
	/* Info.plist full patch filename */
Packit 9f0df5
	(void)snprintf(infofile, sizeof(infofile), "%s/%s/Contents/Info.plist",
Packit 9f0df5
		PCSCLITE_HP_DROPDIR, BUNDLE);
Packit 9f0df5
Packit 9f0df5
	rv = bundleParse(infofile, &plist);
Packit 9f0df5
	if (0 == rv)
Packit 9f0df5
	{
Packit 9f0df5
		/* Log level */
Packit 9f0df5
		rv = LTPBundleFindValueWithKey(&plist, "ifdLogLevel", &values);
Packit 9f0df5
		if (0 == rv)
Packit 9f0df5
		{
Packit 9f0df5
			/* convert from hex or dec or octal */
Packit 9f0df5
			LogLevel = strtoul(list_get_at(values, 0), NULL, 0);
Packit 9f0df5
Packit 9f0df5
			/* print the log level used */
Packit 9f0df5
			DEBUG_INFO2("LogLevel: 0x%.4X", LogLevel);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* Driver options */
Packit 9f0df5
		rv = LTPBundleFindValueWithKey(&plist, "ifdDriverOptions", &values);
Packit 9f0df5
		if (0 == rv)
Packit 9f0df5
		{
Packit 9f0df5
			/* convert from hex or dec or octal */
Packit 9f0df5
			DriverOptions = strtoul(list_get_at(values, 0), NULL, 0);
Packit 9f0df5
Packit 9f0df5
			/* print the log level used */
Packit 9f0df5
			DEBUG_INFO2("DriverOptions: 0x%.4X", DriverOptions);
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		bundleRelease(&plist);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	e = getenv("LIBCCID_ifdLogLevel");
Packit 9f0df5
	if (e)
Packit 9f0df5
	{
Packit 9f0df5
		/* convert from hex or dec or octal */
Packit 9f0df5
		LogLevel = strtoul(e, NULL, 0);
Packit 9f0df5
Packit 9f0df5
		/* print the log level used */
Packit 9f0df5
		DEBUG_INFO2("LogLevel from LIBCCID_ifdLogLevel: 0x%.4X", LogLevel);
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* get the voltage parameter */
Packit 9f0df5
	switch ((DriverOptions >> 4) & 0x03)
Packit 9f0df5
	{
Packit 9f0df5
		case 0:
Packit 9f0df5
			PowerOnVoltage = VOLTAGE_5V;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 1:
Packit 9f0df5
			PowerOnVoltage = VOLTAGE_3V;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 2:
Packit 9f0df5
			PowerOnVoltage = VOLTAGE_1_8V;
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		case 3:
Packit 9f0df5
			PowerOnVoltage = VOLTAGE_AUTO;
Packit 9f0df5
			break;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	/* initialise the Lun to reader_index mapping */
Packit 9f0df5
	InitReaderIndex();
Packit 9f0df5
Packit 9f0df5
	DebugInitialized = TRUE;
Packit 9f0df5
} /* init_driver */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
static char find_baud_rate(unsigned int baudrate, unsigned int *list)
Packit 9f0df5
{
Packit 9f0df5
	int i;
Packit 9f0df5
Packit 9f0df5
	DEBUG_COMM2("Card baud rate: %d", baudrate);
Packit 9f0df5
Packit 9f0df5
	/* Does the reader support the announced smart card data speed? */
Packit 9f0df5
	for (i=0;; i++)
Packit 9f0df5
	{
Packit 9f0df5
		/* end of array marker */
Packit 9f0df5
		if (0 == list[i])
Packit 9f0df5
			break;
Packit 9f0df5
Packit 9f0df5
		DEBUG_COMM2("Reader can do: %d", list[i]);
Packit 9f0df5
Packit 9f0df5
		/* We must take into account that the card_baudrate integral value
Packit 9f0df5
		 * is an approximative result, computed from the d/f float result.
Packit 9f0df5
		 */
Packit 9f0df5
		if ((baudrate < list[i] + 2) && (baudrate > list[i] - 2))
Packit 9f0df5
			return TRUE;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return FALSE;
Packit 9f0df5
} /* find_baud_rate */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
static unsigned int T0_card_timeout(double f, double d, int TC1, int TC2,
Packit 9f0df5
	int clock_frequency)
Packit 9f0df5
{
Packit 9f0df5
	unsigned int timeout = DEFAULT_COM_READ_TIMEOUT;
Packit 9f0df5
	double EGT, WWT;
Packit 9f0df5
	unsigned int t;
Packit 9f0df5
Packit 9f0df5
	/* Timeout applied on ISO_IN or ISO_OUT card exchange
Packit 9f0df5
	 * we choose the maximum computed value.
Packit 9f0df5
	 *
Packit 9f0df5
	 * ISO_IN timeout is the sum of:
Packit 9f0df5
	 * Terminal:					Smart card:
Packit 9f0df5
	 * 5 bytes header cmd  ->
Packit 9f0df5
	 *                    <-		Procedure byte
Packit 9f0df5
	 * 256 data bytes	   ->
Packit 9f0df5
	 *					  <-		SW1-SW2
Packit 9f0df5
	 * = 261 EGT       + 3 WWT     + 3 WWT
Packit 9f0df5
	 *
Packit 9f0df5
	 * ISO_OUT Timeout is the sum of:
Packit 9f0df5
	 * Terminal:                    Smart card:
Packit 9f0df5
	 * 5 bytes header cmd  ->
Packit 9f0df5
	 *					  <-        Procedure byte + 256 data bytes + SW1-SW2
Packit 9f0df5
	 * = 5 EGT          + 1 WWT     + 259 WWT
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	/* clock_frequency is in kHz so the times are in milliseconds and not
Packit 9f0df5
	 * in seconds */
Packit 9f0df5
Packit 9f0df5
	/* may happen with non ISO cards */
Packit 9f0df5
	if ((0 == f) || (0 == d) || (0 == clock_frequency))
Packit 9f0df5
		return 60 * 1000;	/* 60 seconds */
Packit 9f0df5
Packit 9f0df5
	/* EGT */
Packit 9f0df5
	/* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
Packit 9f0df5
	EGT = 12 * f / d / clock_frequency + (f / d) * TC1 / clock_frequency;
Packit 9f0df5
Packit 9f0df5
	/* card WWT */
Packit 9f0df5
	/* see ch. 8.2 Character level, page 15 of ISO 7816-3 */
Packit 9f0df5
	WWT = 960 * TC2 * f / clock_frequency;
Packit 9f0df5
Packit 9f0df5
	/* ISO in */
Packit 9f0df5
	t  = 261 * EGT + (3 + 3) * WWT;
Packit 9f0df5
	if (timeout < t)
Packit 9f0df5
		timeout = t;
Packit 9f0df5
Packit 9f0df5
	/* ISO out */
Packit 9f0df5
	t = 5 * EGT + (1 + 259) * WWT;
Packit 9f0df5
	if (timeout < t)
Packit 9f0df5
		timeout = t;
Packit 9f0df5
Packit 9f0df5
	return timeout;
Packit 9f0df5
} /* T0_card_timeout  */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
static unsigned int T1_card_timeout(double f, double d, int TC1,
Packit 9f0df5
	int BWI, int CWI, int clock_frequency)
Packit 9f0df5
{
Packit 9f0df5
	double EGT, BWT, CWT, etu;
Packit 9f0df5
	unsigned int timeout;
Packit 9f0df5
Packit 9f0df5
	/* Timeout applied on ISO in + ISO out card exchange
Packit 9f0df5
	 *
Packit 9f0df5
     * Timeout is the sum of:
Packit 9f0df5
	 * - ISO in delay between leading edge of the first character sent by the
Packit 9f0df5
	 *   interface device and the last one (NAD PCB LN APDU CKS) = 260 EGT,
Packit 9f0df5
	 * - delay between ISO in and ISO out = BWT,
Packit 9f0df5
	 * - ISO out delay between leading edge of the first character sent by the
Packit 9f0df5
	 *   card and the last one (NAD PCB LN DATAS CKS) = 260 CWT.
Packit 9f0df5
	 */
Packit 9f0df5
Packit 9f0df5
	/* clock_frequency is in kHz so the times are in milliseconds and not
Packit 9f0df5
	 * in seconds */
Packit 9f0df5
Packit 9f0df5
	/* may happen with non ISO cards */
Packit 9f0df5
	if ((0 == f) || (0 == d) || (0 == clock_frequency))
Packit 9f0df5
		return 60 * 1000;	/* 60 seconds */
Packit 9f0df5
Packit 9f0df5
	/* see ch. 6.5.2 Transmission factors F and D, page 12 of ISO 7816-3 */
Packit 9f0df5
	etu = f / d / clock_frequency;
Packit 9f0df5
Packit 9f0df5
	/* EGT */
Packit 9f0df5
	/* see ch. 6.5.3 Extra Guard Time, page 12 of ISO 7816-3 */
Packit 9f0df5
	EGT = 12 * etu + (f / d) * TC1 / clock_frequency;
Packit 9f0df5
Packit 9f0df5
	/* card BWT */
Packit 9f0df5
	/* see ch. 9.5.3.2 Block Waiting Time, page 20 of ISO 7816-3 */
Packit 9f0df5
	BWT = 11 * etu + (1<
Packit 9f0df5
Packit 9f0df5
	/* card CWT */
Packit 9f0df5
	/* see ch. 9.5.3.1 Caracter Waiting Time, page 20 of ISO 7816-3 */
Packit 9f0df5
	CWT = (11 + (1<
Packit 9f0df5
Packit 9f0df5
	timeout = 260*EGT + BWT + 260*CWT;
Packit 9f0df5
Packit 9f0df5
	/* This is the card/reader timeout.  Add 1 second for the libusb
Packit 9f0df5
	 * timeout so we get the error from the reader. */
Packit 9f0df5
	timeout += 1000;
Packit 9f0df5
Packit 9f0df5
	return timeout;
Packit 9f0df5
} /* T1_card_timeout  */
Packit 9f0df5
Packit 9f0df5
Packit 9f0df5
static int get_IFSC(ATR_t *atr, int *idx)
Packit 9f0df5
{
Packit 9f0df5
	int i, ifsc, protocol = -1;
Packit 9f0df5
Packit 9f0df5
	/* default return values */
Packit 9f0df5
	ifsc = -1;
Packit 9f0df5
	*idx = -1;
Packit 9f0df5
Packit 9f0df5
	for (i=0; i
Packit 9f0df5
	{
Packit 9f0df5
		/* TAi (i>2) present and protocol=1 => IFSC */
Packit 9f0df5
		if (i >= 2 && protocol == 1
Packit 9f0df5
			&& atr->ib[i][ATR_INTERFACE_BYTE_TA].present)
Packit 9f0df5
		{
Packit 9f0df5
			ifsc = atr->ib[i][ATR_INTERFACE_BYTE_TA].value;
Packit 9f0df5
			*idx = i+1;
Packit 9f0df5
			/* only the first TAi (i>2) must be used */
Packit 9f0df5
			break;
Packit 9f0df5
		}
Packit 9f0df5
Packit 9f0df5
		/* protocol T=? */
Packit 9f0df5
		if (atr->ib[i][ATR_INTERFACE_BYTE_TD].present)
Packit 9f0df5
			protocol = atr->ib[i][ATR_INTERFACE_BYTE_TD].value & 0x0F;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	if (ifsc > 254)
Packit 9f0df5
	{
Packit 9f0df5
		/* 0xFF is not a valid value for IFSC */
Packit 9f0df5
		DEBUG_INFO2("Non ISO IFSC: 0x%X", ifsc);
Packit 9f0df5
		ifsc = 254;
Packit 9f0df5
	}
Packit 9f0df5
Packit 9f0df5
	return ifsc;
Packit 9f0df5
} /* get_IFSC */
Packit 9f0df5