attr_dissector_fn_t
[wireshark-sm.git] / wiretap / packetlogger.c
blob515c873360935b630c8d942c5690197d60ec0064
1 /* packetlogger.c
2 * Routines for opening Apple's (Bluetooth) PacketLogger file format captures
3 * Copyright 2008-2009, Stephen Fisher (see AUTHORS file)
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * Based on commview.c, Linux's BlueZ-Gnome Analyzer program and hexdumps of
10 * the output files from Apple's PacketLogger tool.
12 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include "config.h"
16 #include "packetlogger.h"
18 #include <stdlib.h>
19 #include <string.h>
21 #include "wtap-int.h"
22 #include "file_wrappers.h"
24 typedef struct {
25 bool byte_swapped;
26 } packetlogger_t;
28 typedef struct packetlogger_header {
29 uint32_t len;
30 uint32_t ts_secs;
31 uint32_t ts_usecs;
32 } packetlogger_header_t;
34 /* Packet types. */
35 #define PKT_HCI_COMMAND 0x00
36 #define PKT_HCI_EVENT 0x01
37 #define PKT_SENT_ACL_DATA 0x02
38 #define PKT_RECV_ACL_DATA 0x03
39 #define PKT_SENT_SCO_DATA 0x08
40 #define PKT_RECV_SCO_DATA 0x09
41 #define PKT_LMP_SEND 0x0A
42 #define PKT_LMP_RECV 0x0B
43 #define PKT_SYSLOG 0xF7
44 #define PKT_KERNEL 0xF8
45 #define PKT_KERNEL_DEBUG 0xF9
46 #define PKT_ERROR 0xFA
47 #define PKT_POWER 0xFB
48 #define PKT_NOTE 0xFC
49 #define PKT_CONFIG 0xFD
50 #define PKT_NEW_CONTROLLER 0xFE
52 static bool packetlogger_read(wtap *wth, wtap_rec *rec, Buffer *buf,
53 int *err, char **err_info,
54 int64_t *data_offset);
55 static bool packetlogger_seek_read(wtap *wth, int64_t seek_off,
56 wtap_rec *rec,
57 Buffer *buf, int *err, char **err_info);
58 static bool packetlogger_read_header(packetlogger_header_t *pl_hdr,
59 FILE_T fh, bool byte_swapped,
60 int *err, char **err_info);
61 static void packetlogger_byte_swap_header(packetlogger_header_t *pl_hdr);
62 static wtap_open_return_val packetlogger_check_record(wtap *wth,
63 packetlogger_header_t *pl_hdr,
64 int *err,
65 char **err_info);
66 static bool packetlogger_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec,
67 Buffer *buf, int *err,
68 char **err_info);
70 static int packetlogger_file_type_subtype = -1;
72 void register_packetlogger(void);
75 * Number of packets to try reading.
77 #define PACKETS_TO_CHECK 5
79 wtap_open_return_val packetlogger_open(wtap *wth, int *err, char **err_info)
81 bool byte_swapped = false;
82 packetlogger_header_t pl_hdr;
83 wtap_open_return_val ret;
84 packetlogger_t *packetlogger;
87 * Try to read the first record.
89 if(!packetlogger_read_header(&pl_hdr, wth->fh, byte_swapped,
90 err, err_info)) {
92 * Either an immediate EOF or a short read indicates
93 * that the file is probably not a PacketLogger file.
95 if (*err != 0 && *err != WTAP_ERR_SHORT_READ)
96 return WTAP_OPEN_ERROR;
97 return WTAP_OPEN_NOT_MINE;
101 * If the upper 16 bits of the length are non-zero and the lower
102 * 16 bits are zero, assume the file is byte-swapped from our
103 * byte order.
105 if ((pl_hdr.len & 0x0000FFFF) == 0 &&
106 (pl_hdr.len & 0xFFFF0000) != 0) {
108 * Byte-swap the header.
110 packetlogger_byte_swap_header(&pl_hdr);
111 byte_swapped = true;
115 * Check whether the first record looks like a PacketLogger
116 * record.
118 ret = packetlogger_check_record(wth, &pl_hdr, err, err_info);
119 if (ret != WTAP_OPEN_MINE) {
121 * Either we got an error or it's not valid.
123 if (ret == WTAP_OPEN_NOT_MINE) {
125 * Not valid, so not a PacketLogger file.
127 return WTAP_OPEN_NOT_MINE;
131 * Error. If it failed with a short read, we don't fail,
132 * so we treat it as a valid file and can then report
133 * it as a truncated file.
135 if (*err != WTAP_ERR_SHORT_READ)
136 return WTAP_OPEN_ERROR;
137 } else {
139 * Now try reading a few more packets.
141 for (int i = 1; i < PACKETS_TO_CHECK; i++) {
143 * Read and check the file header; we've already
144 * decided whether this would be a byte-swapped file
145 * or not, so we swap iff we decided it was.
147 if (!packetlogger_read_header(&pl_hdr, wth->fh,
148 byte_swapped, err, err_info)) {
149 if (*err == 0) {
150 /* EOF; no more packets to try. */
151 break;
155 * A short read indicates that the file
156 * is probably not a PacketLogger file.
158 if (*err != WTAP_ERR_SHORT_READ)
159 return WTAP_OPEN_ERROR;
160 return WTAP_OPEN_NOT_MINE;
164 * Check whether this record looks like a PacketLogger
165 * record.
167 ret = packetlogger_check_record(wth, &pl_hdr, err,
168 err_info);
169 if (ret != WTAP_OPEN_MINE) {
171 * Either we got an error or it's not valid.
173 if (ret == WTAP_OPEN_NOT_MINE) {
175 * Not valid, so not a PacketLogger
176 * file.
178 return WTAP_OPEN_NOT_MINE;
182 * Error. If it failed with a short read,
183 * we don't fail, we just stop checking
184 * records, so we treat it as a valid file
185 * and can then report it as a truncated file.
187 if (*err != WTAP_ERR_SHORT_READ)
188 return WTAP_OPEN_ERROR;
189 break;
194 /* No file header. Reset the fh to 0 so we can read the first packet */
195 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
196 return WTAP_OPEN_ERROR;
198 /* This is a PacketLogger file */
199 packetlogger = g_new(packetlogger_t, 1);
200 packetlogger->byte_swapped = byte_swapped;
201 wth->priv = (void *)packetlogger;
203 /* Set up the pointers to the handlers for this file type */
204 wth->subtype_read = packetlogger_read;
205 wth->subtype_seek_read = packetlogger_seek_read;
207 wth->file_type_subtype = packetlogger_file_type_subtype;
208 wth->file_encap = WTAP_ENCAP_PACKETLOGGER;
209 wth->file_tsprec = WTAP_TSPREC_USEC;
212 * Add an IDB; we don't know how many interfaces were
213 * involved, so we just say one interface, about which
214 * we only know the link-layer type, snapshot length,
215 * and time stamp resolution.
217 wtap_add_generated_idb(wth);
219 return WTAP_OPEN_MINE; /* Our kind of file */
222 static bool
223 packetlogger_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err,
224 char **err_info, int64_t *data_offset)
226 *data_offset = file_tell(wth->fh);
228 return packetlogger_read_packet(wth, wth->fh, rec, buf, err, err_info);
231 static bool
232 packetlogger_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec,
233 Buffer *buf, int *err, char **err_info)
235 if(file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
236 return false;
238 if(!packetlogger_read_packet(wth, wth->random_fh, rec, buf, err, err_info)) {
239 if(*err == 0)
240 *err = WTAP_ERR_SHORT_READ;
242 return false;
244 return true;
247 static bool
248 packetlogger_read_header(packetlogger_header_t *pl_hdr, FILE_T fh,
249 bool byte_swapped, int *err, char **err_info)
251 if (!wtap_read_bytes_or_eof(fh, &pl_hdr->len, 4, err, err_info))
252 return false;
253 if (!wtap_read_bytes(fh, &pl_hdr->ts_secs, 4, err, err_info))
254 return false;
255 if (!wtap_read_bytes(fh, &pl_hdr->ts_usecs, 4, err, err_info))
256 return false;
258 /* Convert multi-byte values to host endian */
259 if (byte_swapped)
260 packetlogger_byte_swap_header(pl_hdr);
262 return true;
265 static void
266 packetlogger_byte_swap_header(packetlogger_header_t *pl_hdr)
268 pl_hdr->len = GUINT32_SWAP_LE_BE(pl_hdr->len);
269 pl_hdr->ts_secs = GUINT32_SWAP_LE_BE(pl_hdr->ts_secs);
270 pl_hdr->ts_usecs = GUINT32_SWAP_LE_BE(pl_hdr->ts_usecs);
273 static wtap_open_return_val
274 packetlogger_check_record(wtap *wth, packetlogger_header_t *pl_hdr, int *err,
275 char **err_info)
277 uint32_t length;
278 uint8_t type;
280 /* Is the header length valid? If not, assume it's not ours. */
281 if (pl_hdr->len < 8 || pl_hdr->len >= 65536)
282 return WTAP_OPEN_NOT_MINE;
284 /* Is the microseconds field of the time stap out of range? */
285 if (pl_hdr->ts_usecs >= 1000000)
286 return WTAP_OPEN_NOT_MINE;
289 * If we have any payload, it's a type field; read and check it.
291 length = pl_hdr->len - 8;
292 if (length != 0) {
294 * Check the type field.
296 if (!wtap_read_bytes(wth->fh, &type, 1, err, err_info)) {
297 if (*err != WTAP_ERR_SHORT_READ)
298 return WTAP_OPEN_ERROR;
299 return WTAP_OPEN_NOT_MINE;
302 /* Verify this file belongs to us */
303 switch (type) {
305 case PKT_HCI_COMMAND:
306 case PKT_HCI_EVENT:
307 case PKT_SENT_ACL_DATA:
308 case PKT_RECV_ACL_DATA:
309 case PKT_SENT_SCO_DATA:
310 case PKT_RECV_SCO_DATA:
311 case PKT_LMP_SEND:
312 case PKT_LMP_RECV:
313 case PKT_SYSLOG:
314 case PKT_KERNEL:
315 case PKT_KERNEL_DEBUG:
316 case PKT_ERROR:
317 case PKT_POWER:
318 case PKT_NOTE:
319 case PKT_CONFIG:
320 case PKT_NEW_CONTROLLER:
321 break;
323 default:
324 return WTAP_OPEN_NOT_MINE;
327 length--;
329 if (length != 0) {
331 * Now try to read past the rest of the packet bytes;
332 * if that fails with a short read, we don't fail,
333 * so that we can report the file as a truncated
334 * PacketLogger file.
336 if (!wtap_read_bytes(wth->fh, NULL, length,
337 err, err_info))
338 return WTAP_OPEN_ERROR;
341 return WTAP_OPEN_MINE;
344 static bool
345 packetlogger_read_packet(wtap *wth, FILE_T fh, wtap_rec *rec, Buffer *buf,
346 int *err, char **err_info)
348 packetlogger_t *packetlogger = (packetlogger_t *)wth->priv;
349 packetlogger_header_t pl_hdr;
351 if(!packetlogger_read_header(&pl_hdr, fh, packetlogger->byte_swapped,
352 err, err_info))
353 return false;
355 if (pl_hdr.len < 8) {
356 *err = WTAP_ERR_BAD_FILE;
357 *err_info = ws_strdup_printf("packetlogger: record length %u is too small", pl_hdr.len);
358 return false;
360 if (pl_hdr.len - 8 > WTAP_MAX_PACKET_SIZE_STANDARD) {
362 * Probably a corrupt capture file; don't blow up trying
363 * to allocate space for an immensely-large packet.
365 *err = WTAP_ERR_BAD_FILE;
366 *err_info = ws_strdup_printf("packetlogger: File has %u-byte packet, bigger than maximum of %u",
367 pl_hdr.len - 8, WTAP_MAX_PACKET_SIZE_STANDARD);
368 return false;
371 rec->rec_type = REC_TYPE_PACKET;
372 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
373 rec->presence_flags = WTAP_HAS_TS;
375 rec->rec_header.packet_header.len = pl_hdr.len - 8;
376 rec->rec_header.packet_header.caplen = pl_hdr.len - 8;
378 rec->ts.secs = (time_t)pl_hdr.ts_secs;
379 rec->ts.nsecs = (int)(pl_hdr.ts_usecs * 1000);
381 return wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info);
384 static const struct supported_block_type packetlogger_blocks_supported[] = {
386 * We support packet blocks, with no comments or other options.
388 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
391 static const struct file_type_subtype_info packetlogger_info = {
392 "macOS PacketLogger", "pklg", "pklg", NULL,
393 false, BLOCKS_SUPPORTED(packetlogger_blocks_supported),
394 NULL, NULL, NULL
397 void register_packetlogger(void)
399 packetlogger_file_type_subtype = wtap_register_file_type_subtype(&packetlogger_info);
402 * Register name for backwards compatibility with the
403 * wtap_filetypes table in Lua.
405 wtap_register_backwards_compatibility_lua_name("PACKETLOGGER",
406 packetlogger_file_type_subtype);
410 * Editor modelines - https://www.wireshark.org/tools/modelines.html
412 * Local variables:
413 * c-basic-offset: 8
414 * tab-width: 8
415 * indent-tabs-mode: t
416 * End:
418 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
419 * :indentSize=8:tabSize=8:noTabs=false: