Correctly compute the "real" length for isochronous transfers.
When reading memory-mapped Linux capture files, fix up the "real" length
field, in case the file was written by a program doing a capture with
the bug.
optimize.c
pcap-common.c
pcap-options.c
+ pcap-usb-linux-common.c
pcap.c
savefile.c
sf-pcapng.c
COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
fmtutils.c \
savefile.c sf-pcap.c sf-pcapng.c pcap-common.c pcap-options.c \
- bpf_image.c bpf_filter.c bpf_dump.c
+ pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c
GENERATED_C_SRC = scanner.c grammar.c
LIBOBJS = @LIBOBJS@
pcap-int.h \
pcap-rpcap.h \
pcap-types.h \
+ pcap-usb-linux-common.h \
pflog.h \
portability.h \
ppp.h \
#include "pflog.h"
+#include "pcap-usb-linux-common.h"
+
#include "pcap-common.h"
/*
break;
}
}
+
+void
+fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, u_char *data)
+{
+ if (linktype == DLT_USB_LINUX_MMAPPED) {
+ /*
+ * In older versions of libpcap, in memory-mapped captures,
+ * the "on-the-bus length" for isochronous transfers was
+ * miscalculated; it needed to be calculated based on the
+ * offsets and lengths in the descriptors, not on the raw
+ * URB length, but it wasn't. Recalculate it from the
+ * packet data.
+ */
+ set_linux_usb_mmapped_length(hdr, data);
+ }
+}
extern void swap_pseudo_headers(int linktype, struct pcap_pkthdr *hdr,
u_char *data);
+extern void fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr,
+ u_char *data);
+
extern u_int max_snaplen_for_dlt(int dlt);
--- /dev/null
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-usb-linux-common.c - common code for everything that needs to
+ * deal with Linux USB captures.
+ */
+
+#include "pcap/pcap.h"
+#include "pcap/usb.h"
+
+#include "pcap-usb-linux-common.h"
+
+/*
+ * Compute, from the data provided by the Linux USB memory-mapped capture
+ * mechanism, the amount of packet data that would have been provided
+ * had the capture mechanism not chopped off any data at the end, if, in
+ * fact, it did so.
+ *
+ * Set the "unsliced length" field of the packet header to that value.
+ */
+void
+set_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
+{
+ const pcap_usb_header_mmapped *hdr;
+ u_int bytes_left;
+
+ bytes_left = pkth->caplen;
+ if (bytes_left < sizeof (pcap_usb_header_mmapped)) {
+ /*
+ * We don't have the full metadata header, so give up.
+ */
+ return;
+ }
+ bytes_left -= sizeof (pcap_usb_header_mmapped);
+
+ hdr = (const pcap_usb_header_mmapped *) bp;
+ if (hdr->data_flag) {
+ /*
+ * No data; just base the on-the-bus length on hdr->data_len
+ * (so that it's >= the captured length).
+ */
+ pkth->len = sizeof(pcap_usb_header_mmapped) + hdr->data_len;
+ } else {
+ /*
+ * We got data; calculate the on-the-bus length based on
+ * the data length prior to the USB monitor device discarding
+ * data due to its buffer being too small.
+ */
+ usb_isodesc *descs;
+ u_int pre_truncation_data_len;
+
+ descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped));
+
+ /*
+ * For most transfers, urb_len is that amount.
+ */
+ pre_truncation_data_len = hdr->urb_len;
+ if (hdr->transfer_type == URB_ISOCHRONOUS &&
+ hdr->event_type == URB_COMPLETE &&
+ (hdr->endpoint_number & URB_TRANSFER_IN)) {
+ /*
+ * For "this is complete" incoming isochronous
+ * transfer events, however, the data isn't
+ * contiguous, and the isochronous descriptos
+ * show how it's scattered.
+ *
+ * Find the end of the last chunk of data in
+ * the buffer referred to by the isochronous
+ * descriptors; that indicates how far into
+ * the buffer the data would have gone.
+ *
+ * Make sure we don't run past the end of the
+ * captured data while processing the isochronous
+ * descriptors.
+ */
+ pre_truncation_data_len = 0;
+ for (uint32_t desc = 0;
+ desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc);
+ desc++, bytes_left -= sizeof (usb_isodesc)) {
+ u_int desc_end;
+
+ desc_end = descs[desc].offset + descs[desc].len;
+ if (desc_end > pre_truncation_data_len)
+ pre_truncation_data_len = desc_end;
+ }
+ }
+ pkth->len = sizeof(pcap_usb_header_mmapped) +
+ (hdr->ndesc * sizeof (usb_isodesc)) +
+ pre_truncation_data_len;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * pcap-usb-linux-common.h - common code for everything that needs to
+ * deal with Linux USB captures.
+ */
+
+extern void set_linux_usb_mmapped_length(struct pcap_pkthdr *pkth,
+ const u_char *bp);
#include "pcap-int.h"
#include "pcap-usb-linux.h"
+#include "pcap-usb-linux-common.h"
#include "pcap/usb.h"
#include "extract.h"
struct mon_bin_mfetch fetch;
int32_t vec[VEC_SIZE];
struct pcap_pkthdr pkth;
+ u_char *bp;
pcap_usb_header_mmapped* hdr;
int nflush = 0;
int packets = 0;
* packets if we break out of the loop here.
*/
+ /* Get a pointer to this packet's buffer */
+ bp = &handlep->mmapbuf[vec[i]];
+
+ /* That begins with a metadata header */
+ hdr = (pcap_usb_header_mmapped*) bp;
+
/* discard filler */
- hdr = (pcap_usb_header_mmapped*) &handlep->mmapbuf[vec[i]];
if (hdr->event_type == '@')
continue;
if (hdr->data_len < clen)
clen = hdr->data_len;
pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen;
- if (hdr->data_flag) {
- /*
- * No data; just base the on-the-wire length
- * on hdr->data_len (so that it's >= the
- * captured length).
- */
- pkth.len = sizeof(pcap_usb_header_mmapped) +
- hdr->data_len;
- } else {
- /*
- * We got data; base the on-the-wire length
- * on hdr->urb_len, so that it includes
- * data discarded by the USB monitor device
- * due to its buffer being too small.
- */
- pkth.len = sizeof(pcap_usb_header_mmapped) +
- (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len;
- }
+ set_linux_usb_mmapped_length(&pkth, bp);
pkth.ts.tv_sec = (time_t)hdr->ts_sec;
pkth.ts.tv_usec = hdr->ts_usec;
if (p->swapped)
swap_pseudo_headers(p->linktype, hdr, *data);
+ fixup_pcap_pkthdr(p->linktype, hdr, *data);
+
return (1);
}
if (p->swapped)
swap_pseudo_headers(p->linktype, hdr, *data);
+ fixup_pcap_pkthdr(p->linktype, hdr, *data);
+
return (1);
}