Reworked the estream memory buffer allocation.
[gnupg.git] / tools / ccidmon.c
blob03bfc436b8451f6772913de4a81439fafde00a81
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.
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <assert.h>
37 #include <unistd.h>
38 #include <signal.h>
41 #ifndef PACKAGE_VERSION
42 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
43 #endif
44 #ifndef PACKAGE_BUGREPORT
45 # define PACKAGE_BUGREPORT "devnull@example.org"
46 #endif
47 #define PGM "ccidmon"
49 /* Option flags. */
50 static int verbose;
51 static int debug;
52 static int skip_escape;
53 static int usb_bus, usb_dev;
55 /* Error counter. */
56 static int any_error;
58 /* Data storage. */
59 struct
61 int is_bi;
62 char address[50];
63 int count;
64 char data[2000];
65 } databuffer;
68 enum {
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. */
106 static void
107 die (const char *format, ...)
109 va_list arg_ptr;
111 fflush (stdout);
112 fprintf (stderr, "%s: ", PGM);
114 va_start (arg_ptr, format);
115 vfprintf (stderr, format, arg_ptr);
116 va_end (arg_ptr);
117 putc ('\n', stderr);
119 exit (1);
123 /* Print diagnostic message. */
124 static void
125 err (const char *format, ...)
127 va_list arg_ptr;
129 any_error = 1;
131 fflush (stdout);
132 fprintf (stderr, "%s: ", PGM);
134 va_start (arg_ptr, format);
135 vfprintf (stderr, format, arg_ptr);
136 va_end (arg_ptr);
137 putc ('\n', stderr);
141 /* Convert a little endian stored 4 byte value into an unsigned
142 integer. */
143 static unsigned int
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
151 integer. */
152 static unsigned int
153 convert_le_u16 (const unsigned char *buf)
155 return buf[0] | (buf[1] << 8);
161 static void
162 print_pr_data (const unsigned char *data, size_t datalen, size_t off)
164 int needlf = 0;
165 int first = 1;
167 for (; off < datalen; off++)
169 if (!(off % 16) || first)
171 if (needlf)
172 putchar ('\n');
173 printf (" [%04d] ", off);
175 printf (" %02X", data[off]);
176 needlf = 1;
177 first = 0;
179 if (needlf)
180 putchar ('\n');
184 static void
185 print_p2r_header (const char *name, const unsigned char *msg, size_t msglen)
187 printf ("%s:\n", name);
188 if (msglen < 7)
189 return;
190 printf (" dwLength ..........: %u\n", convert_le_u32 (msg+1));
191 printf (" bSlot .............: %u\n", msg[5]);
192 printf (" bSeq ..............: %u\n", msg[6]);
196 static void
197 print_p2r_iccpoweron (const unsigned char *msg, size_t msglen)
199 print_p2r_header ("PC_to_RDR_IccPowerOn", msg, msglen);
200 if (msglen < 10)
201 return;
202 printf (" bPowerSelect ......: 0x%02x (%s)\n", msg[7],
203 msg[7] == 0? "auto":
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);
211 static void
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);
219 static void
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);
227 static void
228 print_p2r_xfrblock (const unsigned char *msg, size_t msglen)
230 unsigned int val;
232 print_p2r_header ("PC_to_RDR_XfrBlock", msg, msglen);
233 if (msglen < 10)
234 return;
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);
246 static void
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);
254 static void
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);
262 static void
263 print_p2r_setparameters (const unsigned char *msg, size_t msglen)
265 print_p2r_header ("PC_to_RDR_SetParameters", msg, msglen);
266 if (msglen < 10)
267 return;
268 printf (" bProtocolNum ......: 0x%02x\n", msg[7]);
269 print_pr_data (msg, msglen, 8);
273 static void
274 print_p2r_escape (const unsigned char *msg, size_t msglen)
276 if (skip_escape)
277 return;
278 print_p2r_header ("PC_to_RDR_Escape", msg, msglen);
279 print_pr_data (msg, msglen, 7);
283 static void
284 print_p2r_iccclock (const unsigned char *msg, size_t msglen)
286 print_p2r_header ("PC_to_RDR_IccClock", msg, msglen);
287 if (msglen < 10)
288 return;
289 printf (" bClockCommand .....: 0x%02x\n", msg[7]);
290 print_pr_data (msg, msglen, 8);
294 static void
295 print_p2r_to0apdu (const unsigned char *msg, size_t msglen)
297 print_p2r_header ("PC_to_RDR_T0APDU", msg, msglen);
298 if (msglen < 10)
299 return;
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);
307 static void
308 print_p2r_secure (const unsigned char *msg, size_t msglen)
310 unsigned int val;
312 print_p2r_header ("PC_to_RDR_Secure", msg, msglen);
313 if (msglen < 10)
314 return;
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);
326 static void
327 print_p2r_mechanical (const unsigned char *msg, size_t msglen)
329 print_p2r_header ("PC_to_RDR_Mechanical", msg, msglen);
330 if (msglen < 10)
331 return;
332 printf (" bFunction .........: 0x%02x\n", msg[7]);
333 print_pr_data (msg, msglen, 8);
337 static void
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);
345 static void
346 print_p2r_setdatarate (const unsigned char *msg, size_t msglen)
348 print_p2r_header ("PC_to_RDR_SetDataRate", msg, msglen);
349 if (msglen < 10)
350 return;
351 print_pr_data (msg, msglen, 7);
355 static void
356 print_p2r_unknown (const unsigned char *msg, size_t msglen)
358 print_p2r_header ("Unknown PC_to_RDR command", msg, msglen);
359 if (msglen < 10)
360 return;
361 print_pr_data (msg, msglen, 0);
365 static void
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);
372 break;
373 case PC_to_RDR_IccPowerOff:
374 print_p2r_iccpoweroff (msg, msglen);
375 break;
376 case PC_to_RDR_GetSlotStatus:
377 print_p2r_getslotstatus (msg, msglen);
378 break;
379 case PC_to_RDR_XfrBlock:
380 print_p2r_xfrblock (msg, msglen);
381 break;
382 case PC_to_RDR_GetParameters:
383 print_p2r_getparameters (msg, msglen);
384 break;
385 case PC_to_RDR_ResetParameters:
386 print_p2r_resetparameters (msg, msglen);
387 break;
388 case PC_to_RDR_SetParameters:
389 print_p2r_setparameters (msg, msglen);
390 break;
391 case PC_to_RDR_Escape:
392 print_p2r_escape (msg, msglen);
393 break;
394 case PC_to_RDR_IccClock:
395 print_p2r_iccclock (msg, msglen);
396 break;
397 case PC_to_RDR_T0APDU:
398 print_p2r_to0apdu (msg, msglen);
399 break;
400 case PC_to_RDR_Secure:
401 print_p2r_secure (msg, msglen);
402 break;
403 case PC_to_RDR_Mechanical:
404 print_p2r_mechanical (msg, msglen);
405 break;
406 case PC_to_RDR_Abort:
407 print_p2r_abort (msg, msglen);
408 break;
409 case PC_to_RDR_SetDataRate:
410 print_p2r_setdatarate (msg, msglen);
411 break;
412 default:
413 print_p2r_unknown (msg, msglen);
414 break;
419 static void
420 print_r2p_header (const char *name, const unsigned char *msg, size_t msglen)
422 printf ("%s:\n", name);
423 if (msglen < 9)
424 return;
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]);
429 if (msg[8])
430 printf (" bError ............: %u\n", msg[8]);
434 static void
435 print_r2p_datablock (const unsigned char *msg, size_t msglen)
437 print_r2p_header ("RDR_to_PC_DataBlock", msg, msglen);
438 if (msglen < 10)
439 return;
440 if (msg[9])
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);
450 static void
451 print_r2p_slotstatus (const unsigned char *msg, size_t msglen)
453 print_r2p_header ("RDR_to_PC_SlotStatus", msg, msglen);
454 if (msglen < 10)
455 return;
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);
465 static void
466 print_r2p_parameters (const unsigned char *msg, size_t msglen)
468 print_r2p_header ("RDR_to_PC_Parameters", msg, msglen);
469 if (msglen < 10)
470 return;
472 printf (" protocol ..........: T=%d\n", msg[9]);
473 if (msglen == 17 && msg[9] == 1)
475 /* Protocol T=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]);
484 else
485 print_pr_data (msg, msglen, 10);
489 static void
490 print_r2p_escape (const unsigned char *msg, size_t msglen)
492 if (skip_escape)
493 return;
494 print_r2p_header ("RDR_to_PC_Escape", msg, msglen);
495 if (msglen < 10)
496 return;
497 printf (" buffer[9] .........: %02X\n", msg[9]);
498 print_pr_data (msg, msglen, 10);
502 static void
503 print_r2p_datarate (const unsigned char *msg, size_t msglen)
505 print_r2p_header ("RDR_to_PC_DataRate", msg, msglen);
506 if (msglen < 10)
507 return;
508 if (msglen >= 18)
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);
514 else
515 print_pr_data (msg, msglen, 10);
519 static void
520 print_r2p_unknown (const unsigned char *msg, size_t msglen)
522 print_r2p_header ("Unknown RDR_to_PC command", msg, msglen);
523 if (msglen < 10)
524 return;
525 printf (" bMessageType ......: %02X\n", msg[0]);
526 printf (" buffer[9] .........: %02X\n", msg[9]);
527 print_pr_data (msg, msglen, 10);
531 static void
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);
538 break;
539 case RDR_to_PC_SlotStatus:
540 print_r2p_slotstatus (msg, msglen);
541 break;
542 case RDR_to_PC_Parameters:
543 print_r2p_parameters (msg, msglen);
544 break;
545 case RDR_to_PC_Escape:
546 print_r2p_escape (msg, msglen);
547 break;
548 case RDR_to_PC_DataRate:
549 print_r2p_datarate (msg, msglen);
550 break;
551 default:
552 print_r2p_unknown (msg, msglen);
553 break;
559 static void
560 flush_data (void)
562 if (!databuffer.count)
563 return;
565 if (verbose)
566 printf ("Address: %s\n", databuffer.address);
567 if (databuffer.is_bi)
569 print_r2p (databuffer.data, databuffer.count);
570 if (verbose)
571 putchar ('\n');
573 else
574 print_p2r (databuffer.data, databuffer.count);
576 databuffer.count = 0;
579 static void
580 collect_data (char *hexdata, const char *address, unsigned int lineno)
582 size_t length;
583 int is_bi;
584 char *s;
585 unsigned int value;
587 is_bi = (*address && address[1] == 'i');
589 if (databuffer.is_bi != is_bi || strcmp (databuffer.address, address))
590 flush_data ();
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))
600 continue;
601 if (!hexdigitp (*s))
603 err ("invalid hex digit in line %u - line skipped", lineno);
604 break;
606 value = xtoi_1 (*s) * 16;
607 s++;
608 if (!hexdigitp (*s))
610 err ("invalid hex digit in line %u - line skipped", lineno);
611 break;
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));
619 break;
621 databuffer.data[length++] = value;
623 databuffer.count = length;
627 static void
628 parse_line (char *line, unsigned int lineno)
630 char *p;
631 char *event_type, *address, *data, *status, *datatag;
633 if (debug)
634 printf ("line[%u] =`%s'\n", lineno, line);
636 p = strtok (line, " ");
637 if (!p)
638 die ("invalid line %d (no URB)");
639 p = strtok (NULL, " ");
640 if (!p)
641 die ("invalid line %d (no timestamp)");
642 event_type = strtok (NULL, " ");
643 if (!event_type)
644 die ("invalid line %d (no event type)");
645 address = strtok (NULL, " ");
646 if (!address)
647 die ("invalid line %d (no address");
648 if (usb_bus || usb_dev)
650 int bus, dev;
652 p = strchr (address, ':');
653 if (!p)
654 die ("invalid line %d (invalid address");
655 p++;
656 bus = atoi (p);
657 p = strchr (p, ':');
658 if (!p)
659 die ("invalid line %d (invalid address");
660 p++;
661 dev = atoi (p);
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, " ");
669 if (!status)
670 return;
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, " ");
675 if (!p)
676 return; /* No data length. */
678 datatag = strtok (NULL, " ");
679 if (datatag && *datatag == '=')
681 data = strtok (NULL, "");
682 collect_data (data?data:"", address, lineno);
687 static void
688 parse_input (FILE *fp)
690 char line[2000];
691 size_t length;
692 unsigned int lineno = 0;
694 while (fgets (line, sizeof (line), fp))
696 lineno++;
697 length = strlen (line);
698 if (length && line[length - 1] == '\n')
699 line[--length] = 0;
700 else
701 err ("line number %u too long or last line not terminated", lineno);
702 if (length && line[length - 1] == '\r')
703 line[--length] = 0;
704 parse_line (line, lineno);
706 flush_data ();
707 if (ferror (fp))
708 err ("error reading input at line %u: %s", lineno, strerror (errno));
712 int
713 main (int argc, char **argv)
715 int last_argc = -1;
717 if (argc)
719 argc--; argv++;
721 while (argc && last_argc != argc )
723 last_argc = argc;
724 if (!strcmp (*argv, "--"))
726 argc--; argv++;
727 break;
729 else if (!strcmp (*argv, "--version"))
731 fputs (PGM " (GnuPG) " PACKAGE_VERSION "\n", stdout);
732 exit (0);
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 ".");
743 exit (0);
745 else if (!strcmp (*argv, "--verbose"))
747 verbose = 1;
748 argc--; argv++;
750 else if (!strcmp (*argv, "--debug"))
752 verbose = debug = 1;
753 argc--; argv++;
755 else if (!strcmp (*argv, "--skip-escape"))
757 skip_escape = 1;
758 argc--; argv++;
762 if (argc > 1)
763 die ("usage: " PGM " [BUS:DEV] (try --help for more information)\n");
765 if (argc == 1)
767 const char *s = strchr (argv[0], ':');
769 usb_bus = atoi (argv[0]);
770 if (s)
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);
779 parse_input (stdin);
781 return any_error? 1:0;
786 Local Variables:
787 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"
788 End: