Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright (c) 1993, 1994, 1995, 1996, 1997
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  *
     21  * pcap-usb-linux-common.h - common code for everything that needs to
     22  * deal with Linux USB captures, whether live or in a capture file;
     23  * the later means that this is *not* Linux-only.
     24  */
     25 
     26 #include <limits.h>
     27 
     28 /*
     29  * Return the sum of the two u_int arguments if that sum fits in a u_int,
     30  * and return UINT_MAX otherwise.
     31  */
     32 static inline u_int
     33 u_int_sum(u_int a, u_int b)
     34 {
     35 	return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX);
     36 }
     37 
     38 /*
     39  * Is this a completion event for an isochronous transfer?
     40  */
     41 static inline int
     42 is_isochronous_transfer_completion(const pcap_usb_header_mmapped *hdr)
     43 {
     44 	return (hdr->transfer_type == URB_ISOCHRONOUS &&
     45 	    hdr->event_type == URB_COMPLETE &&
     46 	    (hdr->endpoint_number & URB_TRANSFER_IN));
     47 }
     48 
     49 /*
     50  * Total length of the pseudo-header, including the isochronous
     51  * descriptors.
     52  */
     53 static inline uint32_t
     54 iso_pseudo_header_len(const pcap_usb_header_mmapped *usb_hdr)
     55 {
     56 	return (sizeof(pcap_usb_header_mmapped) +
     57 	    usb_hdr->ndesc * sizeof (usb_isodesc));
     58 }
     59 
     60 /*
     61  * Calculate the packet length for a "this is complete" incoming
     62  * isochronous transfer event.
     63  *
     64  * Calculating that from hdr->urb_len is not correct, because the
     65  * data is not contiguous, and the isochroous descriptors show how
     66  * it's scattered.
     67  */
     68 static inline u_int
     69 incoming_isochronous_transfer_completed_len(struct pcap_pkthdr *phdr,
     70     const u_char *bp)
     71 {
     72 	const pcap_usb_header_mmapped *hdr;
     73 	u_int bytes_left;
     74 	const usb_isodesc *descs;
     75 	u_int pre_truncation_data_len;
     76 
     77 	/*
     78 	 * All callers of this routine must ensure that pkth->caplen is
     79 	 * >= sizeof (pcap_usb_header_mmapped).
     80 	 */
     81 	bytes_left = phdr->caplen;
     82 	bytes_left -= sizeof (pcap_usb_header_mmapped);
     83 
     84 	hdr = (const pcap_usb_header_mmapped *) bp;
     85 	descs = (const usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped));
     86 
     87 	/*
     88 	 * Find the end of the last chunk of data in the buffer
     89 	 * referred to by the isochronous descriptors; that indicates
     90 	 * how far into the buffer the data would have gone.
     91 	 *
     92 	 * Make sure we don't run past the end of the captured data
     93 	 * while processing the isochronous descriptors.
     94 	 */
     95 	pre_truncation_data_len = 0;
     96 	for (uint32_t desc = 0;
     97 	    desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc);
     98 	    desc++, bytes_left -= sizeof (usb_isodesc)) {
     99 		u_int desc_end;
    100 
    101 		if (descs[desc].len != 0) {
    102 			/*
    103 			 * Compute the end offset of the data
    104 			 * for this descriptor, i.e. the offset
    105 			 * of the byte after the data.  Clamp
    106 			 * the sum at UINT_MAX, so that it fits
    107 			 * in a u_int.
    108 			 */
    109 			desc_end = u_int_sum(descs[desc].offset,
    110 			    descs[desc].len);
    111 			if (desc_end > pre_truncation_data_len)
    112 				pre_truncation_data_len = desc_end;
    113 		}
    114 	}
    115 
    116 	/*
    117 	 * Return the sum of the total header length (memory-mapped
    118 	 * header and ISO descriptors) and the data length, clamped
    119 	 * to UINT_MAX.
    120 	 *
    121 	 * We've made sure that the number of descriptors is
    122 	 * <= USB_MAXDESC, so we know that the total size,
    123 	 * in bytes, of the descriptors fits in a 32-bit
    124 	 * integer.
    125 	 */
    126 	return (u_int_sum(iso_pseudo_header_len(hdr), pre_truncation_data_len));
    127 }
    128