xref: /freebsd/contrib/libpcap/pcap-usb-linux-common.h (revision b59017c5cad90d0f09a59e68c00457b7faf93e7c)
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