6 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "file_wrappers.h"
33 * Symbian's btsnoop format is derived from Sun's snoop format.
34 * See RFC 1761 for a description of the "snoop" file format.
37 /* Magic number in "btsnoop" files. */
38 static const char btsnoop_magic
[] = {
39 'b', 't', 's', 'n', 'o', 'o', 'p', '\0'
42 /* "btsnoop" file header (minus magic number). */
44 guint32 version
; /* version number (should be 1) */
45 guint32 datalink
; /* datalink type */
48 /* "btsnoop" record header. */
49 struct btsnooprec_hdr
{
50 guint32 orig_len
; /* actual length of packet */
51 guint32 incl_len
; /* number of octets captured in file */
52 guint32 flags
; /* packet flags */
53 guint32 cum_drops
; /* cumulative number of dropped packets */
54 gint64 ts_usec
; /* timestamp microseconds */
57 /* H1 is unframed data with the packet type encoded in the flags field of capture header */
58 /* It can be used for any datalink by placing logging above the datalink layer of HCI */
59 #define KHciLoggerDatalinkTypeH1 1001
60 /* H4 is the serial HCI with packet type encoded in the first byte of each packet */
61 #define KHciLoggerDatalinkTypeH4 1002
62 /* CSR's PPP derived bluecore serial protocol - in practice we log in H1 format after deframing */
63 #define KHciLoggerDatalinkTypeBCSP 1003
64 /* H5 is the official three wire serial protocol derived from BCSP*/
65 #define KHciLoggerDatalinkTypeH5 1004
67 #define KHciLoggerHostToController 0
68 #define KHciLoggerControllerToHost 0x00000001
69 #define KHciLoggerACLDataFrame 0
70 #define KHciLoggerCommandOrEvent 0x00000002
72 static const gint64 KUnixTimeBase
= G_GINT64_CONSTANT(0x00dcddb30f2f8000); /* offset from symbian - unix time */
74 static gboolean
btsnoop_read(wtap
*wth
, int *err
, gchar
**err_info
,
76 static gboolean
btsnoop_seek_read(wtap
*wth
, gint64 seek_off
,
77 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int length
,
78 int *err
, gchar
**err_info
);
79 static gboolean
btsnoop_read_record(wtap
*wth
, FILE_T fh
,
80 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int *err
, gchar
**err_info
);
82 int btsnoop_open(wtap
*wth
, int *err
, gchar
**err_info
)
85 char magic
[sizeof btsnoop_magic
];
86 struct btsnoop_hdr hdr
;
88 int file_encap
=WTAP_ENCAP_UNKNOWN
;
90 /* Read in the string that should be at the start of a "btsnoop" file */
91 errno
= WTAP_ERR_CANT_READ
;
92 bytes_read
= file_read(magic
, sizeof magic
, wth
->fh
);
93 if (bytes_read
!= sizeof magic
) {
94 *err
= file_error(wth
->fh
, err_info
);
95 if (*err
!= 0 && *err
!= WTAP_ERR_SHORT_READ
)
100 if (memcmp(magic
, btsnoop_magic
, sizeof btsnoop_magic
) != 0) {
104 /* Read the rest of the header. */
105 errno
= WTAP_ERR_CANT_READ
;
106 bytes_read
= file_read(&hdr
, sizeof hdr
, wth
->fh
);
107 if (bytes_read
!= sizeof hdr
) {
108 *err
= file_error(wth
->fh
, err_info
);
110 *err
= WTAP_ERR_SHORT_READ
;
115 * Make sure it's a version we support.
117 hdr
.version
= g_ntohl(hdr
.version
);
118 if (hdr
.version
!= 1) {
119 *err
= WTAP_ERR_UNSUPPORTED
;
120 *err_info
= g_strdup_printf("btsnoop: version %u unsupported", hdr
.version
);
124 hdr
.datalink
= g_ntohl(hdr
.datalink
);
125 switch (hdr
.datalink
) {
126 case KHciLoggerDatalinkTypeH1
:
127 file_encap
=WTAP_ENCAP_BLUETOOTH_HCI
;
129 case KHciLoggerDatalinkTypeBCSP
:
130 *err
= WTAP_ERR_UNSUPPORTED
;
131 *err_info
= g_strdup_printf("btsnoop: BCSP capture logs unsupported");
133 case KHciLoggerDatalinkTypeH5
:
134 *err
= WTAP_ERR_UNSUPPORTED
;
135 *err_info
= g_strdup_printf("btsnoop: H5 capture logs unsupported");
137 case KHciLoggerDatalinkTypeH4
:
138 file_encap
=WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR
;
141 *err
= WTAP_ERR_UNSUPPORTED
;
142 *err_info
= g_strdup_printf("btsnoop: datalink type %u unknown or unsupported", hdr
.datalink
);
146 wth
->subtype_read
= btsnoop_read
;
147 wth
->subtype_seek_read
= btsnoop_seek_read
;
148 wth
->file_encap
= file_encap
;
149 wth
->snapshot_length
= 0; /* not available in header */
150 wth
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
151 wth
->file_type_subtype
= WTAP_FILE_TYPE_SUBTYPE_BTSNOOP
;
155 static gboolean
btsnoop_read(wtap
*wth
, int *err
, gchar
**err_info
,
158 *data_offset
= file_tell(wth
->fh
);
160 return btsnoop_read_record(wth
, wth
->fh
, &wth
->phdr
, wth
->frame_buffer
,
164 static gboolean
btsnoop_seek_read(wtap
*wth
, gint64 seek_off
,
165 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int length _U_
,
166 int *err
, gchar
**err_info
)
168 if (file_seek(wth
->random_fh
, seek_off
, SEEK_SET
, err
) == -1)
171 return btsnoop_read_record(wth
, wth
->random_fh
, phdr
, buf
, err
, err_info
);
174 static gboolean
btsnoop_read_record(wtap
*wth
, FILE_T fh
,
175 struct wtap_pkthdr
*phdr
, Buffer
*buf
, int *err
, gchar
**err_info
)
178 struct btsnooprec_hdr hdr
;
184 /* Read record header. */
186 errno
= WTAP_ERR_CANT_READ
;
187 bytes_read
= file_read(&hdr
, sizeof hdr
, fh
);
188 if (bytes_read
!= sizeof hdr
) {
189 *err
= file_error(fh
, err_info
);
190 if (*err
== 0 && bytes_read
!= 0)
191 *err
= WTAP_ERR_SHORT_READ
;
195 packet_size
= g_ntohl(hdr
.incl_len
);
196 orig_size
= g_ntohl(hdr
.orig_len
);
197 flags
= g_ntohl(hdr
.flags
);
198 if (packet_size
> WTAP_MAX_PACKET_SIZE
) {
200 * Probably a corrupt capture file; don't blow up trying
201 * to allocate space for an immensely-large packet.
203 *err
= WTAP_ERR_BAD_FILE
;
204 *err_info
= g_strdup_printf("btsnoop: File has %u-byte packet, bigger than maximum of %u",
205 packet_size
, WTAP_MAX_PACKET_SIZE
);
209 ts
= GINT64_FROM_BE(hdr
.ts_usec
);
212 phdr
->presence_flags
= WTAP_HAS_TS
|WTAP_HAS_CAP_LEN
;
213 phdr
->ts
.secs
= (guint
)(ts
/ 1000000);
214 phdr
->ts
.nsecs
= (guint
)((ts
% 1000000) * 1000);
215 phdr
->caplen
= packet_size
;
216 phdr
->len
= orig_size
;
217 if(wth
->file_encap
== WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR
)
219 phdr
->pseudo_header
.p2p
.sent
= (flags
& KHciLoggerControllerToHost
) ? FALSE
: TRUE
;
221 else if(wth
->file_encap
== WTAP_ENCAP_BLUETOOTH_HCI
)
223 phdr
->pseudo_header
.bthci
.sent
= (flags
& KHciLoggerControllerToHost
) ? FALSE
: TRUE
;
224 if(flags
& KHciLoggerCommandOrEvent
)
226 if(phdr
->pseudo_header
.bthci
.sent
)
228 phdr
->pseudo_header
.bthci
.channel
= BTHCI_CHANNEL_COMMAND
;
232 phdr
->pseudo_header
.bthci
.channel
= BTHCI_CHANNEL_EVENT
;
237 phdr
->pseudo_header
.bthci
.channel
= BTHCI_CHANNEL_ACL
;
242 /* Read packet data. */
243 return wtap_read_packet_bytes(fh
, buf
, phdr
->caplen
, err
, err_info
);
246 /* Returns 0 if we could write the specified encapsulation type,
247 an error indication otherwise. */
248 int btsnoop_dump_can_write_encap(int encap
)
250 /* Per-packet encapsulations aren't supported. */
251 if (encap
== WTAP_ENCAP_PER_PACKET
)
252 return WTAP_ERR_ENCAP_PER_PACKET_UNSUPPORTED
;
254 /* XXX - for now we only support WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR */
255 if (encap
!= WTAP_ENCAP_BLUETOOTH_H4_WITH_PHDR
)
256 return WTAP_ERR_UNSUPPORTED_ENCAP
;
261 struct hci_flags_mapping
268 static const struct hci_flags_mapping hci_flags
[] =
270 { 0x02, TRUE
, KHciLoggerHostToController
|KHciLoggerACLDataFrame
}, /* HCI_H4_TYPE_ACL */
271 { 0x02, FALSE
, KHciLoggerControllerToHost
|KHciLoggerACLDataFrame
}, /* HCI_H4_TYPE_ACL */
272 { 0x01, TRUE
, KHciLoggerHostToController
|KHciLoggerCommandOrEvent
}, /* HCI_H4_TYPE_CMD */
273 { 0x04, FALSE
, KHciLoggerControllerToHost
|KHciLoggerCommandOrEvent
}, /* HCI_H4_TYPE_EVT */
276 static guint8
btsnoop_lookup_flags(guint8 hci_type
, gboolean sent
, guint8
*flags
)
280 for (i
=0; i
< G_N_ELEMENTS(hci_flags
); ++i
)
282 if (hci_flags
[i
].hci_type
== hci_type
&&
283 hci_flags
[i
].sent
== sent
)
285 *flags
= hci_flags
[i
].flags
;
292 static gboolean
btsnoop_dump_partial_rec_hdr(wtap_dumper
*wdh _U_
,
293 const struct wtap_pkthdr
*phdr
,
294 const union wtap_pseudo_header
*pseudo_header
,
295 const guint8
*pd
, int *err
,
296 struct btsnooprec_hdr
*rec_hdr
)
302 if (!btsnoop_lookup_flags(*pd
, pseudo_header
->p2p
.sent
, &flags
)) {
303 *err
= WTAP_ERR_UNSUPPORTED
;
307 nsecs
= phdr
->ts
.nsecs
;
308 ts_usec
= ((gint64
) phdr
->ts
.secs
* 1000000) + (nsecs
/ 1000);
309 ts_usec
+= KUnixTimeBase
;
311 rec_hdr
->flags
= GUINT32_TO_BE(flags
);
312 rec_hdr
->cum_drops
= GUINT32_TO_BE(0);
313 rec_hdr
->ts_usec
= GINT64_TO_BE(ts_usec
);
318 /* FIXME: How do we support multiple backends?*/
319 static gboolean
btsnoop_dump_h1(wtap_dumper
*wdh
,
320 const struct wtap_pkthdr
*phdr
,
321 const guint8
*pd
, int *err
)
323 const union wtap_pseudo_header
*pseudo_header
= &phdr
->pseudo_header
;
324 struct btsnooprec_hdr rec_hdr
;
326 if (!btsnoop_dump_partial_rec_hdr(wdh
, phdr
, pseudo_header
, pd
, err
, &rec_hdr
))
329 rec_hdr
.incl_len
= GUINT32_TO_BE(phdr
->caplen
-1);
330 rec_hdr
.orig_len
= GUINT32_TO_BE(phdr
->len
-1);
332 if (!wtap_dump_file_write(wdh
, &rec_hdr
, sizeof rec_hdr
, err
))
335 wdh
->bytes_dumped
+= sizeof rec_hdr
;
337 /* Skip HCI packet type */
340 if (!wtap_dump_file_write(wdh
, pd
, phdr
->caplen
-1, err
))
343 wdh
->bytes_dumped
+= phdr
->caplen
-1;
348 static gboolean
btsnoop_dump_h4(wtap_dumper
*wdh
,
349 const struct wtap_pkthdr
*phdr
,
350 const guint8
*pd
, int *err
)
352 const union wtap_pseudo_header
*pseudo_header
= &phdr
->pseudo_header
;
353 struct btsnooprec_hdr rec_hdr
;
355 if (!btsnoop_dump_partial_rec_hdr(wdh
, phdr
, pseudo_header
, pd
, err
, &rec_hdr
))
358 rec_hdr
.incl_len
= GUINT32_TO_BE(phdr
->caplen
);
359 rec_hdr
.orig_len
= GUINT32_TO_BE(phdr
->len
);
361 if (!wtap_dump_file_write(wdh
, &rec_hdr
, sizeof rec_hdr
, err
))
364 wdh
->bytes_dumped
+= sizeof rec_hdr
;
366 if (!wtap_dump_file_write(wdh
, pd
, phdr
->caplen
, err
))
369 wdh
->bytes_dumped
+= phdr
->caplen
;
374 /* FIXME: How do we support multiple backends?*/
375 gboolean
btsnoop_dump_open_h1(wtap_dumper
*wdh
, int *err
)
377 struct btsnoop_hdr file_hdr
;
379 /* This is a libpcap file */
380 wdh
->subtype_write
= btsnoop_dump_h1
;
381 wdh
->subtype_close
= NULL
;
383 /* Write the file header. */
384 switch (wdh
->file_type_subtype
) {
386 case WTAP_FILE_TYPE_SUBTYPE_BTSNOOP
:
387 wdh
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
391 /* We should never get here - our open routine
392 should only get called for the types above. */
393 *err
= WTAP_ERR_UNSUPPORTED_FILE_TYPE
;
397 if (!wtap_dump_file_write(wdh
, btsnoop_magic
, sizeof btsnoop_magic
, err
))
400 wdh
->bytes_dumped
+= sizeof btsnoop_magic
;
402 /* current "btsnoop" format is 1 */
403 file_hdr
.version
= GUINT32_TO_BE(1);
404 /* HCI type encoded in first byte */
405 file_hdr
.datalink
= GUINT32_TO_BE(KHciLoggerDatalinkTypeH1
);
407 if (!wtap_dump_file_write(wdh
, &file_hdr
, sizeof file_hdr
, err
))
410 wdh
->bytes_dumped
+= sizeof file_hdr
;
415 /* Returns TRUE on success, FALSE on failure; sets "*err" to an error code on
417 gboolean
btsnoop_dump_open_h4(wtap_dumper
*wdh
, int *err
)
419 struct btsnoop_hdr file_hdr
;
421 /* This is a libpcap file */
422 wdh
->subtype_write
= btsnoop_dump_h4
;
423 wdh
->subtype_close
= NULL
;
425 /* Write the file header. */
426 switch (wdh
->file_type_subtype
) {
428 case WTAP_FILE_TYPE_SUBTYPE_BTSNOOP
:
429 wdh
->tsprecision
= WTAP_FILE_TSPREC_USEC
;
433 /* We should never get here - our open routine
434 should only get called for the types above. */
435 *err
= WTAP_ERR_UNSUPPORTED_FILE_TYPE
;
439 if (!wtap_dump_file_write(wdh
, btsnoop_magic
, sizeof btsnoop_magic
, err
))
442 wdh
->bytes_dumped
+= sizeof btsnoop_magic
;
444 /* current "btsnoop" format is 1 */
445 file_hdr
.version
= GUINT32_TO_BE(1);
446 /* HCI type encoded in first byte */
447 file_hdr
.datalink
= GUINT32_TO_BE(KHciLoggerDatalinkTypeH4
);
449 if (!wtap_dump_file_write(wdh
, &file_hdr
, sizeof file_hdr
, err
))
452 wdh
->bytes_dumped
+= sizeof file_hdr
;