2 * Routines for the Bluetooth SCO dissection
3 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
5 * Refactored for wireshark checkin
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/packet.h>
18 #include <epan/addr_resolv.h>
20 #include "packet-bluetooth.h"
21 #include "packet-bthci_sco.h"
23 /* Initialize the protocol and registered fields */
24 static int proto_bthci_sco
;
25 static int hf_bthci_sco_reserved
;
26 static int hf_bthci_sco_packet_status
;
27 static int hf_bthci_sco_chandle
;
28 static int hf_bthci_sco_length
;
29 static int hf_bthci_sco_data
;
31 static int hf_bthci_sco_connect_in
;
32 static int hf_bthci_sco_disconnect_in
;
33 static int hf_bthci_sco_stream_number
;
35 /* Initialize the subtree pointers */
36 static int ett_bthci_sco
;
38 wmem_tree_t
*bthci_sco_stream_numbers
;
40 static dissector_handle_t bthci_sco_handle
;
42 static const value_string packet_status_vals
[] = {
43 { 0x00, "Correctly Received Data"},
44 { 0x01, "Possibly Invalid Data"},
45 { 0x02, "No Data Received"},
46 { 0x03, "Data Partially Lost"},
50 void proto_register_bthci_sco(void);
51 void proto_reg_handoff_bthci_sco(void);
53 /* Code to actually dissect the packets */
55 dissect_bthci_sco(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
58 proto_tree
*bthci_sco_tree
;
61 bluetooth_data_t
*bluetooth_data
;
62 wmem_tree_key_t key
[6];
63 uint32_t k_connection_handle
;
64 uint32_t k_frame_number
;
65 uint32_t k_interface_id
;
66 uint32_t k_adapter_id
;
67 uint32_t k_bd_addr_oui
;
68 uint32_t k_bd_addr_id
;
69 uint16_t packet_status
;
70 remote_bdaddr_t
*remote_bdaddr
;
71 const char *localhost_name
;
72 uint8_t *localhost_bdaddr
;
73 const char *localhost_ether_addr
;
74 char *localhost_addr_name
;
76 localhost_bdaddr_entry_t
*localhost_bdaddr_entry
;
77 localhost_name_entry_t
*localhost_name_entry
;
78 chandle_session_t
*chandle_session
;
81 bthci_sco_stream_number_t
*sco_stream_number
;
83 ti
= proto_tree_add_item(tree
, proto_bthci_sco
, tvb
, offset
, tvb_captured_length(tvb
), ENC_NA
);
84 bthci_sco_tree
= proto_item_add_subtree(ti
, ett_bthci_sco
);
86 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HCI_SCO");
88 switch (pinfo
->p2p_dir
) {
90 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
93 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
96 col_set_str(pinfo
->cinfo
, COL_INFO
, "UnknownDirection ");
100 proto_tree_add_item(bthci_sco_tree
, hf_bthci_sco_reserved
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
101 proto_tree_add_item(bthci_sco_tree
, hf_bthci_sco_packet_status
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
102 proto_tree_add_item(bthci_sco_tree
, hf_bthci_sco_chandle
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
103 flags
= tvb_get_letohs(tvb
, offset
);
106 packet_status
= (flags
>> 12) & 0x03;
107 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "SCO - %s", val_to_str(packet_status
, packet_status_vals
, "%u"));
109 proto_tree_add_item(bthci_sco_tree
, hf_bthci_sco_length
, tvb
, offset
, 1, ENC_LITTLE_ENDIAN
);
112 bluetooth_data
= (bluetooth_data_t
*) data
;
113 DISSECTOR_ASSERT(bluetooth_data
);
115 k_interface_id
= bluetooth_data
->interface_id
;
116 k_adapter_id
= bluetooth_data
->adapter_id
;
117 k_connection_handle
= flags
& 0x0fff;
118 k_frame_number
= pinfo
->num
;
121 key
[0].key
= &k_interface_id
;
123 key
[1].key
= &k_adapter_id
;
127 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bthci_sco_stream_numbers
, key
);
128 sco_stream_number
= (subtree
) ? (bthci_sco_stream_number_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
131 key
[2].key
= &k_connection_handle
;
135 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->chandle_sessions
, key
);
136 chandle_session
= (subtree
) ? (chandle_session_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
137 if (!(chandle_session
&&
138 chandle_session
->connect_in_frame
< pinfo
->num
&&
139 chandle_session
->disconnect_in_frame
> pinfo
->num
)){
140 chandle_session
= NULL
;
144 key
[3].key
= &k_frame_number
;
148 /* remote bdaddr and name */
149 remote_bdaddr
= (remote_bdaddr_t
*)wmem_tree_lookup32_array_le(bluetooth_data
->chandle_to_bdaddr
, key
);
150 if (remote_bdaddr
&& remote_bdaddr
->interface_id
== bluetooth_data
->interface_id
&&
151 remote_bdaddr
->adapter_id
== bluetooth_data
->adapter_id
&&
152 remote_bdaddr
->chandle
== (flags
& 0x0fff)) {
153 uint32_t bd_addr_oui
;
155 device_name_t
*device_name
;
156 const char *remote_name
;
157 const char *remote_ether_addr
;
158 char *remote_addr_name
;
161 bd_addr_oui
= remote_bdaddr
->bd_addr
[0] << 16 | remote_bdaddr
->bd_addr
[1] << 8 | remote_bdaddr
->bd_addr
[2];
162 bd_addr_id
= remote_bdaddr
->bd_addr
[3] << 16 | remote_bdaddr
->bd_addr
[4] << 8 | remote_bdaddr
->bd_addr
[5];
164 k_bd_addr_oui
= bd_addr_oui
;
165 k_bd_addr_id
= bd_addr_id
;
166 k_frame_number
= pinfo
->num
;
169 key
[0].key
= &k_interface_id
;
171 key
[1].key
= &k_adapter_id
;
173 key
[2].key
= &k_bd_addr_id
;
175 key
[3].key
= &k_bd_addr_oui
;
177 key
[4].key
= &k_frame_number
;
181 device_name
= (device_name_t
*)wmem_tree_lookup32_array_le(bluetooth_data
->bdaddr_to_name
, key
);
182 if (device_name
&& device_name
->bd_addr_oui
== bd_addr_oui
&& device_name
->bd_addr_id
== bd_addr_id
)
183 remote_name
= device_name
->name
;
187 remote_ether_addr
= get_ether_name(remote_bdaddr
->bd_addr
);
188 remote_length
= (int)(strlen(remote_ether_addr
) + 3 + strlen(remote_name
) + 1);
189 remote_addr_name
= (char *)wmem_alloc(pinfo
->pool
, remote_length
);
191 snprintf(remote_addr_name
, remote_length
, "%s (%s)", remote_ether_addr
, remote_name
);
193 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
194 set_address(&pinfo
->net_src
, AT_STRINGZ
, (int)strlen(remote_name
) + 1, remote_name
);
195 set_address(&pinfo
->dl_src
, AT_ETHER
, 6, remote_bdaddr
->bd_addr
);
196 set_address(&pinfo
->src
, AT_STRINGZ
, (int)strlen(remote_addr_name
) + 1, remote_addr_name
);
197 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
198 set_address(&pinfo
->net_dst
, AT_STRINGZ
, (int)strlen(remote_name
) + 1, remote_name
);
199 set_address(&pinfo
->dl_dst
, AT_ETHER
, 6, remote_bdaddr
->bd_addr
);
200 set_address(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(remote_addr_name
) + 1, remote_addr_name
);
203 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
204 set_address(&pinfo
->net_src
, AT_STRINGZ
, 1, "");
205 set_address(&pinfo
->dl_src
, AT_STRINGZ
, 1, "");
206 set_address(&pinfo
->src
, AT_STRINGZ
, 10, "remote ()");
207 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
208 set_address(&pinfo
->net_dst
, AT_STRINGZ
, 1, "");
209 set_address(&pinfo
->dl_dst
, AT_STRINGZ
, 1, "");
210 set_address(&pinfo
->dst
, AT_STRINGZ
, 10, "remote ()");
214 k_interface_id
= bluetooth_data
->interface_id
;
215 k_adapter_id
= bluetooth_data
->adapter_id
;
216 k_frame_number
= pinfo
->num
;
218 /* localhost bdaddr and name */
220 key
[0].key
= &k_interface_id
;
222 key
[1].key
= &k_adapter_id
;
224 key
[2].key
= &k_frame_number
;
229 localhost_bdaddr_entry
= (localhost_bdaddr_entry_t
*)wmem_tree_lookup32_array_le(bluetooth_data
->localhost_bdaddr
, key
);
230 localhost_bdaddr
= (uint8_t *) wmem_alloc(pinfo
->pool
, 6);
231 if (localhost_bdaddr_entry
&& localhost_bdaddr_entry
->interface_id
== bluetooth_data
->interface_id
&&
232 localhost_bdaddr_entry
->adapter_id
== bluetooth_data
->adapter_id
) {
234 localhost_ether_addr
= get_ether_name(localhost_bdaddr_entry
->bd_addr
);
235 memcpy(localhost_bdaddr
, localhost_bdaddr_entry
->bd_addr
, 6);
237 localhost_ether_addr
= "localhost";
238 /* XXX - is this the right value to use? */
239 memset(localhost_bdaddr
, 0, 6);
242 localhost_name_entry
= (localhost_name_entry_t
*)wmem_tree_lookup32_array_le(bluetooth_data
->localhost_name
, key
);
243 if (localhost_name_entry
&& localhost_name_entry
->interface_id
== bluetooth_data
->interface_id
&&
244 localhost_name_entry
->adapter_id
== bluetooth_data
->adapter_id
)
245 localhost_name
= localhost_name_entry
->name
;
249 localhost_length
= (int)(strlen(localhost_ether_addr
) + 3 + strlen(localhost_name
) + 1);
250 localhost_addr_name
= (char *)wmem_alloc(pinfo
->pool
, localhost_length
);
252 snprintf(localhost_addr_name
, localhost_length
, "%s (%s)", localhost_ether_addr
, localhost_name
);
254 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
255 set_address(&pinfo
->net_dst
, AT_STRINGZ
, (int)strlen(localhost_name
) + 1, localhost_name
);
256 set_address(&pinfo
->dl_dst
, AT_ETHER
, 6, localhost_bdaddr
);
257 set_address(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(localhost_addr_name
) + 1, localhost_addr_name
);
258 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
259 set_address(&pinfo
->net_src
, AT_STRINGZ
, (int)strlen(localhost_name
) + 1, localhost_name
);
260 set_address(&pinfo
->dl_src
, AT_ETHER
, 6, localhost_bdaddr
);
261 set_address(&pinfo
->src
, AT_STRINGZ
, (int)strlen(localhost_addr_name
) + 1, localhost_addr_name
);
264 proto_tree_add_item(bthci_sco_tree
, hf_bthci_sco_data
, tvb
, offset
, tvb_reported_length(tvb
), ENC_NA
);
266 if (chandle_session
) {
267 sub_item
= proto_tree_add_uint(bthci_sco_tree
, hf_bthci_sco_connect_in
, tvb
, 0, 0, chandle_session
->connect_in_frame
);
268 proto_item_set_generated(sub_item
);
270 if (chandle_session
->disconnect_in_frame
< UINT32_MAX
) {
271 sub_item
= proto_tree_add_uint(bthci_sco_tree
, hf_bthci_sco_disconnect_in
, tvb
, 0, 0, chandle_session
->disconnect_in_frame
);
272 proto_item_set_generated(sub_item
);
275 if (sco_stream_number
) {
276 sub_item
= proto_tree_add_uint(bthci_sco_tree
, hf_bthci_sco_stream_number
, tvb
, 0, 0, sco_stream_number
->stream_number
);
277 proto_item_set_generated(sub_item
);
280 return tvb_reported_length(tvb
);
285 proto_register_bthci_sco(void)
287 static hf_register_info hf
[] = {
288 { &hf_bthci_sco_reserved
,
289 { "Reserved", "bthci_sco.reserved",
290 FT_UINT16
, BASE_HEX
, NULL
, 0xC000,
293 { &hf_bthci_sco_packet_status
,
294 { "Packet Status", "bthci_sco.packet_status",
295 FT_UINT16
, BASE_HEX
, VALS(packet_status_vals
), 0x3000,
298 { &hf_bthci_sco_chandle
,
299 { "Connection Handle", "bthci_sco.chandle",
300 FT_UINT16
, BASE_HEX
, NULL
, 0x0FFF,
303 { &hf_bthci_sco_connect_in
,
304 { "Connect in frame", "bthci_sco.connect_in",
305 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
308 { &hf_bthci_sco_disconnect_in
,
309 { "Disconnect in frame", "bthci_sco.disconnect_in",
310 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
313 { &hf_bthci_sco_stream_number
,
314 { "Stream Number", "bthci_sco.stream_number",
315 FT_UINT32
, BASE_DEC
, NULL
, 0x00,
318 { &hf_bthci_sco_length
,
319 { "Data Total Length", "bthci_sco.length",
320 FT_UINT8
, BASE_DEC
, NULL
, 0x0,
323 { &hf_bthci_sco_data
,
324 { "Data", "bthci_sco.data",
325 FT_NONE
, BASE_NONE
, NULL
, 0x0,
330 /* Setup protocol subtree array */
331 static int *ett
[] = {
335 /* Register the protocol name and description */
336 proto_bthci_sco
= proto_register_protocol("Bluetooth HCI SCO Packet", "HCI_SCO", "bthci_sco");
337 bthci_sco_handle
= register_dissector("bthci_sco", dissect_bthci_sco
, proto_bthci_sco
);
339 bthci_sco_stream_numbers
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
341 /* Required function calls to register the header fields and subtrees used */
342 proto_register_field_array(proto_bthci_sco
, hf
, array_length(hf
));
343 proto_register_subtree_array(ett
, array_length(ett
));
348 proto_reg_handoff_bthci_sco(void)
350 dissector_add_uint("hci_h4.type", HCI_H4_TYPE_SCO
, bthci_sco_handle
);
351 dissector_add_uint("hci_h1.type", BTHCI_CHANNEL_SCO
, bthci_sco_handle
);
355 * Editor modelines - https://www.wireshark.org/tools/modelines.html
360 * indent-tabs-mode: nil
363 * vi: set shiftwidth=4 tabstop=8 expandtab:
364 * :indentSize=4:tabSize=8:noTabs=true: