/[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 563 - (show annotations) (download)
Tue Nov 25 22:55:58 2003 UTC (9 years, 5 months ago) by rousseau
File MIME type: text/plain
File size: 14020 byte(s)
use a updated version of acx_pthread.m4 needed for FreeBSD
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 "ifdhandler.h"
25 #include "config.h"
26 #include "debug.h"
27 #include "defs.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("Entering IFDHCreateChannel (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("OpenReader 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("entering IFDHCloseChannel (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("entering IFDHGetCapabilities (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 return IFD_SUCCESS;
218 } /* IFDHGetCapabilities */
219
220
221 RESPONSECODE IFDHSetCapabilities(DWORD Lun, DWORD Tag,
222 DWORD Length, PUCHAR Value)
223 {
224 /*
225 * This function should set the slot/card capabilities for a
226 * particular slot/card specified by Lun. Again, if you have only 1
227 * card slot and don't mind loading a new driver for each reader then
228 * ignore Lun.
229 *
230 * Tag - the tag for the information needing set
231 *
232 * Length - the length of the returned data Value - the value of the
233 * data
234 *
235 * returns:
236 *
237 * IFD_SUCCESS IFD_ERROR_TAG IFD_ERROR_SET_FAILURE
238 * IFD_ERROR_VALUE_READ_ONLY
239 */
240
241 /* By default, say it worked */
242
243 DEBUG_PERIODIC2("entering IFDHSetCapabilities (lun: %X)", Lun);
244
245 /* if (CheckLun(Lun))
246 return IFD_COMMUNICATION_ERROR; */
247
248 return IFD_SUCCESS;
249 } /* IFDHSetCapabilities */
250
251
252 RESPONSECODE IFDHSetProtocolParameters(DWORD Lun, DWORD Protocol,
253 UCHAR Flags, UCHAR PTS1, UCHAR PTS2, UCHAR PTS3)
254 {
255 /*
256 * This function should set the PTS of a particular card/slot using
257 * the three PTS parameters sent
258 *
259 * Protocol - 0 .... 14 T=0 .... T=14 Flags - Logical OR of possible
260 * values: IFD_NEGOTIATE_PTS1 IFD_NEGOTIATE_PTS2 IFD_NEGOTIATE_PTS3 to
261 * determine which PTS values to negotiate. PTS1,PTS2,PTS3 - PTS
262 * Values.
263 *
264 * returns:
265 *
266 * IFD_SUCCESS IFD_ERROR_PTS_FAILURE IFD_COMMUNICATION_ERROR
267 * IFD_PROTOCOL_NOT_SUPPORTED
268 */
269
270 DEBUG_INFO2("entering IFDHSetProtocolParameters (lun: %X)", Lun);
271
272 /* if (CheckLun(Lun))
273 return IFD_COMMUNICATION_ERROR; */
274
275 return IFD_SUCCESS;
276 } /* IFDHSetProtocolParameters */
277
278
279 RESPONSECODE IFDHPowerICC(DWORD Lun, DWORD Action,
280 PUCHAR Atr, PDWORD AtrLength)
281 {
282 /*
283 * This function controls the power and reset signals of the smartcard
284 * reader at the particular reader/slot specified by Lun.
285 *
286 * Action - Action to be taken on the card.
287 *
288 * IFD_POWER_UP - Power and reset the card if not done so (store the
289 * ATR and return it and it's length).
290 *
291 * IFD_POWER_DOWN - Power down the card if not done already
292 * (Atr/AtrLength should be zero'd)
293 *
294 * IFD_RESET - Perform a quick reset on the card. If the card is not
295 * powered power up the card. (Store and return the Atr/Length)
296 *
297 * Atr - Answer to Reset of the card. The driver is responsible for
298 * caching this value in case IFDHGetCapabilities is called requesting
299 * the ATR and it's length. This should not exceed MAX_ATR_SIZE.
300 *
301 * AtrLength - Length of the Atr. This should not exceed
302 * MAX_ATR_SIZE.
303 *
304 * Notes:
305 *
306 * Memory cards without an ATR should return IFD_SUCCESS on reset but
307 * the Atr should be zero'd and the length should be zero
308 *
309 * Reset errors should return zero for the AtrLength and return
310 * IFD_ERROR_POWER_ACTION.
311 *
312 * returns:
313 *
314 * IFD_SUCCESS IFD_ERROR_POWER_ACTION IFD_COMMUNICATION_ERROR
315 * IFD_NOT_SUPPORTED
316 */
317
318 int nlength;
319 RESPONSECODE return_value = IFD_SUCCESS;
320 unsigned char pcbuffer[RESP_BUF_SIZE];
321
322 DEBUG_INFO2("entering IFDHPowerICC (lun: %X)", Lun);
323
324 /* By default, assume it won't work :) */
325 *AtrLength = 0;
326
327 if (CheckLun(Lun))
328 return IFD_COMMUNICATION_ERROR;
329
330 switch (Action)
331 {
332 case IFD_POWER_UP:
333 case IFD_RESET:
334 nlength = sizeof(pcbuffer);
335 if (CmdPowerOn(Lun, &nlength, pcbuffer) != IFD_SUCCESS)
336 {
337 DEBUG_CRITICAL("PowerUp failed");
338 return_value = IFD_ERROR_POWER_ACTION;
339 goto end;
340 }
341
342 /* Power up successful, set state variable to memorise it */
343 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
344 MASK_POWERFLAGS_PUP;
345 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags &=
346 ~MASK_POWERFLAGS_PDWN;
347
348 /* Reset is returned, even if TCK is wrong */
349 CcidSlots[LunToReaderIndex(Lun)].nATRLength = *AtrLength =
350 (nlength < MAX_ATR_SIZE) ? nlength : MAX_ATR_SIZE;
351 memcpy(Atr, pcbuffer, *AtrLength);
352 memcpy(CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer,
353 pcbuffer, *AtrLength);
354 break;
355
356 case IFD_POWER_DOWN:
357 /* Clear ATR buffer */
358 CcidSlots[LunToReaderIndex(Lun)].nATRLength = 0;
359 *CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer = '\0';
360
361 /* Memorise the request */
362 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
363 MASK_POWERFLAGS_PDWN;
364 /* send the command */
365 return_value = CmdPowerOff(Lun);
366 break;
367
368 default:
369 DEBUG_CRITICAL("IFDHPowerICC Action not supported");
370 return_value = IFD_NOT_SUPPORTED;
371 }
372 end:
373
374 return return_value;
375 } /* IFDHPowerICC */
376
377
378 RESPONSECODE IFDHTransmitToICC(DWORD Lun, SCARD_IO_HEADER SendPci,
379 PUCHAR TxBuffer, DWORD TxLength,
380 PUCHAR RxBuffer, PDWORD RxLength, PSCARD_IO_HEADER RecvPci)
381 {
382 /*
383 * This function performs an APDU exchange with the card/slot
384 * specified by Lun. The driver is responsible for performing any
385 * protocol specific exchanges such as T=0/1 ... differences. Calling
386 * this function will abstract all protocol differences.
387 *
388 * SendPci Protocol - 0, 1, .... 14 Length - Not used.
389 *
390 * TxBuffer - Transmit APDU example (0x00 0xA4 0x00 0x00 0x02 0x3F
391 * 0x00) TxLength - Length of this buffer. RxBuffer - Receive APDU
392 * example (0x61 0x14) RxLength - Length of the received APDU. This
393 * function will be passed the size of the buffer of RxBuffer and this
394 * function is responsible for setting this to the length of the
395 * received APDU. This should be ZERO on all errors. The resource
396 * manager will take responsibility of zeroing out any temporary APDU
397 * buffers for security reasons.
398 *
399 * RecvPci Protocol - 0, 1, .... 14 Length - Not used.
400 *
401 * Notes: The driver is responsible for knowing what type of card it
402 * has. If the current slot/card contains a memory card then this
403 * command should ignore the Protocol and use the MCT style commands
404 * for support for these style cards and transmit them appropriately.
405 * If your reader does not support memory cards or you don't want to
406 * then ignore this.
407 *
408 * RxLength should be set to zero on error.
409 *
410 * returns:
411 *
412 * IFD_SUCCESS IFD_COMMUNICATION_ERROR IFD_RESPONSE_TIMEOUT
413 * IFD_ICC_NOT_PRESENT IFD_PROTOCOL_NOT_SUPPORTED
414 */
415
416 RESPONSECODE return_value = IFD_SUCCESS; /* Assume it will work */
417
418 DEBUG_INFO2("entering IFDHTransmitToICC (lun: %X)", Lun);
419
420 if (CheckLun(Lun))
421 return IFD_COMMUNICATION_ERROR;
422
423 switch (SendPci.Protocol)
424 {
425 case T_0:
426 case T_1:
427 return_value = CmdXfrBlock(Lun, TxLength, TxBuffer, RxLength,
428 RxBuffer);
429 break;
430
431 default:
432 return_value = IFD_PROTOCOL_NOT_SUPPORTED;
433 }
434
435 if (return_value != IFD_SUCCESS)
436 *RxLength = 0;
437
438 return return_value;
439 } /* IFDHTransmitToICC */
440
441
442 RESPONSECODE IFDHControl(DWORD Lun, PUCHAR TxBuffer,
443 DWORD TxLength, PUCHAR RxBuffer, PDWORD RxLength)
444 {
445 /*
446 * This function performs a data exchange with the reader (not the
447 * card) specified by Lun. Here XXXX will only be used. It is
448 * responsible for abstracting functionality such as PIN pads,
449 * biometrics, LCD panels, etc. You should follow the MCT, CTBCS
450 * specifications for a list of accepted commands to implement.
451 *
452 * TxBuffer - Transmit data TxLength - Length of this buffer. RxBuffer
453 * - Receive data RxLength - Length of the received data. This
454 * function will be passed the length of the buffer RxBuffer and it
455 * must set this to the length of the received data.
456 *
457 * Notes: RxLength should be zero on error.
458 */
459
460 DEBUG_INFO2("entering IFDHControl (lun: %X)", Lun);
461
462 /* if (CheckLun(Lun))
463 return IFD_COMMUNICATION_ERROR; */
464
465 return IFD_SUCCESS;
466 } /* IFDHControl */
467
468
469 RESPONSECODE IFDHICCPresence(DWORD Lun)
470 {
471 /*
472 * This function returns the status of the card inserted in the
473 * reader/slot specified by Lun. It will return either:
474 *
475 * returns: IFD_ICC_PRESENT IFD_ICC_NOT_PRESENT
476 * IFD_COMMUNICATION_ERROR
477 */
478
479 unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
480 RESPONSECODE return_value = IFD_COMMUNICATION_ERROR;
481
482 DEBUG_PERIODIC2("entering IFDHICCPresence (lun: %X)", Lun);
483
484 if (CheckLun(Lun))
485 return IFD_COMMUNICATION_ERROR;
486
487 if (CmdGetSlotStatus(Lun, pcbuffer) != IFD_SUCCESS)
488 return IFD_COMMUNICATION_ERROR;
489
490 switch (pcbuffer[7]) /* bStatus */
491 {
492 case 0x00:
493 return_value = IFD_ICC_PRESENT;
494 break;
495
496 case 0x01:
497 return_value = IFD_ICC_PRESENT;
498 break;
499
500 case 0x02:
501 return_value = IFD_ICC_NOT_PRESENT;
502 break;
503 }
504
505 return return_value;
506 } /* IFDHICCPresence */
507

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5