4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * File format support for usbdump file format
7 * Copyright (c) 2017 by Jaap Keuter <jaap.keuter@xs4all.nl>
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * This wiretap is for an usbdump file format reader. The format is
14 * reverse engineered from FreeBSD source code.
16 * File format is little endian!
19 * ---------------------------------
20 * 0E 00 90 9A header magic
23 * 00 00 00 00 00 00 00 00 reserved
24 * 00 00 00 00 00 00 00 00
25 * 00 00 00 00 00 00 00 00
29 * ---------------------------------
30 * F0 26 00 00 length of multiframe read from bpf (9968 octets)
32 * Frame, bpf header (little endian)
33 * ---------------------------------
36 * 98 00 00 00 capture length (152)
37 * 98 00 00 00 data length (152)
38 * 1C header length (28)
39 * 04 bpf word alignment size
40 * 00 00 00 00 00 00 00 00 padding
43 * Frame, captured data
44 * ---------------------------------
45 * 98 00 00 00 00 00 00 00 length, ....
51 #include "file_wrappers.h"
54 void wtap_register_usbdump(void);
56 #define USBDUMP_MAGIC 0x9a90000e
58 /* Private data needed to read the file initially. */
61 uint32_t multiframe_size
;
62 bool multiframe_overrun
;
66 static bool usbdump_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
,
67 int *err
, char **err_info
,
68 int64_t *data_offset
);
69 static bool usbdump_seek_read(wtap
*wth
, int64_t seek_off
,
70 wtap_rec
*rec
, Buffer
*buf
,
71 int *err
, char **err_info
);
72 static bool usbdump_read_packet(wtap
*wth
, FILE_T fh
,
73 wtap_rec
*rec
, Buffer
*buf
,
74 int *err
, char **err_info
);
76 static int usbdump_file_type_subtype
;
79 * Try to interpret a file as a usbdump formatted file.
80 * Read relevant parts of the given file and collect information needed to
81 * read the individual frames. Return value indicates whether or not this is
82 * recognized as an usbdump file.
84 static wtap_open_return_val
85 usbdump_open(wtap
*wth
, int *err
, char **err_info
)
89 uint32_t multiframe_size
;
90 usbdump_info_t
*usbdump_info
;
92 /* Read in the number that should be at the start of a "usbdump" file */
93 if (!wtap_read_bytes(wth
->fh
, &magic
, sizeof magic
, err
, err_info
)) {
94 if (*err
!= WTAP_ERR_SHORT_READ
)
95 return WTAP_OPEN_ERROR
;
96 return WTAP_OPEN_NOT_MINE
;
99 /* Check the file magic */
100 if (GUINT32_FROM_LE(magic
) != USBDUMP_MAGIC
)
102 return WTAP_OPEN_NOT_MINE
;
105 /* Read the version of the header */
106 if (!wtap_read_bytes(wth
->fh
, &version
, sizeof version
, err
, err_info
)) {
107 if (*err
!= WTAP_ERR_SHORT_READ
)
108 return WTAP_OPEN_ERROR
;
109 return WTAP_OPEN_NOT_MINE
;
112 /* Check for the supported version number */
113 if (GUINT16_FROM_BE(version
) != 3) {
114 /* We only support version 0.3 */
115 *err
= WTAP_ERR_UNSUPPORTED
;
116 *err_info
= ws_strdup_printf("usbdump: version %u.%u unsupported",
117 version
>> 8, version
& 0xff);
118 return WTAP_OPEN_NOT_MINE
;
121 /* Read the reserved field of the header */
122 if (!wtap_read_bytes(wth
->fh
, NULL
, 26, err
, err_info
)) {
123 if (*err
!= WTAP_ERR_SHORT_READ
)
124 return WTAP_OPEN_ERROR
;
125 return WTAP_OPEN_NOT_MINE
;
128 /* Read the initial multiframe size field */
129 if (!wtap_read_bytes(wth
->fh
, &multiframe_size
, sizeof multiframe_size
,
131 if (*err
!= WTAP_ERR_SHORT_READ
)
132 return WTAP_OPEN_ERROR
;
133 return WTAP_OPEN_NOT_MINE
;
136 /* Create a private structure to track the multiframe */
137 usbdump_info
= g_new(usbdump_info_t
, 1);
138 usbdump_info
->version
= GUINT16_FROM_BE(version
);
139 usbdump_info
->multiframe_size
= GUINT32_FROM_LE(multiframe_size
);
140 usbdump_info
->multiframe_overrun
= false;
143 * We are convinced this is a usbdump format file.
144 * Setup the wiretap structure and fill it with info of this format.
146 wth
->priv
= (void *)usbdump_info
;
147 wth
->subtype_read
= usbdump_read
;
148 wth
->subtype_seek_read
= usbdump_seek_read
;
149 wth
->file_type_subtype
= usbdump_file_type_subtype
;
150 wth
->file_encap
= WTAP_ENCAP_USB_FREEBSD
;
151 wth
->file_tsprec
= WTAP_TSPREC_USEC
;
153 return WTAP_OPEN_MINE
;
157 * Sequential read with offset reporting.
158 * Read the next frame in the file and adjust for the multiframe size
159 * indication. Report back where reading of this frame started to
160 * support subsequent random access read.
163 usbdump_read(wtap
*wth
, wtap_rec
*rec
, Buffer
*buf
, int *err
, char **err_info
,
164 int64_t *data_offset
)
166 usbdump_info_t
*usbdump_info
= (usbdump_info_t
*)wth
->priv
;
168 /* Report the current file location */
169 *data_offset
= file_tell(wth
->fh
);
171 /* Try to read a packet worth of data */
172 if (!usbdump_read_packet(wth
, wth
->fh
, rec
, buf
, err
, err_info
))
175 /* Check if we overrun the multiframe during the last read */
176 if (usbdump_info
->multiframe_overrun
)
178 *err
= WTAP_ERR_BAD_FILE
;
179 *err_info
= ws_strdup_printf("Multiframe overrun");
183 /* See if we reached the end of the multiframe */
184 if (usbdump_info
->multiframe_size
== 0)
187 * Try to read the subsequent multiframe size field.
188 * This will fail at end of file, but that is accepted.
190 wtap_read_bytes_or_eof(wth
->fh
, &usbdump_info
->multiframe_size
,
191 sizeof usbdump_info
->multiframe_size
,
199 * Random access read.
200 * Read the frame at the given offset in the file. Store the frame data
201 * in a buffer and fill in the packet header info.
204 usbdump_seek_read(wtap
*wth
, int64_t seek_off
, wtap_rec
*rec
,
205 Buffer
*buf
, int *err
, char **err_info
)
207 /* Seek to the desired file position at the start of the frame */
208 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
211 /* Try to read a packet worth of data */
212 if (!usbdump_read_packet(wth
, wth
->random_fh
, rec
, buf
, err
, err_info
)) {
214 *err
= WTAP_ERR_SHORT_READ
;
222 * Read the actual frame data from the file.
223 * This requires reading the header, determine the size, read frame size worth
224 * of data into the buffer and setting the packet header fields to the values
225 * of the frame header.
227 * Also, for the sequential read, keep track of the position in the multiframe
228 * so that we can find the next multiframe size field.
231 usbdump_read_packet(wtap
*wth
, FILE_T fh
, wtap_rec
*rec
, Buffer
*buf
,
232 int *err
, char **err_info
)
234 usbdump_info_t
*usbdump_info
= (usbdump_info_t
*)wth
->priv
;
237 uint8_t bpf_hdr_len
, alignment
;
239 /* Read the packet header */
240 if (!wtap_read_bytes_or_eof(fh
, bpf_hdr
, 18, err
, err_info
))
244 bpf_hdr_len
= bpf_hdr
[16];
245 alignment
= bpf_hdr
[17];
247 /* Check header length */
248 if (bpf_hdr_len
> 18)
250 /* Read packet header padding */
251 if (!wtap_read_bytes_or_eof(fh
, NULL
, bpf_hdr_len
- 18, err
, err_info
))
255 /* Keep track of multiframe_size and detect overrun */
256 if (usbdump_info
->multiframe_size
< bpf_hdr_len
) {
257 usbdump_info
->multiframe_overrun
= true;
259 usbdump_info
->multiframe_size
-= bpf_hdr_len
;
262 /* Setup the per packet structure and fill it with info from this frame */
263 rec
->rec_type
= REC_TYPE_PACKET
;
264 rec
->block
= wtap_block_create(WTAP_BLOCK_PACKET
);
265 rec
->presence_flags
= WTAP_HAS_TS
| WTAP_HAS_CAP_LEN
;
266 rec
->ts
.secs
= (uint32_t)bpf_hdr
[3] << 24 | (uint32_t)bpf_hdr
[2] << 16 |
267 (uint32_t)bpf_hdr
[1] << 8 | (uint32_t)bpf_hdr
[0];
268 rec
->ts
.nsecs
= ((uint32_t)bpf_hdr
[7] << 24 | (uint32_t)bpf_hdr
[6] << 16 |
269 (uint32_t)bpf_hdr
[5] << 8 | (uint32_t)bpf_hdr
[4]) * 1000;
270 rec
->rec_header
.packet_header
.caplen
= (uint32_t)bpf_hdr
[11] << 24 | (uint32_t)bpf_hdr
[10] << 16 |
271 (uint32_t)bpf_hdr
[9] << 8 | (uint32_t)bpf_hdr
[8];
272 rec
->rec_header
.packet_header
.len
= (uint32_t)bpf_hdr
[15] << 24 | (uint32_t)bpf_hdr
[14] << 16 |
273 (uint32_t)bpf_hdr
[13] << 8 | (uint32_t)bpf_hdr
[12];
275 /* Read the packet data */
276 if (!wtap_read_packet_bytes(fh
, buf
, rec
->rec_header
.packet_header
.caplen
, err
, err_info
))
279 /* Keep track of multiframe_size and detect overrun */
280 if (usbdump_info
->multiframe_size
< rec
->rec_header
.packet_header
.caplen
) {
281 usbdump_info
->multiframe_overrun
= true;
283 usbdump_info
->multiframe_size
-= rec
->rec_header
.packet_header
.caplen
;
286 /* Check for and apply alignment as defined in the frame header */
287 uint8_t pad_len
= (uint32_t)alignment
-
288 (((uint32_t)bpf_hdr_len
+ rec
->rec_header
.packet_header
.caplen
) &
289 ((uint32_t)alignment
- 1));
290 if (pad_len
< alignment
) {
291 /* Read alignment from the file */
292 if (!wtap_read_bytes(fh
, NULL
, pad_len
, err
, err_info
))
295 /* Keep track of multiframe_size and detect overrun */
296 if (usbdump_info
->multiframe_size
< pad_len
) {
297 usbdump_info
->multiframe_overrun
= true;
299 usbdump_info
->multiframe_size
-= pad_len
;
307 * Register with wiretap.
308 * Register how we can handle an unknown file to see if this is a valid
309 * usbdump file and register information about this file format.
311 static const struct supported_block_type usbdump_blocks_supported
[] = {
312 /* We support packet blocks, with no comments or other options. */
313 { WTAP_BLOCK_PACKET
, MULTIPLE_BLOCKS_SUPPORTED
, NO_OPTIONS_SUPPORTED
}
315 static const struct file_type_subtype_info fi
= {
321 BLOCKS_SUPPORTED(usbdump_blocks_supported
),
328 wtap_register_usbdump(void)
330 struct open_info oi
= {
339 wtap_register_open_info(&oi
, false);
341 usbdump_file_type_subtype
= wtap_register_file_type_subtype(&fi
);
345 * Editor modelines - https://www.wireshark.org/tools/modelines.html
350 * indent-tabs-mode: nil
353 * vi: set shiftwidth=4 tabstop=8 expandtab:
354 * :indentSize=4:tabSize=8:noTabs=true: