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