File Coverage

blib/lib/NetPacket/USBMon.pm
Criterion Covered Total %
statement 77 79 97.4
branch 10 12 83.3
condition n/a
subroutine 19 19 100.0
pod 1 1 100.0
total 107 111 96.4


line stmt bran cond sub pod time code
1             package NetPacket::USBMon;
2             our $AUTHORITY = 'cpan:YANICK';
3             #ABSTRACT: Assemble and disassemble USB packets captured via Linux USBMon interface.
4             $NetPacket::USBMon::VERSION = '1.7.2';
5 2     2   70107 use 5.10.0;
  2         32  
6 2     2   11 use strict;
  2         4  
  2         65  
7 2     2   13 use warnings;
  2         3  
  2         89  
8              
9 2     2   446 use parent 'NetPacket';
  2         297  
  2         12  
10              
11             our @EXPORT_OK = qw(
12             USB_TYPE_SUBMISSION USB_TYPE_CALLBACK USB_TYPE_ERROR
13             USB_XFER_TYPE_ISO USB_XFER_TYPE_INTR
14             USB_XFER_TYPE_CONTROL USB_XFER_TYPE_BULK
15             USB_FLAG_SETUP_IRRELEVANT USB_FLAG_SETUP_RELEVANT
16             USB_FLAG_DATA_ERROR USB_FLAG_DATA_INCOMING
17             USB_FLAG_DATA_OUTGOING USB_FLAG_DATA_PRESENT
18             USB_TYPE_VENDOR
19             );
20              
21             our %EXPORT_TAGS =(
22             ALL => \@EXPORT_OK,
23             types => [qw(USB_TYPE_SUBMISSION USB_TYPE_CALLBACK
24             USB_TYPE_ERROR)],
25             xfer_types => [qw(USB_XFER_TYPE_ISO USB_XFER_TYPE_INTR
26             USB_XFER_TYPE_CONTROL USB_XFER_TYPE_BULK)],
27             setup_flags => [qw(USB_FLAG_SETUP_IRRELEVANT USB_FLAG_SETUP_RELEVANT)],
28             data_flags => [qw(USB_FLAG_DATA_ERROR USB_FLAG_DATA_INCOMING
29             USB_FLAG_DATA_OUTGOING USB_FLAG_DATA_PRESENT)],
30             setup_types => [qw(USB_TYPE_VENDOR)],
31             );
32              
33              
34 2     2   263 use constant USB_TYPE_SUBMISSION => 'S';
  2         12  
  2         181  
35 2     2   15 use constant USB_TYPE_CALLBACK => 'C';
  2         4  
  2         106  
36 2     2   11 use constant USB_TYPE_ERROR => 'E';
  2         5  
  2         101  
37              
38 2     2   12 use constant USB_XFER_TYPE_ISO => 0;
  2         4  
  2         101  
39 2     2   11 use constant USB_XFER_TYPE_INTR => 1;
  2         4  
  2         116  
40 2     2   14 use constant USB_XFER_TYPE_CONTROL => 2;
  2         3  
  2         105  
41 2     2   12 use constant USB_XFER_TYPE_BULK => 3;
  2         5  
  2         101  
42              
43 2     2   11 use constant USB_FLAG_SETUP_IRRELEVANT => '-';
  2         5  
  2         128  
44 2     2   13 use constant USB_FLAG_SETUP_RELEVANT => chr(0);
  2         4  
  2         103  
45              
46 2     2   12 use constant USB_FLAG_DATA_ERROR => 'E';
  2         4  
  2         118  
47 2     2   13 use constant USB_FLAG_DATA_INCOMING => '<';
  2         4  
  2         106  
48 2     2   12 use constant USB_FLAG_DATA_OUTGOING => '>';
  2         4  
  2         107  
49 2     2   12 use constant USB_FLAG_DATA_PRESENT => chr(0);
  2         4  
  2         106  
50              
51 2     2   29 use constant USB_TYPE_VENDOR => 0x40;
  2         5  
  2         883  
52              
53             sub decode
54             {
55 7     7 1 45641 my $class = shift;
56 7         10 my $packet = shift;
57 7         11 my $parent = shift;
58              
59 7         59 my($id, $type, $xfer_type, $epnum, $devnum, $busnum, $flag_setup,
60             $flag_data, $ts_sec, $ts_usec, $status, $length, $len_cap,
61             $s, $interval, $start_frame, $xfer_flags, $ndesc, $rest) =
62             unpack('a8CCCCS
63              
64             # Try to grok quads. We may lose some address information with 32-bit
65             # Perl parsing 64-bit captures, or timestamp after 2038. Still the best
66             # we can do.
67 7         18 eval {
68 7         14 $id = unpack ('Q<', $id);
69 7         15 $ts_sec = unpack ('Q<', $ts_sec);
70             };
71 7 50       17 if ($@) {
72 0         0 ($id) = unpack ('L
73 0         0 ($ts_sec) = unpack ('L
74             }
75              
76 7 100       77 my $self = {
77             _parent => $parent,
78             _frame => $packet,
79              
80             id => $id,
81             type => chr($type),
82             xfer_type => $xfer_type,
83             ep => {
84             num => ($epnum & 0x7f),
85             dir => ($epnum & 0x80 ? 'IN' : 'OUT'),
86             },
87             devnum => $devnum,
88             busnum => $busnum,
89             flag_setup => chr($flag_setup),
90             flag_data => chr($flag_data),
91             ts_sec => $ts_sec,
92             ts_usec => $ts_usec,
93             status => $status,
94             length => $length,
95             len_cap => $len_cap,
96             interval => $interval,
97             start_frame => $start_frame,
98             xfer_flags => $xfer_flags,
99             ndesc => $ndesc,
100             };
101              
102             # Setup
103 7 100       22 if ($self->{flag_setup} ne USB_FLAG_SETUP_IRRELEVANT) {
104 3         4 my $setup = {};
105 3         5 my $rest;
106              
107 3         11 ($setup->{bmRequestType}, $setup->{bRequest}, $rest)
108             = unpack('CCa*', $s);
109              
110 3 100       9 if ($setup->{bmRequestType} & USB_TYPE_VENDOR) {
111             ($setup->{wValue}, $setup->{wIndex},
112 2         6 $setup->{wLength}) = unpack('S<3', $rest);
113             } else {
114             # Unknown setup request;
115 1         3 $setup->{data} = $rest;
116             }
117              
118 3         6 $self->{setup} = $setup;
119             }
120              
121             # Isochronous descriptors
122 7 100       16 if ($self->{xfer_type} == USB_XFER_TYPE_ISO) {
123 1         3 my $iso = {};
124 1         4 ($iso->{error_count}, $iso->{numdesc}) = unpack('i
125 1         3 $self->{iso} = $iso;
126             }
127              
128             # Data
129             warn 'Payload length mismatch'
130 7 50       21 if length($rest) ne $self->{len_cap};
131 7         12 $self->{data} = $rest;
132              
133 7         41 return bless $self, $class;
134             }
135              
136             1;
137              
138             __END__