File Coverage

blib/lib/NetPacket/USBMon.pm
Criterion Covered Total %
statement 79 81 97.5
branch 10 12 83.3
condition n/a
subroutine 20 20 100.0
pod 1 1 100.0
total 110 114 96.4


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