NEEDED??? epan/dissectors/packet-dcerpc.c dissect_ndr_c_and_or_v_array_core dissect_n...
[wireshark-sm.git] / wiretap / btsnoop.c
blob85cb33e5ce71e7ecb50e78a0763b2c82e57a4c58
1 /* btsnoop.c
3 * Wiretap Library
4 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
10 #include "btsnoop.h"
12 #include <string.h>
13 #include "wtap-int.h"
14 #include "file_wrappers.h"
17 * Symbian's btsnoop format is derived from Sun's snoop format.
18 * See RFC 1761 for a description of the "snoop" file format.
19 * See
21 * https://gitlab.com/wireshark/wireshark/uploads/6d44fa94c164b58516e8577f44a6ccdc/btmodified_rfc1761.txt
23 * for a description of the btsnoop format.
26 /* Magic number in "btsnoop" files. */
27 static const char btsnoop_magic[] = {
28 'b', 't', 's', 'n', 'o', 'o', 'p', '\0'
31 /* "btsnoop" file header (minus magic number). */
32 struct btsnoop_hdr {
33 uint32_t version; /* version number (should be 1) */
34 uint32_t datalink; /* datalink type */
37 /* "btsnoop" record header. */
38 struct btsnooprec_hdr {
39 uint32_t orig_len; /* actual length of packet */
40 uint32_t incl_len; /* number of octets captured in file */
41 uint32_t flags; /* packet flags */
42 uint32_t cum_drops; /* cumulative number of dropped packets */
43 int64_t ts_usec; /* timestamp microseconds */
46 /* H1 is unframed data with the packet type encoded in the flags field of capture header */
47 /* It can be used for any datalink by placing logging above the datalink layer of HCI */
48 #define KHciLoggerDatalinkTypeH1 1001
49 /* H4 is the serial HCI with packet type encoded in the first byte of each packet */
50 #define KHciLoggerDatalinkTypeH4 1002
51 /* CSR's PPP derived bluecore serial protocol - in practice we log in H1 format after deframing */
52 #define KHciLoggerDatalinkTypeBCSP 1003
53 /* H5 is the official three wire serial protocol derived from BCSP*/
54 #define KHciLoggerDatalinkTypeH5 1004
55 /* Linux Monitor */
56 #define KHciLoggerDatalinkLinuxMonitor 2001
57 /* BlueZ 5 Simulator */
58 #define KHciLoggerDatalinkBlueZ5Simulator 2002
60 #define KHciLoggerHostToController 0
61 #define KHciLoggerControllerToHost 0x00000001
62 #define KHciLoggerACLDataFrame 0
63 #define KHciLoggerCommandOrEvent 0x00000002
65 static const int64_t KUnixTimeBase = INT64_C(0x00dcddb30f2f8000); /* offset from symbian - unix time */
67 static bool btsnoop_read(wtap *wth, wtap_rec *rec, Buffer *buf,
68 int *err, char **err_info, int64_t *offset);
69 static bool btsnoop_seek_read(wtap *wth, int64_t seek_off,
70 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
71 static bool btsnoop_read_record(wtap *wth, FILE_T fh,
72 wtap_rec *rec, Buffer *buf, int *err, char **err_info);
74 static int btsnoop_file_type_subtype = -1;
76 void register_btsnoop(void);
78 wtap_open_return_val btsnoop_open(wtap *wth, int *err, char **err_info)
80 char magic[sizeof btsnoop_magic];
81 struct btsnoop_hdr hdr;
83 int file_encap=WTAP_ENCAP_UNKNOWN;
85 /* Read in the string that should be at the start of a "btsnoop" file */
86 if (!wtap_read_bytes(wth->fh, magic, sizeof magic, err, err_info)) {
87 if (*err != WTAP_ERR_SHORT_READ)
88 return WTAP_OPEN_ERROR;
89 return WTAP_OPEN_NOT_MINE;
92 if (memcmp(magic, btsnoop_magic, sizeof btsnoop_magic) != 0) {
93 return WTAP_OPEN_NOT_MINE;
96 /* Read the rest of the header. */
97 if (!wtap_read_bytes(wth->fh, &hdr, sizeof hdr, err, err_info))
98 return WTAP_OPEN_ERROR;
101 * Make sure it's a version we support.
103 hdr.version = g_ntohl(hdr.version);
104 if (hdr.version != 1) {
105 *err = WTAP_ERR_UNSUPPORTED;
106 *err_info = ws_strdup_printf("btsnoop: version %u unsupported", hdr.version);
107 return WTAP_OPEN_ERROR;
110 hdr.datalink = g_ntohl(hdr.datalink);
111 switch (hdr.datalink) {
112 case KHciLoggerDatalinkTypeH1:
113 file_encap=WTAP_ENCAP_BLUETOOTH_HCI;
114 break;
115 case KHciLoggerDatalinkTypeH4:
116 file_encap=WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR;
117 break;
118 case KHciLoggerDatalinkTypeBCSP:
119 *err = WTAP_ERR_UNSUPPORTED;
120 *err_info = g_strdup("btsnoop: BCSP capture logs unsupported");
121 return WTAP_OPEN_ERROR;
122 case KHciLoggerDatalinkTypeH5:
123 *err = WTAP_ERR_UNSUPPORTED;
124 *err_info = g_strdup("btsnoop: H5 capture logs unsupported");
125 return WTAP_OPEN_ERROR;
126 case KHciLoggerDatalinkLinuxMonitor:
127 file_encap=WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR;
128 break;
129 case KHciLoggerDatalinkBlueZ5Simulator:
130 *err = WTAP_ERR_UNSUPPORTED;
131 *err_info = g_strdup("btsnoop: BlueZ 5 Simulator capture logs unsupported");
132 return WTAP_OPEN_ERROR;
133 default:
134 *err = WTAP_ERR_UNSUPPORTED;
135 *err_info = ws_strdup_printf("btsnoop: datalink type %u unknown or unsupported", hdr.datalink);
136 return WTAP_OPEN_ERROR;
139 wth->subtype_read = btsnoop_read;
140 wth->subtype_seek_read = btsnoop_seek_read;
141 wth->file_encap = file_encap;
142 wth->snapshot_length = 0; /* not available in header */
143 wth->file_tsprec = WTAP_TSPREC_USEC;
144 wth->file_type_subtype = btsnoop_file_type_subtype;
147 * Add an IDB; we don't know how many interfaces were
148 * involved, so we just say one interface, about which
149 * we only know the link-layer type, snapshot length,
150 * and time stamp resolution.
152 wtap_add_generated_idb(wth);
154 return WTAP_OPEN_MINE;
157 static bool btsnoop_read(wtap *wth, wtap_rec *rec, Buffer *buf,
158 int *err, char **err_info, int64_t *offset)
160 *offset = file_tell(wth->fh);
162 return btsnoop_read_record(wth, wth->fh, rec, buf, err, err_info);
165 static bool btsnoop_seek_read(wtap *wth, int64_t seek_off,
166 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
168 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
169 return false;
171 return btsnoop_read_record(wth, wth->random_fh, rec, buf, err, err_info);
174 static bool btsnoop_read_record(wtap *wth, FILE_T fh,
175 wtap_rec *rec, Buffer *buf, int *err, char **err_info)
177 struct btsnooprec_hdr hdr;
178 uint32_t packet_size;
179 uint32_t flags;
180 uint32_t orig_size;
181 int64_t ts;
183 /* Read record header. */
185 if (!wtap_read_bytes_or_eof(fh, &hdr, sizeof hdr, err, err_info))
186 return false;
188 packet_size = g_ntohl(hdr.incl_len);
189 orig_size = g_ntohl(hdr.orig_len);
190 flags = g_ntohl(hdr.flags);
191 if (packet_size > WTAP_MAX_PACKET_SIZE_STANDARD) {
193 * Probably a corrupt capture file; don't blow up trying
194 * to allocate space for an immensely-large packet.
196 *err = WTAP_ERR_BAD_FILE;
197 *err_info = ws_strdup_printf("btsnoop: File has %u-byte packet, bigger than maximum of %u",
198 packet_size, WTAP_MAX_PACKET_SIZE_STANDARD);
199 return false;
202 ts = GINT64_FROM_BE(hdr.ts_usec);
203 ts -= KUnixTimeBase;
205 rec->rec_type = REC_TYPE_PACKET;
206 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
207 rec->presence_flags = WTAP_HAS_TS|WTAP_HAS_CAP_LEN;
208 rec->ts.secs = (unsigned)(ts / 1000000);
209 rec->ts.nsecs = (unsigned)((ts % 1000000) * 1000);
210 rec->rec_header.packet_header.caplen = packet_size;
211 rec->rec_header.packet_header.len = orig_size;
212 if(wth->file_encap == WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR)
214 rec->rec_header.packet_header.pseudo_header.p2p.sent = (flags & KHciLoggerControllerToHost) ? false : true;
215 } else if(wth->file_encap == WTAP_ENCAP_BLUETOOTH_HCI) {
216 rec->rec_header.packet_header.pseudo_header.bthci.sent = (flags & KHciLoggerControllerToHost) ? false : true;
217 if(flags & KHciLoggerCommandOrEvent)
219 if(rec->rec_header.packet_header.pseudo_header.bthci.sent)
221 rec->rec_header.packet_header.pseudo_header.bthci.channel = BTHCI_CHANNEL_COMMAND;
223 else
225 rec->rec_header.packet_header.pseudo_header.bthci.channel = BTHCI_CHANNEL_EVENT;
228 else
230 rec->rec_header.packet_header.pseudo_header.bthci.channel = BTHCI_CHANNEL_ACL;
232 } else if (wth->file_encap == WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR) {
233 rec->rec_header.packet_header.pseudo_header.btmon.opcode = flags & 0xFFFF;
234 rec->rec_header.packet_header.pseudo_header.btmon.adapter_id = flags >> 16;
238 /* Read packet data. */
239 return wtap_read_packet_bytes(fh, buf, rec->rec_header.packet_header.caplen, err, err_info);
242 /* Returns 0 if we could write the specified encapsulation type,
243 an error indication otherwise. */
244 static int btsnoop_dump_can_write_encap(int encap)
246 /* Per-packet encapsulations aren't supported. */
247 if (encap == WTAP_ENCAP_PER_PACKET)
248 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
251 * XXX - for now we only support WTAP_ENCAP_BLUETOOTH_HCI,
252 * WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR, and
253 * WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR.
255 if (encap != WTAP_ENCAP_BLUETOOTH_HCI &&
256 encap != WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR &&
257 encap != WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR)
258 return WTAP_ERR_UNWRITABLE_ENCAP;
260 return 0;
263 static bool btsnoop_dump(wtap_dumper *wdh,
264 const wtap_rec *rec,
265 const uint8_t *pd, int *err, char **err_info)
267 const union wtap_pseudo_header *pseudo_header = &rec->rec_header.packet_header.pseudo_header;
268 struct btsnooprec_hdr rec_hdr;
269 uint32_t flags;
270 int64_t nsecs;
271 int64_t ts_usec;
273 /* We can only write packet records. */
274 if (rec->rec_type != REC_TYPE_PACKET) {
275 *err = WTAP_ERR_UNWRITABLE_REC_TYPE;
276 return false;
280 * Make sure this packet doesn't have a link-layer type that
281 * differs from the one for the file.
283 if (wdh->file_encap != rec->rec_header.packet_header.pkt_encap) {
284 *err = WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED;
285 return false;
288 /* Don't write out anything bigger than we can read. */
289 if (rec->rec_header.packet_header.caplen > WTAP_MAX_PACKET_SIZE_STANDARD) {
290 *err = WTAP_ERR_PACKET_TOO_LARGE;
291 return false;
294 rec_hdr.incl_len = GUINT32_TO_BE(rec->rec_header.packet_header.caplen);
295 rec_hdr.orig_len = GUINT32_TO_BE(rec->rec_header.packet_header.len);
297 switch (wdh->file_encap) {
299 case WTAP_ENCAP_BLUETOOTH_HCI:
300 switch (pseudo_header->bthci.channel) {
302 case BTHCI_CHANNEL_COMMAND:
303 if (!pseudo_header->bthci.sent) {
304 *err = WTAP_ERR_UNWRITABLE_REC_DATA;
305 *err_info = ws_strdup_printf("btsnoop: Command channel, sent false");
306 return false;
308 flags = KHciLoggerCommandOrEvent|KHciLoggerHostToController;
309 break;
311 case BTHCI_CHANNEL_EVENT:
312 if (pseudo_header->bthci.sent) {
313 *err = WTAP_ERR_UNWRITABLE_REC_DATA;
314 *err_info = ws_strdup_printf("btsnoop: Event channel, sent true");
315 return false;
317 flags = KHciLoggerCommandOrEvent|KHciLoggerControllerToHost;
318 break;
320 case BTHCI_CHANNEL_ACL:
321 if (pseudo_header->bthci.sent)
322 flags = KHciLoggerACLDataFrame|KHciLoggerHostToController;
323 else
324 flags = KHciLoggerACLDataFrame|KHciLoggerControllerToHost;
325 break;
327 default:
328 *err = WTAP_ERR_UNWRITABLE_REC_DATA;
329 *err_info = ws_strdup_printf("btsnoop: Unknown channel %u",
330 pseudo_header->bthci.channel);
331 return false;
333 break;
335 case WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR:
336 if (pseudo_header->p2p.sent)
337 flags = KHciLoggerHostToController;
338 else
339 flags = KHciLoggerControllerToHost;
340 if (rec->rec_header.packet_header.caplen >= 1 &&
341 (pd[0] == 0x01 || pd[0] == 0x04))
342 flags |= KHciLoggerCommandOrEvent;
343 break;
345 case WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR:
346 flags = (pseudo_header->btmon.adapter_id << 16) | pseudo_header->btmon.opcode;
347 break;
349 default:
350 /* We should never get here - our open routine should only get
351 called for the types above. */
352 *err = WTAP_ERR_INTERNAL;
353 *err_info = ws_strdup_printf("btsnoop: invalid encapsulation %u",
354 wdh->file_encap);
355 return false;
357 rec_hdr.flags = GUINT32_TO_BE(flags);
358 rec_hdr.cum_drops = GUINT32_TO_BE(0);
360 nsecs = rec->ts.nsecs;
361 ts_usec = ((int64_t) rec->ts.secs * 1000000) + (nsecs / 1000);
362 ts_usec += KUnixTimeBase;
363 rec_hdr.ts_usec = GINT64_TO_BE(ts_usec);
365 if (!wtap_dump_file_write(wdh, &rec_hdr, sizeof rec_hdr, err))
366 return false;
367 if (!wtap_dump_file_write(wdh, pd, rec->rec_header.packet_header.caplen, err))
368 return false;
369 return true;
372 /* Returns true on success, false on failure; sets "*err" to an error code on
373 failure */
374 static bool btsnoop_dump_open(wtap_dumper *wdh, int *err, char **err_info _U_)
376 struct btsnoop_hdr file_hdr;
377 uint32_t datalink;
379 /* This is a btsnoop file */
380 wdh->subtype_write = btsnoop_dump;
382 switch (wdh->file_encap) {
384 case WTAP_ENCAP_BLUETOOTH_HCI:
385 datalink = KHciLoggerDatalinkTypeH1;
386 break;
388 case WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR:
389 datalink = KHciLoggerDatalinkTypeH4;
390 break;
392 case WTAP_ENCAP_BLUETOOTH_LINUX_MONITOR:
393 datalink = KHciLoggerDatalinkLinuxMonitor;
394 break;
396 default:
397 /* We should never get here - our open routine should only get
398 called for the types above. */
399 *err = WTAP_ERR_INTERNAL;
400 *err_info = ws_strdup_printf("btsnoop: invalid encapsulation %u",
401 wdh->file_encap);
402 return false;
405 /* Write the file header. */
406 if (!wtap_dump_file_write(wdh, btsnoop_magic, sizeof btsnoop_magic, err))
407 return false;
409 /* current "btsnoop" format is 1 */
410 file_hdr.version = GUINT32_TO_BE(1);
411 /* HCI type encoded in first byte */
412 file_hdr.datalink = GUINT32_TO_BE(datalink);
414 if (!wtap_dump_file_write(wdh, &file_hdr, sizeof file_hdr, err))
415 return false;
417 return true;
420 static const struct supported_block_type btsnoop_blocks_supported[] = {
422 * We support packet blocks, with no comments or other options.
424 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
427 static const struct file_type_subtype_info btsnoop_info = {
428 "Symbian OS btsnoop", "btsnoop", "log", NULL,
429 false, BLOCKS_SUPPORTED(btsnoop_blocks_supported),
430 btsnoop_dump_can_write_encap, btsnoop_dump_open, NULL
433 void register_btsnoop(void)
435 btsnoop_file_type_subtype = wtap_register_file_type_subtype(&btsnoop_info);
438 * Register name for backwards compatibility with the
439 * wtap_filetypes table in Lua.
441 wtap_register_backwards_compatibility_lua_name("BTSNOOP",
442 btsnoop_file_type_subtype);
446 * Editor modelines - https://www.wireshark.org/tools/modelines.html
448 * Local variables:
449 * c-basic-offset: 4
450 * tab-width: 8
451 * indent-tabs-mode: nil
452 * End:
454 * vi: set shiftwidth=4 tabstop=8 expandtab:
455 * :indentSize=4:tabSize=8:noTabs=true: