nametoaddr.c
optimize.c
pcap-common.c
- pcap-usb-linux-common.c
pcap-util.c
pcap.c
savefile.c
COMMON_C_SRC = pcap.c gencode.c optimize.c nametoaddr.c etherent.c \
fmtutils.c pcap-util.c \
savefile.c sf-pcap.c sf-pcapng.c pcap-common.c \
- pcap-usb-linux-common.c bpf_image.c bpf_filter.c bpf_dump.c
+ bpf_image.c bpf_filter.c bpf_dump.c
GENERATED_C_SRC = scanner.c grammar.c
LIBOBJS = @LIBOBJS@
+++ /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 <limits.h> /* for UINT_MAX */
-
-#include "pcap/pcap.h"
-#include "pcap/usb.h"
-
-#include "pcap-usb-linux-common.h"
-
-/*
- * Return the sum of the two u_int arguments if that sum fits in a u_int,
- * and return UINT_MAX otherwise.
- */
-static inline u_int
-u_int_sum(u_int a, u_int b)
-{
- return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX);
-}
-
-/*
- * 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
-fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp)
-{
- const pcap_usb_header_mmapped *hdr;
- u_int bytes_left;
-
- /*
- * All callers of this routine must ensure that pkth->caplen is
- * >= sizeof (pcap_usb_header_mmapped).
- */
- bytes_left = pkth->caplen;
- bytes_left -= sizeof (pcap_usb_header_mmapped);
-
- hdr = (const pcap_usb_header_mmapped *) bp;
- if (!hdr->data_flag && hdr->transfer_type == URB_ISOCHRONOUS &&
- hdr->event_type == URB_COMPLETE &&
- (hdr->endpoint_number & URB_TRANSFER_IN) &&
- hdr->ndesc <= USB_MAXDESC &&
- pkth->len == sizeof(pcap_usb_header_mmapped) +
- (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len) {
- usb_isodesc *descs;
- u_int pre_truncation_descriptors_len;
- u_int pre_truncation_header_len;
- u_int pre_truncation_data_len;
- u_int pre_truncation_len;
-
- descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped));
-
- /*
- * We have data (yes, data_flag is 0 if we *do* have data),
- * and this is a "this is complete" incoming isochronous
- * transfer event, and the length was calculated based
- * on the URB length.
- *
- * That's not correct, because the data isn't contiguous,
- * and the isochronous descriptors 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;
-
- if (descs[desc].len != 0) {
- /*
- * Compute the end offset of the data
- * for this descriptor, i.e. the offset
- * of the byte after the data. Clamp
- * the sum at UINT_MAX, so that it fits
- * in a u_int.
- */
- desc_end = u_int_sum(descs[desc].offset,
- descs[desc].len);
- if (desc_end > pre_truncation_data_len)
- pre_truncation_data_len = desc_end;
- }
- }
-
- /*
- * Now calculate the total length based on that data
- * length.
- *
- * We've made sure that the number of descriptors is
- * <= USB_MAXDESC, so we know that the total size,
- * in bytes, of the desciptors fits in a 32-bit
- * integer.
- */
- pre_truncation_descriptors_len =
- hdr->ndesc * sizeof (usb_isodesc);
-
- /*
- * Now, add the length of the memory-mapped header and
- * the length of the ISO descriptors, clamping the
- * result at UINT_MAX.
- */
- pre_truncation_header_len = u_int_sum(sizeof(pcap_usb_header_mmapped),
- pre_truncation_descriptors_len);
-
- /*
- * Now, add the total header length (memory-mapped header
- * and ISO descriptors) and the data length, clamping
- * the result at UINT_MAX.
- */
- pre_truncation_len = u_int_sum(pre_truncation_header_len,
- pre_truncation_data_len);
-
- /*
- * pre_truncation_len is now the smaller of
- * UINT_MAX and the total header plus data length.
- * That's guaranteed to fit in a UINT_MAX.
- */
- if (pre_truncation_len >= pkth->caplen)
- pkth->len = pre_truncation_len;
-
- /*
- * If the captured length is greater than the length,
- * use the captured length.
- *
- * For completion events for incoming isochronous transfers,
- * it's based on data_len, which is calculated the same way
- * we calculated pre_truncation_data_len above, except that
- * it has access to all the isochronous descriptors, not
- * just the ones that the kernel were able to provide us or,
- * for a capture file, that weren't sliced off by a snapshot
- * length.
- *
- * However, it might have been reduced by the USB capture
- * mechanism arbitrarily limiting the amount of data it
- * provides to userland, or by the libpcap capture code
- * limiting it to being no more than the snapshot, so
- * we don't want to just use it all the time; we only
- * do so to try to get a better estimate of the actual
- * length - and to make sure the on-the-network length
- * is always >= the captured length.
- */
- if (pkth->caplen > pkth->len)
- pkth->len = pkth->caplen;
- }
-}
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* pcap-usb-linux-common.h - common code for everything that needs to
- * deal with Linux USB captures.
+ * deal with Linux USB captures, whether live or in a capture file;
+ * the later means that this is *not* Linux-only.
*/
-extern void fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth,
- const u_char *bp);
+#include <limits.h>
+
+/*
+ * Return the sum of the two u_int arguments if that sum fits in a u_int,
+ * and return UINT_MAX otherwise.
+ */
+static inline u_int
+u_int_sum(u_int a, u_int b)
+{
+ return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX);
+}
+
+/*
+ * Is this a completion event for an isochronous transfer?
+ */
+static inline int
+is_isochronous_transfer_completion(const pcap_usb_header_mmapped *hdr)
+{
+ return (hdr->transfer_type == URB_ISOCHRONOUS &&
+ hdr->event_type == URB_COMPLETE &&
+ (hdr->endpoint_number & URB_TRANSFER_IN));
+}
+
+/*
+ * Total length of the pseudo-header, including the isochronous
+ * descriptors.
+ */
+static inline uint32_t
+iso_pseudo_header_len(const pcap_usb_header_mmapped *usb_hdr)
+{
+ return (sizeof(pcap_usb_header_mmapped) +
+ usb_hdr->ndesc * sizeof (usb_isodesc));
+}
+
+/*
+ * Calculate the packet length for a "this is complete" incoming
+ * isochronous transfer event.
+ *
+ * Calculating that from hdr->urb_len is not correct, because the
+ * data is not contiguous, and the isochroous descriptors show how
+ * it's scattered.
+ */
+static inline u_int
+incoming_isochronous_transfer_completed_len(struct pcap_pkthdr *phdr,
+ const u_char *bp)
+{
+ const pcap_usb_header_mmapped *hdr;
+ u_int bytes_left;
+ const usb_isodesc *descs;
+ u_int pre_truncation_data_len;
+
+ /*
+ * All callers of this routine must ensure that pkth->caplen is
+ * >= sizeof (pcap_usb_header_mmapped).
+ */
+ bytes_left = phdr->caplen;
+ bytes_left -= sizeof (pcap_usb_header_mmapped);
+
+ hdr = (const pcap_usb_header_mmapped *) bp;
+ descs = (const usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped));
+
+ /*
+ * 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;
+
+ if (descs[desc].len != 0) {
+ /*
+ * Compute the end offset of the data
+ * for this descriptor, i.e. the offset
+ * of the byte after the data. Clamp
+ * the sum at UINT_MAX, so that it fits
+ * in a u_int.
+ */
+ desc_end = u_int_sum(descs[desc].offset,
+ descs[desc].len);
+ if (desc_end > pre_truncation_data_len)
+ pre_truncation_data_len = desc_end;
+ }
+ }
+
+ /*
+ * Return the sum of the total header length (memory-mapped
+ * header and ISO descriptors) and the data length, clamped
+ * to UINT_MAX.
+ *
+ * We've made sure that the number of descriptors is
+ * <= USB_MAXDESC, so we know that the total size,
+ * in bytes, of the descriptors fits in a 32-bit
+ * integer.
+ */
+ return (u_int_sum(iso_pseudo_header_len(hdr), pre_truncation_data_len));
+}
#include <config.h>
#endif
+#include "pcap/usb.h"
#include "pcap-int.h"
#include "pcap-usb-linux.h"
#include "pcap-usb-linux-common.h"
-#include "pcap/usb.h"
#include "extract.h"
pkth.caplen = sizeof(pcap_usb_header) + clen;
if (info.hdr->data_flag) {
/*
- * No data; just base the on-the-wire length on
+ * No data; just base the original length on
* info.hdr->data_len (so that it's >= the captured
* length).
*/
pkth.len = sizeof(pcap_usb_header) + info.hdr->data_len;
} else {
/*
- * We got data; base the on-the-wire length on
+ * We got data; base the original length on
* info.hdr->urb_len, so that it includes data
* discarded by the USB monitor device due to
* its buffer being too small.
pkth.caplen = sizeof(pcap_usb_header_mmapped) + clen;
if (hdr->data_flag) {
/*
- * No data; just base the on-the-wire length
+ * No data; just base the original length
* on hdr->data_len (so that it's >= the
- * captured length).
+ * captured length). Clamp the result
+ * at UINT_MAX, so it fits in an unsigned
+ * int.
*/
- pkth.len = sizeof(pcap_usb_header_mmapped) +
- hdr->data_len;
+ pkth.len = u_int_sum(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;
-
- /*
- * Now clean it up if it's a completion
- * event for an incoming isochronous
- * transfer.
+ * We got data.
*/
- fix_linux_usb_mmapped_length(&pkth, bp);
+ if (is_isochronous_transfer_completion(hdr)) {
+ /*
+ * For isochronous transfer completion
+ * events, hdr->urb_len doesn't take
+ * into account the way the data is
+ * put into the buffer, as it doesn't
+ * count any padding between the
+ * chunks of isochronous data, so
+ * we have to calculate the amount
+ * of data from the isochronous
+ * descriptors.
+ */
+ pkth.len = incoming_isochronous_transfer_completed_len(&pkth, bp);
+ } else {
+ /*
+ * For everything else, the original
+ * data length is just the length of
+ * the memory-mapped Linux USB header
+ * plus hdr->urb_len; we use
+ * hdr->urb_len so that it includes
+ * data discarded by the USB monitor
+ * device due to its buffer being
+ * too small. Clamp the result at
+ * UINT_MAX, so it fits in an
+ * unsigned int.
+ */
+ pkth.len = u_int_sum(sizeof(pcap_usb_header_mmapped),
+ hdr->urb_len);
+ }
}
pkth.ts.tv_sec = (time_t)hdr->ts_sec;
pkth.ts.tv_usec = hdr->ts_usec;
#include <pcap-types.h>
+#include "pcap/can_socketcan.h"
+#include "pcap/sll.h"
+#include "pcap/usb.h"
+#include "pcap/nflog.h"
+
#include "pcap-int.h"
#include "extract.h"
#include "pcap-usb-linux-common.h"
#include "pcap-util.h"
-
#include "pflog.h"
-#include "pcap/can_socketcan.h"
-#include "pcap/sll.h"
-#include "pcap/usb.h"
-#include "pcap/nflog.h"
/*
* Most versions of the DLT_PFLOG pseudo-header have UID and PID fields
}
}
+static inline int
+packet_length_might_be_wrong(struct pcap_pkthdr *hdr,
+ const pcap_usb_header_mmapped *usb_hdr)
+{
+ uint32_t old_style_packet_length;
+
+ /*
+ * Calculate the packet length the old way.
+ * We know that the multiplication won't overflow, but
+ * we don't know that the additions won't. Calculate
+ * it with no overflow checks, as that's how it
+ * would have been calculated when it was captured.
+ */
+ old_style_packet_length = iso_pseudo_header_len(usb_hdr) +
+ usb_hdr->urb_len;
+ return (hdr->len == old_style_packet_length);
+}
+
void
pcapint_post_process(int linktype, int swapped, struct pcap_pkthdr *hdr,
u_char *data)
if (swapped)
swap_pseudo_headers(linktype, hdr, data);
- pcapint_fixup_pcap_pkthdr(linktype, hdr, data);
-}
+ /*
+ * Is this a memory-mapped Linux USB capture?
+ */
+ if (linktype == DLT_USB_LINUX_MMAPPED) {
+ /*
+ * Yes.
+ *
+ * In older versions of libpcap, in memory-mapped Linux
+ * USB captures, the original length of completion events
+ * for incoming 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.
+ *
+ * If this packet contains transferred data (yes, data_flag
+ * is 0 if we *do* have data), it's a completion event
+ * for an incoming isochronous transfer, and the
+ * transfer length appears to have been calculated
+ * from the raw URB length, fix it.
+ *
+ * We only do this if we have the full USB pseudo-header,
+ * because we will have to look at that header and at
+ * all of the isochronous descriptors.
+ */
+ if (hdr->caplen < sizeof (pcap_usb_header_mmapped)) {
+ /*
+ * We don't have the full pseudo-header.
+ */
+ return;
+ }
-void
-pcapint_fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr, const u_char *data)
-{
- const pcap_usb_header_mmapped *usb_hdr;
+ const pcap_usb_header_mmapped *usb_hdr =
+ (const pcap_usb_header_mmapped *) data;
- usb_hdr = (const pcap_usb_header_mmapped *) data;
- if (linktype == DLT_USB_LINUX_MMAPPED &&
- hdr->caplen >= sizeof (pcap_usb_header_mmapped)) {
/*
- * In older versions of libpcap, in memory-mapped captures,
- * the "on-the-bus length" for completion events for
- * incoming 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.
+ * Make sure the number of descriptors is sane.
*
- * If this packet contains transferred data (yes, data_flag
- * is 0 if we *do* have data), and the total on-the-network
- * length is equal to the value calculated from the raw URB
- * length, then it might be one of those transfers.
+ * The Linux binary USB monitor code limits the number of
+ * isochronous descriptors to 128; if the number in the file
+ * is larger than that, either 1) the file's been damaged
+ * or 2) the file was produced after the number was raised
+ * in the kernel.
*
- * We only do this if we have the full USB pseudo-header.
+ * In case 1), the number can't be trusted, so don't rely on
+ * it to attempt to fix the original length field in the pcap
+ * or pcapng header.
+ *
+ * In case 2), the system was probably running a version of
+ * libpcap that didn't miscalculate the original length, so
+ * it probably doesn't need to be fixed.
+ *
+ * This avoids the possibility of the product of the number of
+ * descriptors and the size of descriptors won't overflow an
+ * unsigned 32-bit integer.
*/
+ if (usb_hdr->ndesc > USB_MAXDESC)
+ return;
+
if (!usb_hdr->data_flag &&
- hdr->len == sizeof(pcap_usb_header_mmapped) +
- (usb_hdr->ndesc * sizeof (usb_isodesc)) + usb_hdr->urb_len) {
+ is_isochronous_transfer_completion(usb_hdr) &&
+ packet_length_might_be_wrong(hdr, usb_hdr)) {
+ u_int len;
+
+ /*
+ * Make sure we have all of the descriptors,
+ * as we will have to look at all of them.
+ *
+ * If not, we don't bother trying to fix
+ * anything.
+ */
+ if (hdr->caplen < iso_pseudo_header_len(usb_hdr))
+ return;
+
+ /*
+ * Calculate what the length should have been.
+ */
+ len = incoming_isochronous_transfer_completed_len(hdr,
+ data);
+
+ /*
+ * len is the smaller of UINT_MAX and the total
+ * header plus data length. That's guaranteed
+ * to fit in a UINT_MAX.
+ *
+ * Don't reduce the original length to a value
+ * below the captured length, however, as that
+ * is bogus.
+ */
+ if (len >= hdr->caplen)
+ hdr->len = len;
+
/*
- * It might need fixing; fix it if it's a completion
- * event for an incoming isochronous transfer.
+ * If the captured length is greater than the
+ * length, use the captured length.
+ *
+ * For completion events for incoming isochronous
+ * transfers, it's based on data_len, which is
+ * calculated the same way we calculated
+ * pre_truncation_data_len above, except that
+ * it has access to all the isochronous descriptors,
+ * not just the ones that the kernel were able to
+ * provide us or, for a capture file, that weren't
+ * sliced off by a snapshot length.
+ *
+ * However, it might have been reduced by the USB
+ * capture mechanism arbitrarily limiting the amount
+ * of data it provides to userland, or by the libpcap
+ * capture code limiting it to being no more than the
+ * snapshot, so we don't want to just use it all the
+ * time; we only do so to try to get a better estimate
+ * of the actual length - and to make sure the
+ * original length is always >= the captured length.
*/
- fix_linux_usb_mmapped_length(hdr, data);
+ if (hdr->caplen > hdr->len)
+ hdr->len = hdr->caplen;
}
}
}
extern void pcapint_post_process(int linktype, int swapped,
struct pcap_pkthdr *hdr, u_char *data);
-
-extern void pcapint_fixup_pcap_pkthdr(int linktype, struct pcap_pkthdr *hdr,
- const u_char *data);
-