/src/libpcap/pcap-usb-linux-common.c
Line | Count | Source (jump to first uncovered line) |
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.c - common code for everything that needs to |
22 | | * deal with Linux USB captures. |
23 | | */ |
24 | | |
25 | | #include <limits.h> /* for UINT_MAX */ |
26 | | |
27 | | #include "pcap/pcap.h" |
28 | | #include "pcap/usb.h" |
29 | | |
30 | | #include "pcap-usb-linux-common.h" |
31 | | |
32 | | /* |
33 | | * Return the sum of the two u_int arguments if that sum fits in a u_int, |
34 | | * and return UINT_MAX otherwise. |
35 | | */ |
36 | | static inline u_int |
37 | | u_int_sum(u_int a, u_int b) |
38 | 13.8k | { |
39 | 13.8k | return (((b) <= UINT_MAX - (a)) ? (a) + (b) : UINT_MAX); |
40 | 13.8k | } |
41 | | |
42 | | /* |
43 | | * Compute, from the data provided by the Linux USB memory-mapped capture |
44 | | * mechanism, the amount of packet data that would have been provided |
45 | | * had the capture mechanism not chopped off any data at the end, if, in |
46 | | * fact, it did so. |
47 | | * |
48 | | * Set the "unsliced length" field of the packet header to that value. |
49 | | */ |
50 | | void |
51 | | fix_linux_usb_mmapped_length(struct pcap_pkthdr *pkth, const u_char *bp) |
52 | 3.24k | { |
53 | 3.24k | const pcap_usb_header_mmapped *hdr; |
54 | 3.24k | u_int bytes_left; |
55 | | |
56 | | /* |
57 | | * All callers of this routine must ensure that pkth->caplen is |
58 | | * >= sizeof (pcap_usb_header_mmapped). |
59 | | */ |
60 | 3.24k | bytes_left = pkth->caplen; |
61 | 3.24k | bytes_left -= sizeof (pcap_usb_header_mmapped); |
62 | | |
63 | 3.24k | hdr = (const pcap_usb_header_mmapped *) bp; |
64 | 3.24k | if (!hdr->data_flag && hdr->transfer_type == URB_ISOCHRONOUS && |
65 | 3.24k | hdr->event_type == URB_COMPLETE && |
66 | 3.24k | (hdr->endpoint_number & URB_TRANSFER_IN) && |
67 | 3.24k | pkth->len == sizeof(pcap_usb_header_mmapped) + |
68 | 1.67k | (hdr->ndesc * sizeof (usb_isodesc)) + hdr->urb_len) { |
69 | 1.67k | usb_isodesc *descs; |
70 | 1.67k | u_int pre_truncation_descriptors_len; |
71 | 1.67k | u_int pre_truncation_header_len; |
72 | 1.67k | u_int pre_truncation_data_len; |
73 | 1.67k | u_int pre_truncation_len; |
74 | | |
75 | 1.67k | descs = (usb_isodesc *) (bp + sizeof(pcap_usb_header_mmapped)); |
76 | | |
77 | | /* |
78 | | * We have data (yes, data_flag is 0 if we *do* have data), |
79 | | * and this is a "this is complete" incoming isochronous |
80 | | * transfer event, and the length was calculated based |
81 | | * on the URB length. |
82 | | * |
83 | | * That's not correct, because the data isn't contiguous, |
84 | | * and the isochronous descriptors show how it's scattered. |
85 | | * |
86 | | * Find the end of the last chunk of data in the buffer |
87 | | * referred to by the isochronous descriptors; that indicates |
88 | | * how far into the buffer the data would have gone. |
89 | | * |
90 | | * Make sure we don't run past the end of the captured data |
91 | | * while processing the isochronous descriptors. |
92 | | */ |
93 | 1.67k | pre_truncation_data_len = 0; |
94 | 1.67k | for (uint32_t desc = 0; |
95 | 17.8k | desc < hdr->ndesc && bytes_left >= sizeof (usb_isodesc); |
96 | 16.1k | desc++, bytes_left -= sizeof (usb_isodesc)) { |
97 | 16.1k | u_int desc_end; |
98 | | |
99 | 16.1k | if (descs[desc].len != 0) { |
100 | | /* |
101 | | * Compute the end offset of the data |
102 | | * for this descriptor, i.e. the offset |
103 | | * of the byte after the data. Clamp |
104 | | * the sum at UINT_MAX, so that it fits |
105 | | * in a u_int. |
106 | | */ |
107 | 10.4k | desc_end = u_int_sum(descs[desc].offset, |
108 | 10.4k | descs[desc].len); |
109 | 10.4k | if (desc_end > pre_truncation_data_len) |
110 | 1.17k | pre_truncation_data_len = desc_end; |
111 | 10.4k | } |
112 | 16.1k | } |
113 | | |
114 | | /* |
115 | | * Now calculate the total length based on that data |
116 | | * length. |
117 | | * |
118 | | * First, make sure the total length of the ISO |
119 | | * descriptors fits in an unsigned int. We know |
120 | | * that sizeof (usb_isodesc) is a small power-of-2 |
121 | | * integer (16 bytes), so we just check whether |
122 | | * hdr->ndesc < (UINT_MAX + (uint64_t)1) / sizeof (usb_isodesc), |
123 | | * as that would mean that hdr->ndesc * sizeof (usb_isodesc) |
124 | | * is < (UINT_MAX + (uint64_t)1) and thus <= UINT_MAX. |
125 | | * ((UINT_MAX + (uint64_t)1) will probably be computed |
126 | | * at compile time with most C compilers.) |
127 | | */ |
128 | 1.67k | if (hdr->ndesc < (UINT_MAX + (uint64_t)1) / sizeof (usb_isodesc)) { |
129 | | /* |
130 | | * It fits. |
131 | | */ |
132 | 1.67k | pre_truncation_descriptors_len = |
133 | 1.67k | hdr->ndesc * sizeof (usb_isodesc); |
134 | 1.67k | } else { |
135 | | /* |
136 | | * It doesn't fit. |
137 | | */ |
138 | 0 | pre_truncation_descriptors_len = UINT_MAX; |
139 | 0 | } |
140 | | |
141 | | /* |
142 | | * Now, add the length of the memory-mapped header and |
143 | | * the length of the ISO descriptors, clamping the |
144 | | * result at UINT_MAX. |
145 | | */ |
146 | 1.67k | pre_truncation_header_len = u_int_sum(sizeof(pcap_usb_header_mmapped), |
147 | 1.67k | pre_truncation_descriptors_len); |
148 | | |
149 | | /* |
150 | | * Now, add the total header length (memory-mapped header |
151 | | * and ISO descriptors) and the data length, clamping |
152 | | * the result at UINT_MAX. |
153 | | */ |
154 | 1.67k | pre_truncation_len = u_int_sum(pre_truncation_header_len, |
155 | 1.67k | pre_truncation_data_len); |
156 | | |
157 | | /* |
158 | | * pre_truncation_len is now the smaller of |
159 | | * UINT_MAX and the total header plus data length. |
160 | | * That's guaranteed to fit in a UINT_MAX. |
161 | | */ |
162 | 1.67k | if (pre_truncation_len >= pkth->caplen) |
163 | 1.27k | pkth->len = pre_truncation_len; |
164 | | |
165 | | /* |
166 | | * If the captured length is greater than the length, |
167 | | * use the captured length. |
168 | | * |
169 | | * For completion events for incoming isochronous transfers, |
170 | | * it's based on data_len, which is calculated the same way |
171 | | * we calculated pre_truncation_data_len above, except that |
172 | | * it has access to all the isochronous descriptors, not |
173 | | * just the ones that the kernel were able to provide us or, |
174 | | * for a capture file, that weren't sliced off by a snapshot |
175 | | * length. |
176 | | * |
177 | | * However, it might have been reduced by the USB capture |
178 | | * mechanism arbitrarily limiting the amount of data it |
179 | | * provides to userland, or by the libpcap capture code |
180 | | * limiting it to being no more than the snapshot, so |
181 | | * we don't want to just use it all the time; we only |
182 | | * do so to try to get a better estimate of the actual |
183 | | * length - and to make sure the on-the-network length |
184 | | * is always >= the captured length. |
185 | | */ |
186 | 1.67k | if (pkth->caplen > pkth->len) |
187 | 398 | pkth->len = pkth->caplen; |
188 | 1.67k | } |
189 | 3.24k | } |