xref: /minix3/external/bsd/libpcap/dist/pcap-usb-linux.c (revision d56f51ea7d8b9045e5c8e2028422523d3f9a5840)
1*d56f51eaSDavid van Moolenbroek /*	$NetBSD: pcap-usb-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $	*/
2*d56f51eaSDavid van Moolenbroek 
3*d56f51eaSDavid van Moolenbroek /*
4*d56f51eaSDavid van Moolenbroek  * Copyright (c) 2006 Paolo Abeni (Italy)
5*d56f51eaSDavid van Moolenbroek  * All rights reserved.
6*d56f51eaSDavid van Moolenbroek  *
7*d56f51eaSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
8*d56f51eaSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
9*d56f51eaSDavid van Moolenbroek  * are met:
10*d56f51eaSDavid van Moolenbroek  *
11*d56f51eaSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
12*d56f51eaSDavid van Moolenbroek  * notice, this list of conditions and the following disclaimer.
13*d56f51eaSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
14*d56f51eaSDavid van Moolenbroek  * notice, this list of conditions and the following disclaimer in the
15*d56f51eaSDavid van Moolenbroek  * documentation and/or other materials provided with the distribution.
16*d56f51eaSDavid van Moolenbroek  * 3. The name of the author may not be used to endorse or promote
17*d56f51eaSDavid van Moolenbroek  * products derived from this software without specific prior written
18*d56f51eaSDavid van Moolenbroek  * permission.
19*d56f51eaSDavid van Moolenbroek  *
20*d56f51eaSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21*d56f51eaSDavid van Moolenbroek  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*d56f51eaSDavid van Moolenbroek  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23*d56f51eaSDavid van Moolenbroek  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24*d56f51eaSDavid van Moolenbroek  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25*d56f51eaSDavid van Moolenbroek  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26*d56f51eaSDavid van Moolenbroek  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27*d56f51eaSDavid van Moolenbroek  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28*d56f51eaSDavid van Moolenbroek  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29*d56f51eaSDavid van Moolenbroek  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30*d56f51eaSDavid van Moolenbroek  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31*d56f51eaSDavid van Moolenbroek  *
32*d56f51eaSDavid van Moolenbroek  * USB sniffing API implementation for Linux platform
33*d56f51eaSDavid van Moolenbroek  * By Paolo Abeni <paolo.abeni@email.it>
34*d56f51eaSDavid van Moolenbroek  * Modifications: Kris Katterjohn <katterjohn@gmail.com>
35*d56f51eaSDavid van Moolenbroek  *
36*d56f51eaSDavid van Moolenbroek  */
37*d56f51eaSDavid van Moolenbroek 
38*d56f51eaSDavid van Moolenbroek #include <sys/cdefs.h>
39*d56f51eaSDavid van Moolenbroek __RCSID("$NetBSD: pcap-usb-linux.c,v 1.3 2015/03/31 21:39:42 christos Exp $");
40*d56f51eaSDavid van Moolenbroek 
41*d56f51eaSDavid van Moolenbroek #ifdef HAVE_CONFIG_H
42*d56f51eaSDavid van Moolenbroek #include "config.h"
43*d56f51eaSDavid van Moolenbroek #endif
44*d56f51eaSDavid van Moolenbroek 
45*d56f51eaSDavid van Moolenbroek #include "pcap-int.h"
46*d56f51eaSDavid van Moolenbroek #include "pcap-usb-linux.h"
47*d56f51eaSDavid van Moolenbroek #include "pcap/usb.h"
48*d56f51eaSDavid van Moolenbroek 
49*d56f51eaSDavid van Moolenbroek #ifdef NEED_STRERROR_H
50*d56f51eaSDavid van Moolenbroek #include "strerror.h"
51*d56f51eaSDavid van Moolenbroek #endif
52*d56f51eaSDavid van Moolenbroek 
53*d56f51eaSDavid van Moolenbroek #include <ctype.h>
54*d56f51eaSDavid van Moolenbroek #include <errno.h>
55*d56f51eaSDavid van Moolenbroek #include <stdlib.h>
56*d56f51eaSDavid van Moolenbroek #include <unistd.h>
57*d56f51eaSDavid van Moolenbroek #include <fcntl.h>
58*d56f51eaSDavid van Moolenbroek #include <string.h>
59*d56f51eaSDavid van Moolenbroek #include <dirent.h>
60*d56f51eaSDavid van Moolenbroek #include <byteswap.h>
61*d56f51eaSDavid van Moolenbroek #include <netinet/in.h>
62*d56f51eaSDavid van Moolenbroek #include <sys/ioctl.h>
63*d56f51eaSDavid van Moolenbroek #include <sys/mman.h>
64*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LINUX_USBDEVICE_FS_H
65*d56f51eaSDavid van Moolenbroek /*
66*d56f51eaSDavid van Moolenbroek  * We might need <linux/compiler.h> to define __user for
67*d56f51eaSDavid van Moolenbroek  * <linux/usbdevice_fs.h>.
68*d56f51eaSDavid van Moolenbroek  */
69*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LINUX_COMPILER_H
70*d56f51eaSDavid van Moolenbroek #include <linux/compiler.h>
71*d56f51eaSDavid van Moolenbroek #endif /* HAVE_LINUX_COMPILER_H */
72*d56f51eaSDavid van Moolenbroek #include <linux/usbdevice_fs.h>
73*d56f51eaSDavid van Moolenbroek #endif /* HAVE_LINUX_USBDEVICE_FS_H */
74*d56f51eaSDavid van Moolenbroek 
75*d56f51eaSDavid van Moolenbroek #define USB_IFACE "usbmon"
76*d56f51eaSDavid van Moolenbroek #define USB_TEXT_DIR_OLD "/sys/kernel/debug/usbmon"
77*d56f51eaSDavid van Moolenbroek #define USB_TEXT_DIR "/sys/kernel/debug/usb/usbmon"
78*d56f51eaSDavid van Moolenbroek #define SYS_USB_BUS_DIR "/sys/bus/usb/devices"
79*d56f51eaSDavid van Moolenbroek #define PROC_USB_BUS_DIR "/proc/bus/usb"
80*d56f51eaSDavid van Moolenbroek #define USB_LINE_LEN 4096
81*d56f51eaSDavid van Moolenbroek 
82*d56f51eaSDavid van Moolenbroek #if __BYTE_ORDER == __LITTLE_ENDIAN
83*d56f51eaSDavid van Moolenbroek #define htols(s) s
84*d56f51eaSDavid van Moolenbroek #define htoll(l) l
85*d56f51eaSDavid van Moolenbroek #define htol64(ll) ll
86*d56f51eaSDavid van Moolenbroek #else
87*d56f51eaSDavid van Moolenbroek #define htols(s) bswap_16(s)
88*d56f51eaSDavid van Moolenbroek #define htoll(l) bswap_32(l)
89*d56f51eaSDavid van Moolenbroek #define htol64(ll) bswap_64(ll)
90*d56f51eaSDavid van Moolenbroek #endif
91*d56f51eaSDavid van Moolenbroek 
92*d56f51eaSDavid van Moolenbroek struct mon_bin_stats {
93*d56f51eaSDavid van Moolenbroek 	u_int32_t queued;
94*d56f51eaSDavid van Moolenbroek 	u_int32_t dropped;
95*d56f51eaSDavid van Moolenbroek };
96*d56f51eaSDavid van Moolenbroek 
97*d56f51eaSDavid van Moolenbroek struct mon_bin_get {
98*d56f51eaSDavid van Moolenbroek 	pcap_usb_header *hdr;
99*d56f51eaSDavid van Moolenbroek 	void *data;
100*d56f51eaSDavid van Moolenbroek 	size_t data_len;   /* Length of data (can be zero) */
101*d56f51eaSDavid van Moolenbroek };
102*d56f51eaSDavid van Moolenbroek 
103*d56f51eaSDavid van Moolenbroek struct mon_bin_mfetch {
104*d56f51eaSDavid van Moolenbroek 	int32_t *offvec;   /* Vector of events fetched */
105*d56f51eaSDavid van Moolenbroek 	int32_t nfetch;    /* Number of events to fetch (out: fetched) */
106*d56f51eaSDavid van Moolenbroek 	int32_t nflush;    /* Number of events to flush */
107*d56f51eaSDavid van Moolenbroek };
108*d56f51eaSDavid van Moolenbroek 
109*d56f51eaSDavid van Moolenbroek #define MON_IOC_MAGIC 0x92
110*d56f51eaSDavid van Moolenbroek 
111*d56f51eaSDavid van Moolenbroek #define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
112*d56f51eaSDavid van Moolenbroek #define MON_IOCX_URB  _IOWR(MON_IOC_MAGIC, 2, struct mon_bin_hdr)
113*d56f51eaSDavid van Moolenbroek #define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
114*d56f51eaSDavid van Moolenbroek #define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
115*d56f51eaSDavid van Moolenbroek #define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
116*d56f51eaSDavid van Moolenbroek #define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
117*d56f51eaSDavid van Moolenbroek #define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
118*d56f51eaSDavid van Moolenbroek #define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
119*d56f51eaSDavid van Moolenbroek 
120*d56f51eaSDavid van Moolenbroek #define MON_BIN_SETUP 	0x1 /* setup hdr is present*/
121*d56f51eaSDavid van Moolenbroek #define MON_BIN_SETUP_ZERO 	0x2 /* setup buffer is not available */
122*d56f51eaSDavid van Moolenbroek #define MON_BIN_DATA_ZERO 	0x4 /* data buffer is not available */
123*d56f51eaSDavid van Moolenbroek #define MON_BIN_ERROR 	0x8
124*d56f51eaSDavid van Moolenbroek 
125*d56f51eaSDavid van Moolenbroek /*
126*d56f51eaSDavid van Moolenbroek  * Private data for capturing on Linux USB.
127*d56f51eaSDavid van Moolenbroek  */
128*d56f51eaSDavid van Moolenbroek struct pcap_usb_linux {
129*d56f51eaSDavid van Moolenbroek 	u_char *mmapbuf;	/* memory-mapped region pointer */
130*d56f51eaSDavid van Moolenbroek 	size_t mmapbuflen;	/* size of region */
131*d56f51eaSDavid van Moolenbroek 	int bus_index;
132*d56f51eaSDavid van Moolenbroek 	u_int packets_read;
133*d56f51eaSDavid van Moolenbroek };
134*d56f51eaSDavid van Moolenbroek 
135*d56f51eaSDavid van Moolenbroek /* forward declaration */
136*d56f51eaSDavid van Moolenbroek static int usb_activate(pcap_t *);
137*d56f51eaSDavid van Moolenbroek static int usb_stats_linux(pcap_t *, struct pcap_stat *);
138*d56f51eaSDavid van Moolenbroek static int usb_stats_linux_bin(pcap_t *, struct pcap_stat *);
139*d56f51eaSDavid van Moolenbroek static int usb_read_linux(pcap_t *, int , pcap_handler , u_char *);
140*d56f51eaSDavid van Moolenbroek static int usb_read_linux_bin(pcap_t *, int , pcap_handler , u_char *);
141*d56f51eaSDavid van Moolenbroek static int usb_read_linux_mmap(pcap_t *, int , pcap_handler , u_char *);
142*d56f51eaSDavid van Moolenbroek static int usb_inject_linux(pcap_t *, const void *, size_t);
143*d56f51eaSDavid van Moolenbroek static int usb_setdirection_linux(pcap_t *, pcap_direction_t);
144*d56f51eaSDavid van Moolenbroek static void usb_cleanup_linux_mmap(pcap_t *);
145*d56f51eaSDavid van Moolenbroek 
146*d56f51eaSDavid van Moolenbroek /* facility to add an USB device to the device list*/
147*d56f51eaSDavid van Moolenbroek static int
usb_dev_add(pcap_if_t ** alldevsp,int n,char * err_str)148*d56f51eaSDavid van Moolenbroek usb_dev_add(pcap_if_t** alldevsp, int n, char *err_str)
149*d56f51eaSDavid van Moolenbroek {
150*d56f51eaSDavid van Moolenbroek 	char dev_name[10];
151*d56f51eaSDavid van Moolenbroek 	char dev_descr[30];
152*d56f51eaSDavid van Moolenbroek 	snprintf(dev_name, 10, USB_IFACE"%d", n);
153*d56f51eaSDavid van Moolenbroek 	snprintf(dev_descr, 30, "USB bus number %d", n);
154*d56f51eaSDavid van Moolenbroek 
155*d56f51eaSDavid van Moolenbroek 	if (pcap_add_if(alldevsp, dev_name, 0,
156*d56f51eaSDavid van Moolenbroek 	    dev_descr, err_str) < 0)
157*d56f51eaSDavid van Moolenbroek 		return -1;
158*d56f51eaSDavid van Moolenbroek 	return 0;
159*d56f51eaSDavid van Moolenbroek }
160*d56f51eaSDavid van Moolenbroek 
161*d56f51eaSDavid van Moolenbroek int
usb_findalldevs(pcap_if_t ** alldevsp,char * err_str)162*d56f51eaSDavid van Moolenbroek usb_findalldevs(pcap_if_t **alldevsp, char *err_str)
163*d56f51eaSDavid van Moolenbroek {
164*d56f51eaSDavid van Moolenbroek 	struct dirent* data;
165*d56f51eaSDavid van Moolenbroek 	int ret = 0;
166*d56f51eaSDavid van Moolenbroek 	DIR* dir;
167*d56f51eaSDavid van Moolenbroek 	int n;
168*d56f51eaSDavid van Moolenbroek 	char* name;
169*d56f51eaSDavid van Moolenbroek 	size_t len;
170*d56f51eaSDavid van Moolenbroek 
171*d56f51eaSDavid van Moolenbroek 	/* try scanning sysfs usb bus directory */
172*d56f51eaSDavid van Moolenbroek 	dir = opendir(SYS_USB_BUS_DIR);
173*d56f51eaSDavid van Moolenbroek 	if (dir != NULL) {
174*d56f51eaSDavid van Moolenbroek 		while ((ret == 0) && ((data = readdir(dir)) != 0)) {
175*d56f51eaSDavid van Moolenbroek 			name = data->d_name;
176*d56f51eaSDavid van Moolenbroek 
177*d56f51eaSDavid van Moolenbroek 			if (strncmp(name, "usb", 3) != 0)
178*d56f51eaSDavid van Moolenbroek 				continue;
179*d56f51eaSDavid van Moolenbroek 
180*d56f51eaSDavid van Moolenbroek 			if (sscanf(&name[3], "%d", &n) == 0)
181*d56f51eaSDavid van Moolenbroek 				continue;
182*d56f51eaSDavid van Moolenbroek 
183*d56f51eaSDavid van Moolenbroek 			ret = usb_dev_add(alldevsp, n, err_str);
184*d56f51eaSDavid van Moolenbroek 		}
185*d56f51eaSDavid van Moolenbroek 
186*d56f51eaSDavid van Moolenbroek 		closedir(dir);
187*d56f51eaSDavid van Moolenbroek 		return ret;
188*d56f51eaSDavid van Moolenbroek 	}
189*d56f51eaSDavid van Moolenbroek 
190*d56f51eaSDavid van Moolenbroek 	/* that didn't work; try scanning procfs usb bus directory */
191*d56f51eaSDavid van Moolenbroek 	dir = opendir(PROC_USB_BUS_DIR);
192*d56f51eaSDavid van Moolenbroek 	if (dir != NULL) {
193*d56f51eaSDavid van Moolenbroek 		while ((ret == 0) && ((data = readdir(dir)) != 0)) {
194*d56f51eaSDavid van Moolenbroek 			name = data->d_name;
195*d56f51eaSDavid van Moolenbroek 			len = strlen(name);
196*d56f51eaSDavid van Moolenbroek 
197*d56f51eaSDavid van Moolenbroek 			/* if this file name does not end with a number it's not of our interest */
198*d56f51eaSDavid van Moolenbroek 			if ((len < 1) || !isdigit(name[--len]))
199*d56f51eaSDavid van Moolenbroek 				continue;
200*d56f51eaSDavid van Moolenbroek 			while (isdigit(name[--len]));
201*d56f51eaSDavid van Moolenbroek 			if (sscanf(&name[len+1], "%d", &n) != 1)
202*d56f51eaSDavid van Moolenbroek 				continue;
203*d56f51eaSDavid van Moolenbroek 
204*d56f51eaSDavid van Moolenbroek 			ret = usb_dev_add(alldevsp, n, err_str);
205*d56f51eaSDavid van Moolenbroek 		}
206*d56f51eaSDavid van Moolenbroek 
207*d56f51eaSDavid van Moolenbroek 		closedir(dir);
208*d56f51eaSDavid van Moolenbroek 		return ret;
209*d56f51eaSDavid van Moolenbroek 	}
210*d56f51eaSDavid van Moolenbroek 
211*d56f51eaSDavid van Moolenbroek 	/* neither of them worked */
212*d56f51eaSDavid van Moolenbroek 	return 0;
213*d56f51eaSDavid van Moolenbroek }
214*d56f51eaSDavid van Moolenbroek 
215*d56f51eaSDavid van Moolenbroek static
usb_mmap(pcap_t * handle)216*d56f51eaSDavid van Moolenbroek int usb_mmap(pcap_t* handle)
217*d56f51eaSDavid van Moolenbroek {
218*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
219*d56f51eaSDavid van Moolenbroek 	int len = ioctl(handle->fd, MON_IOCQ_RING_SIZE);
220*d56f51eaSDavid van Moolenbroek 	if (len < 0)
221*d56f51eaSDavid van Moolenbroek 		return 0;
222*d56f51eaSDavid van Moolenbroek 
223*d56f51eaSDavid van Moolenbroek 	handlep->mmapbuflen = len;
224*d56f51eaSDavid van Moolenbroek 	handlep->mmapbuf = mmap(0, handlep->mmapbuflen, PROT_READ,
225*d56f51eaSDavid van Moolenbroek 	    MAP_SHARED, handle->fd, 0);
226*d56f51eaSDavid van Moolenbroek 	return handlep->mmapbuf != MAP_FAILED;
227*d56f51eaSDavid van Moolenbroek }
228*d56f51eaSDavid van Moolenbroek 
229*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LINUX_USBDEVICE_FS_H
230*d56f51eaSDavid van Moolenbroek 
231*d56f51eaSDavid van Moolenbroek #define CTRL_TIMEOUT    (5*1000)        /* milliseconds */
232*d56f51eaSDavid van Moolenbroek 
233*d56f51eaSDavid van Moolenbroek #define USB_DIR_IN		0x80
234*d56f51eaSDavid van Moolenbroek #define USB_TYPE_STANDARD	0x00
235*d56f51eaSDavid van Moolenbroek #define USB_RECIP_DEVICE	0x00
236*d56f51eaSDavid van Moolenbroek 
237*d56f51eaSDavid van Moolenbroek #define USB_REQ_GET_DESCRIPTOR	6
238*d56f51eaSDavid van Moolenbroek 
239*d56f51eaSDavid van Moolenbroek #define USB_DT_DEVICE		1
240*d56f51eaSDavid van Moolenbroek 
241*d56f51eaSDavid van Moolenbroek /* probe the descriptors of the devices attached to the bus */
242*d56f51eaSDavid van Moolenbroek /* the descriptors will end up in the captured packet stream */
243*d56f51eaSDavid van Moolenbroek /* and be decoded by external apps like wireshark */
244*d56f51eaSDavid van Moolenbroek /* without these identifying probes packet data can't be fully decoded */
245*d56f51eaSDavid van Moolenbroek static void
probe_devices(int bus)246*d56f51eaSDavid van Moolenbroek probe_devices(int bus)
247*d56f51eaSDavid van Moolenbroek {
248*d56f51eaSDavid van Moolenbroek 	struct usbdevfs_ctrltransfer ctrl;
249*d56f51eaSDavid van Moolenbroek 	struct dirent* data;
250*d56f51eaSDavid van Moolenbroek 	int ret = 0;
251*d56f51eaSDavid van Moolenbroek 	char buf[40];
252*d56f51eaSDavid van Moolenbroek 	DIR* dir;
253*d56f51eaSDavid van Moolenbroek 
254*d56f51eaSDavid van Moolenbroek 	/* scan usb bus directories for device nodes */
255*d56f51eaSDavid van Moolenbroek 	snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d", bus);
256*d56f51eaSDavid van Moolenbroek 	dir = opendir(buf);
257*d56f51eaSDavid van Moolenbroek 	if (!dir)
258*d56f51eaSDavid van Moolenbroek 		return;
259*d56f51eaSDavid van Moolenbroek 
260*d56f51eaSDavid van Moolenbroek 	while ((ret >= 0) && ((data = readdir(dir)) != 0)) {
261*d56f51eaSDavid van Moolenbroek 		int fd;
262*d56f51eaSDavid van Moolenbroek 		char* name = data->d_name;
263*d56f51eaSDavid van Moolenbroek 
264*d56f51eaSDavid van Moolenbroek 		if (name[0] == '.')
265*d56f51eaSDavid van Moolenbroek 			continue;
266*d56f51eaSDavid van Moolenbroek 
267*d56f51eaSDavid van Moolenbroek 		snprintf(buf, sizeof(buf), "/dev/bus/usb/%03d/%s", bus, data->d_name);
268*d56f51eaSDavid van Moolenbroek 
269*d56f51eaSDavid van Moolenbroek 		fd = open(buf, O_RDWR);
270*d56f51eaSDavid van Moolenbroek 		if (fd == -1)
271*d56f51eaSDavid van Moolenbroek 			continue;
272*d56f51eaSDavid van Moolenbroek 
273*d56f51eaSDavid van Moolenbroek 		/*
274*d56f51eaSDavid van Moolenbroek 		 * Sigh.  Different kernels have different member names
275*d56f51eaSDavid van Moolenbroek 		 * for this structure.
276*d56f51eaSDavid van Moolenbroek 		 */
277*d56f51eaSDavid van Moolenbroek #ifdef HAVE_USBDEVFS_CTRLTRANSFER_BREQUESTTYPE
278*d56f51eaSDavid van Moolenbroek 		ctrl.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
279*d56f51eaSDavid van Moolenbroek 		ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
280*d56f51eaSDavid van Moolenbroek 		ctrl.wValue = USB_DT_DEVICE << 8;
281*d56f51eaSDavid van Moolenbroek 		ctrl.wIndex = 0;
282*d56f51eaSDavid van Moolenbroek  		ctrl.wLength = sizeof(buf);
283*d56f51eaSDavid van Moolenbroek #else
284*d56f51eaSDavid van Moolenbroek 		ctrl.requesttype = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
285*d56f51eaSDavid van Moolenbroek 		ctrl.request = USB_REQ_GET_DESCRIPTOR;
286*d56f51eaSDavid van Moolenbroek 		ctrl.value = USB_DT_DEVICE << 8;
287*d56f51eaSDavid van Moolenbroek 		ctrl.index = 0;
288*d56f51eaSDavid van Moolenbroek  		ctrl.length = sizeof(buf);
289*d56f51eaSDavid van Moolenbroek #endif
290*d56f51eaSDavid van Moolenbroek 		ctrl.data = buf;
291*d56f51eaSDavid van Moolenbroek 		ctrl.timeout = CTRL_TIMEOUT;
292*d56f51eaSDavid van Moolenbroek 
293*d56f51eaSDavid van Moolenbroek 		ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
294*d56f51eaSDavid van Moolenbroek 
295*d56f51eaSDavid van Moolenbroek 		close(fd);
296*d56f51eaSDavid van Moolenbroek 	}
297*d56f51eaSDavid van Moolenbroek 	closedir(dir);
298*d56f51eaSDavid van Moolenbroek }
299*d56f51eaSDavid van Moolenbroek #endif /* HAVE_LINUX_USBDEVICE_FS_H */
300*d56f51eaSDavid van Moolenbroek 
301*d56f51eaSDavid van Moolenbroek pcap_t *
usb_create(const char * device,char * ebuf,int * is_ours)302*d56f51eaSDavid van Moolenbroek usb_create(const char *device, char *ebuf, int *is_ours)
303*d56f51eaSDavid van Moolenbroek {
304*d56f51eaSDavid van Moolenbroek 	const char *cp;
305*d56f51eaSDavid van Moolenbroek 	char *cpend;
306*d56f51eaSDavid van Moolenbroek 	long devnum;
307*d56f51eaSDavid van Moolenbroek 	pcap_t *p;
308*d56f51eaSDavid van Moolenbroek 
309*d56f51eaSDavid van Moolenbroek 	/* Does this look like a USB monitoring device? */
310*d56f51eaSDavid van Moolenbroek 	cp = strrchr(device, '/');
311*d56f51eaSDavid van Moolenbroek 	if (cp == NULL)
312*d56f51eaSDavid van Moolenbroek 		cp = device;
313*d56f51eaSDavid van Moolenbroek 	/* Does it begin with USB_IFACE? */
314*d56f51eaSDavid van Moolenbroek 	if (strncmp(cp, USB_IFACE, sizeof USB_IFACE - 1) != 0) {
315*d56f51eaSDavid van Moolenbroek 		/* Nope, doesn't begin with USB_IFACE */
316*d56f51eaSDavid van Moolenbroek 		*is_ours = 0;
317*d56f51eaSDavid van Moolenbroek 		return NULL;
318*d56f51eaSDavid van Moolenbroek 	}
319*d56f51eaSDavid van Moolenbroek 	/* Yes - is USB_IFACE followed by a number? */
320*d56f51eaSDavid van Moolenbroek 	cp += sizeof USB_IFACE - 1;
321*d56f51eaSDavid van Moolenbroek 	devnum = strtol(cp, &cpend, 10);
322*d56f51eaSDavid van Moolenbroek 	if (cpend == cp || *cpend != '\0') {
323*d56f51eaSDavid van Moolenbroek 		/* Not followed by a number. */
324*d56f51eaSDavid van Moolenbroek 		*is_ours = 0;
325*d56f51eaSDavid van Moolenbroek 		return NULL;
326*d56f51eaSDavid van Moolenbroek 	}
327*d56f51eaSDavid van Moolenbroek 	if (devnum < 0) {
328*d56f51eaSDavid van Moolenbroek 		/* Followed by a non-valid number. */
329*d56f51eaSDavid van Moolenbroek 		*is_ours = 0;
330*d56f51eaSDavid van Moolenbroek 		return NULL;
331*d56f51eaSDavid van Moolenbroek 	}
332*d56f51eaSDavid van Moolenbroek 
333*d56f51eaSDavid van Moolenbroek 	/* OK, it's probably ours. */
334*d56f51eaSDavid van Moolenbroek 	*is_ours = 1;
335*d56f51eaSDavid van Moolenbroek 
336*d56f51eaSDavid van Moolenbroek 	p = pcap_create_common(device, ebuf, sizeof (struct pcap_usb_linux));
337*d56f51eaSDavid van Moolenbroek 	if (p == NULL)
338*d56f51eaSDavid van Moolenbroek 		return (NULL);
339*d56f51eaSDavid van Moolenbroek 
340*d56f51eaSDavid van Moolenbroek 	p->activate_op = usb_activate;
341*d56f51eaSDavid van Moolenbroek 	return (p);
342*d56f51eaSDavid van Moolenbroek }
343*d56f51eaSDavid van Moolenbroek 
344*d56f51eaSDavid van Moolenbroek static int
usb_activate(pcap_t * handle)345*d56f51eaSDavid van Moolenbroek usb_activate(pcap_t* handle)
346*d56f51eaSDavid van Moolenbroek {
347*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
348*d56f51eaSDavid van Moolenbroek 	char 		full_path[USB_LINE_LEN];
349*d56f51eaSDavid van Moolenbroek 
350*d56f51eaSDavid van Moolenbroek 	/* Initialize some components of the pcap structure. */
351*d56f51eaSDavid van Moolenbroek 	handle->bufsize = handle->snapshot;
352*d56f51eaSDavid van Moolenbroek 	handle->offset = 0;
353*d56f51eaSDavid van Moolenbroek 	handle->linktype = DLT_USB_LINUX;
354*d56f51eaSDavid van Moolenbroek 
355*d56f51eaSDavid van Moolenbroek 	handle->inject_op = usb_inject_linux;
356*d56f51eaSDavid van Moolenbroek 	handle->setfilter_op = install_bpf_program; /* no kernel filtering */
357*d56f51eaSDavid van Moolenbroek 	handle->setdirection_op = usb_setdirection_linux;
358*d56f51eaSDavid van Moolenbroek 	handle->set_datalink_op = NULL;	/* can't change data link type */
359*d56f51eaSDavid van Moolenbroek 	handle->getnonblock_op = pcap_getnonblock_fd;
360*d56f51eaSDavid van Moolenbroek 	handle->setnonblock_op = pcap_setnonblock_fd;
361*d56f51eaSDavid van Moolenbroek 
362*d56f51eaSDavid van Moolenbroek 	/*get usb bus index from device name */
363*d56f51eaSDavid van Moolenbroek 	if (sscanf(handle->opt.source, USB_IFACE"%d", &handlep->bus_index) != 1)
364*d56f51eaSDavid van Moolenbroek 	{
365*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
366*d56f51eaSDavid van Moolenbroek 			"Can't get USB bus index from %s", handle->opt.source);
367*d56f51eaSDavid van Moolenbroek 		return PCAP_ERROR;
368*d56f51eaSDavid van Moolenbroek 	}
369*d56f51eaSDavid van Moolenbroek 
370*d56f51eaSDavid van Moolenbroek 	/*now select the read method: try to open binary interface */
371*d56f51eaSDavid van Moolenbroek 	snprintf(full_path, USB_LINE_LEN, LINUX_USB_MON_DEV"%d", handlep->bus_index);
372*d56f51eaSDavid van Moolenbroek 	handle->fd = open(full_path, O_RDONLY, 0);
373*d56f51eaSDavid van Moolenbroek 	if (handle->fd >= 0)
374*d56f51eaSDavid van Moolenbroek 	{
375*d56f51eaSDavid van Moolenbroek 		if (handle->opt.rfmon) {
376*d56f51eaSDavid van Moolenbroek 			/*
377*d56f51eaSDavid van Moolenbroek 			 * Monitor mode doesn't apply to USB devices.
378*d56f51eaSDavid van Moolenbroek 			 */
379*d56f51eaSDavid van Moolenbroek 			close(handle->fd);
380*d56f51eaSDavid van Moolenbroek 			return PCAP_ERROR_RFMON_NOTSUP;
381*d56f51eaSDavid van Moolenbroek 		}
382*d56f51eaSDavid van Moolenbroek 
383*d56f51eaSDavid van Moolenbroek 		/* binary api is available, try to use fast mmap access */
384*d56f51eaSDavid van Moolenbroek 		if (usb_mmap(handle)) {
385*d56f51eaSDavid van Moolenbroek 			handle->linktype = DLT_USB_LINUX_MMAPPED;
386*d56f51eaSDavid van Moolenbroek 			handle->stats_op = usb_stats_linux_bin;
387*d56f51eaSDavid van Moolenbroek 			handle->read_op = usb_read_linux_mmap;
388*d56f51eaSDavid van Moolenbroek 			handle->cleanup_op = usb_cleanup_linux_mmap;
389*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LINUX_USBDEVICE_FS_H
390*d56f51eaSDavid van Moolenbroek 			probe_devices(handlep->bus_index);
391*d56f51eaSDavid van Moolenbroek #endif
392*d56f51eaSDavid van Moolenbroek 
393*d56f51eaSDavid van Moolenbroek 			/*
394*d56f51eaSDavid van Moolenbroek 			 * "handle->fd" is a real file, so "select()" and
395*d56f51eaSDavid van Moolenbroek 			 * "poll()" work on it.
396*d56f51eaSDavid van Moolenbroek 			 */
397*d56f51eaSDavid van Moolenbroek 			handle->selectable_fd = handle->fd;
398*d56f51eaSDavid van Moolenbroek 			return 0;
399*d56f51eaSDavid van Moolenbroek 		}
400*d56f51eaSDavid van Moolenbroek 
401*d56f51eaSDavid van Moolenbroek 		/* can't mmap, use plain binary interface access */
402*d56f51eaSDavid van Moolenbroek 		handle->stats_op = usb_stats_linux_bin;
403*d56f51eaSDavid van Moolenbroek 		handle->read_op = usb_read_linux_bin;
404*d56f51eaSDavid van Moolenbroek #ifdef HAVE_LINUX_USBDEVICE_FS_H
405*d56f51eaSDavid van Moolenbroek 		probe_devices(handlep->bus_index);
406*d56f51eaSDavid van Moolenbroek #endif
407*d56f51eaSDavid van Moolenbroek 	}
408*d56f51eaSDavid van Moolenbroek 	else {
409*d56f51eaSDavid van Moolenbroek 		/*Binary interface not available, try open text interface */
410*d56f51eaSDavid van Moolenbroek 		snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR"/%dt", handlep->bus_index);
411*d56f51eaSDavid van Moolenbroek 		handle->fd = open(full_path, O_RDONLY, 0);
412*d56f51eaSDavid van Moolenbroek 		if (handle->fd < 0)
413*d56f51eaSDavid van Moolenbroek 		{
414*d56f51eaSDavid van Moolenbroek 			if (errno == ENOENT)
415*d56f51eaSDavid van Moolenbroek 			{
416*d56f51eaSDavid van Moolenbroek 				/*
417*d56f51eaSDavid van Moolenbroek 				 * Not found at the new location; try
418*d56f51eaSDavid van Moolenbroek 				 * the old location.
419*d56f51eaSDavid van Moolenbroek 				 */
420*d56f51eaSDavid van Moolenbroek 				snprintf(full_path, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%dt", handlep->bus_index);
421*d56f51eaSDavid van Moolenbroek 				handle->fd = open(full_path, O_RDONLY, 0);
422*d56f51eaSDavid van Moolenbroek 			}
423*d56f51eaSDavid van Moolenbroek 			if (handle->fd < 0) {
424*d56f51eaSDavid van Moolenbroek 				/* no more fallback, give it up*/
425*d56f51eaSDavid van Moolenbroek 				snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
426*d56f51eaSDavid van Moolenbroek 					"Can't open USB bus file %s: %s", full_path, strerror(errno));
427*d56f51eaSDavid van Moolenbroek 				return PCAP_ERROR;
428*d56f51eaSDavid van Moolenbroek 			}
429*d56f51eaSDavid van Moolenbroek 		}
430*d56f51eaSDavid van Moolenbroek 
431*d56f51eaSDavid van Moolenbroek 		if (handle->opt.rfmon) {
432*d56f51eaSDavid van Moolenbroek 			/*
433*d56f51eaSDavid van Moolenbroek 			 * Monitor mode doesn't apply to USB devices.
434*d56f51eaSDavid van Moolenbroek 			 */
435*d56f51eaSDavid van Moolenbroek 			close(handle->fd);
436*d56f51eaSDavid van Moolenbroek 			return PCAP_ERROR_RFMON_NOTSUP;
437*d56f51eaSDavid van Moolenbroek 		}
438*d56f51eaSDavid van Moolenbroek 
439*d56f51eaSDavid van Moolenbroek 		handle->stats_op = usb_stats_linux;
440*d56f51eaSDavid van Moolenbroek 		handle->read_op = usb_read_linux;
441*d56f51eaSDavid van Moolenbroek 	}
442*d56f51eaSDavid van Moolenbroek 
443*d56f51eaSDavid van Moolenbroek 	/*
444*d56f51eaSDavid van Moolenbroek 	 * "handle->fd" is a real file, so "select()" and "poll()"
445*d56f51eaSDavid van Moolenbroek 	 * work on it.
446*d56f51eaSDavid van Moolenbroek 	 */
447*d56f51eaSDavid van Moolenbroek 	handle->selectable_fd = handle->fd;
448*d56f51eaSDavid van Moolenbroek 
449*d56f51eaSDavid van Moolenbroek 	/* for plain binary access and text access we need to allocate the read
450*d56f51eaSDavid van Moolenbroek 	 * buffer */
451*d56f51eaSDavid van Moolenbroek 	handle->buffer = malloc(handle->bufsize);
452*d56f51eaSDavid van Moolenbroek 	if (!handle->buffer) {
453*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
454*d56f51eaSDavid van Moolenbroek 			 "malloc: %s", pcap_strerror(errno));
455*d56f51eaSDavid van Moolenbroek 		close(handle->fd);
456*d56f51eaSDavid van Moolenbroek 		return PCAP_ERROR;
457*d56f51eaSDavid van Moolenbroek 	}
458*d56f51eaSDavid van Moolenbroek 	return 0;
459*d56f51eaSDavid van Moolenbroek }
460*d56f51eaSDavid van Moolenbroek 
461*d56f51eaSDavid van Moolenbroek static inline int
ascii_to_int(char c)462*d56f51eaSDavid van Moolenbroek ascii_to_int(char c)
463*d56f51eaSDavid van Moolenbroek {
464*d56f51eaSDavid van Moolenbroek 	return c < 'A' ? c- '0': ((c<'a') ? c - 'A' + 10: c-'a'+10);
465*d56f51eaSDavid van Moolenbroek }
466*d56f51eaSDavid van Moolenbroek 
467*d56f51eaSDavid van Moolenbroek /*
468*d56f51eaSDavid van Moolenbroek  * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
469*d56f51eaSDavid van Moolenbroek  * <linux-kernel-source>/drivers/usb/mon/mon_text.c for urb string
470*d56f51eaSDavid van Moolenbroek  * format description
471*d56f51eaSDavid van Moolenbroek  */
472*d56f51eaSDavid van Moolenbroek static int
usb_read_linux(pcap_t * handle,int max_packets,pcap_handler callback,u_char * user)473*d56f51eaSDavid van Moolenbroek usb_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
474*d56f51eaSDavid van Moolenbroek {
475*d56f51eaSDavid van Moolenbroek 	/* see:
476*d56f51eaSDavid van Moolenbroek 	* /usr/src/linux/Documentation/usb/usbmon.txt
477*d56f51eaSDavid van Moolenbroek 	* for message format
478*d56f51eaSDavid van Moolenbroek 	*/
479*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
480*d56f51eaSDavid van Moolenbroek 	unsigned timestamp;
481*d56f51eaSDavid van Moolenbroek 	int tag, cnt, ep_num, dev_addr, dummy, ret, urb_len, data_len;
482*d56f51eaSDavid van Moolenbroek 	char etype, pipeid1, pipeid2, status[16], urb_tag, line[USB_LINE_LEN];
483*d56f51eaSDavid van Moolenbroek 	char *string = line;
484*d56f51eaSDavid van Moolenbroek 	u_char * rawdata = handle->buffer;
485*d56f51eaSDavid van Moolenbroek 	struct pcap_pkthdr pkth;
486*d56f51eaSDavid van Moolenbroek 	pcap_usb_header* uhdr = (pcap_usb_header*)handle->buffer;
487*d56f51eaSDavid van Moolenbroek 	u_char urb_transfer=0;
488*d56f51eaSDavid van Moolenbroek 	int incoming=0;
489*d56f51eaSDavid van Moolenbroek 
490*d56f51eaSDavid van Moolenbroek 	/* ignore interrupt system call errors */
491*d56f51eaSDavid van Moolenbroek 	do {
492*d56f51eaSDavid van Moolenbroek 		ret = read(handle->fd, line, USB_LINE_LEN - 1);
493*d56f51eaSDavid van Moolenbroek 		if (handle->break_loop)
494*d56f51eaSDavid van Moolenbroek 		{
495*d56f51eaSDavid van Moolenbroek 			handle->break_loop = 0;
496*d56f51eaSDavid van Moolenbroek 			return -2;
497*d56f51eaSDavid van Moolenbroek 		}
498*d56f51eaSDavid van Moolenbroek 	} while ((ret == -1) && (errno == EINTR));
499*d56f51eaSDavid van Moolenbroek 	if (ret < 0)
500*d56f51eaSDavid van Moolenbroek 	{
501*d56f51eaSDavid van Moolenbroek 		if (errno == EAGAIN)
502*d56f51eaSDavid van Moolenbroek 			return 0;	/* no data there */
503*d56f51eaSDavid van Moolenbroek 
504*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
505*d56f51eaSDavid van Moolenbroek 		    "Can't read from fd %d: %s", handle->fd, strerror(errno));
506*d56f51eaSDavid van Moolenbroek 		return -1;
507*d56f51eaSDavid van Moolenbroek 	}
508*d56f51eaSDavid van Moolenbroek 
509*d56f51eaSDavid van Moolenbroek 	/* read urb header; %n argument may increment return value, but it's
510*d56f51eaSDavid van Moolenbroek 	* not mandatory, so does not count on it*/
511*d56f51eaSDavid van Moolenbroek 	string[ret] = 0;
512*d56f51eaSDavid van Moolenbroek 	ret = sscanf(string, "%x %d %c %c%c:%d:%d %s%n", &tag, &timestamp, &etype,
513*d56f51eaSDavid van Moolenbroek 		&pipeid1, &pipeid2, &dev_addr, &ep_num, status,
514*d56f51eaSDavid van Moolenbroek 		&cnt);
515*d56f51eaSDavid van Moolenbroek 	if (ret < 8)
516*d56f51eaSDavid van Moolenbroek 	{
517*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
518*d56f51eaSDavid van Moolenbroek 		    "Can't parse USB bus message '%s', too few tokens (expected 8 got %d)",
519*d56f51eaSDavid van Moolenbroek 		    string, ret);
520*d56f51eaSDavid van Moolenbroek 		return -1;
521*d56f51eaSDavid van Moolenbroek 	}
522*d56f51eaSDavid van Moolenbroek 	uhdr->id = tag;
523*d56f51eaSDavid van Moolenbroek 	uhdr->device_address = dev_addr;
524*d56f51eaSDavid van Moolenbroek 	uhdr->bus_id = handlep->bus_index;
525*d56f51eaSDavid van Moolenbroek 	uhdr->status = 0;
526*d56f51eaSDavid van Moolenbroek 	string += cnt;
527*d56f51eaSDavid van Moolenbroek 
528*d56f51eaSDavid van Moolenbroek 	/* don't use usbmon provided timestamp, since it have low precision*/
529*d56f51eaSDavid van Moolenbroek 	if (gettimeofday(&pkth.ts, NULL) < 0)
530*d56f51eaSDavid van Moolenbroek 	{
531*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
532*d56f51eaSDavid van Moolenbroek 			"Can't get timestamp for message '%s' %d:%s",
533*d56f51eaSDavid van Moolenbroek 			string, errno, strerror(errno));
534*d56f51eaSDavid van Moolenbroek 		return -1;
535*d56f51eaSDavid van Moolenbroek 	}
536*d56f51eaSDavid van Moolenbroek 	uhdr->ts_sec = pkth.ts.tv_sec;
537*d56f51eaSDavid van Moolenbroek 	uhdr->ts_usec = pkth.ts.tv_usec;
538*d56f51eaSDavid van Moolenbroek 
539*d56f51eaSDavid van Moolenbroek 	/* parse endpoint information */
540*d56f51eaSDavid van Moolenbroek 	if (pipeid1 == 'C')
541*d56f51eaSDavid van Moolenbroek 		urb_transfer = URB_CONTROL;
542*d56f51eaSDavid van Moolenbroek 	else if (pipeid1 == 'Z')
543*d56f51eaSDavid van Moolenbroek 		urb_transfer = URB_ISOCHRONOUS;
544*d56f51eaSDavid van Moolenbroek 	else if (pipeid1 == 'I')
545*d56f51eaSDavid van Moolenbroek 		urb_transfer = URB_INTERRUPT;
546*d56f51eaSDavid van Moolenbroek 	else if (pipeid1 == 'B')
547*d56f51eaSDavid van Moolenbroek 		urb_transfer = URB_BULK;
548*d56f51eaSDavid van Moolenbroek 	if (pipeid2 == 'i') {
549*d56f51eaSDavid van Moolenbroek 		ep_num |= URB_TRANSFER_IN;
550*d56f51eaSDavid van Moolenbroek 		incoming = 1;
551*d56f51eaSDavid van Moolenbroek 	}
552*d56f51eaSDavid van Moolenbroek 	if (etype == 'C')
553*d56f51eaSDavid van Moolenbroek 		incoming = !incoming;
554*d56f51eaSDavid van Moolenbroek 
555*d56f51eaSDavid van Moolenbroek 	/* direction check*/
556*d56f51eaSDavid van Moolenbroek 	if (incoming)
557*d56f51eaSDavid van Moolenbroek 	{
558*d56f51eaSDavid van Moolenbroek 		if (handle->direction == PCAP_D_OUT)
559*d56f51eaSDavid van Moolenbroek 			return 0;
560*d56f51eaSDavid van Moolenbroek 	}
561*d56f51eaSDavid van Moolenbroek 	else
562*d56f51eaSDavid van Moolenbroek 		if (handle->direction == PCAP_D_IN)
563*d56f51eaSDavid van Moolenbroek 			return 0;
564*d56f51eaSDavid van Moolenbroek 	uhdr->event_type = etype;
565*d56f51eaSDavid van Moolenbroek 	uhdr->transfer_type = urb_transfer;
566*d56f51eaSDavid van Moolenbroek 	uhdr->endpoint_number = ep_num;
567*d56f51eaSDavid van Moolenbroek 	pkth.caplen = sizeof(pcap_usb_header);
568*d56f51eaSDavid van Moolenbroek 	rawdata += sizeof(pcap_usb_header);
569*d56f51eaSDavid van Moolenbroek 
570*d56f51eaSDavid van Moolenbroek 	/* check if this is a setup packet */
571*d56f51eaSDavid van Moolenbroek 	ret = sscanf(status, "%d", &dummy);
572*d56f51eaSDavid van Moolenbroek 	if (ret != 1)
573*d56f51eaSDavid van Moolenbroek 	{
574*d56f51eaSDavid van Moolenbroek 		/* this a setup packet, setup data can be filled with underscore if
575*d56f51eaSDavid van Moolenbroek 		* usbmon has not been able to read them, so we must parse this fields as
576*d56f51eaSDavid van Moolenbroek 		* strings */
577*d56f51eaSDavid van Moolenbroek 		pcap_usb_setup* shdr;
578*d56f51eaSDavid van Moolenbroek 		char str1[3], str2[3], str3[5], str4[5], str5[5];
579*d56f51eaSDavid van Moolenbroek 		ret = sscanf(string, "%s %s %s %s %s%n", str1, str2, str3, str4,
580*d56f51eaSDavid van Moolenbroek 		str5, &cnt);
581*d56f51eaSDavid van Moolenbroek 		if (ret < 5)
582*d56f51eaSDavid van Moolenbroek 		{
583*d56f51eaSDavid van Moolenbroek 			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
584*d56f51eaSDavid van Moolenbroek 				"Can't parse USB bus message '%s', too few tokens (expected 5 got %d)",
585*d56f51eaSDavid van Moolenbroek 				string, ret);
586*d56f51eaSDavid van Moolenbroek 			return -1;
587*d56f51eaSDavid van Moolenbroek 		}
588*d56f51eaSDavid van Moolenbroek 		string += cnt;
589*d56f51eaSDavid van Moolenbroek 
590*d56f51eaSDavid van Moolenbroek 		/* try to convert to corresponding integer */
591*d56f51eaSDavid van Moolenbroek 		shdr = &uhdr->setup;
592*d56f51eaSDavid van Moolenbroek 		shdr->bmRequestType = strtoul(str1, 0, 16);
593*d56f51eaSDavid van Moolenbroek 		shdr->bRequest = strtoul(str2, 0, 16);
594*d56f51eaSDavid van Moolenbroek 		shdr->wValue = htols(strtoul(str3, 0, 16));
595*d56f51eaSDavid van Moolenbroek 		shdr->wIndex = htols(strtoul(str4, 0, 16));
596*d56f51eaSDavid van Moolenbroek 		shdr->wLength = htols(strtoul(str5, 0, 16));
597*d56f51eaSDavid van Moolenbroek 
598*d56f51eaSDavid van Moolenbroek 		uhdr->setup_flag = 0;
599*d56f51eaSDavid van Moolenbroek 	}
600*d56f51eaSDavid van Moolenbroek 	else
601*d56f51eaSDavid van Moolenbroek 		uhdr->setup_flag = 1;
602*d56f51eaSDavid van Moolenbroek 
603*d56f51eaSDavid van Moolenbroek 	/* read urb data */
604*d56f51eaSDavid van Moolenbroek 	ret = sscanf(string, " %d%n", &urb_len, &cnt);
605*d56f51eaSDavid van Moolenbroek 	if (ret < 1)
606*d56f51eaSDavid van Moolenbroek 	{
607*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
608*d56f51eaSDavid van Moolenbroek 		  "Can't parse urb length from '%s'", string);
609*d56f51eaSDavid van Moolenbroek 		return -1;
610*d56f51eaSDavid van Moolenbroek 	}
611*d56f51eaSDavid van Moolenbroek 	string += cnt;
612*d56f51eaSDavid van Moolenbroek 
613*d56f51eaSDavid van Moolenbroek 	/* urb tag is not present if urb length is 0, so we can stop here
614*d56f51eaSDavid van Moolenbroek 	 * text parsing */
615*d56f51eaSDavid van Moolenbroek 	pkth.len = urb_len+pkth.caplen;
616*d56f51eaSDavid van Moolenbroek 	uhdr->urb_len = urb_len;
617*d56f51eaSDavid van Moolenbroek 	uhdr->data_flag = 1;
618*d56f51eaSDavid van Moolenbroek 	data_len = 0;
619*d56f51eaSDavid van Moolenbroek 	if (uhdr->urb_len == 0)
620*d56f51eaSDavid van Moolenbroek 		goto got;
621*d56f51eaSDavid van Moolenbroek 
622*d56f51eaSDavid van Moolenbroek 	/* check for data presence; data is present if and only if urb tag is '=' */
623*d56f51eaSDavid van Moolenbroek 	if (sscanf(string, " %c", &urb_tag) != 1)
624*d56f51eaSDavid van Moolenbroek 	{
625*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
626*d56f51eaSDavid van Moolenbroek 			"Can't parse urb tag from '%s'", string);
627*d56f51eaSDavid van Moolenbroek 		return -1;
628*d56f51eaSDavid van Moolenbroek 	}
629*d56f51eaSDavid van Moolenbroek 
630*d56f51eaSDavid van Moolenbroek 	if (urb_tag != '=')
631*d56f51eaSDavid van Moolenbroek 		goto got;
632*d56f51eaSDavid van Moolenbroek 
633*d56f51eaSDavid van Moolenbroek 	/* skip urb tag and following space */
634*d56f51eaSDavid van Moolenbroek 	string += 3;
635*d56f51eaSDavid van Moolenbroek 
636*d56f51eaSDavid van Moolenbroek 	/* if we reach this point we got some urb data*/
637*d56f51eaSDavid van Moolenbroek 	uhdr->data_flag = 0;
638*d56f51eaSDavid van Moolenbroek 
639*d56f51eaSDavid van Moolenbroek 	/* read all urb data; if urb length is greater then the usbmon internal
640*d56f51eaSDavid van Moolenbroek 	 * buffer length used by the kernel to spool the URB, we get only
641*d56f51eaSDavid van Moolenbroek 	 * a partial information.
642*d56f51eaSDavid van Moolenbroek 	 * At least until linux 2.6.17 there is no way to set usbmon intenal buffer
643*d56f51eaSDavid van Moolenbroek 	 * length and default value is 130. */
644*d56f51eaSDavid van Moolenbroek 	while ((string[0] != 0) && (string[1] != 0) && (pkth.caplen < handle->snapshot))
645*d56f51eaSDavid van Moolenbroek 	{
646*d56f51eaSDavid van Moolenbroek 		rawdata[0] = ascii_to_int(string[0]) * 16 + ascii_to_int(string[1]);
647*d56f51eaSDavid van Moolenbroek 		rawdata++;
648*d56f51eaSDavid van Moolenbroek 		string+=2;
649*d56f51eaSDavid van Moolenbroek 		if (string[0] == ' ')
650*d56f51eaSDavid van Moolenbroek 			string++;
651*d56f51eaSDavid van Moolenbroek 		pkth.caplen++;
652*d56f51eaSDavid van Moolenbroek 		data_len++;
653*d56f51eaSDavid van Moolenbroek 	}
654*d56f51eaSDavid van Moolenbroek 
655*d56f51eaSDavid van Moolenbroek got:
656*d56f51eaSDavid van Moolenbroek 	uhdr->data_len = data_len;
657*d56f51eaSDavid van Moolenbroek 	if (pkth.caplen > handle->snapshot)
658*d56f51eaSDavid van Moolenbroek 		pkth.caplen = handle->snapshot;
659*d56f51eaSDavid van Moolenbroek 
660*d56f51eaSDavid van Moolenbroek 	if (handle->fcode.bf_insns == NULL ||
661*d56f51eaSDavid van Moolenbroek 	    bpf_filter(handle->fcode.bf_insns, handle->buffer,
662*d56f51eaSDavid van Moolenbroek 	      pkth.len, pkth.caplen)) {
663*d56f51eaSDavid van Moolenbroek 		handlep->packets_read++;
664*d56f51eaSDavid van Moolenbroek 		callback(user, &pkth, handle->buffer);
665*d56f51eaSDavid van Moolenbroek 		return 1;
666*d56f51eaSDavid van Moolenbroek 	}
667*d56f51eaSDavid van Moolenbroek 	return 0;	/* didn't pass filter */
668*d56f51eaSDavid van Moolenbroek }
669*d56f51eaSDavid van Moolenbroek 
670*d56f51eaSDavid van Moolenbroek static int
usb_inject_linux(pcap_t * handle,const void * buf,size_t size)671*d56f51eaSDavid van Moolenbroek usb_inject_linux(pcap_t *handle, const void *buf, size_t size)
672*d56f51eaSDavid van Moolenbroek {
673*d56f51eaSDavid van Moolenbroek 	snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on "
674*d56f51eaSDavid van Moolenbroek 		"USB devices");
675*d56f51eaSDavid van Moolenbroek 	return (-1);
676*d56f51eaSDavid van Moolenbroek }
677*d56f51eaSDavid van Moolenbroek 
678*d56f51eaSDavid van Moolenbroek static int
usb_stats_linux(pcap_t * handle,struct pcap_stat * stats)679*d56f51eaSDavid van Moolenbroek usb_stats_linux(pcap_t *handle, struct pcap_stat *stats)
680*d56f51eaSDavid van Moolenbroek {
681*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
682*d56f51eaSDavid van Moolenbroek 	int dummy, ret, consumed, cnt;
683*d56f51eaSDavid van Moolenbroek 	char string[USB_LINE_LEN];
684*d56f51eaSDavid van Moolenbroek 	char token[USB_LINE_LEN];
685*d56f51eaSDavid van Moolenbroek 	char * ptr = string;
686*d56f51eaSDavid van Moolenbroek 	int fd;
687*d56f51eaSDavid van Moolenbroek 
688*d56f51eaSDavid van Moolenbroek 	snprintf(string, USB_LINE_LEN, USB_TEXT_DIR"/%ds", handlep->bus_index);
689*d56f51eaSDavid van Moolenbroek 	fd = open(string, O_RDONLY, 0);
690*d56f51eaSDavid van Moolenbroek 	if (fd < 0)
691*d56f51eaSDavid van Moolenbroek 	{
692*d56f51eaSDavid van Moolenbroek 		if (errno == ENOENT)
693*d56f51eaSDavid van Moolenbroek 		{
694*d56f51eaSDavid van Moolenbroek 			/*
695*d56f51eaSDavid van Moolenbroek 			 * Not found at the new location; try the old
696*d56f51eaSDavid van Moolenbroek 			 * location.
697*d56f51eaSDavid van Moolenbroek 			 */
698*d56f51eaSDavid van Moolenbroek 			snprintf(string, USB_LINE_LEN, USB_TEXT_DIR_OLD"/%ds", handlep->bus_index);
699*d56f51eaSDavid van Moolenbroek 			fd = open(string, O_RDONLY, 0);
700*d56f51eaSDavid van Moolenbroek 		}
701*d56f51eaSDavid van Moolenbroek 		if (fd < 0) {
702*d56f51eaSDavid van Moolenbroek 			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
703*d56f51eaSDavid van Moolenbroek 				"Can't open USB stats file %s: %s",
704*d56f51eaSDavid van Moolenbroek 				string, strerror(errno));
705*d56f51eaSDavid van Moolenbroek 			return -1;
706*d56f51eaSDavid van Moolenbroek 		}
707*d56f51eaSDavid van Moolenbroek 	}
708*d56f51eaSDavid van Moolenbroek 
709*d56f51eaSDavid van Moolenbroek 	/* read stats line */
710*d56f51eaSDavid van Moolenbroek 	do {
711*d56f51eaSDavid van Moolenbroek 		ret = read(fd, string, USB_LINE_LEN-1);
712*d56f51eaSDavid van Moolenbroek 	} while ((ret == -1) && (errno == EINTR));
713*d56f51eaSDavid van Moolenbroek 	close(fd);
714*d56f51eaSDavid van Moolenbroek 
715*d56f51eaSDavid van Moolenbroek 	if (ret < 0)
716*d56f51eaSDavid van Moolenbroek 	{
717*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
718*d56f51eaSDavid van Moolenbroek 			"Can't read stats from fd %d ", fd);
719*d56f51eaSDavid van Moolenbroek 		return -1;
720*d56f51eaSDavid van Moolenbroek 	}
721*d56f51eaSDavid van Moolenbroek 	string[ret] = 0;
722*d56f51eaSDavid van Moolenbroek 
723*d56f51eaSDavid van Moolenbroek 	/* extract info on dropped urbs */
724*d56f51eaSDavid van Moolenbroek 	for (consumed=0; consumed < ret; ) {
725*d56f51eaSDavid van Moolenbroek 		/* from the sscanf man page:
726*d56f51eaSDavid van Moolenbroek  		 * The C standard says: "Execution of a %n directive does
727*d56f51eaSDavid van Moolenbroek  		 * not increment the assignment count returned at the completion
728*d56f51eaSDavid van Moolenbroek 		 * of  execution" but the Corrigendum seems to contradict this.
729*d56f51eaSDavid van Moolenbroek 		 * Do not make any assumptions on the effect of %n conversions
730*d56f51eaSDavid van Moolenbroek 		 * on the return value and explicitly check for cnt assignmet*/
731*d56f51eaSDavid van Moolenbroek 		int ntok;
732*d56f51eaSDavid van Moolenbroek 
733*d56f51eaSDavid van Moolenbroek 		cnt = -1;
734*d56f51eaSDavid van Moolenbroek 		ntok = sscanf(ptr, "%s%n", token, &cnt);
735*d56f51eaSDavid van Moolenbroek 		if ((ntok < 1) || (cnt < 0))
736*d56f51eaSDavid van Moolenbroek 			break;
737*d56f51eaSDavid van Moolenbroek 		consumed += cnt;
738*d56f51eaSDavid van Moolenbroek 		ptr += cnt;
739*d56f51eaSDavid van Moolenbroek 		if (strcmp(token, "nreaders") == 0)
740*d56f51eaSDavid van Moolenbroek 			ret = sscanf(ptr, "%d", &stats->ps_drop);
741*d56f51eaSDavid van Moolenbroek 		else
742*d56f51eaSDavid van Moolenbroek 			ret = sscanf(ptr, "%d", &dummy);
743*d56f51eaSDavid van Moolenbroek 		if (ntok != 1)
744*d56f51eaSDavid van Moolenbroek 			break;
745*d56f51eaSDavid van Moolenbroek 		consumed += cnt;
746*d56f51eaSDavid van Moolenbroek 		ptr += cnt;
747*d56f51eaSDavid van Moolenbroek 	}
748*d56f51eaSDavid van Moolenbroek 
749*d56f51eaSDavid van Moolenbroek 	stats->ps_recv = handlep->packets_read;
750*d56f51eaSDavid van Moolenbroek 	stats->ps_ifdrop = 0;
751*d56f51eaSDavid van Moolenbroek 	return 0;
752*d56f51eaSDavid van Moolenbroek }
753*d56f51eaSDavid van Moolenbroek 
754*d56f51eaSDavid van Moolenbroek static int
usb_setdirection_linux(pcap_t * p,pcap_direction_t d)755*d56f51eaSDavid van Moolenbroek usb_setdirection_linux(pcap_t *p, pcap_direction_t d)
756*d56f51eaSDavid van Moolenbroek {
757*d56f51eaSDavid van Moolenbroek 	p->direction = d;
758*d56f51eaSDavid van Moolenbroek 	return 0;
759*d56f51eaSDavid van Moolenbroek }
760*d56f51eaSDavid van Moolenbroek 
761*d56f51eaSDavid van Moolenbroek 
762*d56f51eaSDavid van Moolenbroek static int
usb_stats_linux_bin(pcap_t * handle,struct pcap_stat * stats)763*d56f51eaSDavid van Moolenbroek usb_stats_linux_bin(pcap_t *handle, struct pcap_stat *stats)
764*d56f51eaSDavid van Moolenbroek {
765*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
766*d56f51eaSDavid van Moolenbroek 	int ret;
767*d56f51eaSDavid van Moolenbroek 	struct mon_bin_stats st;
768*d56f51eaSDavid van Moolenbroek 	ret = ioctl(handle->fd, MON_IOCG_STATS, &st);
769*d56f51eaSDavid van Moolenbroek 	if (ret < 0)
770*d56f51eaSDavid van Moolenbroek 	{
771*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
772*d56f51eaSDavid van Moolenbroek 			"Can't read stats from fd %d:%s ", handle->fd, strerror(errno));
773*d56f51eaSDavid van Moolenbroek 		return -1;
774*d56f51eaSDavid van Moolenbroek 	}
775*d56f51eaSDavid van Moolenbroek 
776*d56f51eaSDavid van Moolenbroek 	stats->ps_recv = handlep->packets_read + st.queued;
777*d56f51eaSDavid van Moolenbroek 	stats->ps_drop = st.dropped;
778*d56f51eaSDavid van Moolenbroek 	stats->ps_ifdrop = 0;
779*d56f51eaSDavid van Moolenbroek 	return 0;
780*d56f51eaSDavid van Moolenbroek }
781*d56f51eaSDavid van Moolenbroek 
782*d56f51eaSDavid van Moolenbroek /*
783*d56f51eaSDavid van Moolenbroek  * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
784*d56f51eaSDavid van Moolenbroek  * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
785*d56f51eaSDavid van Moolenbroek  */
786*d56f51eaSDavid van Moolenbroek static int
usb_read_linux_bin(pcap_t * handle,int max_packets,pcap_handler callback,u_char * user)787*d56f51eaSDavid van Moolenbroek usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
788*d56f51eaSDavid van Moolenbroek {
789*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
790*d56f51eaSDavid van Moolenbroek 	struct mon_bin_get info;
791*d56f51eaSDavid van Moolenbroek 	int ret;
792*d56f51eaSDavid van Moolenbroek 	struct pcap_pkthdr pkth;
793*d56f51eaSDavid van Moolenbroek 	int clen = handle->snapshot - sizeof(pcap_usb_header);
794*d56f51eaSDavid van Moolenbroek 
795*d56f51eaSDavid van Moolenbroek 	/* the usb header is going to be part of 'packet' data*/
796*d56f51eaSDavid van Moolenbroek 	info.hdr = (pcap_usb_header*) handle->buffer;
797*d56f51eaSDavid van Moolenbroek 	info.data = handle->buffer + sizeof(pcap_usb_header);
798*d56f51eaSDavid van Moolenbroek 	info.data_len = clen;
799*d56f51eaSDavid van Moolenbroek 
800*d56f51eaSDavid van Moolenbroek 	/* ignore interrupt system call errors */
801*d56f51eaSDavid van Moolenbroek 	do {
802*d56f51eaSDavid van Moolenbroek 		ret = ioctl(handle->fd, MON_IOCX_GET, &info);
803*d56f51eaSDavid van Moolenbroek 		if (handle->break_loop)
804*d56f51eaSDavid van Moolenbroek 		{
805*d56f51eaSDavid van Moolenbroek 			handle->break_loop = 0;
806*d56f51eaSDavid van Moolenbroek 			return -2;
807*d56f51eaSDavid van Moolenbroek 		}
808*d56f51eaSDavid van Moolenbroek 	} while ((ret == -1) && (errno == EINTR));
809*d56f51eaSDavid van Moolenbroek 	if (ret < 0)
810*d56f51eaSDavid van Moolenbroek 	{
811*d56f51eaSDavid van Moolenbroek 		if (errno == EAGAIN)
812*d56f51eaSDavid van Moolenbroek 			return 0;	/* no data there */
813*d56f51eaSDavid van Moolenbroek 
814*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
815*d56f51eaSDavid van Moolenbroek 		    "Can't read from fd %d: %s", handle->fd, strerror(errno));
816*d56f51eaSDavid van Moolenbroek 		return -1;
817*d56f51eaSDavid van Moolenbroek 	}
818*d56f51eaSDavid van Moolenbroek 
819*d56f51eaSDavid van Moolenbroek 	/* we can get less that than really captured from kernel, depending on
820*d56f51eaSDavid van Moolenbroek 	 * snaplen, so adjust header accordingly */
821*d56f51eaSDavid van Moolenbroek 	if (info.hdr->data_len < clen)
822*d56f51eaSDavid van Moolenbroek 		clen = info.hdr->data_len;
823*d56f51eaSDavid van Moolenbroek 	info.hdr->data_len = clen;
824*d56f51eaSDavid van Moolenbroek 	pkth.caplen = clen + sizeof(pcap_usb_header);
825*d56f51eaSDavid van Moolenbroek 	pkth.len = info.hdr->data_len + sizeof(pcap_usb_header);
826*d56f51eaSDavid van Moolenbroek 	pkth.ts.tv_sec = info.hdr->ts_sec;
827*d56f51eaSDavid van Moolenbroek 	pkth.ts.tv_usec = info.hdr->ts_usec;
828*d56f51eaSDavid van Moolenbroek 
829*d56f51eaSDavid van Moolenbroek 	if (handle->fcode.bf_insns == NULL ||
830*d56f51eaSDavid van Moolenbroek 	    bpf_filter(handle->fcode.bf_insns, handle->buffer,
831*d56f51eaSDavid van Moolenbroek 	      pkth.len, pkth.caplen)) {
832*d56f51eaSDavid van Moolenbroek 		handlep->packets_read++;
833*d56f51eaSDavid van Moolenbroek 		callback(user, &pkth, handle->buffer);
834*d56f51eaSDavid van Moolenbroek 		return 1;
835*d56f51eaSDavid van Moolenbroek 	}
836*d56f51eaSDavid van Moolenbroek 
837*d56f51eaSDavid van Moolenbroek 	return 0;	/* didn't pass filter */
838*d56f51eaSDavid van Moolenbroek }
839*d56f51eaSDavid van Moolenbroek 
840*d56f51eaSDavid van Moolenbroek /*
841*d56f51eaSDavid van Moolenbroek  * see <linux-kernel-source>/Documentation/usb/usbmon.txt and
842*d56f51eaSDavid van Moolenbroek  * <linux-kernel-source>/drivers/usb/mon/mon_bin.c binary ABI
843*d56f51eaSDavid van Moolenbroek  */
844*d56f51eaSDavid van Moolenbroek #define VEC_SIZE 32
845*d56f51eaSDavid van Moolenbroek static int
usb_read_linux_mmap(pcap_t * handle,int max_packets,pcap_handler callback,u_char * user)846*d56f51eaSDavid van Moolenbroek usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
847*d56f51eaSDavid van Moolenbroek {
848*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
849*d56f51eaSDavid van Moolenbroek 	struct mon_bin_mfetch fetch;
850*d56f51eaSDavid van Moolenbroek 	int32_t vec[VEC_SIZE];
851*d56f51eaSDavid van Moolenbroek 	struct pcap_pkthdr pkth;
852*d56f51eaSDavid van Moolenbroek 	pcap_usb_header* hdr;
853*d56f51eaSDavid van Moolenbroek 	int nflush = 0;
854*d56f51eaSDavid van Moolenbroek 	int packets = 0;
855*d56f51eaSDavid van Moolenbroek 	int clen, max_clen;
856*d56f51eaSDavid van Moolenbroek 
857*d56f51eaSDavid van Moolenbroek 	max_clen = handle->snapshot - sizeof(pcap_usb_header);
858*d56f51eaSDavid van Moolenbroek 
859*d56f51eaSDavid van Moolenbroek 	for (;;) {
860*d56f51eaSDavid van Moolenbroek 		int i, ret;
861*d56f51eaSDavid van Moolenbroek 		int limit = max_packets - packets;
862*d56f51eaSDavid van Moolenbroek 		if (limit <= 0)
863*d56f51eaSDavid van Moolenbroek 			limit = VEC_SIZE;
864*d56f51eaSDavid van Moolenbroek 		if (limit > VEC_SIZE)
865*d56f51eaSDavid van Moolenbroek 			limit = VEC_SIZE;
866*d56f51eaSDavid van Moolenbroek 
867*d56f51eaSDavid van Moolenbroek 		/* try to fetch as many events as possible*/
868*d56f51eaSDavid van Moolenbroek 		fetch.offvec = vec;
869*d56f51eaSDavid van Moolenbroek 		fetch.nfetch = limit;
870*d56f51eaSDavid van Moolenbroek 		fetch.nflush = nflush;
871*d56f51eaSDavid van Moolenbroek 		/* ignore interrupt system call errors */
872*d56f51eaSDavid van Moolenbroek 		do {
873*d56f51eaSDavid van Moolenbroek 			ret = ioctl(handle->fd, MON_IOCX_MFETCH, &fetch);
874*d56f51eaSDavid van Moolenbroek 			if (handle->break_loop)
875*d56f51eaSDavid van Moolenbroek 			{
876*d56f51eaSDavid van Moolenbroek 				handle->break_loop = 0;
877*d56f51eaSDavid van Moolenbroek 				return -2;
878*d56f51eaSDavid van Moolenbroek 			}
879*d56f51eaSDavid van Moolenbroek 		} while ((ret == -1) && (errno == EINTR));
880*d56f51eaSDavid van Moolenbroek 		if (ret < 0)
881*d56f51eaSDavid van Moolenbroek 		{
882*d56f51eaSDavid van Moolenbroek 			if (errno == EAGAIN)
883*d56f51eaSDavid van Moolenbroek 				return 0;	/* no data there */
884*d56f51eaSDavid van Moolenbroek 
885*d56f51eaSDavid van Moolenbroek 			snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
886*d56f51eaSDavid van Moolenbroek 			    "Can't mfetch fd %d: %s", handle->fd, strerror(errno));
887*d56f51eaSDavid van Moolenbroek 			return -1;
888*d56f51eaSDavid van Moolenbroek 		}
889*d56f51eaSDavid van Moolenbroek 
890*d56f51eaSDavid van Moolenbroek 		/* keep track of processed events, we will flush them later */
891*d56f51eaSDavid van Moolenbroek 		nflush = fetch.nfetch;
892*d56f51eaSDavid van Moolenbroek 		for (i=0; i<fetch.nfetch; ++i) {
893*d56f51eaSDavid van Moolenbroek 			/* discard filler */
894*d56f51eaSDavid van Moolenbroek 			hdr = (pcap_usb_header*) &handlep->mmapbuf[vec[i]];
895*d56f51eaSDavid van Moolenbroek 			if (hdr->event_type == '@')
896*d56f51eaSDavid van Moolenbroek 				continue;
897*d56f51eaSDavid van Moolenbroek 
898*d56f51eaSDavid van Moolenbroek 			/* we can get less that than really captured from kernel, depending on
899*d56f51eaSDavid van Moolenbroek 	 		* snaplen, so adjust header accordingly */
900*d56f51eaSDavid van Moolenbroek 			clen = max_clen;
901*d56f51eaSDavid van Moolenbroek 			if (hdr->data_len < clen)
902*d56f51eaSDavid van Moolenbroek 				clen = hdr->data_len;
903*d56f51eaSDavid van Moolenbroek 
904*d56f51eaSDavid van Moolenbroek 			/* get packet info from header*/
905*d56f51eaSDavid van Moolenbroek 			pkth.caplen = clen + sizeof(pcap_usb_header_mmapped);
906*d56f51eaSDavid van Moolenbroek 			pkth.len = hdr->data_len + sizeof(pcap_usb_header_mmapped);
907*d56f51eaSDavid van Moolenbroek 			pkth.ts.tv_sec = hdr->ts_sec;
908*d56f51eaSDavid van Moolenbroek 			pkth.ts.tv_usec = hdr->ts_usec;
909*d56f51eaSDavid van Moolenbroek 
910*d56f51eaSDavid van Moolenbroek 			if (handle->fcode.bf_insns == NULL ||
911*d56f51eaSDavid van Moolenbroek 			    bpf_filter(handle->fcode.bf_insns, (u_char*) hdr,
912*d56f51eaSDavid van Moolenbroek 			      pkth.len, pkth.caplen)) {
913*d56f51eaSDavid van Moolenbroek 				handlep->packets_read++;
914*d56f51eaSDavid van Moolenbroek 				callback(user, &pkth, (u_char*) hdr);
915*d56f51eaSDavid van Moolenbroek 				packets++;
916*d56f51eaSDavid van Moolenbroek 			}
917*d56f51eaSDavid van Moolenbroek 		}
918*d56f51eaSDavid van Moolenbroek 
919*d56f51eaSDavid van Moolenbroek 		/* with max_packets specifying "unlimited" we stop afer the first chunk*/
920*d56f51eaSDavid van Moolenbroek 		if (PACKET_COUNT_IS_UNLIMITED(max_packets) || (packets == max_packets))
921*d56f51eaSDavid van Moolenbroek 			break;
922*d56f51eaSDavid van Moolenbroek 	}
923*d56f51eaSDavid van Moolenbroek 
924*d56f51eaSDavid van Moolenbroek 	/* flush pending events*/
925*d56f51eaSDavid van Moolenbroek 	if (ioctl(handle->fd, MON_IOCH_MFLUSH, nflush) == -1) {
926*d56f51eaSDavid van Moolenbroek 		snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
927*d56f51eaSDavid van Moolenbroek 		    "Can't mflush fd %d: %s", handle->fd, strerror(errno));
928*d56f51eaSDavid van Moolenbroek 		return -1;
929*d56f51eaSDavid van Moolenbroek 	}
930*d56f51eaSDavid van Moolenbroek 	return packets;
931*d56f51eaSDavid van Moolenbroek }
932*d56f51eaSDavid van Moolenbroek 
933*d56f51eaSDavid van Moolenbroek static void
usb_cleanup_linux_mmap(pcap_t * handle)934*d56f51eaSDavid van Moolenbroek usb_cleanup_linux_mmap(pcap_t* handle)
935*d56f51eaSDavid van Moolenbroek {
936*d56f51eaSDavid van Moolenbroek 	struct pcap_usb_linux *handlep = handle->priv;
937*d56f51eaSDavid van Moolenbroek 
938*d56f51eaSDavid van Moolenbroek 	/* if we have a memory-mapped buffer, unmap it */
939*d56f51eaSDavid van Moolenbroek 	if (handlep->mmapbuf != NULL) {
940*d56f51eaSDavid van Moolenbroek 		munmap(handlep->mmapbuf, handlep->mmapbuflen);
941*d56f51eaSDavid van Moolenbroek 		handlep->mmapbuf = NULL;
942*d56f51eaSDavid van Moolenbroek 	}
943*d56f51eaSDavid van Moolenbroek 	pcap_cleanup_live_common(handle);
944*d56f51eaSDavid van Moolenbroek }
945