/[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 613 - (show annotations) (download)
Thu Jan 15 13:51:40 2004 UTC (9 years, 4 months ago) by rousseau
File MIME type: text/plain
File size: 10917 byte(s)
split CmdXfrBlockShortAPDU() in CCID_Transmit() and CCID_Receive()
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
26 #include "pcscdefines.h"
27 #include "commands.h"
28 #include "ccid.h"
29 #include "defs.h"
30 #include "ifdhandler.h"
31 #include "config.h"
32 #include "debug.h"
33
34
35 /*****************************************************************************
36 *
37 * CmdPowerOn
38 *
39 ****************************************************************************/
40 RESPONSECODE CmdPowerOn(int lun, int * nlength, unsigned char buffer[])
41 {
42 unsigned char cmd[10];
43 status_t res;
44 int atr_len, length, count = 1;
45 RESPONSECODE return_value = IFD_SUCCESS;
46 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
47
48 /* store length of buffer[] */
49 length = *nlength;
50 again:
51 cmd[0] = 0x62; /* IccPowerOn */
52 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
53 cmd[5] = 0; /* slot number */
54 cmd[6] = ccid_descriptor->bSeq++;
55 if (ccid_descriptor->dwFeatures & CCID_CLASS_AUTO_VOLTAGE)
56 cmd[7] = 0x00; /* Automatic voltage selection */
57 else
58 cmd[7] = 0x01; /* 5.0V */
59 cmd[8] = cmd[9] = 0; /* RFU */
60
61 res = WritePort(lun, sizeof(cmd), cmd);
62 if (res != STATUS_SUCCESS)
63 return IFD_COMMUNICATION_ERROR;
64
65 /* reset available buffer size */
66 /* needed if we go back after a switch to ISO mode */
67 *nlength = length;
68
69 res = ReadPort(lun, nlength, buffer);
70 if (res != STATUS_SUCCESS)
71 return IFD_COMMUNICATION_ERROR;
72
73 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
74 {
75 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
76
77 /* Protocol error in EMV mode */
78 if (buffer[ERROR_OFFSET] == 0xBB &&
79 ccid_descriptor->readerID == GEMPC433)
80 {
81 if ((return_value = CmdEscape(lun, ESC_GEMPC_SET_ISO_MODE)) != IFD_SUCCESS)
82 return return_value;
83
84 /* avoid looping if we can't switch mode */
85 if (count--)
86 goto again;
87 else
88 DEBUG_CRITICAL("Can't set reader in ISO mode");
89 }
90
91 return IFD_COMMUNICATION_ERROR;
92 }
93
94 /* extract the ATR */
95 atr_len = dw2i(buffer, 1); /* ATR length */
96 if (atr_len > *nlength)
97 atr_len = *nlength;
98 else
99 *nlength = atr_len;
100
101 memcpy(buffer, buffer+10, atr_len);
102
103 return return_value;
104 } /* CmdPowerOn */
105
106
107 /*****************************************************************************
108 *
109 * Escape
110 *
111 ****************************************************************************/
112 RESPONSECODE CmdEscape(int lun, int command)
113 {
114 unsigned char cmd[12];
115 status_t res;
116 int length;
117 RESPONSECODE return_value = IFD_SUCCESS;
118 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
119
120 cmd[0] = 0x6B; /* PC_to_RDR_Escape */
121 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
122 cmd[5] = 0; /* slot number */
123 cmd[6] = ccid_descriptor->bSeq++;
124 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
125
126 switch (command)
127 {
128 /* Gemplus proprietary */
129 case ESC_GEMPC_SET_ISO_MODE:
130 DEBUG_INFO("Switch reader in ISO mode");
131 cmd[10] = 0x1F; /* switch mode */
132 cmd[11] = 0x01; /* set ISO mode */
133 cmd[1] = 2; /* length of data */
134 length = 12;
135 break;
136
137 /* Gemplus proprietary */
138 case ESC_GEMPC_SET_APDU_MODE:
139 DEBUG_INFO("Switch reader in APDU mode");
140 cmd[10] = 0xA0; /* switch mode */
141 cmd[11] = 0x02; /* set APDU mode */
142 cmd[1] = 2; /* length of data */
143 length = 12;
144 break;
145
146 default:
147 DEBUG_CRITICAL2("Unkown Escape command: %d", command);
148 return return_value;
149 }
150
151 res = WritePort(lun, length, cmd);
152 if (res != STATUS_SUCCESS)
153 return IFD_COMMUNICATION_ERROR;
154
155 length = sizeof(cmd);
156 res = ReadPort(lun, &length, cmd);
157 if (res != STATUS_SUCCESS)
158 return IFD_COMMUNICATION_ERROR;
159
160 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
161 {
162 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
163 return_value = IFD_COMMUNICATION_ERROR;
164 }
165
166 return return_value;
167 } /* Escape */
168
169
170 /*****************************************************************************
171 *
172 * CmdPowerOff
173 *
174 ****************************************************************************/
175 RESPONSECODE CmdPowerOff(int lun)
176 {
177 unsigned char cmd[10];
178 status_t res;
179 int length;
180 RESPONSECODE return_value = IFD_SUCCESS;
181 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
182
183 cmd[0] = 0x63; /* IccPowerOff */
184 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
185 cmd[5] = 0; /* slot number */
186 cmd[6] = ccid_descriptor->bSeq++;
187 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
188
189 res = WritePort(lun, sizeof(cmd), cmd);
190 if (res != STATUS_SUCCESS)
191 return IFD_COMMUNICATION_ERROR;
192
193 length = sizeof(cmd);
194 res = ReadPort(lun, &length, cmd);
195 if (res != STATUS_SUCCESS)
196 return IFD_COMMUNICATION_ERROR;
197
198 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
199 {
200 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
201 return_value = IFD_COMMUNICATION_ERROR;
202 }
203
204 return return_value;
205 } /* CmdPowerOff */
206
207
208 /*****************************************************************************
209 *
210 * CmdGetSlotStatus
211 *
212 ****************************************************************************/
213 RESPONSECODE CmdGetSlotStatus(int lun, unsigned char buffer[])
214 {
215 unsigned char cmd[10];
216 status_t res;
217 int length;
218 RESPONSECODE return_value = IFD_SUCCESS;
219 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
220
221 cmd[0] = 0x65; /* GetSlotStatus */
222 cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
223 cmd[5] = 0; /* slot number */
224 cmd[6] = ccid_descriptor->bSeq++;
225 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
226
227 res = WritePort(lun, sizeof(cmd), cmd);
228 if (res != STATUS_SUCCESS)
229 return IFD_COMMUNICATION_ERROR;
230
231 length = SIZE_GET_SLOT_STATUS;
232 res = ReadPort(lun, &length, buffer);
233 if (res != STATUS_SUCCESS)
234 return IFD_COMMUNICATION_ERROR;
235
236 if (buffer[STATUS_OFFSET] & CCID_COMMAND_FAILED)
237 {
238 ccid_error(buffer[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
239 return_value = IFD_COMMUNICATION_ERROR;
240 }
241
242 return return_value;
243 } /* CmdGetSlotStatus */
244
245
246 /*****************************************************************************
247 *
248 * CmdXfrBlock
249 *
250 ****************************************************************************/
251 RESPONSECODE CmdXfrBlock(int lun, int tx_length, unsigned char tx_buffer[],
252 int *rx_length, unsigned char rx_buffer[])
253 {
254 RESPONSECODE return_value = IFD_SUCCESS;
255 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
256
257 /* command length too big for CCID reader? */
258 if (tx_length > ccid_descriptor->dwMaxCCIDMessageLength)
259 {
260 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
261 tx_length, ccid_descriptor->dwMaxCCIDMessageLength);
262 return_value = IFD_COMMUNICATION_ERROR;
263 goto clean_up_and_return;
264 }
265
266 /* command length too big for CCID driver? */
267 if (tx_length > CMD_BUF_SIZE)
268 {
269 DEBUG_CRITICAL3("Command too long (%d bytes) for max: %d bytes",
270 tx_length, CMD_BUF_SIZE);
271 return_value = IFD_COMMUNICATION_ERROR;
272 goto clean_up_and_return;
273 }
274
275 /* APDU or TPDU? */
276 switch (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK)
277 {
278 case CCID_CLASS_TPDU:
279 return_value = CmdXfrBlockTPDU(lun, tx_length, tx_buffer, rx_length,
280 rx_buffer);
281 break;
282
283 case CCID_CLASS_SHORT_APDU:
284 case CCID_CLASS_EXTENDED_APDU:
285 /* We only support extended APDU if the reader can support the
286 * command length. See test above */
287 return_value = CmdXfrBlockShortAPDU(lun, tx_length, tx_buffer,
288 rx_length, rx_buffer);
289 break;
290
291 default:
292 return_value = IFD_COMMUNICATION_ERROR;
293 }
294
295 clean_up_and_return:
296 return return_value;
297 } /* CmdXfrBlock */
298
299
300 /*****************************************************************************
301 *
302 * CCID_Transmit
303 *
304 ****************************************************************************/
305 RESPONSECODE CCID_Transmit(int lun, int tx_length, unsigned char tx_buffer[])
306 {
307 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
308 _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(lun);
309
310 cmd[0] = 0x6F; /* XfrBlock */
311 i2dw(tx_length, cmd+1); /* APDU length */
312 cmd[5] = 0; /* slot number */
313 cmd[6] = ccid_descriptor->bSeq++;
314 cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */
315 memcpy(cmd+10, tx_buffer, tx_length);
316
317 if (WritePort(lun, 10+tx_length, cmd) != STATUS_SUCCESS)
318 return IFD_COMMUNICATION_ERROR;
319
320 return IFD_SUCCESS;
321 } /* CCID_Transmit */
322
323
324 /*****************************************************************************
325 *
326 * CCID_Receive
327 *
328 ****************************************************************************/
329 RESPONSECODE CCID_Receive(int lun, int *rx_length, unsigned char rx_buffer[])
330 {
331 unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
332 int length;
333 RESPONSECODE return_value = IFD_SUCCESS;
334
335 time_request:
336 length = sizeof(cmd);
337 if (ReadPort(lun, &length, cmd) != STATUS_SUCCESS)
338 return IFD_COMMUNICATION_ERROR;
339
340 if (cmd[STATUS_OFFSET] & CCID_COMMAND_FAILED)
341 {
342 ccid_error(cmd[ERROR_OFFSET], __FILE__, __LINE__); /* bError */
343 *rx_length = 0; /* nothing received */
344 return_value = IFD_COMMUNICATION_ERROR;
345 }
346
347 if (cmd[STATUS_OFFSET] & CCID_TIME_EXTENSION)
348 {
349 DEBUG_CRITICAL2("Time extension requested: 0x%02X", cmd[ERROR_OFFSET]);
350 goto time_request;
351 }
352
353 length = dw2i(cmd, 1);
354 if (length < *rx_length)
355 *rx_length = length;
356 else
357 length = *rx_length;
358 memcpy(rx_buffer, cmd+10, length);
359
360 return return_value;
361 } /* CCID_Receive */
362
363
364 /*****************************************************************************
365 *
366 * CmdXfrBlockTPDU
367 *
368 ****************************************************************************/
369 RESPONSECODE CmdXfrBlockTPDU(int lun, int tx_length, unsigned char tx_buffer[],
370 int *rx_length, unsigned char rx_buffer[])
371 {
372 RESPONSECODE return_value = IFD_SUCCESS;
373
374 DEBUG_COMM2("TPDU: %d bytes", tx_length);
375
376 return_value = CCID_Transmit(lun, tx_length, tx_buffer);
377 if (return_value != IFD_SUCCESS)
378 return return_value;
379
380 return CCID_Receive(lun, rx_length, rx_buffer);
381 } /* CmdXfrBlockTPDU */
382
383
384 /*****************************************************************************
385 *
386 * i2dw
387 *
388 ****************************************************************************/
389 void i2dw(int value, unsigned char buffer[])
390 {
391 buffer[0] = value & 0xFF;
392 buffer[1] = (value >> 8) & 0xFF;
393 buffer[2] = (value >> 16) & 0xFF;
394 buffer[3] = (value >> 24) & 0xFF;
395 } /* i2dw */
396

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5