diff options
Diffstat (limited to 'pcap-usb-linux-common.h')
-rw-r--r-- | pcap-usb-linux-common.h | 107 |
1 files changed, 104 insertions, 3 deletions
diff --git a/pcap-usb-linux-common.h b/pcap-usb-linux-common.h index 8cff7ba1cf6b..333c6b6e0c62 100644 --- a/pcap-usb-linux-common.h +++ b/pcap-usb-linux-common.h @@ -19,8 +19,109 @@ * 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)); +} |