/[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 608 - (hide annotations) (download)
Thu Jan 15 08:30:31 2004 UTC (9 years, 4 months ago) by rousseau
File MIME type: text/plain
File size: 13864 byte(s)
remove function name from debug message since __FUNCTION__ is now used in
DEBUG_* macro definition
1 rousseau 269 /*
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 rousseau 563 #ifdef HAVE_PTHREAD
32 rousseau 463 #include <pthread.h>
33     #endif
34    
35 rousseau 410 /* Array of structures to hold the ATR and other state value of each slot */
36     static CcidDesc CcidSlots[PCSCLITE_MAX_READERS];
37 rousseau 269
38 rousseau 463 /* global mutex */
39 rousseau 563 #ifdef HAVE_PTHREAD
40 rousseau 463 static pthread_mutex_t ifdh_context_mutex = PTHREAD_MUTEX_INITIALIZER;
41     #endif
42 rousseau 269
43 rousseau 463
44 rousseau 269 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 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
82 rousseau 269
83     if (CheckLun(Lun))
84     return IFD_COMMUNICATION_ERROR;
85    
86 rousseau 410 /* Reset ATR buffer */
87 rousseau 269 CcidSlots[LunToReaderIndex(Lun)].nATRLength = 0;
88     *CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer = '\0';
89    
90 rousseau 410 /* Reset PowerFlags */
91 rousseau 269 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags = POWERFLAGS_RAZ;
92    
93 rousseau 563 #ifdef HAVE_PTHREAD
94 rousseau 463 pthread_mutex_lock(&ifdh_context_mutex);
95     #endif
96    
97 rousseau 410 if (OpenPort(Lun, Channel) != STATUS_SUCCESS)
98 rousseau 269 {
99 rousseau 608 DEBUG_CRITICAL("OpenPort failed");
100 rousseau 269 return_value = IFD_COMMUNICATION_ERROR;
101     }
102    
103 rousseau 563 #ifdef HAVE_PTHREAD
104 rousseau 463 pthread_mutex_unlock(&ifdh_context_mutex);
105     #endif
106    
107 rousseau 269 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 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
125 rousseau 269
126     if (CheckLun(Lun))
127     return IFD_COMMUNICATION_ERROR;
128    
129     CmdPowerOff(Lun);
130 rousseau 410 /* No reader status check, if it failed, what can you do ? :) */
131 rousseau 269
132 rousseau 563 #ifdef HAVE_PTHREAD
133 rousseau 463 pthread_mutex_lock(&ifdh_context_mutex);
134     #endif
135    
136 rousseau 410 ClosePort(Lun);
137 rousseau 269
138 rousseau 563 #ifdef HAVE_PTHREAD
139 rousseau 463 pthread_mutex_unlock(&ifdh_context_mutex);
140     #endif
141    
142 rousseau 269 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 rousseau 608 DEBUG_INFO3("lun: %X, tag: %02X", Lun, Tag);
168 rousseau 269
169     if (CheckLun(Lun))
170     return IFD_COMMUNICATION_ERROR;
171    
172     switch (Tag)
173     {
174     case TAG_IFD_ATR:
175 rousseau 410 /* If Length is not zero, powerICC has been performed.
176     * Otherwise, return NULL pointer
177     * Buffer size is stored in *Length */
178 rousseau 269 *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 rousseau 563 #ifdef HAVE_PTHREAD
189 rousseau 269 case TAG_IFD_SIMULTANEOUS_ACCESS:
190     if (*Length >= 1)
191     {
192     *Length = 1;
193 rousseau 410 *Value = PCSCLITE_MAX_READERS;
194 rousseau 269 }
195     break;
196    
197 rousseau 463 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 rousseau 563 #endif
205 rousseau 463
206 rousseau 269 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 rousseau 569
218 rousseau 269 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 rousseau 410 /* By default, say it worked */
243 rousseau 269
244 rousseau 608 DEBUG_PERIODIC2("lun: %X", Lun);
245 rousseau 269
246     /* if (CheckLun(Lun))
247     return IFD_COMMUNICATION_ERROR; */
248    
249 rousseau 569 return IFD_NOT_SUPPORTED;
250 rousseau 269 } /* 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 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
272 rousseau 269
273     /* if (CheckLun(Lun))
274     return IFD_COMMUNICATION_ERROR; */
275    
276 rousseau 569 return IFD_NOT_SUPPORTED;
277 rousseau 269 } /* 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 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
324 rousseau 269
325 rousseau 410 /* By default, assume it won't work :) */
326 rousseau 269 *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 rousseau 410 /* Power up successful, set state variable to memorise it */
344 rousseau 269 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
345     MASK_POWERFLAGS_PUP;
346     CcidSlots[LunToReaderIndex(Lun)].bPowerFlags &=
347     ~MASK_POWERFLAGS_PDWN;
348    
349 rousseau 410 /* Reset is returned, even if TCK is wrong */
350 rousseau 269 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 rousseau 410 /* Clear ATR buffer */
359 rousseau 269 CcidSlots[LunToReaderIndex(Lun)].nATRLength = 0;
360     *CcidSlots[LunToReaderIndex(Lun)].pcATRBuffer = '\0';
361    
362 rousseau 410 /* Memorise the request */
363 rousseau 269 CcidSlots[LunToReaderIndex(Lun)].bPowerFlags |=
364     MASK_POWERFLAGS_PDWN;
365 rousseau 410 /* send the command */
366 rousseau 269 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 rousseau 410 RESPONSECODE return_value = IFD_SUCCESS; /* Assume it will work */
418 rousseau 269
419 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
420 rousseau 269
421     if (CheckLun(Lun))
422     return IFD_COMMUNICATION_ERROR;
423    
424 rousseau 410 switch (SendPci.Protocol)
425 rousseau 269 {
426     case T_0:
427     case T_1:
428     return_value = CmdXfrBlock(Lun, TxLength, TxBuffer, RxLength,
429     RxBuffer);
430     break;
431    
432     default:
433     return_value = IFD_PROTOCOL_NOT_SUPPORTED;
434     }
435    
436     if (return_value != IFD_SUCCESS)
437     *RxLength = 0;
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 rousseau 608 DEBUG_INFO2("lun: %X", Lun);
462 rousseau 269
463     /* if (CheckLun(Lun))
464     return IFD_COMMUNICATION_ERROR; */
465    
466 rousseau 568 /* Set the return length to 0 to avoid problems */
467     if (RxLength)
468     *RxLength = 0;
469    
470 rousseau 569 return IFD_NOT_SUPPORTED;
471 rousseau 269 } /* 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 rousseau 608 DEBUG_PERIODIC2("lun: %X", Lun);
488 rousseau 269
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    

Properties

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

  ViewVC Help
Powered by ViewVC 1.1.5