1 /* $Id: scrw.c,v 1.6 2001/07/20 15:51:45 rees Exp $ */
2 
3 /*
4 copyright 1997, 1999, 2000
5 the regents of the university of michigan
6 all rights reserved
7 
8 permission is granted to use, copy, create derivative works
9 and redistribute this software and such derivative works
10 for any purpose, so long as the name of the university of
11 michigan is not used in any advertising or publicity
12 pertaining to the use or distribution of this software
13 without specific, written prior authorization.  if the
14 above copyright notice or any other identification of the
15 university of michigan is included in any copy of any
16 portion of this software, then the disclaimer below must
17 also be included.
18 
19 this software is provided as is, without representation
20 from the university of michigan as to its fitness for any
21 purpose, and without warranty by the university of
22 michigan of any kind, either express or implied, including
23 without limitation the implied warranties of
24 merchantability and fitness for a particular purpose. the
25 regents of the university of michigan shall not be liable
26 for any damages, including special, indirect, incidental, or
27 consequential damages, with respect to any claim arising
28 out of or in connection with the use of the software, even
29 if it has been or is hereafter advised of the possibility of
30 such damages.
31 */
32 
33 /*
34  * OS independent part
35  *
36  * Jim Rees, University of Michigan, October 1997
37  */
38 
39 #ifdef __palmos__
40 #include <Common.h>
41 #include <System/SysAll.h>
42 #include <System/Unix/unix_stdio.h>
43 #include <System/Unix/unix_stdlib.h>
44 #include <System/Unix/unix_string.h>
45 #include <UI/UIAll.h>
46 #include "field.h"
47 #else
48 #include <stdio.h>
49 #include <string.h>
50 #endif
51 #ifdef SCPERF
52 #define SCPERF_FIRST_APPEARANCE
53 #endif /* SCPERF */
54 #include "sectok.h"
55 #include "sc7816.h"
56 #include "todos_scrw.h"
57 
58 /* external variable */
59 #ifdef BYTECOUNT
60 extern int num_getc, num_putc;
61 #endif /* BYTECOUNT */
62 
63 struct scparam scparam[4];
64 
65 /* reset the card, and return answer to reset (atr) */
66 
67 int
todos_scxreset(int ttyn,int flags,unsigned char * atr,int * ep)68 todos_scxreset(int ttyn, int flags, unsigned char *atr, int *ep)
69 {
70     unsigned char buf[33];
71     int n, err;
72 
73     if (ep)
74 	*ep = SCEOK;
75     else
76 	ep = &err;
77 
78     if (!todos_sccardpresent(ttyn)) {
79 	*ep = SCENOCARD;
80 	return 0;
81     }
82 
83     if (!atr)
84 	atr = buf;
85 
86     if (!(flags & SCRTODOS) && (todos_scsetflags(ttyn, 0, 0) & SCOXDTR))
87 	flags |= SCRTODOS;
88 
89     todos_scsetspeed(ttyn, 9600);
90     todos_scsetflags(ttyn, 0, SCOINVRT);
91 
92     if (todos_scdtr(ttyn, (flags & SCRTODOS)) < 0) {
93 	*ep = SCENOCARD;
94 	return 0;
95     }
96 
97     /* 7816-3 sec 5.2 says >= 40000 clock cycles, ~=12 msec */
98     scsleep(20);
99 
100     todos_scdtr(ttyn, !(flags & SCRTODOS));
101 
102     n = todos_get_atr(ttyn, flags, atr, &scparam[ttyn]);
103     if (!n && ep)
104 	*ep = SCESLAG;
105     if (scparam[ttyn].t < 0 && ep)
106 	*ep = SCENOSUPP;
107 
108     return n;
109 }
110 
111 static int
todos_scioproc(int ttyn,int io,unsigned char * cp)112 todos_scioproc(int ttyn, int io, unsigned char *cp)
113 {
114     int code;
115 
116     /* Wait extra guard time if needed */
117     if (!io && scparam[ttyn].n)
118 	scsleep(((scparam[ttyn].n * scparam[ttyn].etu) + 999) / 1000);
119 
120     code = (!io ? scputc(ttyn, *cp) : scgetc(ttyn, cp, scparam[ttyn].cwt));
121 
122     return code;
123 }
124 
125 /* This does the real work of transferring data to or from the card.  Since the ack
126    handling is the same for both send and receive, we do it all here. */
127 
128 static int
todos_scioT0(int ttyn,int io,int cla,int ins,int p1,int p2,int p3,unsigned char * buf,int * sw1p,int * sw2p)129 todos_scioT0(int ttyn, int io, int cla, int ins, int p1, int p2, int p3, unsigned char *buf, int *sw1p, int *sw2p)
130 {
131     int n = 0, ack, ackxins;
132     unsigned char *bp = buf, c, apdu[5];
133 #ifdef BYTECOUNT
134     int tmp_num_getc, tmp_num_putc;
135 #endif /* BYTECOUNT */
136 
137 #ifdef BYTECOUNT
138     tmp_num_getc = num_getc;
139     tmp_num_putc = num_putc;
140 #endif /* BYTECOUNT */
141 
142 #ifdef SCPERF
143     SetTime("SCIO starts");
144 #endif /* SCPERF */
145 
146 #ifdef DEBUG
147     printf("scioT0 %3s %02x %02x %02x %02x %02x\n", io ? "out" : "in", cla, ins, p1, p2, p3);
148 #endif
149 
150     apdu[0] = cla;
151     apdu[1] = ins;
152     apdu[2] = p1;
153     apdu[3] = p2;
154     apdu[4] = p3;
155     scputblk(ttyn, apdu, 5);
156 
157 #ifdef SCPERF
158     SetTime("Finish sending APDU");
159 #endif /* SCPERF */
160 
161     while (1) {
162 	/* read ack byte; see 7816-3 8.2.2 */
163 	if (scgetc(ttyn, &c, scparam[ttyn].cwt) != SCEOK) {
164 #ifdef DEBUG
165 	    printf("%d ms timeout reading ack\n", scparam[ttyn].cwt);
166 #endif
167 	    return -1;
168 	}
169 	ack = c;
170 
171 	if (ack == 0x60) {
172 	    /* null (no-op but resets timer) */
173 #ifdef DEBUG
174 	    printf("got 0x60 (null) ack; reset timer\n");
175 #endif
176 	    continue;
177 	}
178 
179 	if ((ack & 0xf0) == 0x60 || (ack & 0xf0) == 0x90) {
180 	    /* SW1; get SW2 and return */
181 	    *sw1p = ack;
182 	    if (scgetc(ttyn, &c, scparam[ttyn].cwt) != SCEOK) {
183 #ifdef DEBUG
184 		printf("%d ms timeout reading sw2\n", scparam[ttyn].cwt);
185 #endif
186 		return -1;
187 	    }
188 	    *sw2p = (c & 0xff);
189 	    break;
190 	}
191 
192 	/* we would set VPP here if the interface supported it */
193 
194 	ackxins = (ack ^ ins) & 0xfe;
195 	if (ackxins == 0xfe) {
196 	    if (n < p3) {
197 		/* xfer next data byte */
198 		if (todos_scioproc(ttyn, io, bp++) != SCEOK) {
199 #ifdef DEBUG
200 		    printf("%d ms timeout reading next data byte\n", scparam[ttyn].cwt);
201 #endif
202 		    return -1;
203 		}
204 		n++;
205 	    }
206 
207 	} else if (ackxins == 0) {
208 	    /* xfer all remaining data bytes */
209 	    while (n < p3) {
210 		if (todos_scioproc(ttyn, io, bp++) != SCEOK) {
211 #ifdef DEBUG
212 		    printf("%d ms timeout reading all remaining data bytes\n", scparam[ttyn].cwt);
213 #endif
214 		    return -1;
215 		}
216 		n++;
217 	    }
218 #ifdef SCPERF
219 	    SetTime("Finish sending or receiving DATA");
220 #endif /* SCPERF */
221 	} else {
222 	    /* ?? unknown ack byte */
223 #ifdef DEBUG
224 	    printf("unknown ack %x\n", ack);
225 	    continue;
226 #else
227 	    return -1;
228 #endif
229 	}
230     }
231 
232 #ifdef SCPERF
233     SetTime("Finish scio");
234 #endif /* SCPERF */
235 
236 #ifdef BYTECOUNT
237     tmp_num_putc = num_putc - tmp_num_putc;
238     tmp_num_getc = num_getc - tmp_num_getc - tmp_num_putc;
239     MESSAGE3("#getc=%d, #putc=%d\n", tmp_num_getc, tmp_num_putc);
240 #endif /* BYTECOUNT */
241 
242     return n;
243 }
244 
245 int
todos_scrw(int ttyn,int cla,int ins,int p1,int p2,int ilen,unsigned char * ibuf,int olen,unsigned char * obuf,int * sw1p,int * sw2p)246 todos_scrw(int ttyn, int cla, int ins, int p1, int p2, int ilen, unsigned char *ibuf, int olen, unsigned char *obuf, int *sw1p, int *sw2p)
247 {
248     int r;
249 
250     if (scparam[ttyn].t == 0) {
251 	if (ilen > 0 && ibuf) {
252 	    /* Send "in" data */
253 	    r = (todos_scioT0(ttyn, 0, cla, ins, p1, p2, ilen, ibuf, sw1p, sw2p) >= 0) ? 0 : -1;
254 	    if (r >= 0 && *sw1p == 0x61 && olen >= *sw2p && obuf) {
255 		/* Response available; get it */
256 		r = todos_scioT0(ttyn, 1, cla, 0xc0, 0, 0, *sw2p, obuf, sw1p, sw2p);
257 	    }
258 	} else {
259 	    /* Get "out" data */
260 	    r = todos_scioT0(ttyn, 1, cla, ins, p1, p2, olen, obuf, sw1p, sw2p);
261 	}
262 #ifndef NO_T_EQ_1
263     } else if (scparam[ttyn].t == 1) {
264 	r = scioT1(ttyn, cla, ins, p1, p2, ilen, ibuf, olen, obuf, sw1p, sw2p);
265 #endif
266     } else
267 	r = -1;
268 
269     return r;
270 }
271