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"