diff --git a/pcap-common.c b/pcap-common.c index 61509e4..18c45cd 100644 --- a/pcap-common.c +++ b/pcap-common.c @@ -1123,9 +1123,10 @@ linktype_to_dlt(int linktype) * the reading host's byte order. */ void -swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf) +swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, + int header_len_64_bytes) { - pcap_usb_header *uhdr = (pcap_usb_header *)buf; + pcap_usb_header_mmapped *uhdr = (pcap_usb_header_mmapped *)buf; /* * The URB id is a totally opaque value; do we really need to @@ -1152,4 +1153,27 @@ swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf) if (hdr->caplen < 40) return; uhdr->data_len = SWAPLONG(uhdr->data_len); + + if (header_len_64_bytes) { + /* + * This is either the "version 1" header, with + * 16 bytes of additional fields at the end, or + * a "version 0" header from a memory-mapped + * capture, with 16 bytes of zeroed-out padding + * at the end. Byte swap them as if this were + * a "version 1" header. + */ + if (hdr->caplen < 52) + return; + uhdr->interval = SWAPLONG(uhdr->interval); + if (hdr->caplen < 56) + return; + uhdr->start_frame = SWAPLONG(uhdr->start_frame); + if (hdr->caplen < 60) + return; + uhdr->xfer_flags = SWAPLONG(uhdr->xfer_flags); + if (hdr->caplen < 64) + return; + uhdr->ndesc = SWAPLONG(uhdr->ndesc); + } } diff --git a/pcap-common.h b/pcap-common.h index f198e86..0c80ba3 100644 --- a/pcap-common.h +++ b/pcap-common.h @@ -21,4 +21,5 @@ extern int dlt_to_linktype(int dlt); extern int linktype_to_dlt(int linktype); -extern void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf); +extern void swap_linux_usb_header(const struct pcap_pkthdr *hdr, u_char *buf, + int header_len_64_bytes); diff --git a/pcap/usb.h b/pcap/usb.h index d7de2bd..aa35122 100644 --- a/pcap/usb.h +++ b/pcap/usb.h @@ -54,7 +54,7 @@ /* * USB setup header as defined in USB specification. - * Appears at the front of each packet in DLT_USB captures. + * Appears at the front of each Control S-type packet in DLT_USB captures. */ typedef struct _usb_setup { u_int8_t bmRequestType; @@ -64,6 +64,13 @@ typedef struct _usb_setup { u_int16_t wLength; } pcap_usb_setup; +/* + * Information from the URB for Isochronous transfers. + */ +typedef struct _iso_rec { + int32_t error_count; + int32_t numdesc; +} iso_rec; /* * Header prepended by linux kernel to each event. @@ -87,8 +94,11 @@ typedef struct _usb_header { } pcap_usb_header; /* - * Header prepended by linux kernel to each event, plus padding in the - * internal buffer. + * Header prepended by linux kernel to each event for the 2.6.31 + * and later kernels; for the 2.6.21 through 2.6.30 kernels, the + * "iso_rec" information, and the fields starting with "interval" + * are zeroed-out padding fields. + * * Appears at the front of each packet in DLT_USB_LINUX_MMAPPED captures. */ typedef struct _usb_header_mmapped { @@ -105,8 +115,29 @@ typedef struct _usb_header_mmapped { int32_t status; u_int32_t urb_len; u_int32_t data_len; /* amount of urb data really present in this event*/ - pcap_usb_setup setup; - u_int8_t padding[16]; + union { + pcap_usb_setup setup; + iso_rec iso; + } s; + int32_t interval; /* for Interrupt and Isochronous events */ + int32_t start_frame; /* for Isochronous events */ + u_int32_t xfer_flags; /* copy of URB's transfer flags */ + u_int32_t ndesc; /* number of isochronous descriptors */ } pcap_usb_header_mmapped; +/* + * Isochronous descriptors; for isochronous transfers there might be + * one or more of these at the beginning of the packet data. The + * number of descriptors is given by the "ndesc" field in the header; + * as indicated, in older kernels that don't put the descriptors at + * the beginning of the packet, that field is zeroed out, so that field + * can be trusted even in captures from older kernels. + */ +typedef struct _usb_isodesc { + int32_t status; + u_int32_t offset; + u_int32_t len; + u_int8_t pad[4]; +} usb_isodesc; + #endif diff --git a/sf-pcap-ng.c b/sf-pcap-ng.c index 54a7363..3535777 100644 --- a/sf-pcap-ng.c +++ b/sf-pcap-ng.c @@ -1100,8 +1100,11 @@ found: switch (p->linktype) { case DLT_USB_LINUX: + swap_linux_usb_header(hdr, *data, 0); + break; + case DLT_USB_LINUX_MMAPPED: - swap_linux_usb_header(hdr, *data); + swap_linux_usb_header(hdr, *data, 1); break; } } diff --git a/sf-pcap.c b/sf-pcap.c index bf0a0ea..6903160 100644 --- a/sf-pcap.c +++ b/sf-pcap.c @@ -422,8 +422,11 @@ pcap_next_packet(pcap_t *p, struct pcap_pkthdr *hdr, u_char **data) switch (p->linktype) { case DLT_USB_LINUX: + swap_linux_usb_header(hdr, *data, 0); + break; + case DLT_USB_LINUX_MMAPPED: - swap_linux_usb_header(hdr, *data); + swap_linux_usb_header(hdr, *data, 1); break; } }