/* * gbpserial.c: communicate with a GemPC410 smart card reader * using GemCore protocol * Copyright (C) 2001,2002 Ludovic Rousseau * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * $Id: gbpserial.c,v 1.36 2004/07/03 21:11:42 rousseau Exp $ */ #include #include #include #include #include #include #include #include #include "gempc_ifdhandler.h" #include "GemCore.h" #include "gbpserial.h" #include "Config.h" #include "GCdebug.h" #include "GCCmds.h" #include "GCUtils.h" /* * GBP (Gemplus Bloc Protocol) format * * +-----+-----+-----+---------+-----+ * | NAD | PCB | LEN | DAT ... | EDC | * +-----+-----+-----+---------+-----+ * * NAD: source and destination indentifier * PCB: block type * I-Block (Information) * bit 7 6 5 4-0 * +---+---+---+--------+ * | 0 | S | 0 | unused | * +---+---+---+--------+ * S = Sequence bit * * R-Block (Repeat) * bit 7 6 5 4 3 2 1 0 * +---+---+---+---+---+---+---+---+ * | 1 | 0 | 0 | S | 0 | 0 | E | V | * +---+---+---+---+---+---+---+---+ * V = Error verified by EDC * E = Another error * * S-Block (Synchro) * bit 7 6 5 4 3 2 1 0 * +---+---+---+---+---+---+---+---+ * | 1 | 1 | R | 0 | 0 | 0 | 0 | 0 | * +---+---+---+---+---+---+---+---+ * R = Resync * 0 = request * 1 = response * * LEN: number of bytes in DAT * DAT: data transmitted * EDC: xor on NAD, PCB, LEN and DAT bytes * */ /* indexes in GbpBuffer[] */ #define NAD 0 #define PCB 1 #define LEN 2 #define DAT 3 /* NAD values */ #define NAD_HOST2IFD 0x42 #define NAD_IFD2HOST 0x24 #define NAD_XXX2HOST 0x04 /* communication timeout in seconds */ #define SERIAL_TIMEOUT 60 /* * Global variables containing the file handle of the serial port */ typedef struct { char *device; int fd; signed char bSeq; } intrFace; #if (PCSCLITE_MAX_READERS-16) #error Edit this file and set the number of initialiser to PCSCLITE_MAX_READERS (default was 16 but it has changed) #endif static intrFace gbpDevice[PCSCLITE_MAX_READERS] = { [ 0 ... (PCSCLITE_MAX_READERS-1) ] = {NULL, -1, -1} }; /* complete buffer + 3 bytes used by GBP */ static UCHAR GbpBuffer[PCSCLITE_MAX_READERS][CMD_BUF_SIZE + 3]; int ExplainGBP(const unsigned char buffer[], const int rv); #define SetSerialSpeed(speed, bspeed, step) \ /* set OS speed to speed bauds */ \ cfsetspeed(¤t_termios, bspeed); \ \ DEBUG_INFO("Set serial port baudrate to " speed " (" step ")"); \ if (tcsetattr(gbpDevice[reader].fd, TCSANOW, ¤t_termios) == -1) \ { \ close(gbpDevice[reader].fd); \ gbpDevice[reader].fd = -1; \ DEBUG_INFO2("tcsetattr error: %s", strerror(errno)); \ \ return STATUS_UNSUCCESSFUL; \ } \ \ /* empty in and out serial buffers */ \ DEBUG_INFO("Flush serial buffers (" step ")"); \ if (tcflush(gbpDevice[reader].fd, TCIOFLUSH)) \ DEBUG_INFO2("tcflush() function error: %s", strerror(errno)); /***************************************************************************** * * WriteGBP: Send bytes to the card reader * * remark: buffer already contains the byte length in [0] * *****************************************************************************/ RESPONSECODE WriteGBP(DWORD lun, DWORD length, PUCHAR buffer) { int rv, len, i; UCHAR edc; int reader = LunToReaderIndex(lun); UCHAR *gbpbuffer = GbpBuffer[reader]; #ifdef DEBUG_LEVEL_COMM char debug_header[] = "-> 121234 "; sprintf(debug_header, "-> %06X ", (int)lun); #endif /* PDU length = length + NAD + PCB + LEN */ len = length + 3; /* NAD byte */ gbpbuffer[NAD] = NAD_HOST2IFD; /* PCB byte */ gbpbuffer[PCB] = (gbpDevice[reader].bSeq << 6); /* copy LEN and DATA */ memcpy(gbpbuffer + LEN, buffer, length); /* checksum */ edc = 0; for (i = 0; i < len - 1; i++) edc ^= gbpbuffer[i]; /* EDC byte */ gbpbuffer[len - 1] = edc; /* increment Seq: 0 -> 1 or 1 -> 0 */ gbpDevice[reader].bSeq = (gbpDevice[reader].bSeq + 1) % 2; #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, len); #endif rv = write(gbpDevice[reader].fd, gbpbuffer, len); if (rv < 0) { DEBUG_CRITICAL2("write error: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } /* WriteGBP */ /***************************************************************************** * * ReadGBP: Receive bytes from the card reader * * remark: buffer contains the byte length in [0] * *****************************************************************************/ RESPONSECODE ReadGBP(DWORD lun, PDWORD length, PUCHAR buffer) { int rv, len, to_read, already_read; int i, pcb, edc; DWORD buffer_size; int reader = LunToReaderIndex(lun); UCHAR *gbpbuffer = GbpBuffer[reader]; fd_set fdset; int fd = gbpDevice[reader].fd; struct timeval t; #ifdef DEBUG_LEVEL_COMM char debug_header[] = "<- 121234 "; sprintf(debug_header, "<- %06X ", (int)lun); #endif len = sizeof(GbpBuffer[reader]); buffer_size = *length; /* error by default */ *length = 0; /* use select() to, eventually, timeout */ FD_ZERO(&fdset); FD_SET(fd, &fdset); t.tv_sec = SERIAL_TIMEOUT; t.tv_usec = 0; i = select(fd+1, &fdset, NULL, NULL, &t); if (i == -1) { DEBUG_CRITICAL2("select: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } else if (i == 0) { DEBUG_COMM2("Timeout! (%d sec)", SERIAL_TIMEOUT); return STATUS_UNSUCCESSFUL; } rv = read(fd, gbpbuffer, len); if (rv < 0) return STATUS_UNSUCCESSFUL; /* too short */ if (rv < 4) { #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, rv); ExplainGBP(gbpbuffer, rv); #endif DEBUG_COMM2("only %d byte(s) read", rv); return STATUS_UNSUCCESSFUL; } /* NAD byte */ if ((gbpbuffer[NAD] != NAD_IFD2HOST) && (gbpbuffer[NAD] != NAD_XXX2HOST)) { #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, rv); ExplainGBP(gbpbuffer, rv); #endif DEBUG_COMM2("wrong NAD byte 0x%02X", gbpbuffer[NAD]); return STATUS_NAD_UNKNOWN; } /* PCB byte */ pcb = gbpbuffer[PCB]; if (pcb & 0xA0) { int ret; #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, rv); #endif ret = ExplainGBP(gbpbuffer, rv); DEBUG_COMM("PCB error"); return ret; } /* LEN byte (+4 bytes of protocol) */ to_read = gbpbuffer[LEN] + 4; /* Nb of bytes already read */ already_read = rv; /* Nb of bytes until the end of the buffer */ len -= rv; while (already_read < to_read) { /* use select() to, eventually, timeout */ FD_ZERO(&fdset); FD_SET(fd, &fdset); t.tv_sec = SERIAL_TIMEOUT; t.tv_usec = 0; i = select(fd+1, &fdset, NULL, NULL, &t); if (i == -1) { DEBUG_CRITICAL2("select: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } else if (i == 0) { #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, already_read); #endif DEBUG_COMM2("Timeout! (%d sec)", SERIAL_TIMEOUT); return STATUS_UNSUCCESSFUL; } rv = read(fd, gbpbuffer + already_read, len); if (rv < 0) { #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, already_read); #endif DEBUG_COMM2("read error: %s", strerror(errno)); return STATUS_UNSUCCESSFUL; } already_read += rv; len -= rv; } /* calculate checksum */ edc = 0; for (i = 0; i < to_read; i++) edc ^= gbpbuffer[i]; #ifdef DEBUG_LEVEL_COMM DEBUG_XXD(debug_header, gbpbuffer, to_read); #endif /* verify checksum */ if (edc != 0) { DEBUG_COMM("wrong EDC"); return STATUS_UNSUCCESSFUL; } /* copy up to buffer_size bytes */ if (buffer_size > gbpbuffer[LEN]) *length = gbpbuffer[LEN] + 1; else *length = buffer_size; memcpy(buffer, gbpbuffer + LEN, *length); return STATUS_SUCCESS; } /* ReadGBP */ /***************************************************************************** * * OpenGBP: open the port * *****************************************************************************/ RESPONSECODE OpenGBP(DWORD lun, LPTSTR dev_name) { struct termios current_termios; int ospeed, i; int reader = LunToReaderIndex(lun); DEBUG_COMM3("Lun: %X, device: %s", lun, dev_name); /* check if the same channel is not already used */ for (i=0; i 4) switch (buffer[3]) { case 0x00: DEBUG_COMM(" S: no error"); break; case 0x01: DEBUG_COMM(" S: unknown driver"); break; case 0x02: DEBUG_COMM(" S: operation impossible with this driver"); break; case 0x03: DEBUG_COMM(" S: incorrect number of arguments"); break; case 0x04: DEBUG_COMM(" S: reader command unknown"); break; case 0x05: DEBUG_COMM(" S: response too long for the buffer"); break; case 0x10: DEBUG_COMM(" S: resonse error at the card reset"); break; case 0x12: DEBUG_COMM(" S: message too long"); break; case 0x13: DEBUG_COMM(" S: byte reading error returned by an asynchronous cadr"); break; case 0x15: DEBUG_COMM(" S: card powered down"); break; case 0x1B: DEBUG_COMM(" S: a command has been sent with an incorrect number of parameters"); break; case 0x1C: DEBUG_COMM(" S: overlap on writting flash memory"); break; case 0x1D: DEBUG_COMM(" S: the TCK check byte is incorrect in a micropocessor card ATR"); break; case 0x1E: DEBUG_COMM(" S: an attempt has been made to write a write-protected external memory"); break; case 0x1F: DEBUG_COMM(" S: incorrect data has been send to external memory"); break; case 0xA0: DEBUG_COMM(" S: error in the card reset response"); break; case 0xA1: DEBUG_COMM(" S: card protocol error"); break; case 0xA2: DEBUG_COMM(" S: card malfuntion"); break; case 0xA3: DEBUG_COMM(" S: parity error"); break; case 0xA4: DEBUG_COMM(" S: card has been chaining (T=1)"); break; case 0xA5: DEBUG_COMM(" S: reader has aborted chaining (T=1)"); break; case 0xA6: DEBUG_COMM(" S: resynch successfully performed by GemCore"); break; case 0xA7: DEBUG_COMM(" S: protocol type selection (PTS) error"); break; case 0xB0: DEBUG_COMM(" S: GemCP410 command not supported"); break; case 0xCF: DEBUG_COMM(" S: other key already pressed"); break; case 0xE4: DEBUG_COMM(" S: the card has just send an invalid procedure byte"); break; case 0xE5: DEBUG_COMM(" S: the card has interrupted an exchange"); break; case 0xE7: DEBUG_COMM(" S: error returned by the card"); break; case 0xF7: DEBUG_COMM(" S: card removed"); break; case 0xF8: DEBUG_COMM(" S: the cadr is consuming too much electricity"); break; case 0xFB: DEBUG_COMM(" S: card missing"); break; default: DEBUG_COMM2(" S: UNKNOWN ERROR %02X", buffer[3]); break; } return ret; } /* ExplainGBP */ /***************************************************************************** * * ExplainGBP: print a textual error explanation * *****************************************************************************/ int SetGBPSeqNumber(DWORD lun, int seq) { int reader = LunToReaderIndex(lun); if (gbpDevice[reader].bSeq != -1) { gbpDevice[reader].bSeq = seq; return FALSE; } else return TRUE; } /* SetGBPSeqNumber */