2 * Routines for Bluetooth HCI USB dissection
4 * Copyright 2012, Michal Labedzki for Tieto Corporation
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
15 #include <epan/packet.h>
16 #include <epan/prefs.h>
17 #include <epan/reassemble.h>
19 #include "packet-bluetooth.h"
20 #include "packet-usb.h"
22 static int proto_hci_usb
;
23 static int hf_bthci_usb_data
;
24 static int hf_bthci_usb_packet_fragment
;
25 static int hf_bthci_usb_packet_complete
;
26 static int hf_bthci_usb_packet_unknown_fragment
;
27 static int hf_bthci_usb_setup_request
;
28 static int hf_bthci_usb_setup_value
;
29 static int hf_bthci_usb_setup_adapter_id
;
30 static int hf_bthci_usb_setup_length
;
32 static int ett_hci_usb
;
33 static int ett_hci_usb_msg_fragment
;
34 static int ett_hci_usb_msg_fragments
;
36 static int hf_msg_fragments
;
37 static int hf_msg_fragment
;
38 static int hf_msg_fragment_overlap
;
39 static int hf_msg_fragment_overlap_conflicts
;
40 static int hf_msg_fragment_multiple_tails
;
41 static int hf_msg_fragment_too_long_fragment
;
42 static int hf_msg_fragment_error
;
43 static int hf_msg_fragment_count
;
44 static int hf_msg_reassembled_in
;
45 static int hf_msg_reassembled_length
;
47 static wmem_tree_t
*fragment_info_table
;
49 static reassembly_table hci_usb_reassembly_table
;
51 static dissector_handle_t hci_usb_handle
;
52 static dissector_handle_t bthci_cmd_handle
;
53 static dissector_handle_t bthci_evt_handle
;
54 static dissector_handle_t bthci_acl_handle
;
55 static dissector_handle_t bthci_sco_handle
;
57 typedef struct _fragment_info_t
{
62 static const fragment_items hci_usb_msg_frag_items
= {
63 /* Fragment subtrees */
64 &ett_hci_usb_msg_fragment
,
65 &ett_hci_usb_msg_fragments
,
69 &hf_msg_fragment_overlap
,
70 &hf_msg_fragment_overlap_conflicts
,
71 &hf_msg_fragment_multiple_tails
,
72 &hf_msg_fragment_too_long_fragment
,
73 &hf_msg_fragment_error
,
74 &hf_msg_fragment_count
,
75 /* Reassembled in field */
76 &hf_msg_reassembled_in
,
77 /* Reassembled length field */
78 &hf_msg_reassembled_length
,
79 /* Reassembled data field */
85 static const value_string request_vals
[] = {
86 { 0x00, "Primary Controller Function" },
87 { 0x2B, "AMP Controller Function" },
88 { 0xE0, "Primary Controller Function (Historical)" },
91 static value_string_ext(request_vals_ext
) = VALUE_STRING_EXT_INIT(request_vals
);
94 void proto_register_hci_usb(void);
95 void proto_reg_handoff_hci_usb(void);
98 dissect_hci_usb(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
100 proto_item
*ttree
= NULL
;
101 proto_tree
*titem
= NULL
;
102 proto_item
*pitem
= NULL
;
105 tvbuff_t
*next_tvb
= NULL
;
106 bluetooth_data_t
*bluetooth_data
;
109 fragment_head
*reassembled
;
111 bluetooth_data
= (bluetooth_data_t
*) data
;
113 /* Reject the packet if data is NULL */
117 DISSECTOR_ASSERT(bluetooth_data
->previous_protocol_data_type
== BT_PD_URB_INFO
);
118 urb
= bluetooth_data
->previous_protocol_data
.urb
;
120 titem
= proto_tree_add_item(tree
, proto_hci_usb
, tvb
, offset
, -1, ENC_NA
);
121 ttree
= proto_item_add_subtree(titem
, ett_hci_usb
);
123 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HCI_USB");
125 p2p_dir_save
= pinfo
->p2p_dir
;
126 pinfo
->p2p_dir
= (urb
->is_request
) ? P2P_DIR_SENT
: P2P_DIR_RECV
;
128 switch (pinfo
->p2p_dir
) {
131 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent");
135 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd");
139 col_set_str(pinfo
->cinfo
, COL_INFO
, "UnknownDirection");
144 proto_tree_add_item(ttree
, hf_bthci_usb_setup_request
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
147 proto_tree_add_item(ttree
, hf_bthci_usb_setup_value
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
150 proto_tree_add_item(ttree
, hf_bthci_usb_setup_adapter_id
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
153 proto_tree_add_item(ttree
, hf_bthci_usb_setup_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
157 session_id
= urb
->bus_id
<< 16 | urb
->device_address
<< 8 | ((pinfo
->p2p_dir
== P2P_DIR_RECV
) ? 1 : 0 ) << 7 | urb
->endpoint
;
159 bluetooth_data
->adapter_id
= urb
->bus_id
<< 8 | urb
->device_address
;
160 /* TODO: adapter disconnect on some USB action, for now do not support adapter disconnection */
161 bluetooth_data
->adapter_disconnect_in_frame
= &bluetooth_max_disconnect_in_frame
;
163 next_tvb
= tvb_new_subset_remaining(tvb
, offset
);
164 if (!pinfo
->fd
->visited
&& urb
->transfer_type
!= URB_ISOCHRONOUS
&&
165 tvb_captured_length(tvb
) == tvb_reported_length(tvb
)) {
166 fragment_info_t
*fragment_info
;
168 fragment_info
= (fragment_info_t
*) wmem_tree_lookup32(fragment_info_table
, session_id
);
169 if (fragment_info
== NULL
) {
170 fragment_info
= (fragment_info_t
*) wmem_new(wmem_file_scope(), fragment_info_t
);
171 fragment_info
->fragment_id
= 0;
172 fragment_info
->remaining_length
= 0;
174 wmem_tree_insert32(fragment_info_table
, session_id
, fragment_info
);
177 if (fragment_info
->fragment_id
== 0) {
178 switch(urb
->transfer_type
)
181 fragment_info
->remaining_length
= tvb_get_uint8(tvb
, offset
+ 2) + 3;
184 fragment_info
->remaining_length
= tvb_get_uint8(tvb
, offset
+ 1) + 2;
187 fragment_info
->remaining_length
= tvb_get_letohs(tvb
, offset
+ 2) + 4;
192 fragment_info
->remaining_length
-= tvb_reported_length_remaining(tvb
, offset
);
194 fragment_add_seq_check(&hci_usb_reassembly_table
,
195 tvb
, offset
, pinfo
, session_id
, NULL
,
196 fragment_info
->fragment_id
, tvb_reported_length_remaining(tvb
, offset
), (fragment_info
->remaining_length
== 0) ? false : true);
197 if (fragment_info
->remaining_length
> 0)
198 fragment_info
->fragment_id
+= 1;
200 fragment_info
->fragment_id
= 0;
203 reassembled
= fragment_get_reassembled_id(&hci_usb_reassembly_table
, pinfo
, session_id
);
204 if (reassembled
&& pinfo
->num
< reassembled
->reassembled_in
) {
205 pitem
= proto_tree_add_item(ttree
, hf_bthci_usb_packet_fragment
, tvb
, offset
, -1, ENC_NA
);
206 proto_item_set_generated(pitem
);
208 col_append_str(pinfo
->cinfo
, COL_INFO
, " Fragment");
209 } else if (reassembled
&& pinfo
->num
== reassembled
->reassembled_in
) {
210 pitem
= proto_tree_add_item(ttree
, hf_bthci_usb_packet_complete
, tvb
, offset
, -1, ENC_NA
);
211 proto_item_set_generated(pitem
);
213 if (reassembled
->len
> (unsigned) tvb_reported_length_remaining(tvb
, offset
)) {
214 next_tvb
= process_reassembled_data(tvb
, 0, pinfo
,
215 "Reassembled HCI_USB",
216 reassembled
, &hci_usb_msg_frag_items
,
220 switch(urb
->transfer_type
)
223 call_dissector_with_data(bthci_cmd_handle
, next_tvb
, pinfo
, tree
, bluetooth_data
);
226 call_dissector_with_data(bthci_evt_handle
, next_tvb
, pinfo
, tree
, bluetooth_data
);
229 call_dissector_with_data(bthci_acl_handle
, next_tvb
, pinfo
, tree
, bluetooth_data
);
233 pitem
= proto_tree_add_item(ttree
, hf_bthci_usb_packet_unknown_fragment
, tvb
, offset
, -1, ENC_NA
);
234 proto_item_set_generated(pitem
);
237 if (urb
->transfer_type
== URB_ISOCHRONOUS
) {
238 call_dissector_with_data(bthci_sco_handle
, next_tvb
, pinfo
, tree
, bluetooth_data
);
239 } else if (urb
->transfer_type
== URB_UNKNOWN
) {
240 proto_tree_add_item(ttree
, hf_bthci_usb_data
, tvb
, offset
, -1, ENC_NA
);
243 offset
+= tvb_reported_length_remaining(tvb
, offset
);
245 pinfo
->p2p_dir
= p2p_dir_save
;
251 proto_register_hci_usb(void)
255 static hf_register_info hf
[] = {
257 { "Message fragments", "hci_usb.msg.fragments",
258 FT_NONE
, BASE_NONE
, NULL
, 0x00,
262 { "Message fragment", "hci_usb.msg.fragment",
263 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
266 { &hf_msg_fragment_overlap
,
267 { "Message fragment overlap", "hci_usb.msg.fragment.overlap",
268 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
271 { &hf_msg_fragment_overlap_conflicts
,
272 { "Message fragment overlapping with conflicting data", "hci_usb.msg.fragment.overlap.conflicts",
273 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
276 { &hf_msg_fragment_multiple_tails
,
277 { "Message has multiple tail fragments", "hci_usb.msg.fragment.multiple_tails",
278 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
281 { &hf_msg_fragment_too_long_fragment
,
282 { "Message fragment too long", "hci_usb.msg.fragment.too_long_fragment",
283 FT_BOOLEAN
, BASE_NONE
, NULL
, 0x00,
286 { &hf_msg_fragment_error
,
287 { "Message defragmentation error", "hci_usb.msg.fragment.error",
288 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
291 { &hf_msg_fragment_count
,
292 { "Message fragment count", "hci_usb.msg.fragment.count",
293 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
296 { &hf_msg_reassembled_in
,
297 { "Reassembled in", "hci_usb.msg.reassembled.in",
298 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x00,
301 { &hf_msg_reassembled_length
,
302 { "Reassembled MP2T length", "hci_usb.msg.reassembled.length",
303 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
306 { &hf_bthci_usb_packet_fragment
,
307 { "Packet Fragment", "hci_usb.packet.fragment",
308 FT_NONE
, BASE_NONE
, NULL
, 0x00,
311 { &hf_bthci_usb_packet_complete
,
312 { "Packet Complete", "hci_usb.packet.complete",
313 FT_NONE
, BASE_NONE
, NULL
, 0x00,
316 { &hf_bthci_usb_packet_unknown_fragment
,
317 { "Unknown Packet Fragment", "hci_usb.packet.unknown_fragment",
318 FT_NONE
, BASE_NONE
, NULL
, 0x00,
321 { &hf_bthci_usb_setup_request
,
322 { "bRequest", "hci_usb.setup.bRequest",
323 FT_UINT8
, BASE_DEC
| BASE_EXT_STRING
, &request_vals_ext
, 0x0,
326 { &hf_bthci_usb_setup_value
,
327 { "wValue", "hci_usb.setup.wValue",
328 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
331 { &hf_bthci_usb_setup_adapter_id
,
332 { "Adapter ID", "hci_usb.setup.adapter_id",
333 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
336 { &hf_bthci_usb_setup_length
,
337 { "wLength", "hci_usb.setup.wLength",
338 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
340 { &hf_bthci_usb_data
,
341 { "Unknown Data", "hci_usb.data",
342 FT_NONE
, BASE_NONE
, NULL
, 0x00,
347 static int *ett
[] = {
349 &ett_hci_usb_msg_fragment
,
350 &ett_hci_usb_msg_fragments
,
353 reassembly_table_register(&hci_usb_reassembly_table
,
354 &addresses_reassembly_table_functions
);
355 fragment_info_table
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
357 proto_hci_usb
= proto_register_protocol("Bluetooth HCI USB Transport", "HCI_USB", "hci_usb");
358 proto_register_field_array(proto_hci_usb
, hf
, array_length(hf
));
359 proto_register_subtree_array(ett
, array_length(ett
));
360 hci_usb_handle
= register_dissector("hci_usb", dissect_hci_usb
, proto_hci_usb
);
362 module
= prefs_register_protocol_subtree("Bluetooth", proto_hci_usb
, NULL
);
363 prefs_register_static_text_preference(module
, "bthci_usb.version",
364 "Bluetooth HCI USB Transport from Core 4.0",
365 "Version of protocol supported by this dissector.");
369 proto_reg_handoff_hci_usb(void)
371 bthci_cmd_handle
= find_dissector_add_dependency("bthci_cmd", proto_hci_usb
);
372 bthci_evt_handle
= find_dissector_add_dependency("bthci_evt", proto_hci_usb
);
373 bthci_acl_handle
= find_dissector_add_dependency("bthci_acl", proto_hci_usb
);
374 bthci_sco_handle
= find_dissector_add_dependency("bthci_sco", proto_hci_usb
);
378 * Editor modelines - https://www.wireshark.org/tools/modelines.html
383 * indent-tabs-mode: nil
386 * vi: set shiftwidth=4 tabstop=8 expandtab:
387 * :indentSize=4:tabSize=8:noTabs=true: