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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 611 - (show annotations) (download)
Thu Jan 15 13:41:01 2004 UTC (9 years, 4 months ago) by rousseau
File MIME type: text/plain
File size: 13940 byte(s)
use an (int *) instead of a PDWORD for rx_length argument
1 /*
2 ifdhandler.c: IFDH API
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 #include <stdio.h>
21 #include <string.h>
22
23 #include "pcscdefines.h"
24 #include "defs.h"
25 #include "ifdhandler.h"
26 #include "config.h"
27 #include "debug.h"
28 #include "utils.h"
29 #include "commands.h"
30
31 #ifdef HAVE_PTHREAD
32 #include <pthread.h>
33 #endif
34
35 /* Array of structures to hold the ATR and other state value of each slot */
36 static CcidDesc CcidSlots[PCSCLITE_MAX_READERS];
37
38 /* global mutex */
39 #ifdef HAVE_PTHREAD
40 static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
41 #endif
42
43
44 RESPONSECODE IFDHCreateChannel(DWORD Lun, DWORD Channel)
45 {
46 /*
47 * Lun - Logical Unit Number, use this for multiple card slots or
48 * multiple readers. 0xXXXXYYYY - XXXX multiple readers, YYYY multiple
49 * slots. The resource manager will set these automatically. By
50 * default the resource manager loads a new instance of the driver so
51 * if your reader does not have more than one smartcard slot then
52 * ignore the Lun in all the functions. Future versions of PC/SC might
53 * support loading multiple readers through one instance of the driver
54 * in which XXXX would be important to implement if you want this.
55 */
56
57 /*
58 * Channel - Channel ID. This is denoted by the following: 0x000001 -
59 * /dev/pcsc/1 0x000002 - /dev/pcsc/2 0x000003 - /dev/pcsc/3
60 *
61 * USB readers may choose to ignore this parameter and query the bus
62 * for the particular reader.
63 */
64
65 /*
66 * This function is required to open a communications channel to the
67 * port listed by Channel. For example, the first serial reader on
68 * COM1 would link to /dev/pcsc/1 which would be a sym link to
69 * /dev/ttyS0 on some machines This is used to help with intermachine
70 * independance.
71 *
72 * Once the channel is opened the reader must be in a state in which
73 * it is possible to query IFDHICCPresence() for card status.
74 *
75 * returns:
76 *
77 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
78 */
79 RESPONSECODE return_value = IFD_SUCCESS;
80
81 DEBUG_INFO2("lun: %X", Lun);
82
83 if (CheckLun(Lun))
84 return IFD_COMMUNICATION_ERROR;
85
86 /* Reset ATR buffer */
87 CcidSlots[LunToReaderIndex(Lun)].nATRLength = 0;
88 *CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer = '\0';
89
90 /* Reset PowerFlags */
91 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags = POWERFLAGS_RAZ;
92
93 #ifdef HAVE_PTHREAD
94 pthread_mutex_lock(&ifdh_context_mutex);
95 #endif
96
97 if (OpenPort(Lun, Channel) != STATUS_SUCCESS)
98 {
99 DEBUG_CRITICAL("OpenPort failed");
100 return_value = IFD_COMMUNICATION_ERROR;
101 }
102
103 #ifdef HAVE_PTHREAD
104 pthread_mutex_unlock(&ifdh_context_mutex);
105 #endif
106
107 return return_value;
108 } /* IFDHCreateChannel */
109
110
111 RESPONSECODE IFDHCloseChannel(DWORD Lun)
112 {
113 /*
114 * This function should close the reader communication channel for the
115 * particular reader. Prior to closing the communication channel the
116 * reader should make sure the card is powered down and the terminal
117 * is also powered down.
118 *
119 * returns:
120 *
121 * IFD_SUCCESS IFD_COMMUNICATION_ERROR
122 */
123
124 DEBUG_INFO2("lun: %X", Lun);
125
126 if (CheckLun(Lun))
127 return IFD_COMMUNICATION_ERROR;
128
129 CmdPowerOff(Lun);
130 /* No reader status check, if it failed, what can you do ? :) */
131
132 #ifdef HAVE_PTHREAD
133 pthread_mutex_lock(&ifdh_context_mutex);
134 #endif
135
136 ClosePort(Lun);
137
138 #ifdef HAVE_PTHREAD
139 pthread_mutex_unlock(&ifdh_context_mutex);
140 #endif
141
142 return IFD_SUCCESS;
143 } /* IFDHCloseChannel */
144
145
146 RESPONSECODE IFDHGetCapabilities(DWORD Lun, DWORD Tag,
147 PDWORD Length, PUCHAR Value)
148 {
149 /*
150 * This function should get the slot/card capabilities for a
151 * particular slot/card specified by Lun. Again, if you have only 1
152 * card slot and don't mind loading a new driver for each reader then
153 * ignore Lun.
154 *
155 * Tag - the tag for the information requested example: TAG_IFD_ATR -
156 * return the Atr and it's size (required). these tags are defined in
157 * ifdhandler.h
158 *
159 * Length - the length of the returned data Value - the value of the
160 * data
161 *
162 * returns:
163 *
164 * IFD_SUCCESS IFD_ERROR_TAG
165 */
166
167 DEBUG_INFO3("lun: %X, tag: %02X", Lun, Tag);
168
169 if (CheckLun(Lun))
170 return IFD_COMMUNICATION_ERROR;
171
172 switch (Tag)
173 {
174 case TAG_IFD_ATR:
175 /* If Length is not zero, powerICC has been performed.
176 * Otherwise, return NULL pointer
177 * Buffer size is stored in *Length */
178 *Length = (*Length < CcidSlots[LunToReaderIndex(Lun)]
179 .nATRLength) ?
180 *Length : CcidSlots[LunToReaderIndex(Lun)]
181 .nATRLength;
182
183 if (*Length)
184 memcpy(Value, CcidSlots[LunToReaderIndex(Lun)]
185 .pcATRBuffer, *Length);
186 break;
187
188 #ifdef HAVE_PTHREAD
189 case TAG_IFD_SIMULTANEOUS_ACCESS:
190 if (*Length >= 1)
191 {
192 *Length = 1;
193 *Value = PCSCLITE_MAX_READERS;
194 }
195 break;
196
197 case TAG_IFD_THREAD_SAFE:
198 if (*Length >= 1)
199 {
200 *Length = 1;
201 *Value = 1; /* Can talk to multiple readers at the same time */
202 }
203 break;
204 #endif
205
206 case TAG_IFD_SLOTS_NUMBER:
207 if (*Length >= 1)
208 {
209 *Length = 1;
210 *Value = 1; /* One slot only */
211 }
212 break;
213
214 default:
215 return IFD_ERROR_TAG;
216 }
217
218 return IFD_SUCCESS;
219 } /* IFDHGetCapabilities */
220
221
222 RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
223 DWORD Length, PUCHAR Value)
224 {
225 /*
226 * This function should set the slot/card capabilities for a
227 * particular slot/card specified by Lun. Again, if you have only 1
228 * card slot and don't mind loading a new driver for each reader then
229 * ignore Lun.
230 *
231 * Tag - the tag for the information needing set
232 *
233 * Length - the length of the returned data Value - the value of the
234 * data
235 *
236 * returns:
237 *
238 * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
239 * IFD_ERROR_VALUE_READ_ONLY
240 */
241
242 /* By default, say it worked */
243
244 DEBUG_PERIODIC2("lun: %X", Lun);
245
246 /* if (CheckLun(Lun))
247 return IFD_COMMUNICATION_ERROR; */
248
249 return IFD_NOT_SUPPORTED;
250 } /* IFDHSetCapabilities */
251
252
253 RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
254 UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
255 {
256 /*
257 * This function should set the PTS of a particular card/slot using
258 * the three PTS parameters sent
259 *
260 * Protocol - 0 .... 14 T=0 .... T=14 Flags - Logical OR of possible
261 * values: IFD_NEGOTIATE_PTS1 IFD_NEGOTIATE_PTS2 IFD_NEGOTIATE_PTS3 to
262 * determine which PTS values to negotiate. PTS1,PTS2,PTS3 - PTS
263 * Values.
264 *
265 * returns:
266 *
267 * IFD_SUCCESS IFD_ERROR_PTS_FAILURE IFD_COMMUNICATION_ERROR
268 * IFD_PROTOCOL_NOT_SUPPORTED
269 */
270
271 DEBUG_INFO2("lun: %X", Lun);
272
273 /* if (CheckLun(Lun))
274 return IFD_COMMUNICATION_ERROR; */
275
276 return IFD_NOT_SUPPORTED;
277 } /* IFDHSetProtocolParameters */
278
279
280 RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
281 PUCHAR Atr, PDWORD AtrLength)
282 {
283 /*
284 * This function controls the power and reset signals of the smartcard
285 * reader at the particular reader/slot specified by Lun.
286 *
287 * Action - Action to be taken on the card.
288 *
289 * IFD_POWER_UP - Power and reset the card if not done so (store the
290 * ATR and return it and it's length).
291 *
292 * IFD_POWER_DOWN - Power down the card if not done already
293 * (Atr/AtrLength should be zero'd)
294 *
295 * IFD_RESET - Perform a quick reset on the card. If the card is not
296 * powered power up the card. (Store and return the Atr/Length)
297 *
298 * Atr - Answer to Reset of the card. The driver is responsible for
299 * caching this value in case IFDHGetCapabilities is called requesting
300 * the ATR and it's length. This should not exceed MAX_ATR_SIZE.
301 *
302 * AtrLength - Length of the Atr. This should not exceed
303 * MAX_ATR_SIZE.
304 *
305 * Notes:
306 *
307 * Memory cards without an ATR should return IFD_SUCCESS on reset but
308 * the Atr should be zero'd and the length should be zero
309 *
310 * Reset errors should return zero for the AtrLength and return
311 * IFD_ERROR_POWER_ACTION.
312 *
313 * returns:
314 *
315 * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
316 * IFD_NOT_SUPPORTED
317 */
318
319 int nlength;
320 RESPONSECODE return_value = IFD_SUCCESS;
321 unsigned char pcbuffer[RESP_BUF_SIZE];
322
323 DEBUG_INFO2("lun: %X", Lun);
324
325 /* By default, assume it won't work :) */
326 *AtrLength = 0;
327
328 if (CheckLun(Lun))
329 return IFD_COMMUNICATION_ERROR;
330
331 switch (Action)
332 {
333 case IFD_POWER_UP:
334 case IFD_RESET:
335 nlength = sizeof(pcbuffer);
336 if (CmdPowerOn(Lun, &nlength, pcbuffer) != IFD_SUCCESS)
337 {
338 DEBUG_CRITICAL("PowerUp failed");
339 return_value = IFD_ERROR_POWER_ACTION;
340 goto end;
341 }
342
343 /* Power up successful, set state variable to memorise it */
344 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
345 MASK_POWERFLAGS_PUP;
346 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags &=
347 ~MASK_POWERFLAGS_PDWN;
348
349 /* Reset is returned, even if TCK is wrong */
350 CcidSlots[LunToReaderIndex(Lun)].nATRLength = *AtrLength =
351 (nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
352 memcpy(Atr, pcbuffer, *AtrLength);
353 memcpy(CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer,
354 pcbuffer, *AtrLength);
355 break;
356
357 case IFD_POWER_DOWN:
358 /* Clear ATR buffer */
359 CcidSlots[LunToReaderIndex(Lun)].nATRLength = 0;
360 *CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer = '\0';
361
362 /* Memorise the request */
363 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
364 MASK_POWERFLAGS_PDWN;
365 /* send the command */
366 return_value = CmdPowerOff(Lun);
367 break;
368
369 default:
370 DEBUG_CRITICAL("IFDHPowerICC Action not supported");
371 return_value = IFD_NOT_SUPPORTED;
372 }
373 end:
374
375 return return_value;
376 } /* IFDHPowerICC */
377
378
379 RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
380 PUCHAR TxBuffer, DWORD TxLength,
381 PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci)
382 {
383 /*
384 * This function performs an APDU exchange with the card/slot
385 * specified by Lun. The driver is responsible for performing any
386 * protocol specific exchanges such as T=0/1 ... differences. Calling
387 * this function will abstract all protocol differences.
388 *
389 * SendPci Protocol - 0, 1, .... 14 Length - Not used.
390 *
391 * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
392 * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
393 * example (0x61 0x14) RxLength - Length of the received APDU. This
394 * function will be passed the size of the buffer of RxBuffer and this
395 * function is responsible for setting this to the length of the
396 * received APDU. This should be ZERO on all errors. The resource
397 * manager will take responsibility of zeroing out any temporary APDU
398 * buffers for security reasons.
399 *
400 * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
401 *
402 * Notes: The driver is responsible for knowing what type of card it
403 * has. If the current slot/card contains a memory card then this
404 * command should ignore the Protocol and use the MCT style commands
405 * for support for these style cards and transmit them appropriately.
406 * If your reader does not support memory cards or you don't want to
407 * then ignore this.
408 *
409 * RxLength should be set to zero on error.
410 *
411 * returns:
412 *
413 * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
414 * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
415 */
416
417 RESPONSECODE return_value;
418 int rx_length;
419
420 DEBUG_INFO2("lun: %X", Lun);
421
422 if (CheckLun(Lun))
423 return IFD_COMMUNICATION_ERROR;
424
425 rx_length = *RxLength;
426 switch (SendPci.Protocol)
427 {
428 case T_0:
429 case T_1:
430 return_value = CmdXfrBlock(Lun, TxLength, TxBuffer, &rx_length,
431 RxBuffer);
432 break;
433
434 default:
435 return_value = IFD_PROTOCOL_NOT_SUPPORTED;
436 }
437 *RxLength = rx_length;
438
439 return return_value;
440 } /* IFDHTransmitToICC */
441
442
443 RESPONSECODE IFDHControl(DWORD Lun, PUCHAR TxBuffer,
444 DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
445 {
446 /*
447 * This function performs a data exchange with the reader (not the
448 * card) specified by Lun. Here XXXX will only be used. It is
449 * responsible for abstracting functionality such as PIN pads,
450 * biometrics, LCD panels, etc. You should follow the MCT, CTBCS
451 * specifications for a list of accepted commands to implement.
452 *
453 * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
454 * - Receive data RxLength - Length of the received data. This
455 * function will be passed the length of the buffer RxBuffer and it
456 * must set this to the length of the received data.
457 *
458 * Notes: RxLength should be zero on error.
459 */
460
461 DEBUG_INFO2("lun: %X", Lun);
462
463 /* if (CheckLun(Lun))
464 return IFD_COMMUNICATION_ERROR; */
465
466 /* Set the return length to 0 to avoid problems */
467 if (RxLength)
468 *RxLength = 0;
469
470 return IFD_NOT_SUPPORTED;
471 } /* IFDHControl */
472
473
474 RESPONSECODE IFDHICCPresence(DWORD Lun)
475 {
476 /*
477 * This function returns the status of the card inserted in the
478 * reader/slot specified by Lun. It will return either:
479 *
480 * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
481 * IFD_COMMUNICATION_ERROR
482 */
483
484 unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
485 RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
486
487 DEBUG_PERIODIC2("lun: %X", Lun);
488
489 if (CheckLun(Lun))
490 return IFD_COMMUNICATION_ERROR;
491
492 if (CmdGetSlotStatus(Lun, pcbuffer) != IFD_SUCCESS)
493 return IFD_COMMUNICATION_ERROR;
494
495 switch (pcbuffer[7]) /* bStatus */
496 {
497 case 0x00:
498 return_value = IFD_ICC_PRESENT;
499 break;
500
501 case 0x01:
502 return_value = IFD_ICC_PRESENT;
503 break;
504
505 case 0x02:
506 return_value = IFD_ICC_NOT_PRESENT;
507 break;
508 }
509
510 return return_value;
511 } /* IFDHICCPresence */
512
513
514 CcidDesc *get_ccid_slot(int lun)
515 {
516 return &CcidSlots[LunToReaderIndex(lun)];
517 } /* get_ccid_slot */
518

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5