1 /*****************************************************************************
2 * Copyright ©2017-2019 Gemalto – a Thales Company. All rights Reserved.
3 *
4 * This copy is licensed under the Apache License, Version 2.0 (the "License");
5 * You may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0 or https://www.apache.org/licenses/LICENSE-2.0.html
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 * See the License for the specific language governing permissions and limitations under the License.
11
12 ****************************************************************************/
13
14 /**
15 * @file
16 * $Author$
17 * $Revision$
18 * $Date$
19 *
20 * T=1 implementation.
21 *
22 */
23
24 #include <stddef.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <stdint.h>
33 #include <fcntl.h>
34 #include <log/log.h>
35
36 #include "iso7816_t1.h"
37 #include "checksum.h"
38 #include "transport.h"
39
40 #define T1_REQUEST_RESYNC 0x00
41 #define T1_REQUEST_IFS 0x01
42 #define T1_REQUEST_ABORT 0x02
43 #define T1_REQUEST_WTX 0x03
44 #define T1_REQUEST_RESET 0x05 /* Custom RESET for SPI version */
45
46 #define MAX_RETRIES 3
47
48 #define MAX_WTX_ROUNDS 100
49
50 #define WTX_MAX_VALUE 1
51
52 static void
t1_init_recv_window(struct t1_state * t1,void * buf,size_t n)53 t1_init_recv_window(struct t1_state *t1, void *buf, size_t n)
54 {
55 t1->recv.start = t1->recv.end = buf;
56 t1->recv.size = n;
57 }
58
59 static ptrdiff_t
t1_recv_window_free_size(struct t1_state * t1)60 t1_recv_window_free_size(struct t1_state *t1)
61 {
62 return (ptrdiff_t)t1->recv.size - (t1->recv.end - t1->recv.start);
63 }
64
65 static void
t1_recv_window_append(struct t1_state * t1,const void * buf,int n)66 t1_recv_window_append(struct t1_state *t1, const void *buf, int n)
67 {
68 ptrdiff_t free = t1_recv_window_free_size(t1);
69 ALOGE("gto_esehal SecureElement:t1_recv_window_append free = %d\n", free);
70 if (n > free)
71 n = (int)free;
72 if (n > 0) {
73 memcpy(t1->recv.end, buf, (size_t)n);
74 t1->recv.end += n;
75 }
76 }
77
78 static ptrdiff_t
t1_recv_window_size(struct t1_state * t1)79 t1_recv_window_size(struct t1_state *t1)
80 {
81 return t1->recv.end - t1->recv.start;
82 }
83
84 static void
t1_close_recv_window(struct t1_state * t1)85 t1_close_recv_window(struct t1_state *t1)
86 {
87 t1->recv.start = t1->recv.end;
88 t1->recv.size = 0;
89 }
90
91 static void
t1_init_send_window(struct t1_state * t1,const void * buf,size_t n)92 t1_init_send_window(struct t1_state *t1, const void *buf, size_t n)
93 {
94 t1->send.start = buf;
95 t1->send.end = t1->send.start + n;
96 }
97
98 static ptrdiff_t
t1_send_window_size(struct t1_state * t1)99 t1_send_window_size(struct t1_state *t1)
100 {
101 return t1->send.end - t1->send.start;
102 }
103
104 static void
t1_close_send_window(struct t1_state * t1)105 t1_close_send_window(struct t1_state *t1)
106 {
107 t1->send.end = t1->send.start;
108 }
109
110 static int
do_chk(struct t1_state * t1,uint8_t * buf)111 do_chk(struct t1_state *t1, uint8_t *buf)
112 {
113 int n = 3 + buf[2];
114
115 switch (t1->chk_algo) {
116 case CHECKSUM_LRC:
117 buf[n] = lrc8(buf, n);
118 n++;
119 break;
120
121 case CHECKSUM_CRC: {
122 uint16_t crc = crc_ccitt(0xFFFF, buf, n);
123 buf[n++] = (uint8_t)(crc >> 8);
124 buf[n++] = (uint8_t)(crc);
125 break;
126 }
127 }
128 return n;
129 }
130
131 static int
chk_is_good(struct t1_state * t1,const uint8_t * buf)132 chk_is_good(struct t1_state *t1, const uint8_t *buf)
133 {
134 int n = 3 + buf[2];
135 int match;
136
137 switch (t1->chk_algo) {
138 case CHECKSUM_LRC:
139 match = (buf[n] == lrc8(buf, n));
140 break;
141
142 case CHECKSUM_CRC: {
143 uint16_t crc = crc_ccitt(0xFFFF, buf, n);
144 match = (crc == (buf[n + 1] | (buf[n] << 8)));
145 break;
146 }
147
148 default:
149 match = 0;
150 }
151 return match;
152 }
153
154 static int
write_iblock(struct t1_state * t1,uint8_t * buf)155 write_iblock(struct t1_state *t1, uint8_t *buf)
156 {
157 ptrdiff_t n = t1_send_window_size(t1);
158 uint8_t pcb;
159
160 /* Card asking for more data whereas nothing is left.*/
161 if (n <= 0)
162 return -EBADMSG;
163
164 if (n > t1->ifsc)
165 n = t1->ifsc, pcb = 0x20;
166 else
167 pcb = 0;
168
169 if (t1->send.next)
170 pcb |= 0x40;
171
172 buf[0] = t1->nad;
173 buf[1] = pcb;
174 buf[2] = (uint8_t)n;
175 memcpy(buf + 3, t1->send.start, (size_t)n);
176 return do_chk(t1, buf);
177 }
178
179 static int
write_rblock(struct t1_state * t1,int n,uint8_t * buf)180 write_rblock(struct t1_state *t1, int n, uint8_t *buf)
181 {
182 buf[0] = t1->nad;
183 buf[1] = 0x80 | (n & 3);
184 if (t1->recv.next)
185 buf[1] |= 0x10;
186 buf[2] = 0;
187 return do_chk(t1, buf);
188 }
189
190 static int
write_request(struct t1_state * t1,int request,uint8_t * buf)191 write_request(struct t1_state *t1, int request, uint8_t *buf)
192 {
193 buf[0] = t1->nad;
194 buf[1] = 0xC0 | request;
195
196 request &= 0x1F;
197 if (T1_REQUEST_IFS == request) {
198 /* On response, resend card IFS, else this is request for device IFS */
199 buf[2] = 1;
200 if (buf[1] & 0x20)
201 buf[3] = t1->ifsc;
202 else
203 buf[3] = t1->ifsd;
204 } else if (T1_REQUEST_WTX == request) {
205 buf[2] = 1;
206 buf[3] = t1->wtx;
207 } else
208 buf[2] = 0;
209
210 return do_chk(t1, buf);
211 }
212
213 static void
ack_iblock(struct t1_state * t1)214 ack_iblock(struct t1_state *t1)
215 {
216 ptrdiff_t n = t1_send_window_size(t1);
217
218 if (n > t1->ifsc)
219 n = t1->ifsc;
220 t1->send.start += n;
221
222 /* Next packet sequence number */
223 t1->send.next ^= 1;
224 }
225
226 /* 0 if not more block, 1 otherwize */
227 static int
parse_iblock(struct t1_state * t1,uint8_t * buf)228 parse_iblock(struct t1_state *t1, uint8_t *buf)
229 {
230 uint8_t pcb = buf[1];
231 uint8_t next = !!(pcb & 0x40);
232
233 if (t1->recv.next == next) {
234 t1->recv.next ^= 1;
235 t1_recv_window_append(t1, buf + 3, buf[2]);
236 t1->recv_size += buf[2];
237 }
238
239 /* 1 if more to come */
240 return !!(pcb & 0x20);
241 }
242
243 static int
parse_rblock(struct t1_state * t1,uint8_t * buf)244 parse_rblock(struct t1_state *t1, uint8_t *buf)
245 {
246 int r = 0;
247 uint8_t pcb = buf[1];
248 uint8_t next = !!(pcb & 0x10);
249
250 switch (pcb & 0x2F) {
251 case 0:
252 if ((t1->send.next ^ next) != 0) {
253 /* Acknowledge previous block */
254 t1->retries = MAX_RETRIES;
255 ack_iblock(t1);
256 } else {
257 t1->retries--;
258 if (t1->retries <= 0) r = -ETIMEDOUT;
259 }
260 break;
261
262 case 1:
263 t1->retries--;
264 t1->send.next = next;
265 r = -EREMOTEIO;
266 /* CRC error on previous block, will resend */
267 break;
268
269 case 2:
270 /* Error */
271 t1->state.halt = 1; r = -EIO;
272 break;
273
274 case 3:
275 t1->retries--;
276 r = -EREMOTEIO;
277 t1->state.request = 1;
278 t1->request = T1_REQUEST_RESYNC;
279 break;
280
281 default:
282 t1->state.halt = 1; r = -EOPNOTSUPP;
283 break;
284 }
285 return r;
286 }
287
288 static int
parse_request(struct t1_state * t1,uint8_t * buf)289 parse_request(struct t1_state *t1, uint8_t *buf)
290 {
291 int n = 0;
292
293 uint8_t request = buf[1] & 0x3F;
294
295 t1->request = request;
296 switch (request) {
297 case T1_REQUEST_RESYNC:
298 n = -EOPNOTSUPP;
299 break;
300
301 case T1_REQUEST_IFS:
302 if (buf[2] != 1)
303 n = -EBADMSG;
304 else if ((buf[3] == 0) || (buf[3] == 0xFF))
305 n = -EBADMSG;
306 else
307 t1->ifsc = buf[3];
308 break;
309
310 case T1_REQUEST_ABORT:
311 if (buf[2] == 0) {
312 t1->state.aborted = 1;
313 t1_close_send_window(t1);
314 t1_close_recv_window(t1);
315 } else
316 n = -EBADMSG;
317 break;
318
319 case T1_REQUEST_WTX:
320 if (buf[2] > 1) {
321 n = -EBADMSG;
322 break;
323 } else if (buf[2] == 1) {
324 t1->wtx = buf[3];
325 if (t1->wtx_max_value)
326 if (t1->wtx > WTX_MAX_VALUE)
327 t1->wtx = WTX_MAX_VALUE;
328 if (t1->wtx_max_rounds) {
329 t1->wtx_rounds--;
330 if (t1->wtx_rounds <= 0) {
331 t1->retries = 0;
332 n = -EBADE;
333 }
334 }
335 }
336 break;
337
338 default:
339 n = -EOPNOTSUPP;
340 break;
341 }
342
343 /* Prepare response for next loop step */
344 if (n == 0)
345 t1->state.reqresp = 1;
346
347 return n;
348 }
349
350 /* Find if ATR is changing IFSC value */
351 static void
parse_atr(struct t1_state * t1)352 parse_atr(struct t1_state *t1)
353 {
354 const uint8_t *atr = t1->atr;
355 size_t n = t1->atr_length;
356 int c, y, tck, proto = 0, ifsc = -1;
357
358 /* Parse T0 byte */
359 tck = y = (n > 0 ? atr[0] : 0);
360
361 /* Parse interface bytes */
362 for (size_t j = 1; j < n; j++) {
363 c = atr[j];
364 tck ^= c;
365
366 if ((y & 0xF0) == 0x80)
367 /* This is TDi byte */
368 y = c, proto |= (1 << (c & 15));
369 else if (y >= 16) {
370 /* First TA for T=1 */
371 if ((ifsc < 0) && ((y & 0x1F) == 0x11))
372 ifsc = c;
373 /* Clear interface byte flag just seen */
374 y &= y - 16;
375 } else /* No more interface bytes */
376 y = -1;
377 }
378
379 /* If TA for T=1 seen and ATR checksum is valid */
380 if ((proto & 2) && (tck == 0))
381 t1->ifsc = (uint8_t)ifsc;
382 }
383
384 /* 1 if expected response, 0 if reemit I-BLOCK, negative value is error */
385 static int
parse_response(struct t1_state * t1,uint8_t * buf)386 parse_response(struct t1_state *t1, uint8_t *buf)
387 {
388 int r;
389 uint8_t pcb = buf[1];
390
391 r = 0;
392
393 /* Not a response ? */
394 if (pcb & 0x20) {
395 pcb &= 0x1F;
396 if (pcb == t1->request) {
397 r = 1;
398 switch (pcb) {
399 case T1_REQUEST_IFS:
400 t1->need_ifsd_sync = 0;
401 if ((buf[2] != 1) && (buf[3] != t1->ifsd))
402 r = -EBADMSG;
403 break;
404
405 case T1_REQUEST_RESET:
406 t1->need_reset = 0;
407 if (buf[2] <= sizeof(t1->atr)) {
408 t1->atr_length = buf[2];
409 if (t1->atr_length)
410 memcpy(t1->atr, buf + 3, t1->atr_length);
411 parse_atr(t1);
412 } else
413 r = -EBADMSG;
414 break;
415 case T1_REQUEST_RESYNC:
416 t1->need_resync = 0;
417 t1->send.next = 0;
418 t1->recv.next = 0;
419 break;
420 case T1_REQUEST_ABORT:
421
422 default:
423 /* We never emitted those requests */
424 r = -EBADMSG;
425 break;
426 }
427 }
428 }
429 return r;
430 }
431
432 enum { T1_IBLOCK, T1_RBLOCK, T1_SBLOCK };
433
434 static int
block_kind(const uint8_t * buf)435 block_kind(const uint8_t *buf)
436 {
437 if ((buf[1] & 0x80) == 0)
438 return T1_IBLOCK;
439 else if ((buf[1] & 0x40) == 0)
440 return T1_RBLOCK;
441 else
442 return T1_SBLOCK;
443 }
444
445 static int
read_block(struct t1_state * t1)446 read_block(struct t1_state *t1)
447 {
448 int n;
449
450 n = block_recv(t1, t1->buf, sizeof(t1->buf));
451
452 if (n < 0)
453 return n;
454 else if (n < 3)
455 return -EBADMSG;
456 else {
457 if (!chk_is_good(t1, t1->buf))
458 return -EREMOTEIO;
459
460 if (t1->buf[0] != t1->nadc)
461 return -EBADMSG;
462
463 if (t1->buf[2] == 255)
464 return -EBADMSG;
465 }
466
467 return n;
468 }
469
470 static int
t1_loop(struct t1_state * t1)471 t1_loop(struct t1_state *t1)
472 {
473 int len;
474 int n = 0;
475
476 /* Will happen on first run */
477 if (t1->need_reset) {
478 t1->state.request = 1;
479 t1->request = T1_REQUEST_RESET;
480 } else if (t1->need_resync) {
481 t1->state.request = 1;
482 t1->request = T1_REQUEST_RESYNC;
483 }else if(t1->need_ifsd_sync){
484 t1->state.request = 1;
485 t1->request = T1_REQUEST_IFS;
486 t1->ifsd = 254;
487 }
488
489 while (!t1->state.halt && t1->retries) {
490 if (t1->state.request)
491 n = write_request(t1, t1->request, t1->buf);
492 else if (t1->state.reqresp) {
493 n = write_request(t1, 0x20 | t1->request, t1->buf);
494 /* If response is not seen, card will repost request */
495 t1->state.reqresp = 0;
496 } else if (t1->state.badcrc)
497 /* FIXME "1" -> T1_RBLOCK_CRC_ERROR */
498 n = write_rblock(t1, 1, t1->buf);
499 else if (t1->state.timeout)
500 n = write_rblock(t1, 0, t1->buf);
501 else if (t1_send_window_size(t1))
502 n = write_iblock(t1, t1->buf);
503 else if (t1->state.aborted)
504 n = -EPIPE;
505 else if (t1_recv_window_size(t1) >= 0)
506 /* Acknowledges block received so far */
507 n = write_rblock(t1, 0, t1->buf);
508 else
509 /* Card did not send an I-BLOCK for response */
510 n = -EBADMSG;
511
512 if (n < 0)
513 break;
514
515 len = block_send(t1, t1->buf, n);
516 if (len < 0) {
517 /* failure to send is permanent, give up immediately */
518 n = len;
519 break;
520 }
521
522 n = read_block(t1);
523 if (n < 0) {
524 t1->retries--;
525 switch (n) {
526 /* Error that trigger recovery */
527 case -EREMOTEIO:
528 /* Emit checksum error R-BLOCK */
529 t1->state.badcrc = 1;
530 continue;
531
532 case -ETIMEDOUT:
533 /* resend block */
534 t1->state.timeout = 1;
535 /* restore checksum failure error */
536 if (t1->state.badcrc)
537 n = -EREMOTEIO;
538 continue;
539
540 /* Block read implementation failed */
541 case -EBADMSG: /* fall through */
542
543 /* Other errors are platform specific and not recoverable. */
544 default:
545 t1->retries = 0;
546 continue;
547 }
548 /* Shall never reach this line */
549 break;
550 }
551
552 if (t1->state.badcrc)
553 if ((t1->buf[1] & 0xEF) == 0x81) {
554 /* Resent bad checksum R-BLOCK when response is CRC failure. */
555 t1->retries--;
556 n = -EREMOTEIO;
557 continue;
558 }
559
560 t1->state.badcrc = 0;
561 t1->state.timeout = 0;
562
563 if (t1->state.request) {
564 if (block_kind(t1->buf) == T1_SBLOCK) {
565 n = parse_response(t1, t1->buf);
566 switch (n) {
567 case 0:
568 /* Asked to emit same former I-BLOCK */
569 break;
570
571 case 1:
572 t1->state.request = 0;
573 /* Nothing to do ? leave */
574 if (t1_recv_window_free_size(t1) == 0)
575 t1->state.halt = 1, n = 0;
576 t1->retries = MAX_RETRIES;
577 if(t1->request == T1_REQUEST_RESET) {
578 t1->state.request = 1;
579 t1->request = T1_REQUEST_IFS;
580 t1->ifsd = 254;
581 t1->need_ifsd_sync = 1;
582 }
583 continue;
584
585 default: /* Negative return is error */
586 t1->state.halt = 1;
587 continue;
588 }
589 }
590 /* Re-emit request until response received */
591 t1->retries--;
592 n = -EBADE;
593 } else {
594 switch (block_kind(t1->buf)) {
595 case T1_IBLOCK:
596 t1->retries = MAX_RETRIES;
597 if (t1_send_window_size(t1))
598 /* Acknowledges last IBLOCK sent */
599 ack_iblock(t1);
600 n = parse_iblock(t1, t1->buf);
601 if (t1->state.aborted)
602 continue;
603 if (t1->recv_size > t1->recv_max) {
604 /* Too much data received */
605 n = -EMSGSIZE;
606 t1->state.halt = 1;
607 continue;
608 }
609 if ((n == 0) && (t1_send_window_size(t1) == 0))
610 t1->state.halt = 1;
611 t1->wtx_rounds = t1->wtx_max_rounds;
612 break;
613
614 case T1_RBLOCK:
615 n = parse_rblock(t1, t1->buf);
616 t1->wtx_rounds = t1->wtx_max_rounds;
617 break;
618
619 case T1_SBLOCK:
620 n = parse_request(t1, t1->buf);
621 if (n == 0)
622 /* Send request response on next loop. */
623 t1->state.reqresp = 1;
624 else if ((n == -EBADMSG) || (n == -EOPNOTSUPP))
625 t1->state.halt = 1;
626 break;
627 }
628 }
629 }
630 return n;
631 }
632
633 static void
t1_clear_states(struct t1_state * t1)634 t1_clear_states(struct t1_state *t1)
635 {
636 t1->state.halt = 0;
637 t1->state.request = 0;
638 t1->state.reqresp = 0;
639 t1->state.badcrc = 0;
640 t1->state.timeout = 0;
641 t1->state.aborted = 0;
642
643 t1->wtx = 1;
644 t1->retries = MAX_RETRIES;
645 t1->request = 0xFF;
646
647 t1->wtx_rounds = t1->wtx_max_rounds;
648
649 t1->send.start = t1->send.end = NULL;
650 t1->recv.start = t1->recv.end = NULL;
651 t1->recv.size = 0;
652
653 t1->recv_size = 0; /* Also count discarded bytes */
654 }
655
656 static void
t1_init(struct t1_state * t1)657 t1_init(struct t1_state *t1)
658 {
659 t1_clear_states(t1);
660
661 t1->chk_algo = CHECKSUM_LRC;
662 t1->ifsc = 32;
663 t1->ifsd = 32;
664 t1->bwt = 300; /* milliseconds */
665
666 t1->send.next = 0;
667 t1->recv.next = 0;
668
669 t1->need_reset = 1;
670 t1->need_resync = 0;
671 t1->spi_fd = -1;
672
673 t1->wtx_max_rounds = MAX_WTX_ROUNDS;
674 t1->wtx_max_value = 1;
675
676 t1->recv_max = 65536 + 2; /* Maximum for extended APDU response */
677 t1->recv_size = 0;
678 }
679
680 static void
t1_release(struct t1_state * t1)681 t1_release(struct t1_state *t1)
682 {
683 t1->state.halt = 1;
684 }
685
686 static void
t1_bind(struct t1_state * t1,int src,int dst)687 t1_bind(struct t1_state *t1, int src, int dst)
688 {
689 src &= 7;
690 dst &= 7;
691
692 t1->nad = src | (dst << 4);
693 t1->nadc = dst | (src << 4);
694 }
695
696 static int
697 t1_reset(struct t1_state *t1);
698
699 static int
t1_transceive(struct t1_state * t1,const void * snd_buf,size_t snd_len,void * rcv_buf,size_t rcv_len)700 t1_transceive(struct t1_state *t1, const void *snd_buf,
701 size_t snd_len, void *rcv_buf, size_t rcv_len)
702 {
703 int n, r;
704
705 t1_clear_states(t1);
706
707 t1_init_send_window(t1, snd_buf, snd_len);
708 t1_init_recv_window(t1, rcv_buf, rcv_len);
709
710 n = t1_loop(t1);
711 if (n == 0)
712 /* Received APDU response */
713 n = (int)t1_recv_window_size(t1);
714 else if (n < 0 && t1->state.aborted != 1){
715 if (!(t1->state.request == 1 && t1->request == T1_REQUEST_RESET))
716 {
717 /*Request Soft RESET to the secure element*/
718 r = t1_reset(t1);
719 if (r < 0) n = -0xDEAD; /*Fatal error meaning eSE is not responding to reset*/
720 }
721 }
722 return n;
723 }
724
725 static int
t1_negotiate_ifsd(struct t1_state * t1,int ifsd)726 t1_negotiate_ifsd(struct t1_state *t1, int ifsd)
727 {
728 t1_clear_states(t1);
729 t1->state.request = 1;
730
731 t1->request = T1_REQUEST_IFS;
732 t1->ifsd = ifsd;
733 return t1_loop(t1);
734 }
735
736 static int
t1_reset(struct t1_state * t1)737 t1_reset(struct t1_state *t1)
738 {
739 t1_clear_states(t1);
740 t1->need_reset = 1;
741
742 return t1_loop(t1);
743 }
744
745 static int
t1_resync(struct t1_state * t1)746 t1_resync(struct t1_state *t1)
747 {
748 t1_clear_states(t1);
749 t1->need_resync = 1;
750
751 return t1_loop(t1);
752 }
753
754 void
isot1_init(struct t1_state * t1)755 isot1_init(struct t1_state *t1)
756 {
757 return t1_init(t1);
758 }
759
760 void
isot1_release(struct t1_state * t1)761 isot1_release(struct t1_state *t1)
762 {
763 t1_release(t1);
764 }
765
766 void
isot1_bind(struct t1_state * t1,int src,int dst)767 isot1_bind(struct t1_state *t1, int src, int dst)
768 {
769 t1_bind(t1, src, dst);
770 }
771
772 int
isot1_transceive(struct t1_state * t1,const void * snd_buf,size_t snd_len,void * rcv_buf,size_t rcv_len)773 isot1_transceive(struct t1_state *t1, const void *snd_buf,
774 size_t snd_len, void *rcv_buf, size_t rcv_len)
775 {
776 return t1_transceive(t1, snd_buf, snd_len, rcv_buf, rcv_len);
777 }
778
779 int
isot1_negotiate_ifsd(struct t1_state * t1,int ifsd)780 isot1_negotiate_ifsd(struct t1_state *t1, int ifsd)
781 {
782 return t1_negotiate_ifsd(t1, ifsd);
783 }
784
785 int
isot1_reset(struct t1_state * t1)786 isot1_reset(struct t1_state *t1)
787 {
788 return t1_reset(t1);
789 }
790
791 int
isot1_resync(struct t1_state * t1)792 isot1_resync(struct t1_state *t1)
793 {
794 return t1_resync(t1);
795 }
796
797 int
isot1_get_atr(struct t1_state * t1,void * atr,size_t n)798 isot1_get_atr(struct t1_state *t1, void *atr, size_t n)
799 {
800 int r = 0;
801
802 if (t1->need_reset)
803 r = t1_reset(t1);
804 if (r >= 0) {
805 if (t1->atr_length <= n) {
806 r = t1->atr_length;
807 memcpy(atr, t1->atr, r);
808 } else
809 r = -EFAULT;
810 }
811 return r;
812 }
813