From 87d0db882e422055e04f278c616064d858d6a2ca Mon Sep 17 00:00:00 2001 From: guy Date: Tue, 23 Dec 2008 18:03:22 +0000 Subject: [PATCH] From Jon Smirl: try scanning the sysfs USB directory first and, if that directory doesn't exist, try the procfs USB directory, to handle newer kernels where the relevant director is in sysfs; use the data length, not the URB length, as the amount of data in the packet (the URB length is the amount of space *available* for the data, not the actual amount of data). For the memory-mapped interface, include the padding after the URB and setup header in the packet lengths, and return a different link-layer type so that code reading the packets knows that padding is there. --- gencode.c | 13 ++++++++- pcap-usb-linux.c | 69 +++++++++++++++++++++++++++++++++--------------- pcap.c | 3 ++- pcap/bpf.h | 8 +++++- pcap/usb.h | 8 +++++- savefile.c | 30 ++++++++++++++------- 6 files changed, 96 insertions(+), 35 deletions(-) diff --git a/gencode.c b/gencode.c index 7f020c8..b39d6f3 100644 --- a/gencode.c +++ b/gencode.c @@ -21,7 +21,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.307 2008-12-21 19:28:56 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/gencode.c,v 1.308 2008-12-23 18:03:22 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -1507,6 +1507,16 @@ init_linktype(p) off_nl = -1; off_nl_nosnap = -1; return; + + case DLT_USB_LINUX_MMAP: + /* + * Currently, only raw "link[N:M]" filtering is supported. + */ + off_linktype = -1; + off_macpl = -1; + off_nl = -1; + off_nl_nosnap = -1; + return; } bpf_error("unknown data link type %d", linktype); /* NOTREACHED */ @@ -3360,6 +3370,7 @@ gen_linktype(proto) case DLT_USB: case DLT_USB_LINUX: + case DLT_USB_LINUX_MMAP: bpf_error("USB link-layer type filtering not implemented"); case DLT_BLUETOOTH_HCI_H4: diff --git a/pcap-usb-linux.c b/pcap-usb-linux.c index 4ff62ed..b56d733 100644 --- a/pcap-usb-linux.c +++ b/pcap-usb-linux.c @@ -34,7 +34,7 @@ */ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.27 2008-11-24 18:49:57 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap-usb-linux.c,v 1.28 2008-12-23 18:03:22 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -63,7 +63,8 @@ static const char rcsid[] _U_ = #define USB_IFACE "usb" #define USB_TEXT_DIR "/sys/kernel/debug/usbmon" -#define USB_BUS_DIR "/proc/bus/usb" +#define SYS_USB_BUS_DIR "/sys/bus/usb/devices" +#define PROC_USB_BUS_DIR "/proc/bus/usb" #define USB_LINE_LEN 4096 #if __BYTE_ORDER == __LITTLE_ENDIAN @@ -142,27 +143,52 @@ usb_platform_finddevs(pcap_if_t **alldevsp, char *err_str) struct dirent* data; int ret = 0; DIR* dir; + int n; + char* name; + size_t len; - /* scan procfs usb bus directory */ - dir = opendir(USB_BUS_DIR); - if (!dir) return 0; - while ((ret == 0) && ((data = readdir(dir)) != 0)) { - int n; - char* name = data->d_name; - int len = strlen(name); + /* try scanning sysfs usb bus directory */ + dir = opendir(SYS_USB_BUS_DIR); + if (dir != NULL) { + while ((ret == 0) && ((data = readdir(dir)) != 0)) { + name = data->d_name; - /* if this file name does not end with a number it's not of our interest */ - if ((len < 1) || !isdigit(name[--len])) - continue; - while (isdigit(name[--len])); - if (sscanf(&name[len+1], "%d", &n) != 1) - continue; + if (strncmp(name, "usb", 3) != 0) + continue; - ret = usb_dev_add(alldevsp, n, err_str); + if (sscanf(&name[3], "%d", &n) == 0) + continue; + + ret = usb_dev_add(alldevsp, n, err_str); + } + + closedir(dir); + return ret; } - closedir(dir); - return ret; + /* that didn't work; try scanning procfs usb bus directory */ + dir = opendir(PROC_USB_BUS_DIR); + if (dir != NULL) { + while ((ret == 0) && ((data = readdir(dir)) != 0)) { + name = data->d_name; + len = strlen(name); + + /* if this file name does not end with a number it's not of our interest */ + if ((len < 1) || !isdigit(name[--len])) + continue; + while (isdigit(name[--len])); + if (sscanf(&name[len+1], "%d", &n) != 1) + continue; + + ret = usb_dev_add(alldevsp, n, err_str); + } + + closedir(dir); + return ret; + } + + /* neither of them worked */ + return 0; } static @@ -229,6 +255,7 @@ usb_activate(pcap_t* handle) /* binary api is available, try to use fast mmap access */ if (usb_mmap(handle)) { + handle->linktype = DLT_USB_LINUX_MMAP; handle->stats_op = usb_stats_linux_bin; handle->read_op = usb_read_linux_mmap; handle->cleanup_op = usb_cleanup_linux_mmap; @@ -632,7 +659,7 @@ usb_read_linux_bin(pcap_t *handle, int max_packets, pcap_handler callback, u_cha clen = info.hdr->data_len; info.hdr->data_len = clen; pkth.caplen = clen + sizeof(pcap_usb_header); - pkth.len = info.hdr->urb_len + sizeof(pcap_usb_header); + pkth.len = info.hdr->data_len + sizeof(pcap_usb_header); pkth.ts.tv_sec = info.hdr->ts_sec; pkth.ts.tv_usec = info.hdr->ts_usec; @@ -705,8 +732,8 @@ usb_read_linux_mmap(pcap_t *handle, int max_packets, pcap_handler callback, u_ch clen = hdr->data_len; /* get packet info from header*/ - pkth.caplen = clen + sizeof(pcap_usb_header); - pkth.len = hdr->urb_len + sizeof(pcap_usb_header); + pkth.caplen = clen + MMAPPED_USB_HEADER_SIZE; + pkth.len = hdr->data_len + MMAPPED_USB_HEADER_SIZE; pkth.ts.tv_sec = hdr->ts_sec; pkth.ts.tv_usec = hdr->ts_usec; diff --git a/pcap.c b/pcap.c index f6959dd..b51bbf2 100644 --- a/pcap.c +++ b/pcap.c @@ -33,7 +33,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.126 2008-12-21 19:28:56 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/pcap.c,v 1.127 2008-12-23 18:03:22 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -624,6 +624,7 @@ static struct dlt_choice dlt_choices[] = { DLT_CHOICE(DLT_AX25_KISS, "AX.25 with KISS header"), DLT_CHOICE(DLT_IEEE802_15_4_NONASK_PHY, "IEEE 802.15.4 with non-ASK PHY data"), DLT_CHOICE(DLT_MPLS, "MPLS with label as link-layer header"), + DLT_CHOICE(DLT_USB_LINUX_MMAP, "USB with padded Linux header"), DLT_CHOICE_SENTINEL }; diff --git a/pcap/bpf.h b/pcap/bpf.h index 4fea372..bbb8790 100644 --- a/pcap/bpf.h +++ b/pcap/bpf.h @@ -37,7 +37,7 @@ * * @(#)bpf.h 7.1 (Berkeley) 5/7/91 * - * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.30 2008-12-21 19:28:56 guy Exp $ (LBL) + * @(#) $Header: /tcpdump/master/libpcap/pcap/bpf.h,v 1.31 2008-12-23 18:03:22 guy Exp $ (LBL) */ /* @@ -844,6 +844,12 @@ struct bpf_version { */ #define DLT_MPLS 219 +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define DLT_USB_LINUX_MMAP 220 + /* * DLT and savefile link type values are split into a class and diff --git a/pcap/usb.h b/pcap/usb.h index 63036b8..e0b509f 100644 --- a/pcap/usb.h +++ b/pcap/usb.h @@ -30,7 +30,7 @@ * Basic USB data struct * By Paolo Abeni * - * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.6 2007-09-22 02:06:08 guy Exp $ + * @(#) $Header: /tcpdump/master/libpcap/pcap/usb.h,v 1.7 2008-12-23 18:03:22 guy Exp $ */ #ifndef _PCAP_USB_STRUCTS_H__ @@ -68,6 +68,8 @@ typedef struct _usb_setup { /* * Header prepended by linux kernel to each event. * Appears at the front of each packet in DLT_USB_LINUX captures. + * Appears at the front of each packet, followed by padding to a multiple + * of 64 bytes, in DLT_USB_LINUX_MMAP captures. */ typedef struct _usb_header { u_int64_t id; @@ -86,5 +88,9 @@ typedef struct _usb_header { pcap_usb_setup setup; } pcap_usb_header; +/* + * In DLT_USB_LINUX_MMAP captures, the header is padded to 64 bytes. + */ +#define MMAPPED_USB_HEADER_SIZE (sizeof (pcap_usb_header) + 63) & ~63) #endif diff --git a/savefile.c b/savefile.c index 0dedeee..59070cd 100644 --- a/savefile.c +++ b/savefile.c @@ -30,7 +30,7 @@ #ifndef lint static const char rcsid[] _U_ = - "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.181 2008-12-21 19:28:56 guy Exp $ (LBL)"; + "@(#) $Header: /tcpdump/master/libpcap/savefile.c,v 1.182 2008-12-23 18:03:22 guy Exp $ (LBL)"; #endif #ifdef HAVE_CONFIG_H @@ -483,7 +483,7 @@ static const char rcsid[] _U_ = * USB packets, beginning with a Linux USB header; requested by * Paolo Abeni . */ -#define LINKTYPE_USB_LINUX 189 +#define LINKTYPE_USB_LINUX 189 /* * Controller Area Network (CAN) v. 2.0B packets. @@ -670,6 +670,12 @@ static const char rcsid[] _U_ = */ #define LINKTYPE_MPLS 219 +/* + * USB packets, beginning with a Linux USB header, with the USB header + * padded to 64 bytes; required for memory-mapped access. + */ +#define LINKTYPE_USB_LINUX_MMAP 220 + static struct linktype_map { int dlt; @@ -985,6 +991,9 @@ static struct linktype_map { /* MPLS, with an MPLS label as the link-layer header */ { DLT_MPLS, LINKTYPE_MPLS }, + /* USB with padded Linux header */ + { DLT_USB_LINUX_MMAP, LINKTYPE_USB_LINUX_MMAP }, + { -1, -1 } }; @@ -1555,19 +1564,20 @@ sf_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char *buf, u_int buflen) } /* - * The DLT_USB_LINUX header is in host byte order when capturing - * (it's supplied directly from a memory-mapped buffer shared - * by the kernel). + * The DLT_USB_LINUX and DLT_USB_LINUX_MMAP headers are in host + * byte order when capturing (it's supplied directly from a + * memory-mapped buffer shared by the kernel). * - * When reading a DLT_USB_LINUX capture file, we need to convert - * it from the capturing host's byte order to the reading host's - * byte order. + * When reading a DLT_USB_LINUX or DLT_USB_LINUX_MMAP capture file, + * we need to convert it from the capturing host's byte order to + * the reading host's byte order. */ - if (p->sf.swapped && p->linktype == DLT_USB_LINUX) { + if (p->sf.swapped && + (p->linktype == DLT_USB_LINUX || p->linktype == DLT_USB_LINUX_MMAP)) { pcap_usb_header* uhdr = (pcap_usb_header*) buf; /* * The URB id is a totally opaque value; do we really need to - * converte it to the reading host's byte order??? + * convert it to the reading host's byte order??? */ if (hdr->caplen < 8) return 0;