]>
The Tcpdump Group git mirrors - libpcap/blob - pcap-usb-linux.c
2 * Copyright (c) 1999 - 2005 NetGroup, Politecnico di Torino (Italy)
3 * Copyright (c) 2005 - 2006 CACE Technologies, Davis (California)
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the Politecnico di Torino, CACE Technologies
16 * nor the names of its contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * USB sniffing API implementation for Linux platform
33 * By Paolo Abeni <paolo.abeni@email.com>
42 #include "pcap-usb-linux.h"
45 #ifdef NEED_STRERROR_H
55 #include <netinet/in.h>
57 #define USB_IFACE "usb"
58 #define USB_DIR "/sys/kernel/debug/usbmon"
59 #define USB_LINE_LEN 4096
61 /* forward declaration */
62 static int usb_read_linux(pcap_t
*, int , pcap_handler
, u_char
*);
63 static int usb_inject_linux(pcap_t
*, const void *, size_t);
64 static int usb_setfilter_linux(pcap_t
*, struct bpf_program
*);
65 static int usb_setdirection_linux(pcap_t
*, pcap_direction_t
);
66 static int usb_stats_linux(pcap_t
*, struct pcap_stat
*);
67 static void usb_close_linux(pcap_t
*);
70 usb_platform_finddevs(pcap_if_t
**alldevsp
, char *err_str
)
72 pcap_if_t
*devlist
= *alldevsp
;
74 DIR* dir
= opendir(USB_DIR
);
76 /* it's not fatal, but it would be useful to give a message
79 mount -t debugfs none_debugs /sys/kernel/debug
84 /* scan usbmon directory */
86 while ((data
= readdir(dir
)) != 0)
88 char* name
= data
->d_name
;
89 int len
= strlen(name
);
91 if ((len
>= 2) && name
[len
-1]== 't')
93 int n
= name
[0] - '0';
94 char dev_name
[10], dev_descr
[30];
95 snprintf(dev_name
, 10, USB_IFACE
"%d", n
);
96 snprintf(dev_descr
, 30, "usb bus number %d", n
);
98 if (pcap_add_if(&devlist
, dev_name
, 0,
99 dev_descr
, err_str
) < 0)
113 usb_open_live(const char* bus
, int snaplen
, int promisc
, int to_ms
, char* errmsg
)
115 char full_path
[USB_LINE_LEN
];
118 /* Allocate a handle for this session. */
119 handle
= malloc(sizeof(*handle
));
120 if (handle
== NULL
) {
121 snprintf(errmsg
, PCAP_ERRBUF_SIZE
, "malloc: %s",
122 pcap_strerror(errno
));
126 /* Initialize some components of the pcap structure. */
127 memset(handle
, 0, sizeof(*handle
));
128 handle
->snapshot
= snaplen
;
129 handle
->md
.timeout
= to_ms
;
130 handle
->bufsize
= USB_LINE_LEN
;
132 handle
->linktype
= DLT_USB
;
134 /* get usb bus index from device name */
135 if (sscanf(bus
, USB_IFACE
"%d", &handle
->md
.ifindex
) != 1)
137 snprintf(errmsg
, PCAP_ERRBUF_SIZE
,
138 "Can't get usb bus index from %s", bus
);
143 /* open text output file*/
144 snprintf(full_path
, USB_LINE_LEN
, USB_DIR
"/%dt", handle
->md
.ifindex
);
145 handle
->fd
= open(full_path
, O_RDONLY
, 0);
148 snprintf(errmsg
, PCAP_ERRBUF_SIZE
,
149 "Can't open usb bus file %s: %s", full_path
, strerror(errno
));
154 handle
->buffer
= malloc(handle
->bufsize
+ handle
->offset
);
155 if (!handle
->buffer
) {
156 snprintf(errmsg
, PCAP_ERRBUF_SIZE
,
157 "malloc: %s", pcap_strerror(errno
));
158 usb_close_linux(handle
);
163 * "handle->fd" is a real file , so "select()" and "poll()"
166 handle
->selectable_fd
= handle
->fd
;
168 handle
->read_op
= usb_read_linux
;
169 handle
->inject_op
= usb_inject_linux
;
170 handle
->setfilter_op
= usb_setfilter_linux
;
171 handle
->setdirection_op
= usb_setdirection_linux
;
172 handle
->set_datalink_op
= NULL
; /* can't change data link type */
173 handle
->getnonblock_op
= pcap_getnonblock_fd
;
174 handle
->setnonblock_op
= pcap_setnonblock_fd
;
175 handle
->stats_op
= usb_stats_linux
;
176 handle
->close_op
= usb_close_linux
;
185 return c
< 'A' ? c
- '0': ((c
<'a') ? c
- 'A' + 10: c
-'a'+10);
189 * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
190 * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string
194 usb_read_linux(pcap_t
*handle
, int max_packets
, pcap_handler callback
, u_char
*user
)
197 * /usr/src/linux/Documentation/usb/usbmon.txt
201 int tag
, cnt
, ep_num
, dev_addr
, dummy
, ret
;
202 char etype
, pipeid1
, pipeid2
, status
[16], urb_tag
, line
[4096];
204 u_char
* rawdata
= handle
->buffer
;
205 struct pcap_pkthdr pkth
;
206 pcap_usb_header
* uhdr
= (pcap_usb_header
*)rawdata
;
207 pcap_urb_type_t urb_type
= URB_UNKNOWN
;
209 /* ignore interrupt system call errors */
211 ret
= read(handle
->fd
, line
, USB_LINE_LEN
- 1);
212 if (handle
->break_loop
)
214 handle
->break_loop
= 0;
217 } while ((ret
== -1) && (errno
== EINTR
));
221 return 0; /* no data there */
223 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
224 "Can't read from fd %d: %s", handle
->fd
, strerror(errno
));
228 /* read urb header; %n argument may increment return value, but it's
229 * not mandatory, so does not count on it*/
231 ret
= sscanf(string
, "%x %d %c %c%c:%d:%d %s%n", &tag
, ×tamp
, &etype
,
232 &pipeid1
, &pipeid2
, &dev_addr
, &ep_num
, status
,
236 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
237 "Can't parse usb bus message '%s', too few token (expected 8 got %d)",
241 uhdr
->endpoint_number
= htonl(ep_num
);
242 uhdr
->device_address
= htonl(dev_addr
);
245 /* don't use usbmon provided timestamp, since it have low precision*/
246 if (gettimeofday(&pkth
.ts
, NULL
) < 0)
248 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
249 "Can't get timestamp for message '%s' %d:%s",
250 string
, errno
, strerror(errno
));
254 /* parse endpoint information */
258 urb_type
= URB_CONTROL_INPUT
;
260 urb_type
= URB_CONTROL_OUTPUT
;
262 else if (pipeid1
== 'Z')
265 urb_type
= URB_ISOCHRONOUS_INPUT
;
267 urb_type
= URB_ISOCHRONOUS_OUTPUT
;
269 else if (pipeid1
== 'I')
272 urb_type
= URB_INTERRUPT_INPUT
;
274 urb_type
= URB_INTERRUPT_OUTPUT
;
276 else if (pipeid1
== 'B')
279 urb_type
= URB_BULK_INPUT
;
281 urb_type
= URB_BULK_OUTPUT
;
285 if ((urb_type
== URB_BULK_INPUT
) || (urb_type
== URB_INTERRUPT_INPUT
) ||
286 (urb_type
== URB_ISOCHRONOUS_INPUT
) || (urb_type
== URB_CONTROL_INPUT
))
288 if (handle
->direction
== PCAP_D_OUT
)
292 if (handle
->direction
== PCAP_D_IN
)
295 uhdr
->urb_type
= htonl(urb_type
);
296 pkth
.caplen
= sizeof(pcap_usb_header
);
297 rawdata
+= sizeof(pcap_usb_header
);
299 /* check if this is a setup packet */
300 ret
= sscanf(status
, "%d", &dummy
);
303 /* this a setup packet, setup data can be filled with underscore if
304 * usbmon has not been able to read them, so we must parse this fields as
306 pcap_usb_setup
* shdr
;
307 char str1
[3], str2
[3], str3
[5], str4
[5], str5
[5];
308 ret
= sscanf(string
, "%s %s %s %s %s%n", str1
, str2
, str3
, str4
,
312 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
313 "Can't parse usb bus message '%s', too few token (expected 5 got %d)",
319 /* try to convert to corresponding integer */
320 shdr
= (pcap_usb_setup
*)rawdata
;
321 shdr
->bmRequestType
= strtoul(str1
, 0, 16);
322 shdr
->bRequest
= strtoul(str2
, 0, 16);
323 shdr
->wValue
= htons(strtoul(str3
, 0, 16));
324 shdr
->wIndex
= htons(strtoul(str4
, 0, 16));
325 shdr
->wLength
= htons(strtoul(str5
, 0, 16));
326 uhdr
->setup_packet
= 1;
329 pkth
.caplen
+= sizeof(pcap_usb_setup
);
330 rawdata
+= sizeof(pcap_usb_setup
);
333 uhdr
->setup_packet
= 0;
336 ret
= sscanf(string
, " %d%n", &pkth
.len
, &cnt
);
339 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
340 "Can't parse urb length from '%s'", string
);
344 handle
->md
.packets_read
++;
346 /* urb tag is not present if urb length is 0, so we can stop here
348 pkth
.len
+= pkth
.caplen
;
349 if (pkth
.len
== pkth
.caplen
)
352 /* check for data presence; data is present if and only if urb tag is '=' */
353 if (sscanf(string
, " %c", &urb_tag
) != 1)
355 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
356 "Can't parse urb tag from '%s'", string
);
363 /* skip urb tag and following space */
366 /* read all urb data; if urb length is greater then the usbmon internal
367 * buffer length used by the kernel to spool the URB, we get only
368 * a partial information.
369 * At least until linux 2.6.17 there is no way to set usbmon intenal buffer
370 * length and default value is 130. */
371 while ((string
[0] != 0) && (string
[1] != 0) && (pkth
.caplen
< handle
->snapshot
))
373 rawdata
[0] = ascii_to_int(string
[0]) * 16 + ascii_to_int(string
[1]);
376 if (string
[0] == ' ')
382 handle
->md
.packets_read
++;
383 if (pkth
.caplen
> handle
->snapshot
)
384 pkth
.caplen
= handle
->snapshot
;
387 callback(user
, &pkth
, handle
->buffer
);
392 usb_inject_linux(pcap_t
*handle
, const void *buf
, size_t size
)
394 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
, "inject not supported on "
401 usb_close_linux(pcap_t
* handle
)
403 /* handle fill be freed in pcap_close() 'common' code */
405 free(handle
->buffer
);
410 usb_stats_linux(pcap_t
*handle
, struct pcap_stat
*stats
)
413 char string
[USB_LINE_LEN
];
414 snprintf(string
, USB_LINE_LEN
, USB_DIR
"/%ds", handle
->md
.ifindex
);
416 int fd
= open(string
, O_RDONLY
, 0);
419 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
420 "Can't open usb stats file %s: %s",
421 string
, strerror(errno
));
425 /* read stats line */
427 ret
= read(fd
, string
, USB_LINE_LEN
-1);
428 } while ((ret
== -1) && (errno
== EINTR
));
433 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
434 "Can't read stats from fd %d ", fd
);
439 /* extract info on dropped urbs */
440 ret
= sscanf(string
, "nreaders %d text_lost %d", &dummy
, &stats
->ps_drop
);
443 snprintf(handle
->errbuf
, PCAP_ERRBUF_SIZE
,
444 "Can't parse stat line '%s' expected 2 token got %d",
449 stats
->ps_recv
= handle
->md
.packets_read
;
450 stats
->ps_ifdrop
= 0;
455 usb_setfilter_linux(pcap_t
*p
, struct bpf_program
*fp
)
462 usb_setdirection_linux(pcap_t
*p
, pcap_direction_t d
)