1 /* TODO mix direction bit into the chandle tree lookup so we can handle when fragments sent in both directions simultaneously on the same chandle */
4 * Routines for the Bluetooth ACL dissection
5 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
6 * From: http://affix.sourceforge.net/archive/ethereal_affix-3.patch
8 * Refactored for wireshark checkin
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
34 #include <epan/packet.h>
35 #include <epan/prefs.h>
36 #include <epan/wmem/wmem.h>
38 #include "packet-bluetooth-hci.h"
39 #include "packet-bthci_acl.h"
41 /* Initialize the protocol and registered fields */
42 static int proto_bthci_acl
= -1;
43 static int hf_bthci_acl_chandle
= -1;
44 static int hf_bthci_acl_pb_flag
= -1;
45 static int hf_bthci_acl_bc_flag
= -1;
46 static int hf_bthci_acl_length
= -1;
47 /* static int hf_bthci_acl_data = -1; */
48 static int hf_bthci_acl_continuation_to
= -1;
49 static int hf_bthci_acl_reassembled_in
= -1;
51 /* Initialize the subtree pointers */
52 static gint ett_bthci_acl
= -1;
54 static dissector_handle_t btl2cap_handle
= NULL
;
56 static gboolean acl_reassembly
= TRUE
;
58 typedef struct _multi_fragment_pdu_t
{
63 int cur_off
; /* counter used by reassembly */
64 } multi_fragment_pdu_t
;
66 typedef struct _chandle_data_t
{
67 wmem_tree_t
*start_fragments
; /* indexed by pinfo->fd->num */
73 static wmem_tree_t
*chandle_tree
= NULL
;
75 static const value_string pb_flag_vals
[] = {
76 { 0, "First Non-automatically Flushable Packet" },
77 { 1, "Continuing Fragment" },
78 { 2, "First Automatically Flushable Packet" },
82 static const value_string bc_flag_vals
[] = {
83 { 0, "Point-To-Point" },
84 { 1, "Active Broadcast" },
85 { 2, "Piconet Broadcast" },
89 void proto_register_bthci_acl(void);
90 void proto_reg_handoff_bthci_acl(void);
92 /* Code to actually dissect the packets */
94 dissect_bthci_acl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
97 proto_tree
*bthci_acl_tree
;
102 guint16 pb_flag
, l2cap_length
= 0;
104 bthci_acl_data_t
*acl_data
;
105 chandle_data_t
*chandle_data
;
106 hci_data_t
*hci_data
;
107 wmem_tree_key_t key
[5];
108 guint32 k_connection_handle
;
109 guint32 k_frame_number
;
110 guint32 k_interface_id
;
111 guint32 k_adapter_id
;
112 remote_bdaddr_t
*remote_bdaddr
;
113 const gchar
*localhost_name
;
114 guint8 localhost_bdaddr
[6];
115 const gchar
*localhost_ether_addr
;
116 gchar
*localhost_addr_name
;
117 gint localhost_length
;
118 localhost_bdaddr_entry_t
*localhost_bdaddr_entry
;
119 localhost_name_entry_t
*localhost_name_entry
;
121 ti
= proto_tree_add_item(tree
, proto_bthci_acl
, tvb
, offset
, -1, ENC_NA
);
122 bthci_acl_tree
= proto_item_add_subtree(ti
, ett_bthci_acl
);
124 switch (pinfo
->p2p_dir
) {
126 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
129 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
132 col_add_fstr(pinfo
->cinfo
, COL_INFO
, "Unknown direction %d ",
137 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HCI_ACL");
139 hci_data
= (hci_data_t
*) data
;
140 DISSECTOR_ASSERT(hci_data
);
142 flags
= tvb_get_letohs(tvb
, offset
);
143 pb_flag
= (flags
& 0x3000) >> 12;
144 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_chandle
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
145 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_pb_flag
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
146 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_bc_flag
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
149 acl_data
= wmem_new(wmem_packet_scope(), bthci_acl_data_t
);
151 acl_data
->interface_id
= hci_data
->interface_id
;
152 acl_data
->adapter_id
= hci_data
->adapter_id
;
153 acl_data
->chandle
= flags
& 0x0fff;
154 acl_data
->remote_bd_addr_oui
= 0;
155 acl_data
->remote_bd_addr_id
= 0;
157 k_interface_id
= hci_data
->interface_id
;
158 k_adapter_id
= hci_data
->adapter_id
;
159 k_connection_handle
= flags
& 0x0fff;
160 k_frame_number
= pinfo
->fd
->num
;
163 key
[0].key
= &k_interface_id
;
165 key
[1].key
= &k_adapter_id
;
167 key
[2].key
= &k_connection_handle
;
169 key
[3].key
= &k_frame_number
;
173 /* remote bdaddr and name */
174 remote_bdaddr
= (remote_bdaddr_t
*)wmem_tree_lookup32_array_le(hci_data
->chandle_to_bdaddr_table
, key
);
175 if (remote_bdaddr
&& remote_bdaddr
->interface_id
== hci_data
->interface_id
&&
176 remote_bdaddr
->adapter_id
== hci_data
->adapter_id
&&
177 remote_bdaddr
->chandle
== (flags
& 0x0fff)) {
178 guint32 k_bd_addr_oui
;
179 guint32 k_bd_addr_id
;
182 device_name_t
*device_name
;
183 const gchar
*remote_name
;
184 const gchar
*remote_ether_addr
;
185 gchar
*remote_addr_name
;
188 bd_addr_oui
= remote_bdaddr
->bd_addr
[0] << 16 | remote_bdaddr
->bd_addr
[1] << 8 | remote_bdaddr
->bd_addr
[2];
189 bd_addr_id
= remote_bdaddr
->bd_addr
[3] << 16 | remote_bdaddr
->bd_addr
[4] << 8 | remote_bdaddr
->bd_addr
[5];
191 acl_data
->remote_bd_addr_oui
= bd_addr_oui
;
192 acl_data
->remote_bd_addr_id
= bd_addr_id
;
194 k_bd_addr_oui
= bd_addr_oui
;
195 k_bd_addr_id
= bd_addr_id
;
196 k_frame_number
= pinfo
->fd
->num
;
199 key
[0].key
= &k_bd_addr_id
;
201 key
[1].key
= &k_bd_addr_oui
;
203 key
[2].key
= &k_frame_number
;
207 device_name
= (device_name_t
*)wmem_tree_lookup32_array_le(hci_data
->bdaddr_to_name_table
, key
);
208 if (device_name
&& device_name
->bd_addr_oui
== bd_addr_oui
&& device_name
->bd_addr_id
== bd_addr_id
)
209 remote_name
= device_name
->name
;
213 remote_ether_addr
= get_ether_name(remote_bdaddr
->bd_addr
);
214 remote_length
= (gint
)(strlen(remote_ether_addr
) + 3 + strlen(remote_name
) + 1);
215 remote_addr_name
= (gchar
*)wmem_alloc(pinfo
->pool
, remote_length
);
217 g_snprintf(remote_addr_name
, remote_length
, "%s (%s)", remote_ether_addr
, remote_name
);
219 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
220 SET_ADDRESS(&pinfo
->net_src
, AT_STRINGZ
, (int)strlen(remote_name
) + 1, remote_name
);
221 SET_ADDRESS(&pinfo
->dl_src
, AT_ETHER
, 6, remote_bdaddr
->bd_addr
);
222 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
, (int)strlen(remote_addr_name
) + 1, remote_addr_name
);
223 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
224 SET_ADDRESS(&pinfo
->net_dst
, AT_STRINGZ
, (int)strlen(remote_name
) + 1, remote_name
);
225 SET_ADDRESS(&pinfo
->dl_dst
, AT_ETHER
, 6, remote_bdaddr
->bd_addr
);
226 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(remote_addr_name
) + 1, remote_addr_name
);
229 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
230 SET_ADDRESS(&pinfo
->net_src
, AT_STRINGZ
, 1, "");
231 SET_ADDRESS(&pinfo
->dl_src
, AT_STRINGZ
, 1, "");
232 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
, 10, "remote ()");
233 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
234 SET_ADDRESS(&pinfo
->net_dst
, AT_STRINGZ
, 1, "");
235 SET_ADDRESS(&pinfo
->dl_dst
, AT_STRINGZ
, 1, "");
236 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
, 10, "remote ()");
240 k_interface_id
= hci_data
->interface_id
;
241 k_adapter_id
= hci_data
->adapter_id
;
242 k_frame_number
= pinfo
->fd
->num
;
244 /* localhost bdaddr and name */
246 key
[0].key
= &k_interface_id
;
248 key
[1].key
= &k_adapter_id
;
250 key
[2].key
= &k_frame_number
;
255 localhost_bdaddr_entry
= (localhost_bdaddr_entry_t
*)wmem_tree_lookup32_array_le(hci_data
->localhost_bdaddr
, key
);
256 if (localhost_bdaddr_entry
&& localhost_bdaddr_entry
->interface_id
== hci_data
->interface_id
&&
257 localhost_bdaddr_entry
->adapter_id
== hci_data
->adapter_id
) {
259 localhost_ether_addr
= get_ether_name(localhost_bdaddr_entry
->bd_addr
);
260 memcpy(localhost_bdaddr
, localhost_bdaddr_entry
->bd_addr
, 6);
262 localhost_ether_addr
= "localhost";
263 /* XXX - is this the right value to use? */
264 memset(localhost_bdaddr
, 0, 6);
267 localhost_name_entry
= (localhost_name_entry_t
*)wmem_tree_lookup32_array_le(hci_data
->localhost_name
, key
);
268 if (localhost_name_entry
&& localhost_name_entry
->interface_id
== hci_data
->interface_id
&&
269 localhost_name_entry
->adapter_id
== hci_data
->adapter_id
)
270 localhost_name
= localhost_name_entry
->name
;
274 localhost_length
= (gint
)(strlen(localhost_ether_addr
) + 3 + strlen(localhost_name
) + 1);
275 localhost_addr_name
= (gchar
*)wmem_alloc(pinfo
->pool
, localhost_length
);
277 g_snprintf(localhost_addr_name
, localhost_length
, "%s (%s)", localhost_ether_addr
, localhost_name
);
279 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
280 SET_ADDRESS(&pinfo
->net_dst
, AT_STRINGZ
, (int)strlen(localhost_name
) + 1, localhost_name
);
281 SET_ADDRESS(&pinfo
->dl_dst
, AT_ETHER
, 6, localhost_bdaddr
);
282 SET_ADDRESS(&pinfo
->dst
, AT_STRINGZ
, (int)strlen(localhost_addr_name
) + 1, localhost_addr_name
);
283 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
284 SET_ADDRESS(&pinfo
->net_src
, AT_STRINGZ
, (int)strlen(localhost_name
) + 1, localhost_name
);
285 SET_ADDRESS(&pinfo
->dl_src
, AT_ETHER
, 6, localhost_bdaddr
);
286 SET_ADDRESS(&pinfo
->src
, AT_STRINGZ
, (int)strlen(localhost_addr_name
) + 1, localhost_addr_name
);
289 /* find the chandle_data structure associated with this chandle */
290 k_interface_id
= hci_data
->interface_id
;
291 k_adapter_id
= hci_data
->adapter_id
;
292 k_connection_handle
= flags
& 0x0fff;
293 k_frame_number
= pinfo
->fd
->num
;
296 key
[0].key
= &k_interface_id
;
298 key
[1].key
= &k_adapter_id
;
300 key
[2].key
= &k_connection_handle
;
302 key
[3].key
= &k_frame_number
;
306 chandle_data
= (chandle_data_t
*)wmem_tree_lookup32_array_le(chandle_tree
, key
);
307 if (!(chandle_data
&& chandle_data
->interface_id
== hci_data
->interface_id
&&
308 chandle_data
->adapter_id
== hci_data
->adapter_id
&&
309 chandle_data
->chandle
== (flags
& 0x0fff))) {
310 k_interface_id
= hci_data
->interface_id
;
311 k_adapter_id
= hci_data
->adapter_id
;
312 k_connection_handle
= flags
& 0x0fff;
313 k_frame_number
= pinfo
->fd
->num
;
316 key
[0].key
= &k_interface_id
;
318 key
[1].key
= &k_adapter_id
;
320 key
[2].key
= &k_connection_handle
;
322 key
[3].key
= &k_frame_number
;
326 chandle_data
= (chandle_data_t
*)wmem_alloc(wmem_file_scope(), sizeof(chandle_data_t
));
327 chandle_data
->start_fragments
= wmem_tree_new(wmem_file_scope());
328 chandle_data
->interface_id
= hci_data
->interface_id
;
329 chandle_data
->adapter_id
= hci_data
->adapter_id
;
330 chandle_data
->chandle
= flags
& 0x0fff;
332 wmem_tree_insert32_array(chandle_tree
, key
, chandle_data
);
335 length
= tvb_get_letohs(tvb
, offset
);
336 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
339 /* determine if packet is fragmented */
341 case 0x01: /* Continuation fragment */
344 case 0x00: /* First fragment/packet, non-auto flushable */
345 case 0x02: /* First fragment/packet, auto flushable */
346 l2cap_length
= tvb_get_letohs(tvb
, offset
);
347 fragmented
= (l2cap_length
+ 4 != length
);
350 /* unknown pb_flag */
355 if (!fragmented
|| (!acl_reassembly
&& !(pb_flag
& 0x01))) {
356 /* call L2CAP dissector for PDUs that are not fragmented
357 * also for the first fragment if reassembly is disabled
359 next_tvb
= tvb_new_subset(tvb
, offset
, tvb_length_remaining(tvb
, offset
), length
);
360 if (btl2cap_handle
) {
361 call_dissector_with_data(btl2cap_handle
, next_tvb
, pinfo
, tree
, acl_data
);
367 if (fragmented
&& acl_reassembly
) {
368 multi_fragment_pdu_t
*mfp
= NULL
;
371 if (!(pb_flag
& 0x01)) { /* first fragment */
372 if (!pinfo
->fd
->flags
.visited
) {
373 mfp
= (multi_fragment_pdu_t
*) wmem_new(wmem_file_scope(), multi_fragment_pdu_t
);
374 mfp
->first_frame
= pinfo
->fd
->num
;
376 mfp
->tot_len
= l2cap_length
+ 4;
377 mfp
->reassembled
= (char *) wmem_alloc(wmem_file_scope(), mfp
->tot_len
);
378 len
= tvb_length_remaining(tvb
, offset
);
379 if (len
<= mfp
->tot_len
) {
380 tvb_memcpy(tvb
, (guint8
*) mfp
->reassembled
, offset
, len
);
382 wmem_tree_insert32(chandle_data
->start_fragments
, pinfo
->fd
->num
, mfp
);
385 mfp
= (multi_fragment_pdu_t
*)wmem_tree_lookup32(chandle_data
->start_fragments
, pinfo
->fd
->num
);
387 if (mfp
!= NULL
&& mfp
->last_frame
) {
390 item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_reassembled_in
, tvb
, 0, 0, mfp
->last_frame
);
391 PROTO_ITEM_SET_GENERATED(item
);
392 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [Reassembled in #%u]", mfp
->last_frame
);
395 if (pb_flag
== 0x01) { /* continuation fragment */
396 mfp
= (multi_fragment_pdu_t
*)wmem_tree_lookup32_le(chandle_data
->start_fragments
, pinfo
->fd
->num
);
397 if (!pinfo
->fd
->flags
.visited
) {
398 len
= tvb_length_remaining(tvb
, offset
);
399 if (mfp
!= NULL
&& !mfp
->last_frame
&& (mfp
->tot_len
>= mfp
->cur_off
+ len
)) {
400 tvb_memcpy(tvb
, (guint8
*) mfp
->reassembled
+ mfp
->cur_off
, offset
, len
);
402 if (mfp
->cur_off
== mfp
->tot_len
) {
403 mfp
->last_frame
= pinfo
->fd
->num
;
410 item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_continuation_to
, tvb
, 0, 0, mfp
->first_frame
);
411 PROTO_ITEM_SET_GENERATED(item
);
412 col_append_fstr(pinfo
->cinfo
, COL_INFO
, " [Continuation to #%u]", mfp
->first_frame
);
414 if (mfp
!= NULL
&& mfp
->last_frame
== pinfo
->fd
->num
) {
415 next_tvb
= tvb_new_child_real_data(tvb
, (guint8
*) mfp
->reassembled
, mfp
->tot_len
, mfp
->tot_len
);
416 add_new_data_source(pinfo
, next_tvb
, "Reassembled BTHCI ACL");
418 /* call L2CAP dissector */
419 if (btl2cap_handle
) {
420 call_dissector_with_data(btl2cap_handle
, next_tvb
, pinfo
, tree
, acl_data
);
431 proto_register_bthci_acl(void)
434 /* Setup list of header fields See Section 1.6.1 for details*/
435 static hf_register_info hf
[] = {
436 { &hf_bthci_acl_chandle
,
437 { "Connection Handle", "bthci_acl.chandle",
438 FT_UINT16
, BASE_HEX
, NULL
, 0x0FFF,
441 { &hf_bthci_acl_pb_flag
,
442 { "PB Flag", "bthci_acl.pb_flag",
443 FT_UINT16
, BASE_DEC
, VALS(pb_flag_vals
), 0x3000,
444 "Packet Boundary Flag", HFILL
}
446 { &hf_bthci_acl_bc_flag
,
447 { "BC Flag", "bthci_acl.bc_flag",
448 FT_UINT16
, BASE_DEC
, VALS(bc_flag_vals
), 0xC000,
449 "Broadcast Flag", HFILL
}
451 { &hf_bthci_acl_length
,
452 { "Data Total Length", "bthci_acl.length",
453 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
457 { &hf_bthci_acl_data
,
458 { "Data", "bthci_acl.data",
459 FT_NONE
, BASE_NONE
, NULL
, 0x0,
463 { &hf_bthci_acl_continuation_to
,
464 { "This is a continuation to the PDU in frame", "bthci_acl.continuation_to",
465 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
466 "This is a continuation to the PDU in frame #", HFILL
}
468 { &hf_bthci_acl_reassembled_in
,
469 { "This PDU is reassembled in frame", "bthci_acl.reassembled_in",
470 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
471 "This PDU is reassembled in frame #", HFILL
}
475 /* Setup protocol subtree array */
476 static gint
*ett
[] = {
479 module_t
*bthci_acl_module
;
481 /* Register the protocol name and description */
482 proto_bthci_acl
= proto_register_protocol("Bluetooth HCI ACL Packet", "HCI_ACL", "bthci_acl");
483 new_register_dissector("bthci_acl", dissect_bthci_acl
, proto_bthci_acl
);
485 /* Required function calls to register the header fields and subtrees used */
486 proto_register_field_array(proto_bthci_acl
, hf
, array_length(hf
));
487 proto_register_subtree_array(ett
, array_length(ett
));
489 /* Register configuration preferences */
490 bthci_acl_module
= prefs_register_protocol(proto_bthci_acl
, NULL
);
491 prefs_register_bool_preference(bthci_acl_module
, "hci_acl_reassembly",
492 "Reassemble ACL Fragments",
493 "Whether the ACL dissector should reassemble fragmented PDUs",
496 chandle_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
501 proto_reg_handoff_bthci_acl(void)
503 dissector_handle_t bthci_acl_handle
;
505 bthci_acl_handle
= find_dissector("bthci_acl");
506 dissector_add_uint("hci_h4.type", HCI_H4_TYPE_ACL
, bthci_acl_handle
);
507 dissector_add_uint("hci_h1.type", BTHCI_CHANNEL_ACL
, bthci_acl_handle
);
509 btl2cap_handle
= find_dissector("btl2cap");
513 * Editor modelines - http://www.wireshark.org/tools/modelines.html
518 * indent-tabs-mode: nil
521 * vi: set shiftwidth=4 tabstop=8 expandtab:
522 * :indentSize=4:tabSize=8:noTabs=true: