331 lines
9.7 KiB
C
Executable File
331 lines
9.7 KiB
C
Executable File
#include "../globals.h"
|
|
#include "../oscam-time.h"
|
|
#ifdef WITH_CARDREADER
|
|
#include "icc_async.h"
|
|
|
|
#define OK 0
|
|
#define ERROR 1
|
|
|
|
/* Buffer sizes */
|
|
#define T1_BLOCK_MAX_SIZE 259
|
|
|
|
/* Types of block */
|
|
#define T1_BLOCK_I 0x00
|
|
#define T1_BLOCK_R_OK 0x80
|
|
#define T1_BLOCK_R_EDC_ERR 0x81
|
|
#define T1_BLOCK_R_OTHER_ERR 0x82
|
|
#define T1_BLOCK_S_RESYNCH_REQ 0xC0
|
|
#define T1_BLOCK_S_RESYNCH_RES 0xE0
|
|
#define T1_BLOCK_S_IFS_REQ 0xC1
|
|
#define T1_BLOCK_S_IFS_RES 0xE1
|
|
#define T1_BLOCK_S_ABORT_REQ 0xC2
|
|
#define T1_BLOCK_S_ABORT_RES 0xE2
|
|
#define T1_BLOCK_S_WTX_REQ 0xC3
|
|
#define T1_BLOCK_S_WTX_RES 0xE3
|
|
#define T1_BLOCK_S_VPP_ERR 0xE4
|
|
|
|
#define T1_BLOCK_NAD 0x00
|
|
|
|
#define T1_Block_GetNS(a) ((a[1] >> 6) & 0x01)
|
|
#define T1_Block_GetMore(a) ((a[1] >> 5) & 0x01)
|
|
#define T1_Block_GetNR(a) ((a[1] >> 4) & 0x01)
|
|
#define T1_Block_GetLen(a) a[2]
|
|
|
|
|
|
static unsigned char T1_Block_LRC(unsigned char *data, uint32_t length)
|
|
{
|
|
unsigned char lrc = 0x00;
|
|
uint32_t i;
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
lrc ^= data[i];
|
|
}
|
|
return lrc;
|
|
}
|
|
|
|
static int32_t T1_Block_SendIBlock(struct s_reader *reader, uint8_t *block_data, unsigned char len, unsigned char *inf, unsigned char ns, int32_t more, uint32_t timeout)
|
|
{
|
|
int length = len + 4;
|
|
|
|
block_data[0] = T1_BLOCK_NAD;
|
|
block_data[1] = T1_BLOCK_I | ((ns << 6) & 0x40);
|
|
if(more)
|
|
{
|
|
block_data[1] |= 0x20;
|
|
}
|
|
block_data[2] = len;
|
|
if(len != 0x00)
|
|
{
|
|
memcpy(block_data + 3, inf, len);
|
|
}
|
|
block_data[len + 3] = T1_Block_LRC(block_data, len + 3);
|
|
|
|
return ICC_Async_Transmit(reader, length, 0, block_data, 0, timeout);
|
|
}
|
|
|
|
static int32_t T1_Block_SendRBlock(struct s_reader *reader, uint8_t *block_data, unsigned char type, unsigned char nr, uint32_t timeout)
|
|
{
|
|
int length = 4;
|
|
|
|
block_data[0] = T1_BLOCK_NAD;
|
|
block_data[1] = type | ((nr << 4) & 0x10);
|
|
block_data[2] = 0x00;
|
|
block_data[3] = T1_Block_LRC(block_data, 3);
|
|
|
|
return ICC_Async_Transmit(reader, length, 0, block_data, 0, timeout);
|
|
}
|
|
|
|
static int32_t T1_Block_SendSBlock(struct s_reader *reader, uint8_t *block_data, unsigned char type, unsigned char len, unsigned char *inf, uint32_t timeout)
|
|
{
|
|
int length = 4 + len;
|
|
|
|
block_data[0] = T1_BLOCK_NAD;
|
|
block_data[1] = type;
|
|
block_data[2] = len;
|
|
if(len != 0x00)
|
|
{
|
|
memcpy(block_data + 3, inf, len);
|
|
}
|
|
|
|
block_data[len + 3] = T1_Block_LRC(block_data, len + 3);
|
|
|
|
return ICC_Async_Transmit(reader, length, 0, block_data, 0, timeout);
|
|
}
|
|
|
|
static int32_t Protocol_T1_ReceiveBlock(struct s_reader *reader, uint8_t *block_data, uint32_t *block_length, uint8_t *rsp_type, uint32_t timeout)
|
|
{
|
|
int32_t ret, length;
|
|
|
|
/* Receive four mandatory bytes */
|
|
if(ICC_Async_Receive(reader, 4, block_data, 0, timeout))
|
|
{
|
|
ret = ERROR;
|
|
}
|
|
else
|
|
{
|
|
length = block_data[2];
|
|
if(length != 0x00)
|
|
{
|
|
*block_length = (length + 4 > T1_BLOCK_MAX_SIZE) ? T1_BLOCK_MAX_SIZE : length + 4;
|
|
|
|
/* Receive remaining bytes */
|
|
if(ICC_Async_Receive(reader, *block_length - 4, block_data + 4, 0, timeout))
|
|
{
|
|
ret = ERROR;
|
|
}
|
|
else
|
|
{
|
|
ret = OK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ret = OK;
|
|
*block_length = 4;
|
|
}
|
|
}
|
|
*rsp_type = ((block_data[1] & 0x80) == T1_BLOCK_I) ? T1_BLOCK_I : (block_data[1] & 0xEF);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t Protocol_T1_Command(struct s_reader *reader, unsigned char *command, uint16_t command_len, unsigned char *rsp, uint16_t *lr)
|
|
{
|
|
uint8_t block_data[T1_BLOCK_MAX_SIZE];
|
|
uint8_t rsp_type, bytes, nr, wtx;
|
|
uint16_t counter;
|
|
int32_t ret, timeout;
|
|
bool more;
|
|
uint32_t block_length = 0;
|
|
if(command[1] == T1_BLOCK_S_IFS_REQ)
|
|
{
|
|
uint8_t inf = command[3];
|
|
|
|
/* Create an IFS request S-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendSBlock(reader, block_data, T1_BLOCK_S_IFS_REQ, 1, &inf, timeout);
|
|
if(ret == ERROR)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Sending block S(IFS request, %d)", inf);
|
|
}
|
|
|
|
/* Receive a block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->BWT); // we are going to receive so set Block Waiting Timeout!
|
|
//cs_sleepus(reader->block_delay); // we were sending, now receiving so wait BGT time
|
|
ret = Protocol_T1_ReceiveBlock(reader, block_data, &block_length, &rsp_type, timeout);
|
|
|
|
if(ret == OK)
|
|
{
|
|
/* Positive IFS Response S-Block received */
|
|
if(rsp_type == T1_BLOCK_S_IFS_RES)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Received block S(IFS response, %d)", block_data[3]);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
else if(command[1] == T1_BLOCK_S_RESYNCH_REQ)
|
|
{
|
|
/* Create an Resynch request S-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendSBlock(reader, block_data, T1_BLOCK_S_RESYNCH_REQ, 0, NULL, timeout);
|
|
if(ret == ERROR)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Sending block S(RESYNCH request)");
|
|
}
|
|
|
|
/* Receive a block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->BWT); // we are going to receive so set Block Waiting Timeout!
|
|
//cs_sleepus(reader->block_delay); // we were sending, now receiving so wait BGT time
|
|
ret = Protocol_T1_ReceiveBlock(reader, block_data, &block_length, &rsp_type, timeout);
|
|
|
|
if(ret == OK)
|
|
{
|
|
/* Positive IFS Response S-Block received */
|
|
if(rsp_type == T1_BLOCK_S_RESYNCH_RES)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Received block S(RESYNCH response)");
|
|
reader->ns = 0;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Calculate the number of bytes to send */
|
|
counter = 0;
|
|
bytes = MIN(command_len, reader->ifsc);
|
|
|
|
/* See if chaining is needed */
|
|
more = (command_len > reader->ifsc);
|
|
|
|
/* Increment ns */
|
|
reader->ns = (reader->ns == 1) ? 0 : 1; //toggle from 0 to 1 and back
|
|
|
|
/* Create an I-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendIBlock(reader, block_data, bytes, command, reader->ns, more, timeout);
|
|
rdr_log_dbg(reader, D_IFD, "Sending block I(%d,%d)", reader->ns, more);
|
|
|
|
while((ret == OK) && more)
|
|
{
|
|
/* Receive a block */
|
|
|
|
timeout = ICC_Async_GetTimings(reader, reader->BWT); // we are going to receive so set Block Waiting Timeout!
|
|
//cs_sleepus(reader->block_delay); // we were sending, now receiving so wait BGT time
|
|
ret = Protocol_T1_ReceiveBlock(reader, block_data, &block_length, &rsp_type, timeout);
|
|
|
|
if(ret == OK)
|
|
{
|
|
/* Positive ACK R-Block received */
|
|
if(rsp_type == T1_BLOCK_R_OK)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Received block R(%d)", T1_Block_GetNR(block_data));
|
|
|
|
/* Increment ns */
|
|
reader->ns = (reader->ns == 1) ? 0 : 1; //toggle from 0 to 1 and back
|
|
|
|
/* Calculate the number of bytes to send */
|
|
counter += bytes;
|
|
bytes = MIN(command_len - counter, reader->ifsc);
|
|
|
|
/* See if chaining is needed */
|
|
more = (command_len - counter > reader->ifsc);
|
|
|
|
/* Send an I-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendIBlock(reader, block_data, bytes, command + counter, reader->ns, more, timeout);
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Sending block I(%d,%d)", reader->ns, more);
|
|
|
|
}
|
|
else
|
|
{
|
|
rdr_log_dbg(reader, D_TRACE, "ERROR: T1 Command %02X not implemented", rsp_type);
|
|
return ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rdr_log_dbg(reader, D_TRACE, "ERROR: T1 Command returned error");
|
|
return ERROR;
|
|
}
|
|
}
|
|
|
|
/* Reset counter */
|
|
counter = 0;
|
|
more = 1;
|
|
wtx = 1;
|
|
|
|
while((ret == OK) && more)
|
|
{
|
|
|
|
/* Receive a block */
|
|
timeout = ICC_Async_GetTimings(reader, wtx * reader->BWT); // we are going to receive so set Block Waiting Timeout!
|
|
//cs_sleepus(reader->block_delay); // we were sending, now receiving so wait BGT time
|
|
ret = Protocol_T1_ReceiveBlock(reader, block_data, &block_length, &rsp_type, timeout);
|
|
wtx = 1; // reset WTX value since its only valid for first received I block
|
|
|
|
if(ret == OK)
|
|
{
|
|
if(rsp_type == T1_BLOCK_I)
|
|
{
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Received block I(%d,%d)", T1_Block_GetNS(block_data), T1_Block_GetMore(block_data));
|
|
|
|
bytes = T1_Block_GetLen(block_data);
|
|
|
|
/* Calculate nr */
|
|
nr = (T1_Block_GetNS(block_data) + 1) % 2;
|
|
|
|
if(counter + bytes > T1_BLOCK_MAX_SIZE)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
memcpy(rsp + counter, block_data + 3, bytes);
|
|
counter += bytes;
|
|
|
|
/* See if chaining is requested */
|
|
more = T1_Block_GetMore(block_data);
|
|
|
|
if(more)
|
|
{
|
|
/* Send R-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendRBlock(reader, block_data, T1_BLOCK_R_OK, nr, timeout);
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Sending block R(%d)", nr);
|
|
}
|
|
}
|
|
else if(rsp_type == T1_BLOCK_S_WTX_REQ) /* WTX Request S-Block received */
|
|
{
|
|
/* Get wtx multiplier */
|
|
wtx = block_data[3];
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Received block S(WTX request, %d)", wtx);
|
|
|
|
/* Send an WTX response S-Block */
|
|
timeout = ICC_Async_GetTimings(reader, reader->CWT); // we are going to send: CWT timeout
|
|
//cs_sleepus(reader->block_delay); // we were receiving, now sending so wait BGT time
|
|
ret = T1_Block_SendSBlock(reader, block_data, T1_BLOCK_S_WTX_RES, 1, &wtx, timeout);
|
|
rdr_log_dbg(reader, D_IFD, "Protocol: Sending block S(WTX response, %d)", wtx);
|
|
}
|
|
else
|
|
{
|
|
rdr_log_dbg(reader, D_TRACE, "ERROR: T1 Command %02X not implemented in Receive Block", rsp_type);
|
|
ret = ERROR; //not implemented
|
|
}
|
|
}
|
|
}
|
|
|
|
if(ret == OK)
|
|
{
|
|
*lr = counter;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|