/[pcsclite]/trunk/Drivers/ccid/src/commands.c
ViewVC logotype

Contents of /trunk/Drivers/ccid/src/commands.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 658 - (show annotations) (download)
Tue Jan 27 14:59:16 2004 UTC (9 years, 3 months ago) by rousseau
File MIME type: text/plain
File size: 13191 byte(s)
in case of error exits CCID_Receive() without copying an nonexistent anwser
1 /*
2 commands.c: Commands sent to the card
3 Copyright (C) 2003 Ludovic Rousseau
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 /*
21 * $Id$
22 */
23
24 #include <string.h>
25 #include <stdlib.h>
26
27 #include "pcscdefines.h"
28 #include "commands.h"
29 #include "protocol_t1/protocol_t1.h"
30 #include "ccid.h"
31 #include "defs.h"
32 #include "ifdhandler.h"
33 #include "config.h"
34 #include "debug.h"
35
36
37 /*****************************************************************************
38 *
39 * CmdPowerOn
40 *
41 ****************************************************************************/
42 RESPONSECODE CmdPowerOn(int lun, int * nlength, unsigned char buffer[])
43 {
44 unsigned char cmd[10];
45 status_t res;
46 int atr_len, length, count = 1;
47 RESPONSECODE return_value = IFD_SUCCESS;
48 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
49
50 /* store length of buffer[] */
51 length = *nlength;
52 again:
53 cmd[0] = 0x62; /* IccPowerOn */
54 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
55 cmd[5] = 0; /* slot number */
56 cmd[6] = ccid_descriptor->bSeq++;
57 if (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
58 cmd[7] = 0x00; /* Automatic voltage selection */
59 else
60 cmd[7] = 0x01; /* 5.0V */
61 cmd[8] = cmd[9] = 0; /* RFU */
62
63 res = WritePort(lun, sizeof(cmd), cmd);
64 if (res != STATUS_SUCCESS)
65 return IFD_COMMUNICATION_ERROR;
66
67 /* reset available buffer size */
68 /* needed if we go back after a switch to ISO mode */
69 *nlength = length;
70
71 res = ReadPort(lun, nlength, buffer);
72 if (res != STATUS_SUCCESS)
73 return IFD_COMMUNICATION_ERROR;
74
75 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
76 {
77 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
78
79 /* Protocol error in EMV mode */
80 if (buffer[ERROR_OFFSET] == 0xBB &&
81 ccid_descriptor->readerID == GEMPC433)
82 {
83 if ((return_value = CmdEscape(lun, ESC_GEMPC_SET_ISO_MODE)) != IFD_SUCCESS)
84 return return_value;
85
86 /* avoid looping if we can't switch mode */
87 if (count--)
88 goto again;
89 else
90 DEBUG_CRITICAL("Can't set reader in ISO mode");
91 }
92
93 return IFD_COMMUNICATION_ERROR;
94 }
95
96 /* extract the ATR */
97 atr_len = dw2i(buffer, 1); /* ATR length */
98 if (atr_len > *nlength)
99 atr_len = *nlength;
100 else
101 *nlength = atr_len;
102
103 memcpy(buffer, buffer+10, atr_len);
104
105 return return_value;
106 } /* CmdPowerOn */
107
108
109 /*****************************************************************************
110 *
111 * Escape
112 *
113 ****************************************************************************/
114 RESPONSECODE CmdEscape(int lun, int command)
115 {
116 unsigned char cmd[12];
117 status_t res;
118 int length;
119 RESPONSECODE return_value = IFD_SUCCESS;
120 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
121
122 cmd[0] = 0x6B; /* PC_to_RDR_Escape */
123 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
124 cmd[5] = 0; /* slot number */
125 cmd[6] = ccid_descriptor->bSeq++;
126 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
127
128 switch (command)
129 {
130 /* Gemplus proprietary */
131 case ESC_GEMPC_SET_ISO_MODE:
132 DEBUG_INFO("Switch reader in ISO mode");
133 cmd[10] = 0x1F; /* switch mode */
134 cmd[11] = 0x01; /* set ISO mode */
135 cmd[1] = 2; /* length of data */
136 length = 12;
137 break;
138
139 /* Gemplus proprietary */
140 case ESC_GEMPC_SET_APDU_MODE:
141 DEBUG_INFO("Switch reader in APDU mode");
142 cmd[10] = 0xA0; /* switch mode */
143 cmd[11] = 0x02; /* set APDU mode */
144 cmd[1] = 2; /* length of data */
145 length = 12;
146 break;
147
148 default:
149 DEBUG_CRITICAL2("Unkown Escape command: %d", command);
150 return return_value;
151 }
152
153 res = WritePort(lun, length, cmd);
154 if (res != STATUS_SUCCESS)
155 return IFD_COMMUNICATION_ERROR;
156
157 length = sizeof(cmd);
158 res = ReadPort(lun, &length, cmd);
159 if (res != STATUS_SUCCESS)
160 return IFD_COMMUNICATION_ERROR;
161
162 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
163 {
164 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
165 return_value = IFD_COMMUNICATION_ERROR;
166 }
167
168 return return_value;
169 } /* Escape */
170
171
172 /*****************************************************************************
173 *
174 * CmdPowerOff
175 *
176 ****************************************************************************/
177 RESPONSECODE CmdPowerOff(int lun)
178 {
179 unsigned char cmd[10];
180 status_t res;
181 int length;
182 RESPONSECODE return_value = IFD_SUCCESS;
183 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
184
185 cmd[0] = 0x63; /* IccPowerOff */
186 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
187 cmd[5] = 0; /* slot number */
188 cmd[6] = ccid_descriptor->bSeq++;
189 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
190
191 res = WritePort(lun, sizeof(cmd), cmd);
192 if (res != STATUS_SUCCESS)
193 return IFD_COMMUNICATION_ERROR;
194
195 length = sizeof(cmd);
196 res = ReadPort(lun, &length, cmd);
197 if (res != STATUS_SUCCESS)
198 return IFD_COMMUNICATION_ERROR;
199
200 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
201 {
202 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
203 return_value = IFD_COMMUNICATION_ERROR;
204 }
205
206 return return_value;
207 } /* CmdPowerOff */
208
209
210 /*****************************************************************************
211 *
212 * CmdGetSlotStatus
213 *
214 ****************************************************************************/
215 RESPONSECODE CmdGetSlotStatus(int lun, unsigned char buffer[])
216 {
217 unsigned char cmd[10];
218 status_t res;
219 int length;
220 RESPONSECODE return_value = IFD_SUCCESS;
221 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
222
223 cmd[0] = 0x65; /* GetSlotStatus */
224 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
225 cmd[5] = 0; /* slot number */
226 cmd[6] = ccid_descriptor->bSeq++;
227 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
228
229 res = WritePort(lun, sizeof(cmd), cmd);
230 if (res != STATUS_SUCCESS)
231 return IFD_COMMUNICATION_ERROR;
232
233 length = SIZE_GET_SLOT_STATUS;
234 res = ReadPort(lun, &length, buffer);
235 if (res != STATUS_SUCCESS)
236 return IFD_COMMUNICATION_ERROR;
237
238 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
239 {
240 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
241 return_value = IFD_COMMUNICATION_ERROR;
242 }
243
244 return return_value;
245 } /* CmdGetSlotStatus */
246
247
248 /*****************************************************************************
249 *
250 * CmdXfrBlock
251 *
252 ****************************************************************************/
253 RESPONSECODE CmdXfrBlock(int lun, int tx_length, unsigned char tx_buffer[],
254 int *rx_length, unsigned char rx_buffer[], int protocol)
255 {
256 RESPONSECODE return_value = IFD_SUCCESS;
257 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
258
259 /* command length too big for CCID reader? */
260 if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength)
261 {
262 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
263 tx_length, ccid_descriptor->dwMaxCCIDMessageLength);
264 return_value = IFD_COMMUNICATION_ERROR;
265 goto clean_up_and_return;
266 }
267
268 /* command length too big for CCID driver? */
269 if (tx_length > CMD_BUF_SIZE)
270 {
271 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
272 tx_length, CMD_BUF_SIZE);
273 return_value = IFD_COMMUNICATION_ERROR;
274 goto clean_up_and_return;
275 }
276
277 /* APDU or TPDU? */
278 switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
279 {
280 case CCID_CLASS_TPDU:
281 if (protocol == T_0)
282 return_value = CmdXfrBlockTPDU_T0(lun, tx_length, tx_buffer,
283 rx_length, rx_buffer);
284 else
285 if (protocol == T_1)
286 return_value = CmdXfrBlockTPDU_T1(lun, tx_length,
287 tx_buffer, rx_length, rx_buffer);
288 else
289 return_value = IFD_PROTOCOL_NOT_SUPPORTED;
290 break;
291
292 case CCID_CLASS_SHORT_APDU:
293 case CCID_CLASS_EXTENDED_APDU:
294 /* We only support extended APDU if the reader can support the
295 * command length. See test above */
296 return_value = CmdXfrBlockTPDU_T0(lun, tx_length, tx_buffer,
297 rx_length, rx_buffer);
298 break;
299
300 default:
301 *rx_length = 0;
302 return_value = IFD_COMMUNICATION_ERROR;
303 }
304
305 clean_up_and_return:
306 return return_value;
307 } /* CmdXfrBlock */
308
309
310 /*****************************************************************************
311 *
312 * CCID_Transmit
313 *
314 ****************************************************************************/
315 RESPONSECODE CCID_Transmit(int lun, int tx_length, unsigned char tx_buffer[])
316 {
317 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
318 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
319
320 cmd[0] = 0x6F; /* XfrBlock */
321 i2dw(tx_length, cmd+1); /* APDU length */
322 cmd[5] = 0; /* slot number */
323 cmd[6] = ccid_descriptor->bSeq++;
324 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
325 memcpy(cmd+10, tx_buffer, tx_length);
326
327 if (WritePort(lun, 10+tx_length, cmd) != STATUS_SUCCESS)
328 return IFD_COMMUNICATION_ERROR;
329
330 return IFD_SUCCESS;
331 } /* CCID_Transmit */
332
333
334 /*****************************************************************************
335 *
336 * CCID_Receive
337 *
338 ****************************************************************************/
339 RESPONSECODE CCID_Receive(int lun, int *rx_length, unsigned char rx_buffer[])
340 {
341 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
342 int length;
343
344 time_request:
345 length = sizeof(cmd);
346 if (ReadPort(lun, &length, cmd) != STATUS_SUCCESS)
347 return IFD_COMMUNICATION_ERROR;
348
349 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
350 {
351 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
352 *rx_length = 0; /* nothing received */
353 return IFD_COMMUNICATION_ERROR;
354 }
355
356 if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
357 {
358 DEBUG_CRITICAL2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
359 goto time_request;
360 }
361
362 length = dw2i(cmd, 1);
363 if (length < *rx_length)
364 *rx_length = length;
365 else
366 length = *rx_length;
367 memcpy(rx_buffer, cmd+10, length);
368
369 return IFD_SUCCESS;
370 } /* CCID_Receive */
371
372
373 /*****************************************************************************
374 *
375 * CmdXfrBlockTPDU_T0
376 *
377 ****************************************************************************/
378 RESPONSECODE CmdXfrBlockTPDU_T0(int lun, int tx_length,
379 unsigned char tx_buffer[], int *rx_length, unsigned char rx_buffer[])
380 {
381 RESPONSECODE return_value = IFD_SUCCESS;
382
383 DEBUG_COMM2("T=0: %d bytes", tx_length);
384
385 return_value = CCID_Transmit(lun, tx_length, tx_buffer);
386 if (return_value != IFD_SUCCESS)
387 return return_value;
388
389 return CCID_Receive(lun, rx_length, rx_buffer);
390 } /* CmdXfrBlockTPDU_T0 */
391
392
393 /*****************************************************************************
394 *
395 * CmdXfrBlockTPDU_T1
396 *
397 ****************************************************************************/
398 RESPONSECODE CmdXfrBlockTPDU_T1(int lun, int tx_length,
399 unsigned char tx_buffer[], int *rx_length, unsigned char rx_buffer[])
400 {
401 RESPONSECODE return_value;
402 APDU_Cmd cmd;
403 APDU_Rsp rsp;
404
405 DEBUG_COMM2("T=1: %d bytes", tx_length);
406
407 /* set up command APDU */
408 cmd.command = tx_buffer;
409 cmd.length = tx_length;
410
411 return_value = Protocol_T1_Command(&((get_ccid_slot(lun)) -> t1), &cmd,
412 &rsp);
413
414 if (return_value == PROTOCOL_T1_OK)
415 {
416 return_value = IFD_SUCCESS;
417
418 /* copy the response */
419 memcpy(rx_buffer, rsp.response, rsp.length);
420
421 /* free the allocated response buffer */
422 free(rsp.response);
423
424 *rx_length = rsp.length;
425 }
426 else
427 return_value = IFD_COMMUNICATION_ERROR;
428
429 return return_value;
430 } /* CmdXfrBlockTPDU_T1 */
431
432
433 /*****************************************************************************
434 *
435 * SetParameters
436 *
437 ****************************************************************************/
438 RESPONSECODE SetParameters(int lun, char protocol, int length, unsigned char buffer[])
439 {
440 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
441 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
442
443 DEBUG_COMM2("length: %d bytes", length);
444
445 cmd[0] = 0x61; /* SetParameters */
446 i2dw(length, cmd+1); /* APDU length */
447 cmd[5] = 0; /* slot number */
448 cmd[6] = ccid_descriptor->bSeq++;
449 cmd[7] = protocol; /* bProtocolNum */
450 cmd[8] = cmd[9] = 0; /* RFU */
451 memcpy(cmd+10, buffer, length);
452
453 if (WritePort(lun, 10+length, cmd) != STATUS_SUCCESS)
454 return IFD_COMMUNICATION_ERROR;
455
456 length = sizeof(cmd);
457 if (ReadPort(lun, &length, cmd) != STATUS_SUCCESS)
458 return IFD_COMMUNICATION_ERROR;
459
460 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
461 {
462 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
463 return IFD_COMMUNICATION_ERROR;
464 }
465
466 return IFD_SUCCESS;
467 } /* SetParameters */
468
469
470 /*****************************************************************************
471 *
472 * i2dw
473 *
474 ****************************************************************************/
475 void i2dw(int value, unsigned char buffer[])
476 {
477 buffer[0] = value & 0xFF;
478 buffer[1] = (value >> 8) & 0xFF;
479 buffer[2] = (value >> 16) & 0xFF;
480 buffer[3] = (value >> 24) & 0xFF;
481 } /* i2dw */
482

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

  ViewVC Help
Powered by ViewVC 1.1.5