2 * Routines for the Bluetooth ACL dissection
3 * Copyright 2002, Christoph Scholz <scholz@cs.uni-bonn.de>
4 * - from: http://affix.sourceforge.net/archive/ethereal_affix-3.patch
5 * Copyright 2006, Ronnie Sahlberg
6 * - refactored for Wireshark checkin
7 * Copyright 2014, Michal Labedzki for Tieto Corporation
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include <epan/packet.h>
19 #include <epan/prefs.h>
20 #include <epan/addr_resolv.h>
21 #include <epan/expert.h>
22 #include <epan/proto_data.h>
24 #include "packet-bluetooth.h"
25 #include "packet-bthci_acl.h"
27 /* Initialize the protocol and registered fields */
28 static int proto_bthci_acl
;
29 static int hf_bthci_acl_chandle
;
30 static int hf_bthci_acl_pb_flag
;
31 static int hf_bthci_acl_bc_flag
;
32 static int hf_bthci_acl_length
;
33 static int hf_bthci_acl_data
;
34 static int hf_bthci_acl_continuation_to
;
35 static int hf_bthci_acl_reassembled_in
;
36 static int hf_bthci_acl_connect_in
;
37 static int hf_bthci_acl_disconnect_in
;
38 static int hf_bthci_acl_src_bd_addr
;
39 static int hf_bthci_acl_src_name
;
40 static int hf_bthci_acl_src_role
;
41 static int hf_bthci_acl_dst_bd_addr
;
42 static int hf_bthci_acl_dst_name
;
43 static int hf_bthci_acl_dst_role
;
44 static int hf_bthci_acl_role_last_change_in_frame
;
45 static int hf_bthci_acl_mode
;
46 static int hf_bthci_acl_mode_last_change_in_frame
;
48 /* Initialize the subtree pointers */
49 static int ett_bthci_acl
;
51 static expert_field ei_invalid_session
;
52 static expert_field ei_length_bad
;
54 static dissector_handle_t bthci_acl_handle
;
55 static dissector_handle_t btl2cap_handle
;
57 static bool acl_reassembly
= true;
59 typedef struct _multi_fragment_pdu_t
{
64 int cur_off
; /* counter used by reassembly */
65 } multi_fragment_pdu_t
;
67 typedef struct _chandle_data_t
{
68 wmem_tree_t
*start_fragments
; /* indexed by pinfo->num */
71 static wmem_tree_t
*chandle_tree
;
73 static const value_string role_vals
[] = {
80 static const value_string mode_vals
[] = {
89 static const value_string pb_flag_vals
[] = {
90 { 0, "First Non-automatically Flushable Packet" },
91 { 1, "Continuing Fragment" },
92 { 2, "First Automatically Flushable Packet" },
96 static const value_string bc_flag_vals
[] = {
97 { 0, "Point-To-Point" },
98 { 1, "Active Broadcast" },
99 { 2, "Piconet Broadcast" },
103 static uint32_t invalid_session
;
106 void proto_register_bthci_acl(void);
107 void proto_reg_handoff_bthci_acl(void);
109 /* Code to actually dissect the packets */
111 dissect_bthci_acl(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
113 proto_item
*bthci_acl_item
;
114 proto_tree
*bthci_acl_tree
;
115 proto_item
*sub_item
;
116 proto_item
*length_item
;
121 uint16_t pb_flag
, l2cap_length
= 0;
123 bthci_acl_data_t
*acl_data
;
124 chandle_data_t
*chandle_data
;
125 bluetooth_data_t
*bluetooth_data
;
126 wmem_tree_t
*subtree
;
127 wmem_tree_key_t key
[6];
128 uint32_t interface_id
;
130 uint32_t connection_handle
;
132 uint32_t k_bd_addr_oui
;
133 uint32_t k_bd_addr_id
;
134 uint32_t frame_number
;
135 remote_bdaddr_t
*remote_bdaddr
;
136 const char *localhost_name
;
137 uint8_t localhost_bdaddr
[6];
138 const char *localhost_ether_addr
;
139 char *localhost_addr_name
;
140 int localhost_length
;
141 localhost_bdaddr_entry_t
*localhost_bdaddr_entry
;
142 localhost_name_entry_t
*localhost_name_entry
;
143 static const uint8_t unknown_bd_addr
[6] = {0};
144 const uint8_t *src_bd_addr
= &unknown_bd_addr
[0];
145 const char *src_name
= "";
146 const char *src_addr_name
= "";
147 const uint8_t *dst_bd_addr
= &unknown_bd_addr
[0];
148 const char *dst_name
= "";
149 const char *dst_addr_name
= "";
150 chandle_session_t
*chandle_session
;
151 uint32_t src_role
= ROLE_UNKNOWN
;
152 uint32_t dst_role
= ROLE_UNKNOWN
;
153 uint32_t role_last_change_in_frame
= 0;
154 connection_mode_t
*connection_mode
;
156 uint32_t mode_last_change_in_frame
= 0;
158 /* Reject the packet if data is NULL */
161 bluetooth_data
= (bluetooth_data_t
*) data
;
163 bthci_acl_item
= proto_tree_add_item(tree
, proto_bthci_acl
, tvb
, offset
, -1, ENC_NA
);
164 bthci_acl_tree
= proto_item_add_subtree(bthci_acl_item
, ett_bthci_acl
);
166 switch (pinfo
->p2p_dir
) {
168 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
171 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
174 col_set_str(pinfo
->cinfo
, COL_INFO
, "UnknownDirection ");
178 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HCI_ACL");
180 flags
= tvb_get_letohs(tvb
, offset
);
181 pb_flag
= (flags
& 0x3000) >> 12;
182 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_chandle
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
183 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_pb_flag
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
184 proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_bc_flag
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
187 interface_id
= bluetooth_data
->interface_id
;
188 adapter_id
= bluetooth_data
->adapter_id
;
189 connection_handle
= flags
& 0x0fff;
190 direction
= pinfo
->p2p_dir
;
191 frame_number
= pinfo
->num
;
193 acl_data
= wmem_new(pinfo
->pool
, bthci_acl_data_t
);
194 acl_data
->interface_id
= interface_id
;
195 acl_data
->adapter_id
= adapter_id
;
196 acl_data
->adapter_disconnect_in_frame
= bluetooth_data
->adapter_disconnect_in_frame
;
197 acl_data
->chandle
= connection_handle
;
198 acl_data
->is_btle
= false;
199 acl_data
->is_btle_retransmit
= false;
202 key
[0].key
= &interface_id
;
204 key
[1].key
= &adapter_id
;
206 key
[2].key
= &connection_handle
;
210 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->chandle_sessions
, key
);
211 chandle_session
= (subtree
) ? (chandle_session_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
212 if (chandle_session
&&
213 chandle_session
->connect_in_frame
< pinfo
->num
&&
214 chandle_session
->disconnect_in_frame
> pinfo
->num
) {
215 acl_data
->disconnect_in_frame
= &chandle_session
->disconnect_in_frame
;
217 acl_data
->disconnect_in_frame
= &invalid_session
;
218 chandle_session
= NULL
;
221 acl_data
->remote_bd_addr_oui
= 0;
222 acl_data
->remote_bd_addr_id
= 0;
224 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->chandle_to_mode
, key
);
225 connection_mode
= (subtree
) ? (connection_mode_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
226 if (connection_mode
) {
227 mode
= connection_mode
->mode
;
228 mode_last_change_in_frame
= connection_mode
->change_in_frame
;
231 /* remote bdaddr and name */
232 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->chandle_to_bdaddr
, key
);
233 remote_bdaddr
= (subtree
) ? (remote_bdaddr_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
235 uint32_t bd_addr_oui
;
237 device_name_t
*device_name
;
238 device_role_t
*device_role
;
239 const char *remote_name
;
240 const char *remote_ether_addr
;
241 char *remote_addr_name
;
244 bd_addr_oui
= remote_bdaddr
->bd_addr
[0] << 16 | remote_bdaddr
->bd_addr
[1] << 8 | remote_bdaddr
->bd_addr
[2];
245 bd_addr_id
= remote_bdaddr
->bd_addr
[3] << 16 | remote_bdaddr
->bd_addr
[4] << 8 | remote_bdaddr
->bd_addr
[5];
247 acl_data
->remote_bd_addr_oui
= bd_addr_oui
;
248 acl_data
->remote_bd_addr_id
= bd_addr_id
;
250 k_bd_addr_oui
= bd_addr_oui
;
251 k_bd_addr_id
= bd_addr_id
;
254 key
[0].key
= &interface_id
;
256 key
[1].key
= &adapter_id
;
258 key
[2].key
= &k_bd_addr_id
;
260 key
[3].key
= &k_bd_addr_oui
;
264 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->bdaddr_to_role
, key
);
265 device_role
= (subtree
) ? (device_role_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
267 if ((pinfo
->p2p_dir
== P2P_DIR_SENT
&& device_role
->role
== ROLE_CENTRAL
) ||
268 (pinfo
->p2p_dir
== P2P_DIR_RECV
&& device_role
->role
== ROLE_PERIPHERAL
)) {
269 src_role
= ROLE_PERIPHERAL
;
270 dst_role
= ROLE_CENTRAL
;
271 } else if ((pinfo
->p2p_dir
== P2P_DIR_SENT
&& device_role
->role
== ROLE_PERIPHERAL
) ||
272 (pinfo
->p2p_dir
== P2P_DIR_RECV
&& device_role
->role
== ROLE_CENTRAL
)) {
273 src_role
= ROLE_CENTRAL
;
274 dst_role
= ROLE_PERIPHERAL
;
276 role_last_change_in_frame
= device_role
->change_in_frame
;
279 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->bdaddr_to_name
, key
);
280 device_name
= (subtree
) ? (device_name_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
282 remote_name
= device_name
->name
;
286 remote_ether_addr
= get_ether_name(remote_bdaddr
->bd_addr
);
287 remote_length
= (int)(strlen(remote_ether_addr
) + 3 + strlen(remote_name
) + 1);
288 remote_addr_name
= (char *)wmem_alloc(pinfo
->pool
, remote_length
);
290 snprintf(remote_addr_name
, remote_length
, "%s (%s)", remote_ether_addr
, remote_name
);
292 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
293 src_bd_addr
= remote_bdaddr
->bd_addr
;
294 src_name
= remote_name
;
295 src_addr_name
= remote_addr_name
;
296 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
297 dst_bd_addr
= remote_bdaddr
->bd_addr
;
298 dst_name
= remote_name
;
299 dst_addr_name
= remote_addr_name
;
302 if (pinfo
->p2p_dir
== P2P_DIR_RECV
)
303 src_addr_name
= "remote ()";
304 else if (pinfo
->p2p_dir
== P2P_DIR_SENT
)
305 dst_addr_name
= "remote ()";
308 /* localhost bdaddr and name */
310 key
[0].key
= &interface_id
;
312 key
[1].key
= &adapter_id
;
317 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->localhost_bdaddr
, key
);
318 localhost_bdaddr_entry
= (subtree
) ? (localhost_bdaddr_entry_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
319 if (localhost_bdaddr_entry
) {
320 localhost_ether_addr
= get_ether_name(localhost_bdaddr_entry
->bd_addr
);
321 memcpy(localhost_bdaddr
, localhost_bdaddr_entry
->bd_addr
, 6);
323 localhost_ether_addr
= "localhost";
324 memcpy(localhost_bdaddr
, unknown_bd_addr
, 6);
327 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(bluetooth_data
->localhost_name
, key
);
328 localhost_name_entry
= (subtree
) ? (localhost_name_entry_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
329 if (localhost_name_entry
)
330 localhost_name
= localhost_name_entry
->name
;
334 localhost_length
= (int)(strlen(localhost_ether_addr
) + 3 + strlen(localhost_name
) + 1);
335 localhost_addr_name
= (char *)wmem_alloc(pinfo
->pool
, localhost_length
);
337 snprintf(localhost_addr_name
, localhost_length
, "%s (%s)", localhost_ether_addr
, localhost_name
);
339 if (pinfo
->p2p_dir
== P2P_DIR_RECV
) {
340 dst_bd_addr
= localhost_bdaddr
;
341 dst_name
= localhost_name
;
342 dst_addr_name
= localhost_addr_name
;
343 } else if (pinfo
->p2p_dir
== P2P_DIR_SENT
) {
344 src_bd_addr
= localhost_bdaddr
;
345 src_name
= localhost_name
;
346 src_addr_name
= localhost_addr_name
;
349 /* find the chandle_data structure associated with this chandle */
351 key
[0].key
= &interface_id
;
353 key
[1].key
= &adapter_id
;
355 key
[2].key
= &connection_handle
;
357 key
[3].key
= &direction
;
361 subtree
= (wmem_tree_t
*) wmem_tree_lookup32_array(chandle_tree
, key
);
362 chandle_data
= (subtree
) ? (chandle_data_t
*) wmem_tree_lookup32_le(subtree
, pinfo
->num
) : NULL
;
363 if (!pinfo
->fd
->visited
&& !chandle_data
) {
365 key
[0].key
= &interface_id
;
367 key
[1].key
= &adapter_id
;
369 key
[2].key
= &connection_handle
;
371 key
[3].key
= &direction
;
373 key
[4].key
= &frame_number
;
377 chandle_data
= wmem_new(wmem_file_scope(), chandle_data_t
);
378 chandle_data
->start_fragments
= wmem_tree_new(wmem_file_scope());
380 wmem_tree_insert32_array(chandle_tree
, key
, chandle_data
);
381 } else if (pinfo
->fd
->visited
&& !chandle_data
) {
382 DISSECTOR_ASSERT_HINT(0, "Impossible: no previously session saved");
385 length
= tvb_get_letohs(tvb
, offset
);
386 length_item
= proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_length
, tvb
, offset
, 2, ENC_LITTLE_ENDIAN
);
389 /* determine if packet is fragmented */
391 case 0x01: /* Continuation fragment */
394 case 0x00: /* First fragment/packet, non-auto flushable */
395 case 0x02: /* First fragment/packet, auto flushable */
396 l2cap_length
= tvb_get_letohs(tvb
, offset
);
397 fragmented
= (l2cap_length
+ 4 != length
);
400 /* unknown pb_flag */
404 alloc_address_wmem(pinfo
->pool
, &pinfo
->net_src
, AT_STRINGZ
, (int)strlen(src_name
) + 1, src_name
);
405 alloc_address_wmem(pinfo
->pool
, &pinfo
->dl_src
, AT_ETHER
, 6, src_bd_addr
);
406 alloc_address_wmem(pinfo
->pool
, &pinfo
->src
, AT_STRINGZ
, (int)strlen(src_addr_name
) + 1, src_addr_name
);
408 alloc_address_wmem(pinfo
->pool
, &pinfo
->net_dst
, AT_STRINGZ
, (int)strlen(dst_name
) + 1, dst_name
);
409 alloc_address_wmem(pinfo
->pool
, &pinfo
->dl_dst
, AT_ETHER
, 6, dst_bd_addr
);
410 alloc_address_wmem(pinfo
->pool
, &pinfo
->dst
, AT_STRINGZ
, (int)strlen(dst_addr_name
) + 1, dst_addr_name
);
412 if (!fragmented
|| (!acl_reassembly
&& !(pb_flag
& 0x01))) {
413 /* call L2CAP dissector for PDUs that are not fragmented
414 * also for the first fragment if reassembly is disabled
416 if (length
< tvb_captured_length_remaining(tvb
, offset
)) {
417 expert_add_info(pinfo
, length_item
, &ei_length_bad
);
418 /* Try to dissect as more as possible */
419 length
= tvb_captured_length_remaining(tvb
, offset
);
422 next_tvb
= tvb_new_subset_length_caplen(tvb
, offset
, tvb_captured_length_remaining(tvb
, offset
), length
);
423 call_dissector_with_data(btl2cap_handle
, next_tvb
, pinfo
, tree
, acl_data
);
424 } else if (fragmented
&& acl_reassembly
) {
425 multi_fragment_pdu_t
*mfp
= NULL
;
428 if (!(pb_flag
& 0x01)) { /* first fragment */
429 if (!pinfo
->fd
->visited
) {
430 mfp
= (multi_fragment_pdu_t
*) wmem_new(wmem_file_scope(), multi_fragment_pdu_t
);
431 mfp
->first_frame
= pinfo
->num
;
433 mfp
->tot_len
= l2cap_length
+ 4;
434 mfp
->reassembled
= (char *) wmem_alloc(wmem_file_scope(), mfp
->tot_len
);
435 len
= tvb_captured_length_remaining(tvb
, offset
);
436 if (len
<= mfp
->tot_len
) {
437 tvb_memcpy(tvb
, (uint8_t *) mfp
->reassembled
, offset
, len
);
439 wmem_tree_insert32(chandle_data
->start_fragments
, pinfo
->num
, mfp
);
442 mfp
= (multi_fragment_pdu_t
*)wmem_tree_lookup32(chandle_data
->start_fragments
, pinfo
->num
);
444 if (mfp
!= NULL
&& mfp
->last_frame
) {
447 item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_reassembled_in
, tvb
, 0, 0, mfp
->last_frame
);
448 proto_item_set_generated(item
);
449 col_append_frame_number(pinfo
, COL_INFO
, " [Reassembled in #%u]", mfp
->last_frame
);
452 if (pb_flag
== 0x01) { /* continuation fragment */
453 mfp
= (multi_fragment_pdu_t
*)wmem_tree_lookup32_le(chandle_data
->start_fragments
, pinfo
->num
);
454 if (!pinfo
->fd
->visited
) {
455 len
= tvb_captured_length_remaining(tvb
, offset
);
456 if (mfp
!= NULL
&& !mfp
->last_frame
&& (mfp
->tot_len
>= mfp
->cur_off
+ len
)) {
457 tvb_memcpy(tvb
, (uint8_t *) mfp
->reassembled
+ mfp
->cur_off
, offset
, len
);
459 if (mfp
->cur_off
== mfp
->tot_len
) {
460 mfp
->last_frame
= pinfo
->num
;
467 item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_continuation_to
, tvb
, 0, 0, mfp
->first_frame
);
468 proto_item_set_generated(item
);
469 col_append_frame_number(pinfo
, COL_INFO
, " [Continuation to #%u]", mfp
->first_frame
);
470 if (mfp
->last_frame
&& mfp
->last_frame
!= pinfo
->num
) {
471 item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_reassembled_in
, tvb
, 0, 0, mfp
->last_frame
);
472 proto_item_set_generated(item
);
473 col_append_frame_number(pinfo
, COL_INFO
, " [Reassembled in #%u]", mfp
->last_frame
);
476 if (mfp
!= NULL
&& mfp
->last_frame
== pinfo
->num
) {
477 next_tvb
= tvb_new_child_real_data(tvb
, (uint8_t *) mfp
->reassembled
, mfp
->tot_len
, mfp
->tot_len
);
478 add_new_data_source(pinfo
, next_tvb
, "Reassembled BTHCI ACL");
480 call_dissector_with_data(btl2cap_handle
, next_tvb
, pinfo
, tree
, acl_data
);
485 if (tvb_captured_length_remaining(tvb
, offset
) > 0) {
486 sub_item
= proto_tree_add_item(bthci_acl_tree
, hf_bthci_acl_data
, tvb
, offset
, -1, ENC_NA
);
488 proto_item_append_text(sub_item
, " Fragment");
492 if (chandle_session
) {
493 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_connect_in
, tvb
, 0, 0, chandle_session
->connect_in_frame
);
494 proto_item_set_generated(sub_item
);
496 if (chandle_session
->disconnect_in_frame
< UINT32_MAX
) {
497 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_disconnect_in
, tvb
, 0, 0, chandle_session
->disconnect_in_frame
);
498 proto_item_set_generated(sub_item
);
502 if (acl_data
->disconnect_in_frame
== &invalid_session
) {
503 expert_add_info(pinfo
, bthci_acl_item
, &ei_invalid_session
);
506 if (!pinfo
->fd
->visited
) {
509 addr
= (address
*) wmem_memdup(wmem_file_scope(), &pinfo
->dl_src
, sizeof(address
));
510 addr
->data
= wmem_memdup(wmem_file_scope(), pinfo
->dl_src
.data
, pinfo
->dl_src
.len
);
511 p_add_proto_data(wmem_file_scope(), pinfo
, proto_bluetooth
, BLUETOOTH_DATA_SRC
, addr
);
513 addr
= (address
*) wmem_memdup(wmem_file_scope(), &pinfo
->dl_dst
, sizeof(address
));
514 addr
->data
= wmem_memdup(wmem_file_scope(), pinfo
->dl_dst
.data
, pinfo
->dl_dst
.len
);
515 p_add_proto_data(wmem_file_scope(), pinfo
, proto_bluetooth
, BLUETOOTH_DATA_DST
, addr
);
518 sub_item
= proto_tree_add_ether(bthci_acl_tree
, hf_bthci_acl_src_bd_addr
, tvb
, 0, 0, src_bd_addr
);
519 proto_item_set_generated(sub_item
);
521 sub_item
= proto_tree_add_string(bthci_acl_tree
, hf_bthci_acl_src_name
, tvb
, 0, 0, src_name
);
522 proto_item_set_generated(sub_item
);
524 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_src_role
, tvb
, 0, 0, src_role
);
525 proto_item_set_generated(sub_item
);
527 sub_item
= proto_tree_add_ether(bthci_acl_tree
, hf_bthci_acl_dst_bd_addr
, tvb
, 0, 0, dst_bd_addr
);
528 proto_item_set_generated(sub_item
);
530 sub_item
= proto_tree_add_string(bthci_acl_tree
, hf_bthci_acl_dst_name
, tvb
, 0, 0, dst_name
);
531 proto_item_set_generated(sub_item
);
533 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_dst_role
, tvb
, 0, 0, dst_role
);
534 proto_item_set_generated(sub_item
);
536 if (role_last_change_in_frame
> 0) {
537 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_role_last_change_in_frame
, tvb
, 0, 0, role_last_change_in_frame
);
538 proto_item_set_generated(sub_item
);
541 sub_item
= proto_tree_add_int(bthci_acl_tree
, hf_bthci_acl_mode
, tvb
, 0, 0, mode
);
542 proto_item_set_generated(sub_item
);
544 if (mode_last_change_in_frame
> 0) {
545 sub_item
= proto_tree_add_uint(bthci_acl_tree
, hf_bthci_acl_mode_last_change_in_frame
, tvb
, 0, 0, mode_last_change_in_frame
);
546 proto_item_set_generated(sub_item
);
549 return tvb_captured_length(tvb
);
554 proto_register_bthci_acl(void)
556 module_t
*bthci_acl_module
;
557 expert_module_t
*bthci_acl_expert_module
;
558 /* Setup list of header fields See Section 1.6.1 for details*/
559 static hf_register_info hf
[] = {
560 { &hf_bthci_acl_chandle
,
561 { "Connection Handle", "bthci_acl.chandle",
562 FT_UINT16
, BASE_HEX
, NULL
, 0x0FFF,
565 { &hf_bthci_acl_pb_flag
,
566 { "PB Flag", "bthci_acl.pb_flag",
567 FT_UINT16
, BASE_DEC
, VALS(pb_flag_vals
), 0x3000,
568 "Packet Boundary Flag", HFILL
}
570 { &hf_bthci_acl_bc_flag
,
571 { "BC Flag", "bthci_acl.bc_flag",
572 FT_UINT16
, BASE_DEC
, VALS(bc_flag_vals
), 0xC000,
573 "Broadcast Flag", HFILL
}
575 { &hf_bthci_acl_length
,
576 { "Data Total Length", "bthci_acl.length",
577 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
580 { &hf_bthci_acl_data
,
581 { "Data", "bthci_acl.data",
582 FT_NONE
, BASE_NONE
, NULL
, 0x0,
585 { &hf_bthci_acl_continuation_to
,
586 { "This is a continuation to the PDU in frame", "bthci_acl.continuation_to",
587 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
588 "This is a continuation to the PDU in frame #", HFILL
}
590 { &hf_bthci_acl_reassembled_in
,
591 { "This PDU is reassembled in frame", "bthci_acl.reassembled_in",
592 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
593 "This PDU is reassembled in frame #", HFILL
}
595 { &hf_bthci_acl_connect_in
,
596 { "Connect in frame", "bthci_acl.connect_in",
597 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
600 { &hf_bthci_acl_disconnect_in
,
601 { "Disconnect in frame", "bthci_acl.disconnect_in",
602 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
605 { &hf_bthci_acl_src_bd_addr
,
606 { "Source BD_ADDR", "bthci_acl.src.bd_addr",
607 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
610 { &hf_bthci_acl_src_name
,
611 { "Source Device Name", "bthci_acl.src.name",
612 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
615 { &hf_bthci_acl_src_role
,
616 { "Source Role", "bthci_acl.src.role",
617 FT_UINT32
, BASE_DEC
, VALS(role_vals
), 0x0,
620 { &hf_bthci_acl_dst_bd_addr
,
621 { "Destination BD_ADDR", "bthci_acl.dst.bd_addr",
622 FT_ETHER
, BASE_NONE
, NULL
, 0x0,
625 { &hf_bthci_acl_dst_name
,
626 { "Destination Device Name", "bthci_acl.dst.name",
627 FT_STRINGZ
, BASE_NONE
, NULL
, 0x0,
630 { &hf_bthci_acl_dst_role
,
631 { "Destination Role", "bthci_acl.dst.role",
632 FT_UINT32
, BASE_DEC
, VALS(role_vals
), 0x0,
635 { &hf_bthci_acl_role_last_change_in_frame
,
636 { "Last Role Change in Frame", "bthci_acl.last_change_in_frame.role",
637 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
640 { &hf_bthci_acl_mode
,
641 { "Current Mode", "bthci_acl.mode",
642 FT_INT32
, BASE_DEC
, VALS(mode_vals
), 0x0,
645 { &hf_bthci_acl_mode_last_change_in_frame
,
646 { "Last Mode Change in Frame", "bthci_acl.last_change_in_frame.mode",
647 FT_FRAMENUM
, BASE_NONE
, NULL
, 0x0,
652 /* Setup protocol subtree array */
653 static int *ett
[] = {
657 static ei_register_info ei
[] = {
658 { &ei_invalid_session
, { "bthci_acl.invalid_session", PI_PROTOCOL
, PI_ERROR
, "Frame is out of any \"connection handle\" session", EXPFILL
}},
659 { &ei_length_bad
, { "bthci_acl.length.bad", PI_MALFORMED
, PI_WARN
, "Length too short", EXPFILL
}},
662 /* Register the protocol name and description */
663 proto_bthci_acl
= proto_register_protocol("Bluetooth HCI ACL Packet", "HCI_ACL", "bthci_acl");
664 bthci_acl_handle
= register_dissector("bthci_acl", dissect_bthci_acl
, proto_bthci_acl
);
666 /* Required function calls to register the header fields and subtrees used */
667 proto_register_field_array(proto_bthci_acl
, hf
, array_length(hf
));
668 proto_register_subtree_array(ett
, array_length(ett
));
670 bthci_acl_expert_module
= expert_register_protocol(proto_bthci_acl
);
671 expert_register_field_array(bthci_acl_expert_module
, ei
, array_length(ei
));
673 /* Register configuration preferences */
674 bthci_acl_module
= prefs_register_protocol_subtree("Bluetooth", proto_bthci_acl
, NULL
);
675 prefs_register_bool_preference(bthci_acl_module
, "hci_acl_reassembly",
676 "Reassemble ACL Fragments",
677 "Whether the ACL dissector should reassemble fragmented PDUs",
680 chandle_tree
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
685 proto_reg_handoff_bthci_acl(void)
687 dissector_add_uint("hci_h4.type", HCI_H4_TYPE_ACL
, bthci_acl_handle
);
688 dissector_add_uint("hci_h1.type", BTHCI_CHANNEL_ACL
, bthci_acl_handle
);
690 btl2cap_handle
= find_dissector_add_dependency("btl2cap", proto_bthci_acl
);
694 * Editor modelines - https://www.wireshark.org/tools/modelines.html
699 * indent-tabs-mode: nil
702 * vi: set shiftwidth=4 tabstop=8 expandtab:
703 * :indentSize=4:tabSize=8:noTabs=true: