/src/wireshark/epan/dissectors/file-btsnoop.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* file-btsnoop.c |
2 | | * Routines for BTSNOOP File Format |
3 | | * |
4 | | * Copyright 2014, Michal Labedzki for Tieto Corporation |
5 | | * |
6 | | * Wireshark - Network traffic analyzer |
7 | | * By Gerald Combs <gerald@wireshark.org> |
8 | | * Copyright 1998 Gerald Combs |
9 | | * |
10 | | * SPDX-License-Identifier: GPL-2.0-or-later |
11 | | */ |
12 | | |
13 | | #include "config.h" |
14 | | |
15 | | #include <epan/packet.h> |
16 | | #include <epan/prefs.h> |
17 | | #include <epan/expert.h> |
18 | | #include <wiretap/wtap.h> |
19 | | #include <wsutil/array.h> |
20 | | |
21 | | static dissector_handle_t btsnoop_handle; |
22 | | static dissector_handle_t hci_h1_handle; |
23 | | static dissector_handle_t hci_h4_handle; |
24 | | static dissector_handle_t hci_mon_handle; |
25 | | |
26 | | static int proto_btsnoop; |
27 | | |
28 | | static int hf_btsnoop_header; |
29 | | static int hf_btsnoop_magic_bytes; |
30 | | static int hf_btsnoop_version; |
31 | | static int hf_btsnoop_datalink; |
32 | | static int hf_btsnoop_frame; |
33 | | static int hf_btsnoop_origin_length; |
34 | | static int hf_btsnoop_included_length; |
35 | | static int hf_btsnoop_flags; |
36 | | static int hf_btsnoop_cumulative_dropped_packets; |
37 | | static int hf_btsnoop_timestamp_microseconds; |
38 | | static int hf_btsnoop_payload; |
39 | | static int hf_btsnoop_flags_h1_reserved; |
40 | | static int hf_btsnoop_flags_h1_channel_type; |
41 | | static int hf_btsnoop_flags_h1_direction; |
42 | | static int hf_btsnoop_flags_h4_reserved; |
43 | | static int hf_btsnoop_flags_h4_direction; |
44 | | static int hf_btsnoop_flags_linux_monitor_opcode; |
45 | | static int hf_btsnoop_flags_linux_monitor_adapter_id; |
46 | | |
47 | | static expert_field ei_malformed_frame; |
48 | | static expert_field ei_not_implemented_yet; |
49 | | static expert_field ei_unknown_data; |
50 | | |
51 | | static int ett_btsnoop; |
52 | | static int ett_btsnoop_header; |
53 | | static int ett_btsnoop_frame; |
54 | | static int ett_btsnoop_payload; |
55 | | static int ett_btsnoop_flags; |
56 | | |
57 | | static bool pref_dissect_next_layer; |
58 | | |
59 | | extern value_string_ext hci_mon_opcode_vals_ext; |
60 | | |
61 | | static const value_string datalink_vals[] = { |
62 | | { 1001, "H1" }, |
63 | | { 1002, "H4 (UART)" }, |
64 | | { 1003, "BCSP" }, |
65 | | { 1004, "H5 (3 Wire)" }, |
66 | | { 2001, "Linux Monitor" }, |
67 | | { 2002, "Simulator" }, |
68 | | { 0, NULL } |
69 | | }; |
70 | | |
71 | | static const value_string flags_direction_vals[] = { |
72 | | { 0x00, "Received" }, |
73 | | { 0x01, "Sent" }, |
74 | | { 0, NULL } |
75 | | }; |
76 | | |
77 | | static const value_string flags_h1_channel_type_vals[] = { |
78 | | { 0x00, "ACL" }, |
79 | | { 0x01, "HCI" }, |
80 | | { 0, NULL } |
81 | | }; |
82 | | |
83 | | void proto_register_btsnoop(void); |
84 | | void proto_reg_handoff_btsnoop(void); |
85 | | |
86 | | static int |
87 | | dissect_btsnoop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) |
88 | 0 | { |
89 | 0 | static const uint8_t magic[] = { 'b', 't', 's', 'n', 'o', 'o', 'p', 0}; |
90 | 0 | int offset = 0; |
91 | 0 | uint32_t datalink; |
92 | 0 | uint32_t flags; |
93 | 0 | uint32_t length; |
94 | 0 | proto_tree *main_tree; |
95 | 0 | proto_item *main_item; |
96 | 0 | proto_tree *header_tree; |
97 | 0 | proto_item *header_item; |
98 | 0 | proto_tree *frame_tree; |
99 | 0 | proto_item *frame_item; |
100 | 0 | proto_tree *flags_tree; |
101 | 0 | proto_item *flags_item; |
102 | 0 | proto_tree *payload_tree; |
103 | 0 | proto_item *payload_item; |
104 | 0 | static uint32_t frame_number = 1; |
105 | 0 | tvbuff_t *next_tvb; |
106 | 0 | nstime_t timestamp; |
107 | 0 | uint64_t ts; |
108 | |
|
109 | 0 | if (tvb_memeql(tvb, 0, magic, sizeof(magic)) != 0) |
110 | 0 | return 0; |
111 | | |
112 | 0 | if (offset == 0) frame_number = 1; |
113 | |
|
114 | 0 | main_item = proto_tree_add_item(tree, proto_btsnoop, tvb, offset, -1, ENC_NA); |
115 | 0 | main_tree = proto_item_add_subtree(main_item, ett_btsnoop); |
116 | |
|
117 | 0 | header_item = proto_tree_add_item(main_tree, hf_btsnoop_header, tvb, offset, sizeof(magic) + 4 + 4, ENC_NA); |
118 | 0 | header_tree = proto_item_add_subtree(header_item, ett_btsnoop_header); |
119 | |
|
120 | 0 | proto_tree_add_item(header_tree, hf_btsnoop_magic_bytes, tvb, offset, sizeof(magic), ENC_ASCII | ENC_NA); |
121 | 0 | offset += (int)sizeof(magic); |
122 | |
|
123 | 0 | proto_tree_add_item(header_tree, hf_btsnoop_version, tvb, offset, 4, ENC_BIG_ENDIAN); |
124 | 0 | offset += 4; |
125 | |
|
126 | 0 | proto_tree_add_item(header_tree, hf_btsnoop_datalink, tvb, offset, 4, ENC_BIG_ENDIAN); |
127 | 0 | datalink = tvb_get_ntohl(tvb, offset); |
128 | 0 | offset += 4; |
129 | |
|
130 | 0 | while (tvb_reported_length_remaining(tvb, offset) > 0) { |
131 | 0 | frame_item = proto_tree_add_item(main_tree, hf_btsnoop_frame, tvb, offset, 0, ENC_NA); |
132 | 0 | frame_tree = proto_item_add_subtree(frame_item, ett_btsnoop_frame); |
133 | |
|
134 | 0 | if (tvb_reported_length_remaining(tvb, offset) < 4 * 4 + 8) { |
135 | 0 | expert_add_info(pinfo, frame_item, &ei_malformed_frame); |
136 | 0 | } |
137 | |
|
138 | 0 | proto_item_append_text(frame_item, " %u", frame_number); |
139 | |
|
140 | 0 | proto_tree_add_item(frame_tree, hf_btsnoop_origin_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
141 | 0 | offset += 4; |
142 | |
|
143 | 0 | proto_tree_add_item(frame_tree, hf_btsnoop_included_length, tvb, offset, 4, ENC_BIG_ENDIAN); |
144 | 0 | length = tvb_get_ntohl(tvb, offset); |
145 | 0 | offset += 4; |
146 | |
|
147 | 0 | flags_item = proto_tree_add_item(frame_tree, hf_btsnoop_flags, tvb, offset, 4, ENC_BIG_ENDIAN); |
148 | 0 | flags_tree = proto_item_add_subtree(flags_item, ett_btsnoop_flags); |
149 | 0 | flags = tvb_get_ntohl(tvb, offset); |
150 | 0 | switch (datalink) { |
151 | 0 | case 1001: /* H1 */ |
152 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_h1_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); |
153 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_h1_channel_type, tvb, offset, 4, ENC_BIG_ENDIAN); |
154 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_h1_direction, tvb, offset, 4, ENC_BIG_ENDIAN); |
155 | 0 | break; |
156 | 0 | case 1002: /* H4 */ |
157 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_h4_reserved, tvb, offset, 4, ENC_BIG_ENDIAN); |
158 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_h4_direction, tvb, offset, 4, ENC_BIG_ENDIAN); |
159 | 0 | break; |
160 | 0 | case 2001: /* Linux Monitor */ |
161 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_linux_monitor_adapter_id, tvb, offset , 2, ENC_BIG_ENDIAN); |
162 | 0 | proto_tree_add_item(flags_tree, hf_btsnoop_flags_linux_monitor_opcode, tvb, offset + 2, 2, ENC_BIG_ENDIAN); |
163 | 0 | break; |
164 | 0 | } |
165 | 0 | offset += 4; |
166 | |
|
167 | 0 | proto_tree_add_item(frame_tree, hf_btsnoop_cumulative_dropped_packets, tvb, offset, 4, ENC_BIG_ENDIAN); |
168 | 0 | offset += 4; |
169 | |
|
170 | 0 | ts = tvb_get_ntoh64(tvb, offset) - INT64_C(0x00dcddb30f2f8000); |
171 | 0 | timestamp.secs = (unsigned)(ts / 1000000); |
172 | 0 | timestamp.nsecs =(unsigned)((ts % 1000000) * 1000); |
173 | |
|
174 | 0 | proto_tree_add_time(frame_tree, hf_btsnoop_timestamp_microseconds, tvb, offset, 8, ×tamp); |
175 | 0 | offset += 8; |
176 | |
|
177 | 0 | payload_item = proto_tree_add_item(frame_tree, hf_btsnoop_payload, tvb, offset, length, ENC_NA); |
178 | 0 | payload_tree = proto_item_add_subtree(payload_item, ett_btsnoop_payload); |
179 | |
|
180 | 0 | if (pref_dissect_next_layer) switch (datalink) {\ |
181 | 0 | case 1001: /* H1 */ |
182 | 0 | pinfo->num = frame_number; |
183 | 0 | pinfo->abs_ts = timestamp; |
184 | |
|
185 | 0 | pinfo->pseudo_header->bthci.sent = (flags & 0x01) ? false : true; |
186 | 0 | if (flags & 0x02) { |
187 | 0 | if(pinfo->pseudo_header->bthci.sent) |
188 | 0 | pinfo->pseudo_header->bthci.channel = BTHCI_CHANNEL_COMMAND; |
189 | 0 | else |
190 | 0 | pinfo->pseudo_header->bthci.channel = BTHCI_CHANNEL_EVENT; |
191 | 0 | } else { |
192 | 0 | pinfo->pseudo_header->bthci.channel = BTHCI_CHANNEL_ACL; |
193 | 0 | } |
194 | |
|
195 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, length); |
196 | 0 | call_dissector(hci_h1_handle, next_tvb, pinfo, payload_tree); |
197 | 0 | break; |
198 | 0 | case 1002: /* H4 */ |
199 | 0 | pinfo->num = frame_number; |
200 | 0 | pinfo->abs_ts = timestamp; |
201 | 0 | pinfo->p2p_dir = (flags & 0x01) ? P2P_DIR_RECV : P2P_DIR_SENT; |
202 | |
|
203 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, length); |
204 | 0 | call_dissector(hci_h4_handle, next_tvb, pinfo, payload_tree); |
205 | 0 | break; |
206 | 0 | case 2001: /* Linux Monitor */ |
207 | 0 | pinfo->num = frame_number; |
208 | 0 | pinfo->abs_ts = timestamp; |
209 | |
|
210 | 0 | pinfo->pseudo_header->btmon.opcode = flags & 0xFFFF; |
211 | 0 | pinfo->pseudo_header->btmon.adapter_id = flags >> 16; |
212 | |
|
213 | 0 | next_tvb = tvb_new_subset_length(tvb, offset, length); |
214 | 0 | call_dissector(hci_mon_handle, next_tvb, pinfo, payload_tree); |
215 | 0 | break; |
216 | | |
217 | 0 | case 1003: /* BCSP */ |
218 | 0 | case 1004: /* H5 (3 Wire) */ |
219 | 0 | case 2002: /* Simulator */ |
220 | | /* Not implemented yet */ |
221 | 0 | proto_tree_add_expert(payload_tree, pinfo, &ei_not_implemented_yet, tvb, offset, length); |
222 | 0 | break; |
223 | 0 | default: |
224 | | /* Unknown */ |
225 | 0 | proto_tree_add_expert(payload_tree, pinfo, &ei_unknown_data, tvb, offset, length); |
226 | 0 | } |
227 | 0 | offset += length; |
228 | |
|
229 | 0 | proto_item_set_len(frame_item, 4 * 4 + 8 + length); |
230 | 0 | frame_number += 1; |
231 | 0 | } |
232 | | |
233 | 0 | return offset; |
234 | 0 | } |
235 | | |
236 | | static bool |
237 | | dissect_btsnoop_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) |
238 | 0 | { |
239 | 0 | return dissect_btsnoop(tvb, pinfo, tree, data) > 0; |
240 | 0 | } |
241 | | |
242 | | void |
243 | | proto_register_btsnoop(void) |
244 | 14 | { |
245 | 14 | module_t *module; |
246 | 14 | expert_module_t *expert_module; |
247 | | |
248 | 14 | static hf_register_info hf[] = { |
249 | 14 | { &hf_btsnoop_header, |
250 | 14 | { "Header", "btsnoop.header", |
251 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
252 | 14 | NULL, HFILL } |
253 | 14 | }, |
254 | 14 | { &hf_btsnoop_magic_bytes, |
255 | 14 | { "Magic Bytes", "btsnoop.header.magic_bytes", |
256 | 14 | FT_STRINGZ, BASE_NONE, NULL, 0x00, |
257 | 14 | NULL, HFILL } |
258 | 14 | }, |
259 | 14 | { &hf_btsnoop_version, |
260 | 14 | { "Version", "btsnoop.header.version", |
261 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
262 | 14 | NULL, HFILL } |
263 | 14 | }, |
264 | 14 | { &hf_btsnoop_datalink, |
265 | 14 | { "Datalink", "btsnoop.header.datalink", |
266 | 14 | FT_UINT32, BASE_DEC_HEX, VALS(datalink_vals), 0x00, |
267 | 14 | NULL, HFILL } |
268 | 14 | }, |
269 | 14 | { &hf_btsnoop_frame, |
270 | 14 | { "Frame", "btsnoop.frame", |
271 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
272 | 14 | NULL, HFILL } |
273 | 14 | }, |
274 | 14 | { &hf_btsnoop_origin_length, |
275 | 14 | { "Origin Length", "btsnoop.frame.origin_length", |
276 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
277 | 14 | NULL, HFILL } |
278 | 14 | }, |
279 | 14 | { &hf_btsnoop_included_length, |
280 | 14 | { "Included Length", "btsnoop.frame.included_length", |
281 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
282 | 14 | NULL, HFILL } |
283 | 14 | }, |
284 | 14 | { &hf_btsnoop_flags, |
285 | 14 | { "Flags", "btsnoop.frame.flags", |
286 | 14 | FT_UINT32, BASE_HEX, NULL, 0x00, |
287 | 14 | NULL, HFILL } |
288 | 14 | }, |
289 | 14 | { &hf_btsnoop_cumulative_dropped_packets, |
290 | 14 | { "Cumulative Dropped Packets", "btsnoop.frame.cumulative_dropped_packets", |
291 | 14 | FT_UINT32, BASE_DEC, NULL, 0x00, |
292 | 14 | NULL, HFILL } |
293 | 14 | }, |
294 | 14 | { &hf_btsnoop_timestamp_microseconds, |
295 | 14 | { "Timestamp Microseconds", "btsnoop.frame.timestamp_microseconds", |
296 | 14 | FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x00, |
297 | 14 | NULL, HFILL } |
298 | 14 | }, |
299 | 14 | { &hf_btsnoop_payload, |
300 | 14 | { "Payload", "btsnoop.frame.payload", |
301 | 14 | FT_NONE, BASE_NONE, NULL, 0x00, |
302 | 14 | NULL, HFILL } |
303 | 14 | }, |
304 | 14 | { &hf_btsnoop_flags_h1_reserved, |
305 | 14 | { "Reserved", "btsnoop.frame.flags.h1.reserved", |
306 | 14 | FT_UINT32, BASE_HEX, NULL, 0xFFFFFFFC, |
307 | 14 | NULL, HFILL } |
308 | 14 | }, |
309 | 14 | { &hf_btsnoop_flags_h1_channel_type, |
310 | 14 | { "Channel Type", "btsnoop.frame.flags.h1.channel_type", |
311 | 14 | FT_UINT32, BASE_DEC, VALS(flags_h1_channel_type_vals), 0x02, |
312 | 14 | NULL, HFILL } |
313 | 14 | }, |
314 | 14 | { &hf_btsnoop_flags_h1_direction, |
315 | 14 | { "Direction", "btsnoop.frame.flags.h1.direction", |
316 | 14 | FT_UINT32, BASE_DEC, VALS(flags_direction_vals), 0x01, |
317 | 14 | NULL, HFILL } |
318 | 14 | }, |
319 | 14 | { &hf_btsnoop_flags_h4_reserved, |
320 | 14 | { "Reserved", "btsnoop.frame.flags.h4.reserved", |
321 | 14 | FT_UINT32, BASE_HEX, NULL, 0xFFFFFFFE, |
322 | 14 | NULL, HFILL } |
323 | 14 | }, |
324 | 14 | { &hf_btsnoop_flags_h4_direction, |
325 | 14 | { "Direction", "btsnoop.frame.flags.h4.direction", |
326 | 14 | FT_UINT32, BASE_DEC, VALS(flags_direction_vals), 0x01, |
327 | 14 | NULL, HFILL } |
328 | 14 | }, |
329 | 14 | { &hf_btsnoop_flags_linux_monitor_opcode, |
330 | 14 | { "Opcode", "btsnoop.frame.flags.linux_monitor.opcode", |
331 | 14 | FT_UINT16, BASE_HEX | BASE_EXT_STRING, &hci_mon_opcode_vals_ext, 0x00, |
332 | 14 | NULL, HFILL } |
333 | 14 | }, |
334 | 14 | { &hf_btsnoop_flags_linux_monitor_adapter_id, |
335 | 14 | { "Adapter ID", "btsnoop.frame.flags.linux_monitor.adapter_id", |
336 | 14 | FT_UINT16, BASE_DEC, NULL, 0x00, |
337 | 14 | NULL, HFILL } |
338 | 14 | } |
339 | 14 | }; |
340 | | |
341 | 14 | static ei_register_info ei[] = { |
342 | 14 | { &ei_malformed_frame, { "btsnoop.malformed_frame", PI_PROTOCOL, PI_WARN, "Malformed Frame", EXPFILL }}, |
343 | 14 | { &ei_not_implemented_yet, { "btsnoop.not_implemented_yet", PI_PROTOCOL, PI_WARN, "Not implemented yet", EXPFILL }}, |
344 | 14 | { &ei_unknown_data, { "btsnoop.unknown_data", PI_PROTOCOL, PI_WARN, "Unknown data", EXPFILL }}, |
345 | 14 | }; |
346 | | |
347 | 14 | static int *ett[] = { |
348 | 14 | &ett_btsnoop, |
349 | 14 | &ett_btsnoop_header, |
350 | 14 | &ett_btsnoop_frame, |
351 | 14 | &ett_btsnoop_payload, |
352 | 14 | &ett_btsnoop_flags, |
353 | 14 | }; |
354 | | |
355 | 14 | proto_btsnoop = proto_register_protocol("Symbian OS BTSNOOP File Format", "BTSNOOP", "btsnoop"); |
356 | 14 | proto_register_field_array(proto_btsnoop, hf, array_length(hf)); |
357 | 14 | proto_register_subtree_array(ett, array_length(ett)); |
358 | | |
359 | 14 | btsnoop_handle = register_dissector("btsnoop", dissect_btsnoop, proto_btsnoop); |
360 | | |
361 | 14 | module = prefs_register_protocol(proto_btsnoop, NULL); |
362 | 14 | prefs_register_static_text_preference(module, "version", |
363 | 14 | "BTSNOOP version: 1", |
364 | 14 | "Version of file-format supported by this dissector."); |
365 | | |
366 | 14 | prefs_register_bool_preference(module, "dissect_next_layer", |
367 | 14 | "Dissect next layer", |
368 | 14 | "Dissect next layer", |
369 | 14 | &pref_dissect_next_layer); |
370 | | |
371 | 14 | expert_module = expert_register_protocol(proto_btsnoop); |
372 | 14 | expert_register_field_array(expert_module, ei, array_length(ei)); |
373 | 14 | } |
374 | | |
375 | | void |
376 | | proto_reg_handoff_btsnoop(void) |
377 | 14 | { |
378 | 14 | hci_h1_handle = find_dissector_add_dependency("hci_h1", proto_btsnoop); |
379 | 14 | hci_h4_handle = find_dissector_add_dependency("hci_h4", proto_btsnoop); |
380 | 14 | hci_mon_handle = find_dissector_add_dependency("hci_mon", proto_btsnoop); |
381 | | |
382 | 14 | heur_dissector_add("wtap_file", dissect_btsnoop_heur, "BTSNOOP file", "btsnoop_wtap", proto_btsnoop, HEURISTIC_ENABLE); |
383 | 14 | } |
384 | | |
385 | | /* |
386 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
387 | | * |
388 | | * Local variables: |
389 | | * c-basic-offset: 4 |
390 | | * tab-width: 8 |
391 | | * indent-tabs-mode: nil |
392 | | * End: |
393 | | * |
394 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
395 | | * :indentSize=4:tabSize=8:noTabs=true: |
396 | | */ |