diff options
author | Guy Harris <gharris@sonic.net> | 2022-06-03 18:00:22 -0700 |
---|---|---|
committer | Guy Harris <gharris@sonic.net> | 2022-06-03 18:00:41 -0700 |
commit | 08ab69f4fc5d432eb7de26ee8e33b40ea4b79744 (patch) | |
tree | eff06cc3da09aa6a2a15832c724eaed00ff7b15d /pcap-usb-linux-common.c | |
parent | 04244a1b51e76981c0796c8f96e36827f7f2019c (diff) |
Linux USB: fix incorrect values for the packet length.
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.
Diffstat (limited to 'pcap-usb-linux-common.c')
-rw-r--r-- | pcap-usb-linux-common.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/pcap-usb-linux-common.c b/pcap-usb-linux-common.c new file mode 100644 index 00000000..ef0bb462 --- /dev/null +++ b/pcap-usb-linux-common.c @@ -0,0 +1,108 @@ +/* + * 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; + } +} |