/*
pps.c
Protocol Parameters Selection
This file is part of the Unix driver for Towitoko smartcard readers
Copyright (C) 2000 2001 Carlos Prados <cprados@yahoo.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "pps.h"
#include "atr.h"
#include "protocol_t0.h"
#include "protocol_t1.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
* Not exported constants definition
*/
#define PPS_DEFAULT_PROTOCOL 0x00
/*
* Not exported macros definition
*/
#define PPS_HAS_PPS1(block) ((block[1] & 0x10) == 0x10)
#define PPS_HAS_PPS2(block) ((block[1] & 0x20) == 0x20)
#define PPS_HAS_PPS3(block) ((block[1] & 0x40) == 0x40)
/*
* Not exported funtions declaration
*/
static int PPS_Exchange (PPS * pps, BYTE * params, unsigned *length);
static bool PPS_Match (BYTE * request, unsigned len_request, BYTE * reply, unsigned len_reply);
static unsigned PPS_GetLength (BYTE * block);
static int PPS_InitICC (PPS * pps);
static int PPS_InitProtocol (PPS * pps);
static void PPS_SelectFirstProtocol (PPS * pps);
static BYTE PPS_GetPCK (BYTE * block, unsigned length);
/*
* Exported functions definition
*/
PPS *
PPS_New (ICC_Async * icc)
{
PPS *pps;
pps = (PPS *) malloc (sizeof (PPS));
if (pps != NULL)
{
pps->icc = icc;
pps->protocol = NULL;
pps->parameters.t = PPS_DEFAULT_PROTOCOL;
pps->parameters.f = ATR_DEFAULT_F;
pps->parameters.d = ATR_DEFAULT_D;
pps->parameters.n = ATR_DEFAULT_N;
}
return pps;
}
int
PPS_Perform (PPS * pps, BYTE * params, unsigned *length)
{
ATR *atr;
int ret;
/* Perform PPS Exchange if requested */
if ((*length) > 0)
{
ret = PPS_Exchange (pps, params, length);
/* Get parameters from PPS handsake */
if (ret == PPS_OK)
{
pps->parameters.t = params[1] & 0x0F;
if (PPS_HAS_PPS1 (params))
{
pps->parameters.f = atr_f_table[(params[2] >> 4)];
pps->parameters.d = atr_d_table[(params[2] & 0x0F)];
}
ret = PPS_InitICC(pps);
if (ret != PPS_OK)
return ret;
}
else
return ret;
}
/* Get parameters from ATR */
else
{
PPS_SelectFirstProtocol (pps);
#ifndef PPS_USE_DEFAULT_TIMINGS
atr = ICC_Async_GetAtr (pps->icc);
ATR_GetParameter (atr, ATR_PARAMETER_N, &(pps->parameters.n));
ATR_GetParameter (atr, ATR_PARAMETER_D, &(pps->parameters.d));
ATR_GetParameter (atr, ATR_PARAMETER_F, &(pps->parameters.f));
#endif
}
#ifdef DEBUG_PROTOCOL
printf("PPS: T=%X, F=%.0f, D=%.6f, N=%.0f\n",
pps->parameters.t,
pps->parameters.f,
pps->parameters.d,
pps->parameters.n);
#endif
/* Initialize selected protocol with selected parameters */
ret = PPS_InitProtocol (pps);
return ret;
}
void *
PPS_GetProtocol (PPS * pps)
{
return pps->protocol;
}
PPS_ProtocolParameters *PPS_GetProtocolParameters (PPS * pps)
{
/* User must Remember not to reference this struct after removing PPS */
return &(pps->parameters);
}
void
PPS_Delete (PPS * pps)
{
free (pps);
}
/*
* Not exported funtions definition
*/
static int
PPS_Exchange (PPS * pps, BYTE * params, unsigned *length)
{
BYTE confirm[PPS_MAX_LENGTH];
unsigned len_request, len_confirm;
int ret;
#ifdef DEBUG_PROTOCOL
int i;
#endif
len_request = PPS_GetLength (params);
params[len_request - 1] = PPS_GetPCK(params, len_request - 1);
#ifdef DEBUG_PROTOCOL
printf ("PPS: Sending request: ");
for (i = 0; i < len_request; i++)
printf ("%X ", params[i]);
printf ("\n");
#endif
/* Send PPS request */
if (ICC_Async_Transmit (pps->icc, len_request, params) != ICC_ASYNC_OK)
return PPS_ICC_ERROR;
/* Get PPS confirm */
if (ICC_Async_Receive (pps->icc, 2, confirm) != ICC_ASYNC_OK)
return PPS_ICC_ERROR;
len_confirm = PPS_GetLength (confirm);
if (ICC_Async_Receive (pps->icc, len_confirm - 2, confirm + 2) !=
ICC_ASYNC_OK)
return PPS_ICC_ERROR;
#ifdef DEBUG_PROTOCOL
printf ("PPS: Receivig confirm: ");
for (i = 0; i < len_confirm; i++)
printf ("%X ", confirm[i]);
printf ("\n");
#endif
if (!PPS_Match (params, len_request, confirm, len_confirm))
ret = PPS_HANDSAKE_ERROR;
else
ret = PPS_OK;
/* Copy PPS handsake */
memcpy (params, confirm, len_confirm);
(*length) = len_confirm;
return ret;
}
static bool
PPS_Match (BYTE * request, unsigned len_request, BYTE * confirm, unsigned len_confirm)
{
/* See if the reply differs from request */
if ((len_request != len_confirm) ||
(!memcmp (request, confirm, len_request)))
{
/* See if the card specifies other than default FI and D */
if ((PPS_HAS_PPS1 (confirm)) && (confirm[2] != request[2]))
return FALSE;
}
return TRUE;
}
static unsigned
PPS_GetLength (BYTE * block)
{
unsigned length = 3;
if (PPS_HAS_PPS1 (block))
length++;
if (PPS_HAS_PPS2 (block))
length++;
if (PPS_HAS_PPS3 (block))
length++;
return length;
}
static int
PPS_InitICC (PPS * pps)
{
unsigned long baudrate;
long double work_etu;
/* Work etu = (1/D) * (F/fs) * 1000 milliseconds */
work_etu = (1000 * pps->parameters.f) / (pps->parameters.d * ICC_Async_GetClockRate (pps->icc));
/* Baudrate = 1000 / etu bps */
baudrate = (long unsigned int) (1000 / work_etu);
#ifdef DEBUG_PROTOCOL
printf ("PPS: Baudrate = %d\n", baudrate);
#endif
if (ICC_Async_SetBaudrate (pps->icc, baudrate) != ICC_ASYNC_OK)
return PPS_ICC_ERROR;
return PPS_OK;
}
static int
PPS_InitProtocol (PPS * pps)
{
int ret;
if (pps->parameters.t == ATR_PROTOCOL_TYPE_T0)
{
pps->protocol = Protocol_T0_New ();
if ((pps->protocol) != NULL)
{
ret = Protocol_T0_Init ((Protocol_T0 *) pps->protocol, (ICC_Async *) pps->icc, &(pps->parameters));
if (ret != PROTOCOL_T0_OK)
{
Protocol_T0_Delete ((Protocol_T0 *) pps->protocol);
pps->protocol = NULL;
return PPS_PROTOCOL_ERROR;
}
return PPS_OK;
}
}
else if (pps->parameters.t == ATR_PROTOCOL_TYPE_T1)
{
pps->protocol = Protocol_T1_New ();
if (pps->protocol != NULL)
{
ret = Protocol_T1_Init ((Protocol_T1 *) pps->protocol, (ICC_Async *) pps->icc, &(pps->parameters));
if (ret != PROTOCOL_T1_OK)
{
Protocol_T1_Delete ((Protocol_T1 *) pps->protocol);
pps->protocol = NULL;
return PPS_PROTOCOL_ERROR;
}
return PPS_OK;
}
}
else
pps->protocol = NULL;
return PPS_PROTOCOL_ERROR;
}
static void
PPS_SelectFirstProtocol (PPS * pps)
{
ATR *atr = ICC_Async_GetAtr (pps->icc);
unsigned np;
pps->parameters.t = ATR_PROTOCOL_TYPE_T0;
ATR_GetNumberOfProtocols (atr, &np);
/*
* Get protocol offered by interface bytes T*2 if available,
* (that is, if TD1 is available), * otherwise use default T=0
*/
if (np>1)
ATR_GetProtocolType (atr, 2, &(pps->parameters.t));
#ifdef DEBUG_PROTOCOL
printf ("PPS: Protocol T=%d selected\n", pps->parameters.t);
#endif
}
static BYTE
PPS_GetPCK (BYTE * block, unsigned length)
{
BYTE pck;
unsigned i;
pck = block[0];
for (i = 1; i < length; i++)
pck ^= block[i];
return pck;
}
syntax highlighted by Code2HTML, v. 0.9.1