1 /* ccidmon.c - CCID monitor for use with the Linux usbmon facility.
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 /* This utility takes the output of usbmon, filters out the bulk data
22 and prints the CCID messages in a human friendly way.
41 #ifndef PACKAGE_VERSION
42 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
44 #ifndef PACKAGE_BUGREPORT
45 # define PACKAGE_BUGREPORT "devnull@example.org"
52 static int skip_escape
;
53 static int usb_bus
, usb_dev
;
69 RDR_to_PC_NotifySlotChange
= 0x50,
70 RDR_to_PC_HardwareError
= 0x51,
72 PC_to_RDR_SetParameters
= 0x61,
73 PC_to_RDR_IccPowerOn
= 0x62,
74 PC_to_RDR_IccPowerOff
= 0x63,
75 PC_to_RDR_GetSlotStatus
= 0x65,
76 PC_to_RDR_Secure
= 0x69,
77 PC_to_RDR_T0APDU
= 0x6a,
78 PC_to_RDR_Escape
= 0x6b,
79 PC_to_RDR_GetParameters
= 0x6c,
80 PC_to_RDR_ResetParameters
= 0x6d,
81 PC_to_RDR_IccClock
= 0x6e,
82 PC_to_RDR_XfrBlock
= 0x6f,
83 PC_to_RDR_Mechanical
= 0x71,
84 PC_to_RDR_Abort
= 0x72,
85 PC_to_RDR_SetDataRate
= 0x73,
87 RDR_to_PC_DataBlock
= 0x80,
88 RDR_to_PC_SlotStatus
= 0x81,
89 RDR_to_PC_Parameters
= 0x82,
90 RDR_to_PC_Escape
= 0x83,
91 RDR_to_PC_DataRate
= 0x84
95 #define digitp(p) ((p) >= '0' && (p) <= '9')
96 #define hexdigitp(a) (digitp (a) \
97 || ((a) >= 'A' && (a) <= 'F') \
98 || ((a) >= 'a' && (a) <= 'f'))
99 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
100 #define xtoi_1(p) ((p) <= '9'? ((p)- '0'): \
101 (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
105 /* Print diagnostic message and exit with failure. */
107 die (const char *format
, ...)
112 fprintf (stderr
, "%s: ", PGM
);
114 va_start (arg_ptr
, format
);
115 vfprintf (stderr
, format
, arg_ptr
);
123 /* Print diagnostic message. */
125 err (const char *format
, ...)
132 fprintf (stderr
, "%s: ", PGM
);
134 va_start (arg_ptr
, format
);
135 vfprintf (stderr
, format
, arg_ptr
);
141 /* Convert a little endian stored 4 byte value into an unsigned
144 convert_le_u32 (const unsigned char *buf
)
146 return buf
[0] | (buf
[1] << 8) | (buf
[2] << 16) | (buf
[3] << 24);
150 /* Convert a little endian stored 2 byte value into an unsigned
153 convert_le_u16 (const unsigned char *buf
)
155 return buf
[0] | (buf
[1] << 8);
162 print_pr_data (const unsigned char *data
, size_t datalen
, size_t off
)
167 for (; off
< datalen
; off
++)
169 if (!(off
% 16) || first
)
173 printf (" [%04d] ", off
);
175 printf (" %02X", data
[off
]);
185 print_p2r_header (const char *name
, const unsigned char *msg
, size_t msglen
)
187 printf ("%s:\n", name
);
190 printf (" dwLength ..........: %u\n", convert_le_u32 (msg
+1));
191 printf (" bSlot .............: %u\n", msg
[5]);
192 printf (" bSeq ..............: %u\n", msg
[6]);
197 print_p2r_iccpoweron (const unsigned char *msg
, size_t msglen
)
199 print_p2r_header ("PC_to_RDR_IccPowerOn", msg
, msglen
);
202 printf (" bPowerSelect ......: 0x%02x (%s)\n", msg
[7],
204 msg
[7] == 1? "5.0 V":
205 msg
[7] == 2? "3.0 V":
206 msg
[7] == 3? "1.8 V":"");
207 print_pr_data (msg
, msglen
, 8);
212 print_p2r_iccpoweroff (const unsigned char *msg
, size_t msglen
)
214 print_p2r_header ("PC_to_RDR_IccPowerOff", msg
, msglen
);
215 print_pr_data (msg
, msglen
, 7);
220 print_p2r_getslotstatus (const unsigned char *msg
, size_t msglen
)
222 print_p2r_header ("PC_to_RDR_GetSlotStatus", msg
, msglen
);
223 print_pr_data (msg
, msglen
, 7);
228 print_p2r_xfrblock (const unsigned char *msg
, size_t msglen
)
232 print_p2r_header ("PC_to_RDR_XfrBlock", msg
, msglen
);
235 printf (" bBWI ..............: 0x%02x\n", msg
[7]);
236 val
= convert_le_u16 (msg
+8);
237 printf (" wLevelParameter ...: 0x%04x%s\n", val
,
238 val
== 1? " (continued)":
239 val
== 2? " (continues+ends)":
240 val
== 3? " (continues+continued)":
241 val
== 16? " (DataBlock-expected)":"");
242 print_pr_data (msg
, msglen
, 10);
247 print_p2r_getparameters (const unsigned char *msg
, size_t msglen
)
249 print_p2r_header ("PC_to_RDR_GetParameters", msg
, msglen
);
250 print_pr_data (msg
, msglen
, 7);
255 print_p2r_resetparameters (const unsigned char *msg
, size_t msglen
)
257 print_p2r_header ("PC_to_RDR_ResetParameters", msg
, msglen
);
258 print_pr_data (msg
, msglen
, 7);
263 print_p2r_setparameters (const unsigned char *msg
, size_t msglen
)
265 print_p2r_header ("PC_to_RDR_SetParameters", msg
, msglen
);
268 printf (" bProtocolNum ......: 0x%02x\n", msg
[7]);
269 print_pr_data (msg
, msglen
, 8);
274 print_p2r_escape (const unsigned char *msg
, size_t msglen
)
278 print_p2r_header ("PC_to_RDR_Escape", msg
, msglen
);
279 print_pr_data (msg
, msglen
, 7);
284 print_p2r_iccclock (const unsigned char *msg
, size_t msglen
)
286 print_p2r_header ("PC_to_RDR_IccClock", msg
, msglen
);
289 printf (" bClockCommand .....: 0x%02x\n", msg
[7]);
290 print_pr_data (msg
, msglen
, 8);
295 print_p2r_to0apdu (const unsigned char *msg
, size_t msglen
)
297 print_p2r_header ("PC_to_RDR_T0APDU", msg
, msglen
);
300 printf (" bmChanges .........: 0x%02x\n", msg
[7]);
301 printf (" bClassGetResponse .: 0x%02x\n", msg
[8]);
302 printf (" bClassEnvelope ....: 0x%02x\n", msg
[9]);
303 print_pr_data (msg
, msglen
, 10);
308 print_p2r_secure (const unsigned char *msg
, size_t msglen
)
312 print_p2r_header ("PC_to_RDR_Secure", msg
, msglen
);
315 printf (" bBMI ..............: 0x%02x\n", msg
[7]);
316 val
= convert_le_u16 (msg
+8);
317 printf (" wLevelParameter ...: 0x%04x%s\n", val
,
318 val
== 1? " (continued)":
319 val
== 2? " (continues+ends)":
320 val
== 3? " (continues+continued)":
321 val
== 16? " (DataBlock-expected)":"");
322 print_pr_data (msg
, msglen
, 10);
327 print_p2r_mechanical (const unsigned char *msg
, size_t msglen
)
329 print_p2r_header ("PC_to_RDR_Mechanical", msg
, msglen
);
332 printf (" bFunction .........: 0x%02x\n", msg
[7]);
333 print_pr_data (msg
, msglen
, 8);
338 print_p2r_abort (const unsigned char *msg
, size_t msglen
)
340 print_p2r_header ("PC_to_RDR_Abort", msg
, msglen
);
341 print_pr_data (msg
, msglen
, 7);
346 print_p2r_setdatarate (const unsigned char *msg
, size_t msglen
)
348 print_p2r_header ("PC_to_RDR_SetDataRate", msg
, msglen
);
351 print_pr_data (msg
, msglen
, 7);
356 print_p2r_unknown (const unsigned char *msg
, size_t msglen
)
358 print_p2r_header ("Unknown PC_to_RDR command", msg
, msglen
);
361 print_pr_data (msg
, msglen
, 0);
366 print_p2r (const unsigned char *msg
, size_t msglen
)
368 switch (msglen
? msg
[0]:0)
370 case PC_to_RDR_IccPowerOn
:
371 print_p2r_iccpoweron (msg
, msglen
);
373 case PC_to_RDR_IccPowerOff
:
374 print_p2r_iccpoweroff (msg
, msglen
);
376 case PC_to_RDR_GetSlotStatus
:
377 print_p2r_getslotstatus (msg
, msglen
);
379 case PC_to_RDR_XfrBlock
:
380 print_p2r_xfrblock (msg
, msglen
);
382 case PC_to_RDR_GetParameters
:
383 print_p2r_getparameters (msg
, msglen
);
385 case PC_to_RDR_ResetParameters
:
386 print_p2r_resetparameters (msg
, msglen
);
388 case PC_to_RDR_SetParameters
:
389 print_p2r_setparameters (msg
, msglen
);
391 case PC_to_RDR_Escape
:
392 print_p2r_escape (msg
, msglen
);
394 case PC_to_RDR_IccClock
:
395 print_p2r_iccclock (msg
, msglen
);
397 case PC_to_RDR_T0APDU
:
398 print_p2r_to0apdu (msg
, msglen
);
400 case PC_to_RDR_Secure
:
401 print_p2r_secure (msg
, msglen
);
403 case PC_to_RDR_Mechanical
:
404 print_p2r_mechanical (msg
, msglen
);
406 case PC_to_RDR_Abort
:
407 print_p2r_abort (msg
, msglen
);
409 case PC_to_RDR_SetDataRate
:
410 print_p2r_setdatarate (msg
, msglen
);
413 print_p2r_unknown (msg
, msglen
);
420 print_r2p_header (const char *name
, const unsigned char *msg
, size_t msglen
)
422 printf ("%s:\n", name
);
425 printf (" dwLength ..........: %u\n", convert_le_u32 (msg
+1));
426 printf (" bSlot .............: %u\n", msg
[5]);
427 printf (" bSeq ..............: %u\n", msg
[6]);
428 printf (" bStatus ...........: %u\n", msg
[7]);
430 printf (" bError ............: %u\n", msg
[8]);
435 print_r2p_datablock (const unsigned char *msg
, size_t msglen
)
437 print_r2p_header ("RDR_to_PC_DataBlock", msg
, msglen
);
441 printf (" bChainParameter ...: 0x%02x%s\n", msg
[9],
442 msg
[9] == 1? " (continued)":
443 msg
[9] == 2? " (continues+ends)":
444 msg
[9] == 3? " (continues+continued)":
445 msg
[9] == 16? " (XferBlock-expected)":"");
446 print_pr_data (msg
, msglen
, 10);
451 print_r2p_slotstatus (const unsigned char *msg
, size_t msglen
)
453 print_r2p_header ("RDR_to_PC_SlotStatus", msg
, msglen
);
456 printf (" bClockStatus ......: 0x%02x%s\n", msg
[9],
457 msg
[9] == 0? " (running)":
458 msg
[9] == 1? " (stopped-L)":
459 msg
[9] == 2? " (stopped-H)":
460 msg
[9] == 3? " (stopped)":"");
461 print_pr_data (msg
, msglen
, 10);
466 print_r2p_parameters (const unsigned char *msg
, size_t msglen
)
468 print_r2p_header ("RDR_to_PC_Parameters", msg
, msglen
);
472 printf (" protocol ..........: T=%d\n", msg
[9]);
473 if (msglen
== 17 && msg
[9] == 1)
476 printf (" bmFindexDindex ....: %02X\n", msg
[10]);
477 printf (" bmTCCKST1 .........: %02X\n", msg
[11]);
478 printf (" bGuardTimeT1 ......: %02X\n", msg
[12]);
479 printf (" bmWaitingIntegersT1: %02X\n", msg
[13]);
480 printf (" bClockStop ........: %02X\n", msg
[14]);
481 printf (" bIFSC .............: %d\n", msg
[15]);
482 printf (" bNadValue .........: %d\n", msg
[16]);
485 print_pr_data (msg
, msglen
, 10);
490 print_r2p_escape (const unsigned char *msg
, size_t msglen
)
494 print_r2p_header ("RDR_to_PC_Escape", msg
, msglen
);
497 printf (" buffer[9] .........: %02X\n", msg
[9]);
498 print_pr_data (msg
, msglen
, 10);
503 print_r2p_datarate (const unsigned char *msg
, size_t msglen
)
505 print_r2p_header ("RDR_to_PC_DataRate", msg
, msglen
);
510 printf (" dwClockFrequency ..: %u\n", convert_le_u32 (msg
+10));
511 printf (" dwDataRate ..... ..: %u\n", convert_le_u32 (msg
+14));
512 print_pr_data (msg
, msglen
, 18);
515 print_pr_data (msg
, msglen
, 10);
520 print_r2p_unknown (const unsigned char *msg
, size_t msglen
)
522 print_r2p_header ("Unknown RDR_to_PC command", msg
, msglen
);
525 printf (" bMessageType ......: %02X\n", msg
[0]);
526 printf (" buffer[9] .........: %02X\n", msg
[9]);
527 print_pr_data (msg
, msglen
, 10);
532 print_r2p (const unsigned char *msg
, size_t msglen
)
534 switch (msglen
? msg
[0]:0)
536 case RDR_to_PC_DataBlock
:
537 print_r2p_datablock (msg
, msglen
);
539 case RDR_to_PC_SlotStatus
:
540 print_r2p_slotstatus (msg
, msglen
);
542 case RDR_to_PC_Parameters
:
543 print_r2p_parameters (msg
, msglen
);
545 case RDR_to_PC_Escape
:
546 print_r2p_escape (msg
, msglen
);
548 case RDR_to_PC_DataRate
:
549 print_r2p_datarate (msg
, msglen
);
552 print_r2p_unknown (msg
, msglen
);
562 if (!databuffer
.count
)
566 printf ("Address: %s\n", databuffer
.address
);
567 if (databuffer
.is_bi
)
569 print_r2p (databuffer
.data
, databuffer
.count
);
574 print_p2r (databuffer
.data
, databuffer
.count
);
576 databuffer
.count
= 0;
580 collect_data (char *hexdata
, const char *address
, unsigned int lineno
)
587 is_bi
= (*address
&& address
[1] == 'i');
589 if (databuffer
.is_bi
!= is_bi
|| strcmp (databuffer
.address
, address
))
591 databuffer
.is_bi
= is_bi
;
592 if (strlen (address
) >= sizeof databuffer
.address
)
593 die ("address field too long");
594 strcpy (databuffer
.address
, address
);
596 length
= databuffer
.count
;
597 for (s
=hexdata
; *s
; s
++ )
599 if (ascii_isspace (*s
))
603 err ("invalid hex digit in line %u - line skipped", lineno
);
606 value
= xtoi_1 (*s
) * 16;
610 err ("invalid hex digit in line %u - line skipped", lineno
);
613 value
+= xtoi_1 (*s
);
615 if (length
>= sizeof (databuffer
.data
))
617 err ("too much data at line %u - can handle only up to % bytes",
618 lineno
, sizeof (databuffer
.data
));
621 databuffer
.data
[length
++] = value
;
623 databuffer
.count
= length
;
628 parse_line (char *line
, unsigned int lineno
)
631 char *event_type
, *address
, *data
, *status
, *datatag
;
634 printf ("line[%u] =`%s'\n", lineno
, line
);
636 p
= strtok (line
, " ");
638 die ("invalid line %d (no URB)");
639 p
= strtok (NULL
, " ");
641 die ("invalid line %d (no timestamp)");
642 event_type
= strtok (NULL
, " ");
644 die ("invalid line %d (no event type)");
645 address
= strtok (NULL
, " ");
647 die ("invalid line %d (no address");
648 if (usb_bus
|| usb_dev
)
652 p
= strchr (address
, ':');
654 die ("invalid line %d (invalid address");
659 die ("invalid line %d (invalid address");
663 if ((usb_bus
&& usb_bus
!= bus
) || (usb_dev
&& usb_dev
!= dev
))
664 return; /* We don't want that one. */
666 if (*address
!= 'B' || (address
[1] != 'o' && address
[1] != 'i'))
667 return; /* We only want block in and block out. */
668 status
= strtok (NULL
, " ");
671 if (!strchr ("-0123456789", *status
))
672 return; /* Setup packet. */
673 /* We don't support "Z[io]" types thus we don't need to check here. */
674 p
= strtok (NULL
, " ");
676 return; /* No data length. */
678 datatag
= strtok (NULL
, " ");
679 if (datatag
&& *datatag
== '=')
681 data
= strtok (NULL
, "");
682 collect_data (data
?data
:"", address
, lineno
);
688 parse_input (FILE *fp
)
692 unsigned int lineno
= 0;
694 while (fgets (line
, sizeof (line
), fp
))
697 length
= strlen (line
);
698 if (length
&& line
[length
- 1] == '\n')
701 err ("line number %u too long or last line not terminated", lineno
);
702 if (length
&& line
[length
- 1] == '\r')
704 parse_line (line
, lineno
);
708 err ("error reading input at line %u: %s", lineno
, strerror (errno
));
713 main (int argc
, char **argv
)
721 while (argc
&& last_argc
!= argc
)
724 if (!strcmp (*argv
, "--"))
729 else if (!strcmp (*argv
, "--version"))
731 fputs (PGM
" (GnuPG) " PACKAGE_VERSION
"\n", stdout
);
734 else if (!strcmp (*argv
, "--help"))
736 puts ("Usage: " PGM
" [BUS:DEV]\n"
737 "Parse the output of usbmod assuming it is CCID compliant.\n\n"
738 " --skip-escape do not show escape packets\n"
739 " --verbose enable extra informational output\n"
740 " --debug enable additional debug output\n"
741 " --help display this help and exit\n\n"
742 "Report bugs to " PACKAGE_BUGREPORT
".");
745 else if (!strcmp (*argv
, "--verbose"))
750 else if (!strcmp (*argv
, "--debug"))
755 else if (!strcmp (*argv
, "--skip-escape"))
763 die ("usage: " PGM
" [BUS:DEV] (try --help for more information)\n");
767 const char *s
= strchr (argv
[0], ':');
769 usb_bus
= atoi (argv
[0]);
771 usb_dev
= atoi (s
+1);
772 if (usb_bus
< 1 || usb_bus
> 999 || usb_dev
< 1 || usb_dev
> 999)
773 die ("invalid bus:dev specified");
777 signal (SIGPIPE
, SIG_IGN
);
781 return any_error
? 1:0;
787 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"