diff --git a/epan/dissectors/CMakeLists.txt b/epan/dissectors/CMakeLists.txt index ce9d7f921d..e4eb0457d9 100644 --- a/epan/dissectors/CMakeLists.txt +++ b/epan/dissectors/CMakeLists.txt @@ -779,6 +779,7 @@ set(DISSECTOR_SRC ${CMAKE_CURRENT_SOURCE_DIR}/packet-btl2cap.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-btle.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-btle_rf.c + ${CMAKE_CURRENT_SOURCE_DIR}/packet-btlmp.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-btmesh.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-btmesh-pbadv.c ${CMAKE_CURRENT_SOURCE_DIR}/packet-btmesh-provisioning.c diff --git a/epan/dissectors/packet-btbredr_rf.c b/epan/dissectors/packet-btbredr_rf.c index 8fcdae55b9..41b260ff58 100644 --- a/epan/dissectors/packet-btbredr_rf.c +++ b/epan/dissectors/packet-btbredr_rf.c @@ -1,6 +1,7 @@ /* packet-btbredr_rf.c * Routines for Bluetooth Pseudoheader for BR/EDR Baseband * + * Copyright 2020, Thomas Sailer * Copyright 2014, Michal Labedzki for Tieto Corporation * Copyright 2014, Dominic Spill * @@ -15,12 +16,21 @@ #include #include +#include +#include #include #include "packet-bluetooth.h" +#include "packet-bthci_acl.h" + +/* + * Future Improvements: + * - De-Whiten if the capture hardware did not already do it and we have the UAP + */ static int proto_btbredr_rf = -1; +static int proto_btbredr_fhs = -1; static int hf_rf_channel = -1; static int hf_uncertain_rf_channel = -1; @@ -41,6 +51,7 @@ static int hf_invalid_reference_lower_address_part = -1; static int hf_reference_upper_addres_part = -1; static int hf_invalid_reference_upper_addres_part = -1; static int hf_whitened_packet_header = -1; +static int hf_invalid_packet_header = -1; static int hf_packet_header = -1; static int hf_packet_header_reserved = -1; static int hf_packet_header_lt_addr = -1; @@ -57,6 +68,20 @@ static int hf_packet_header_flow_control = -1; static int hf_packet_header_acknowledge_indication = -1; static int hf_packet_header_sequence_number = -1; static int hf_packet_header_header_error_check = -1; +static int hf_packet_header_broken_lt_addr = -1; +static int hf_packet_header_broken_type = -1; +static int hf_packet_header_broken_type_any = -1; +static int hf_packet_header_broken_type_sco_br = -1; +static int hf_packet_header_broken_type_esco_br = -1; +static int hf_packet_header_broken_type_esco_edr = -1; +static int hf_packet_header_broken_type_acl_br = -1; +static int hf_packet_header_broken_type_acl_edr = -1; +static int hf_packet_header_broken_type_csb_br = -1; +static int hf_packet_header_broken_type_csb_edr = -1; +static int hf_packet_header_broken_flow_control = -1; +static int hf_packet_header_broken_acknowledge_indication = -1; +static int hf_packet_header_broken_sequence_number = -1; +static int hf_packet_header_broken_header_error_check = -1; static int hf_flags = -1; static int hf_flags_reserved_15_14 = -1; static int hf_flags_mic_pass = -1; @@ -76,6 +101,41 @@ static int hf_flags_packet_header_and_br_edr_payload_dewhitened = -1; static int hf_whitened_data = -1; static int hf_encrypted_data = -1; static int hf_data = -1; +static int hf_isochronous_data = -1; +static int hf_asynchronous_data = -1; +static int hf_l2cap_fragment = -1; +static int hf_crc = -1; +static int hf_payload_header2 = -1; +static int hf_payload_header2_llid = -1; +static int hf_payload_header2_flow = -1; +static int hf_payload_header2_length = -1; +static int hf_payload_header2_rfu = -1; +static int hf_payload_header1 = -1; +static int hf_payload_header1_llid = -1; +static int hf_payload_header1_flow = -1; +static int hf_payload_header1_length = -1; +static int hf_l2cap_msg_fragments = -1; +static int hf_l2cap_msg_fragment = -1; +static int hf_l2cap_msg_fragment_overlap = -1; +static int hf_l2cap_msg_fragment_overlap_conflicts = -1; +static int hf_l2cap_msg_fragment_multiple_tails = -1; +static int hf_l2cap_msg_fragment_too_long_fragment = -1; +static int hf_l2cap_msg_fragment_error = -1; +static int hf_l2cap_msg_fragment_count = -1; +static int hf_l2cap_msg_reassembled_in = -1; +static int hf_l2cap_msg_reassembled_length = -1; +static int hf_fhs_parity = -1; +static int hf_fhs_lap = -1; +static int hf_fhs_eir = -1; +static int hf_fhs_reserved = -1; +static int hf_fhs_sr = -1; +static int hf_fhs_sp = -1; +static int hf_fhs_uap = -1; +static int hf_fhs_nap = -1; +static int hf_fhs_class = -1; +static int hf_fhs_ltaddr = -1; +static int hf_fhs_clk = -1; +static int hf_fhs_pagescanmode = -1; #define FLAGS_MIC_PASS 0x2000 #define FLAGS_MIC_CHECKED 0x1000 @@ -102,12 +162,21 @@ static expert_field ei_unexpected_data = EI_INIT; static expert_field ei_reserved_not_zero = EI_INIT; static expert_field ei_incorrect_packet_header_or_hec = EI_INIT; static expert_field ei_packet_header_with_hec_not_checked = EI_INIT; +static expert_field ei_broken_packet_header_format = EI_INIT; +static expert_field ei_incorrect_crc = EI_INIT; +static expert_field ei_missing_fragment_start = EI_INIT; +static expert_field ei_esco_incorrect_ltaddr = EI_INIT; +static expert_field ei_esco_incorrect_length = EI_INIT; static gint ett_btbredr_rf = -1; static gint ett_flags = -1; static gint ett_payload_transport_rate = -1; static gint ett_packet_header = -1; static gint ett_bluetooth_header = -1; +static gint ett_payload_header = -1; +static gint ett_l2cap_msg_fragment = -1; +static gint ett_l2cap_msg_fragments = -1; +static gint ett_btbredr_fhs = -1; static dissector_table_t packet_type_sco_br_table; static dissector_table_t packet_type_esco_br_table; @@ -117,7 +186,85 @@ static dissector_table_t packet_type_acl_edr_table; static dissector_table_t packet_type_csb_br_table; static dissector_table_t packet_type_csb_edr_table; +static dissector_handle_t btlmp_handle; +static dissector_handle_t btl2cap_handle; + static dissector_handle_t btbredr_rf_handle; +static dissector_handle_t btbredr_fhs_handle; + +static wmem_tree_t *connection_info_tree; +static wmem_tree_t *device_info_tree; + +typedef struct _device_info_t { + guint32 interface_id; + guint32 adapter_id; + guint8 bd_addr[6]; + gint8 dir; +} device_info_t; + +typedef struct _reassembly_t { + guint segment_len_rem; + guint32 l2cap_index; + guint seqn : 1; +} reassembly_t; + +#define BDADDR_MASTER 0 +#define BDADDR_SLAVE 1 + +typedef struct _connection_info_t { + reassembly_t reassembly[2]; + nstime_t timestamp; + guint32 btclock; + guint32 interface_id; + guint32 adapter_id; + guint16 escosize[2]; + guint8 bd_addr[2][6]; + guint8 lt_addr; + guint8 escohandle; + guint8 esco : 1; +} connection_info_t; + +typedef struct _btbredr_frame_info_t { + guint retransmit : 1; /* 0 = No, 1 = Retransmitted frame */ + guint ack : 1; /* 0 = Nack, 1 = Ack */ + guint more_fragments : 1; /* 0 = Last fragment, 1 = More fragments */ + guint missing_start : 1; /* 0 = No, 1 = Missing fragment start */ + guint32 l2cap_index; /* Unique identifier for each L2CAP message */ +} btbredr_frame_info_t; + +typedef struct { + bluetooth_data_t *bluetooth_data; + connection_info_t *connection_info; + device_info_t *device_info; +} btbredr_fhs_data_t; + +static const guint8 null_bd_addr[6] = { 0, 0, 0, 0, 0, 0 }; + +/* Reassembly */ +static reassembly_table l2cap_msg_reassembly_table; + +static const fragment_items l2cap_msg_frag_items = { + /* Fragment subtrees */ + &ett_l2cap_msg_fragment, + &ett_l2cap_msg_fragments, + /* Fragment fields */ + &hf_l2cap_msg_fragments, + &hf_l2cap_msg_fragment, + &hf_l2cap_msg_fragment_overlap, + &hf_l2cap_msg_fragment_overlap_conflicts, + &hf_l2cap_msg_fragment_multiple_tails, + &hf_l2cap_msg_fragment_too_long_fragment, + &hf_l2cap_msg_fragment_error, + &hf_l2cap_msg_fragment_count, + /* Reassembled in field */ + &hf_l2cap_msg_reassembled_in, + /* Reassembled length field */ + &hf_l2cap_msg_reassembled_length, + /* Reassembled data field */ + NULL, + /* Tag */ + "BT BR/EDR L2CAP fragments" +}; static const value_string payload_transport_rate_transport_vals[] = { { 0x00, "Any" }, @@ -315,17 +462,32 @@ static const value_string packet_type_csb_edr_vals[] = { { 0, NULL } }; +static const val64_string fhs_scan_repetition_vals[] = { + { 0x00, "R0" }, + { 0x01, "R1" }, + { 0x02, "R2" }, + { 0, NULL } +}; + +static const value_string fhs_page_scan_mode_vals[] = { + { 0x00, "Mandatory Scan Mode" }, + { 0, NULL } +}; + void proto_register_btbredr_rf(void); void proto_reg_handoff_btbredr_rf(void); -static guint8 reverse_bits(guint8 value) +static guint8 +reverse_bits(guint8 value) { - return (value & 0x80) >> 7 | (value & 0x40) >> 5 | (value & 0x20) >> 3 | - (value & 0x10) >> 1 | (value & 0x08) << 1 | (value & 0x04) << 3 | - (value & 0x02) << 5 | (value & 0x01) << 7; + value = ((value >> 1) & 0x55) | ((value << 1) & 0xaa); + value = ((value >> 2) & 0x33) | ((value << 2) & 0xcc); + value = ((value >> 4) & 0x0f) | ((value << 4) & 0xf0); + return value; } -static gboolean check_hec(guint8 uap, guint32 header) +static gboolean +broken_check_hec(guint8 uap, guint32 header) { guint8 hec; guint16 header_data; @@ -349,25 +511,206 @@ static gboolean check_hec(guint8 uap, guint32 header) return lfsr == hec; } +static gboolean +check_hec(guint8 uap, guint32 header) +{ + static const guint32 crc_poly_rev_bt_hec = 0xe5; + header &= 0x3ffff; + header ^= reverse_bits(uap) & 0xff; + for (guint i = 0; i < 10; ++i, header >>= 1) + if (header & 1) + header ^= (crc_poly_rev_bt_hec << 1); + return !header; +} + +static gboolean +check_crc(guint8 uap, tvbuff_t *tvb, gint offset, gint len) +{ + static const guint16 crc_poly_rev_bt_pdu = 0x8408; + guint16 crc = reverse_bits(uap); + crc <<= 8; + for (; len > 0; --len, ++offset) { + crc ^= tvb_get_guint8(tvb, offset) & 0xff; + for (guint i = 0; i < 8; ++i) { + guint16 x = crc & 1; + crc >>= 1; + crc ^= crc_poly_rev_bt_pdu & -x; + } + } + return !crc; +} + +static guint32 +extract_lap(const guint8 bd_addr[6]) +{ + guint32 lap = bd_addr[3]; + lap <<= 8; + lap |= bd_addr[4]; + lap <<= 8; + lap |= bd_addr[5]; + return lap; +} + +static gboolean +is_reserved_lap(guint32 lap) +{ + return (lap >= 0x9e8b00) && (lap <= 0x9e8b3f); +} + +static connection_info_t * +lookup_connection_info(guint32 interface_id, guint32 adapter_id, guint32 lap, guint32 ltaddr, guint32 pktnum) +{ + connection_info_t *cinfo; + wmem_tree_key_t key[6]; + key[0].length = 1; + key[0].key = &interface_id; + key[1].length = 1; + key[1].key = &adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 1; + key[3].key = <addr; + key[4].length = 1; + key[4].key = &pktnum; + key[5].length = 0; + key[5].key = NULL; + cinfo = (connection_info_t *) wmem_tree_lookup32_array_le(connection_info_tree, key); + if (!cinfo) + return NULL; + if (cinfo->interface_id != interface_id || cinfo->adapter_id != adapter_id || + extract_lap(cinfo->bd_addr[BDADDR_MASTER]) != lap || cinfo->lt_addr != ltaddr) + return NULL; + return cinfo; +} + +connection_info_t * +btbredr_rf_add_esco_link(connection_info_t *cinfo, packet_info *pinfo, guint8 handle, guint32 ltaddr, guint16 pktszms, guint16 pktszsm) +{ + connection_info_t *ecinfo; + guint32 lap; + wmem_tree_key_t key[6]; + if (!cinfo || !pinfo || ltaddr >= 8 || !ltaddr) + return NULL; + lap = extract_lap(cinfo->bd_addr[BDADDR_MASTER]); + ecinfo = lookup_connection_info(cinfo->interface_id, cinfo->adapter_id, lap, ltaddr, pinfo->num); + if (ecinfo && (memcmp(cinfo->bd_addr[BDADDR_MASTER], ecinfo->bd_addr[BDADDR_MASTER], 6) || + memcmp(cinfo->bd_addr[BDADDR_SLAVE], ecinfo->bd_addr[BDADDR_SLAVE], 6) || + !ecinfo->esco || ecinfo->escohandle != handle || ecinfo->escosize[0] != pktszms || + ecinfo->escosize[1] != pktszsm)) + ecinfo = NULL; + if (ecinfo) + return ecinfo; + ecinfo = wmem_new0(wmem_file_scope(), connection_info_t); + ecinfo->interface_id = cinfo->interface_id; + ecinfo->adapter_id = cinfo->adapter_id; + ecinfo->lt_addr = ltaddr; + ecinfo->timestamp = cinfo->timestamp; + ecinfo->btclock = cinfo->btclock; + memcpy(ecinfo->bd_addr[BDADDR_MASTER], cinfo->bd_addr[BDADDR_MASTER], 6); + memcpy(ecinfo->bd_addr[BDADDR_SLAVE], cinfo->bd_addr[BDADDR_SLAVE], 6); + ecinfo->escosize[0] = pktszms; + ecinfo->escosize[1] = pktszsm; + ecinfo->escohandle = handle; + ecinfo->esco = 1; + key[0].length = 1; + key[0].key = &cinfo->interface_id; + key[1].length = 1; + key[1].key = &cinfo->adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 1; + key[3].key = <addr; + key[4].length = 1; + key[4].key = &pinfo->num; + key[5].length = 0; + key[5].key = NULL; + wmem_tree_insert32_array(connection_info_tree, key, ecinfo); + return ecinfo; +} + +void +btbredr_rf_remove_esco_link(connection_info_t *cinfo, packet_info *pinfo, guint8 handle) +{ + connection_info_t *ecinfo; + guint32 lap; + wmem_tree_key_t key[6]; + if (!cinfo || !pinfo) + return; + lap = extract_lap(cinfo->bd_addr[BDADDR_MASTER]); + for (guint32 ltaddr = 1; ltaddr < 8; ++ltaddr) { + ecinfo = lookup_connection_info(cinfo->interface_id, cinfo->adapter_id, lap, ltaddr, pinfo->num); + if (!ecinfo) + continue; + if (memcmp(cinfo->bd_addr[BDADDR_MASTER], ecinfo->bd_addr[BDADDR_MASTER], 6) || + memcmp(cinfo->bd_addr[BDADDR_SLAVE], ecinfo->bd_addr[BDADDR_SLAVE], 6) || + !ecinfo->esco || ecinfo->escohandle != handle) + continue; + key[0].length = 1; + key[0].key = &cinfo->interface_id; + key[1].length = 1; + key[1].key = &cinfo->adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 1; + key[3].key = <addr; + key[4].length = 1; + key[4].key = &pinfo->num; + key[5].length = 0; + key[5].key = NULL; + wmem_tree_insert32_array(connection_info_tree, key, ecinfo); + } +} + static gint dissect_btbredr_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { - proto_item *btbredr_rf_item; - proto_tree *btbredr_rf_tree; - proto_item *flags_item; - proto_tree *flags_tree; - proto_item *header_item; - proto_tree *header_tree; - proto_item *reserved_item; - proto_item *hec_item = NULL; - gint offset = 0; - gint hf_x; - guint16 flags; - guint8 payload_and_transport; - gint16 packet_type = PACKET_TYPE_UNKNOWN; - const gchar *packet_type_str = "Unknown"; - dissector_table_t packet_type_table = NULL; - bluetooth_data_t *bluetooth_data = (bluetooth_data_t *) data; + proto_item *btbredr_rf_item; + proto_tree *btbredr_rf_tree; + proto_item *flags_item; + proto_tree *flags_tree; + proto_item *header_item = NULL; + proto_tree *header_tree; + proto_item *reserved_item; + proto_item *hec_item = NULL; + gint offset = 0; + gint hf_x; + gint header_mode; + guint32 interface_id; + guint32 adapter_id; + guint16 flags; + guint32 lap; + guint8 uap = 0; + guint32 ltaddr; + guint8 payload_and_transport; + gint16 packet_type = PACKET_TYPE_UNKNOWN; + const gchar *packet_type_str = "Unknown"; + dissector_table_t packet_type_table = NULL; + gboolean decrypted; + gint isochronous_length = 0; + gboolean isochronous_crc = FALSE; + gboolean isochronous_esco = FALSE; + gint data_length = 0; + gint data_header = 0; + gboolean data_crc = FALSE; + gboolean arqn = FALSE; + gboolean seqn = FALSE; + gint direction = -1; + btbredr_frame_info_t *frame_info = NULL; + connection_info_t *connection_info = NULL; + device_info_t *device_info = NULL; + bluetooth_data_t *bluetooth_data = (bluetooth_data_t *) data; + + if (bluetooth_data) + interface_id = bluetooth_data->interface_id; + else if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) + interface_id = pinfo->rec->rec_header.packet_header.interface_id; + else + interface_id = HCI_INTERFACE_DEFAULT; + + if (bluetooth_data) + adapter_id = bluetooth_data->adapter_id; + else + adapter_id = HCI_ADAPTER_DEFAULT; btbredr_rf_item = proto_tree_add_item(tree, proto_btbredr_rf, tvb, offset, -1, ENC_NA); btbredr_rf_tree = proto_item_add_subtree(btbredr_rf_item, ett_btbredr_rf); @@ -425,8 +768,28 @@ dissect_btbredr_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da offset += 2; proto_tree_add_item(btbredr_rf_tree, hf_lower_address_part, tvb, offset, 4, ENC_LITTLE_ENDIAN); + lap = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) & 0xffffff; offset += 4; + if (!is_reserved_lap(lap)) { + wmem_tree_key_t key[4]; + key[0].length = 1; + key[0].key = &interface_id; + key[1].length = 1; + key[1].key = &adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 0; + key[3].key = NULL; + + device_info = (device_info_t *) wmem_tree_lookup32_array(device_info_tree, key); + } + + if (device_info) { + direction = (device_info->dir == pinfo->p2p_dir) ? BDADDR_MASTER : BDADDR_SLAVE; + uap = device_info->bd_addr[2]; + } + if (flags & FLAGS_REFERENCE_LOWER_ADDRESS_PART_VALID) hf_x = hf_reference_lower_address_part; else @@ -434,69 +797,164 @@ dissect_btbredr_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da proto_tree_add_item(btbredr_rf_tree, hf_x, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; - if (flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) + if (flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) { hf_x = hf_reference_upper_addres_part; - else + uap = tvb_get_guint8(tvb, offset); + } else { hf_x = hf_invalid_reference_upper_addres_part; + } proto_tree_add_item(btbredr_rf_tree, hf_x, tvb, offset, 1, ENC_NA); offset += 1; - if (!(flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED)) { - proto_tree_add_item(btbredr_rf_tree, hf_whitened_packet_header, tvb, offset, 4, ENC_LITTLE_ENDIAN); - } else { + { + guint32 hdr = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); + gboolean have_uap = device_info || !!(flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID); + gboolean is_inquiry = is_reserved_lap(lap); + gboolean is_inquiry_fhs = is_inquiry && (((hdr >> 3) & 0x0f) == 2); + gboolean is_inquiry_broken_fhs = is_inquiry && (((hdr >> 11) & 0x0f) == 2); + if (is_inquiry && !(is_inquiry_fhs || is_inquiry_broken_fhs)) + header_mode = -2; + else if (!(flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED)) + header_mode = -1; + else if ((have_uap || is_inquiry_fhs) && check_hec(is_inquiry_fhs ? 0 : uap, hdr)) + header_mode = 1; + else if ((have_uap || is_inquiry_broken_fhs) && broken_check_hec(is_inquiry_broken_fhs ? 0 : uap, hdr)) + header_mode = 2; + else if (!have_uap) + header_mode = -1; + else + header_mode = 0; + } + + decrypted = !!(flags & FLAGS_BREDR_PAYLOAD_DECRYPTED); + + if (header_mode == -1) { + proto_tree_add_item(btbredr_rf_tree, hf_whitened_packet_header, tvb, offset, 4, ENC_LITTLE_ENDIAN); + } else if (header_mode == -2) { + proto_tree_add_item(btbredr_rf_tree, hf_invalid_packet_header, tvb, offset, 4, ENC_LITTLE_ENDIAN); + } else if (header_mode == 2) { + // broken header format header_item = proto_tree_add_item(btbredr_rf_tree, hf_packet_header, tvb, offset, 4, ENC_LITTLE_ENDIAN); header_tree = proto_item_add_subtree(header_item, ett_bluetooth_header); proto_tree_add_item(header_tree, hf_packet_header_reserved, tvb, offset, 4, ENC_LITTLE_ENDIAN); - proto_tree_add_item(header_tree, hf_packet_header_lt_addr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_lt_addr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + ltaddr = (tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) >> 15) & 7; + arqn = (tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) >> 9) & 1; + seqn = (tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) >> 8) & 1; if (payload_and_transport == (TRANSPORT_SCO | PAYLOAD_BR)) { - proto_tree_add_item(header_tree, hf_packet_header_type_sco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_sco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_sco_br_vals, "Unknown"); packet_type_table = packet_type_sco_br_table; } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_BR)) { - proto_tree_add_item(header_tree, hf_packet_header_type_esco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_esco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_esco_br_vals, "Unknown"); packet_type_table = packet_type_esco_br_table; } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_3)) { - proto_tree_add_item(header_tree, hf_packet_header_type_esco_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_esco_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_esco_edr_vals, "Unknown"); packet_type_table = packet_type_esco_edr_table; } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_BR)) { - proto_tree_add_item(header_tree, hf_packet_header_type_acl_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_acl_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_acl_br_vals, "Unknown"); packet_type_table = packet_type_acl_br_table; } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { - proto_tree_add_item(header_tree, hf_packet_header_type_acl_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_acl_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_acl_edr_vals, "Unknown"); packet_type_table = packet_type_acl_edr_table; } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_BR)) { - proto_tree_add_item(header_tree, hf_packet_header_type_csb_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_csb_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_csb_br_vals, "Unknown"); packet_type_table = packet_type_csb_br_table; } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { - proto_tree_add_item(header_tree, hf_packet_header_type_csb_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_csb_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_csb_edr_vals, "Unknown"); packet_type_table = packet_type_csb_edr_table; } else if ((payload_and_transport >> 4) == TRANSPORT_ANY) { - proto_tree_add_item(header_tree, hf_packet_header_type_any, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_type_any, tvb, offset, 4, ENC_LITTLE_ENDIAN); packet_type = (tvb_get_guint8(tvb, offset + 1) >> 3) & 0xF; packet_type_str = val_to_str_const(packet_type, packet_type_any_vals, "Unknown"); + } else { + proto_tree_add_item(header_tree, hf_packet_header_broken_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); + } + + proto_tree_add_item(header_tree, hf_packet_header_broken_flow_control, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_acknowledge_indication, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_broken_sequence_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); + hec_item = proto_tree_add_item(header_tree, hf_packet_header_broken_header_error_check, tvb, offset, 4, ENC_LITTLE_ENDIAN); + } else if (header_mode >= 0) { + // header format according to Core_v5.2.pdf Vol 2 Part B Chapter 6.4 + header_item = proto_tree_add_item(btbredr_rf_tree, hf_packet_header, tvb, offset, 4, ENC_LITTLE_ENDIAN); + header_tree = proto_item_add_subtree(header_item, ett_bluetooth_header); + + proto_tree_add_item(header_tree, hf_packet_header_lt_addr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + ltaddr = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) & 7; + arqn = (tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) >> 8) & 1; + seqn = (tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN) >> 9) & 1; + + if (payload_and_transport == (TRANSPORT_SCO | PAYLOAD_BR)) { + proto_tree_add_item(header_tree, hf_packet_header_type_sco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_sco_br_vals, "Unknown"); + packet_type_table = packet_type_sco_br_table; + } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_BR)) { + proto_tree_add_item(header_tree, hf_packet_header_type_esco_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_esco_br_vals, "Unknown"); + packet_type_table = packet_type_esco_br_table; + } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_3)) { + proto_tree_add_item(header_tree, hf_packet_header_type_esco_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_esco_edr_vals, "Unknown"); + packet_type_table = packet_type_esco_edr_table; + } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_BR)) { + proto_tree_add_item(header_tree, hf_packet_header_type_acl_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_acl_br_vals, "Unknown"); + packet_type_table = packet_type_acl_br_table; + } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { + proto_tree_add_item(header_tree, hf_packet_header_type_acl_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_acl_edr_vals, "Unknown"); + packet_type_table = packet_type_acl_edr_table; + } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_BR)) { + proto_tree_add_item(header_tree, hf_packet_header_type_csb_br, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_csb_br_vals, "Unknown"); + packet_type_table = packet_type_csb_br_table; + } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { + proto_tree_add_item(header_tree, hf_packet_header_type_csb_edr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_csb_edr_vals, "Unknown"); + packet_type_table = packet_type_csb_edr_table; + } else if ((payload_and_transport >> 4) == TRANSPORT_ANY) { + proto_tree_add_item(header_tree, hf_packet_header_type_any, tvb, offset, 4, ENC_LITTLE_ENDIAN); + + packet_type = (tvb_get_guint8(tvb, offset) >> 3) & 0xF; + packet_type_str = val_to_str_const(packet_type, packet_type_any_vals, "Unknown"); } else { proto_tree_add_item(header_tree, hf_packet_header_type, tvb, offset, 4, ENC_LITTLE_ENDIAN); } @@ -505,18 +963,52 @@ dissect_btbredr_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da proto_tree_add_item(header_tree, hf_packet_header_acknowledge_indication, tvb, offset, 4, ENC_LITTLE_ENDIAN); proto_tree_add_item(header_tree, hf_packet_header_sequence_number, tvb, offset, 4, ENC_LITTLE_ENDIAN); hec_item = proto_tree_add_item(header_tree, hf_packet_header_header_error_check, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(header_tree, hf_packet_header_reserved, tvb, offset, 4, ENC_LITTLE_ENDIAN); } - if ((flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) && - (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED) && - !check_hec(tvb_get_guint8(tvb, offset - 1), tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN))) { - expert_add_info(pinfo, hec_item, &ei_incorrect_packet_header_or_hec); - } - if (!((flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) && - (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED))) { + switch (header_mode) { + case -2: + col_set_str(pinfo->cinfo, COL_INFO, (lap == 0x9e8b33) ? "GIAC" : "DIAC"); + break; + + case -1: expert_add_info(pinfo, hec_item, &ei_packet_header_with_hec_not_checked); + break; + + case 0: + expert_add_info(pinfo, hec_item, &ei_incorrect_packet_header_or_hec); + break; + + case 2: + expert_add_info(pinfo, header_item, &ei_broken_packet_header_format); + break; + + default: + break; } + if (header_mode > 0 && ltaddr) + connection_info = lookup_connection_info(interface_id, adapter_id, lap, ltaddr, pinfo->num); + + if (connection_info && direction >= 0) { + set_address(&pinfo->dl_src, AT_ETHER, sizeof(connection_info->bd_addr[0]), connection_info->bd_addr[direction]); + set_address(&pinfo->dl_dst, AT_ETHER, sizeof(connection_info->bd_addr[0]), connection_info->bd_addr[1 - direction]); + set_address(&pinfo->net_src, AT_ETHER, sizeof(connection_info->bd_addr[0]), connection_info->bd_addr[direction]); + set_address(&pinfo->net_dst, AT_ETHER, sizeof(connection_info->bd_addr[0]), connection_info->bd_addr[1 - direction]); + } else { + clear_address(&pinfo->dl_dst); + clear_address(&pinfo->net_dst); + if (header_mode > 0 && !ltaddr && device_info) { + set_address(&pinfo->dl_src, AT_ETHER, sizeof(device_info->bd_addr), device_info->bd_addr); + set_address(&pinfo->net_src, AT_ETHER, sizeof(device_info->bd_addr), device_info->bd_addr); + } else { + clear_address(&pinfo->dl_src); + clear_address(&pinfo->net_src); + } + } + copy_address_shallow(&pinfo->src, &pinfo->net_src); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + offset += 4; flags_item = proto_tree_add_item(btbredr_rf_tree, hf_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN); @@ -560,30 +1052,918 @@ dissect_btbredr_rf(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *da if (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED) col_append_fstr(pinfo->cinfo, COL_INFO, ", Packet Type: %s", packet_type_str); - if (flags & FLAGS_BR_EDR_DATA_PRESENT) { - if (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED) { - if (flags & FLAGS_BREDR_PAYLOAD_DECRYPTED) { - tvbuff_t *next_tvb; + // Packet Type Table + if (payload_and_transport == (TRANSPORT_SCO | PAYLOAD_BR)) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; - next_tvb = tvb_new_subset_remaining(tvb, offset); - if (!(packet_type_table && packet_type > PACKET_TYPE_UNKNOWN && - dissector_try_uint_new(packet_type_table, packet_type, next_tvb, pinfo, tree, TRUE, bluetooth_data))) - proto_tree_add_item(btbredr_rf_tree, hf_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); - offset = tvb_reported_length(tvb); - } else { - proto_tree_add_item(btbredr_rf_tree, hf_encrypted_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); - offset = tvb_reported_length(tvb); - } - } else { - proto_tree_add_item(btbredr_rf_tree, hf_whitened_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); - offset = tvb_reported_length(tvb); + case 2: // FHS + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 0; + data_crc = TRUE; + decrypted = TRUE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + case 5: // HV1 + isochronous_length = 10; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 6: // HV2 + isochronous_length = 20; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 7: // HV3 + isochronous_length = 30; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 8: // DV + isochronous_length = 10; + isochronous_crc = FALSE; + data_length = 10; + data_header = 1; + data_crc = TRUE; + break; + + default: + break; } - } else { - if (tvb_captured_length_remaining(tvb, offset) > 0) - proto_tree_add_expert(btbredr_rf_tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_captured_length_remaining(tvb, offset)); - offset = tvb_reported_length(tvb); - } + } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_BR)) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + case 7: // EV3 + isochronous_length = 30; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 12: // EV4 + isochronous_length = 120; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 13: // EV5 + isochronous_length = 180; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + default: + break; + } + } else if (payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_eSCO | PAYLOAD_EDR_3)) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 6: // 2-EV3 + isochronous_length = 60; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 7: // 3-EV3 + isochronous_length = 90; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 12: // 2-EV5 + isochronous_length = 360; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 13: // 3-EV5 + isochronous_length = 540; + isochronous_crc = TRUE; + isochronous_esco = TRUE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + default: + break; + } + } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_BR)) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 2: // FHS + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 0; + data_crc = TRUE; + decrypted = TRUE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + case 4: // DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 28; + data_header = 1; + data_crc = TRUE; + break; + + case 9: // AUX1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 30; + data_header = 1; + data_crc = FALSE; + break; + + case 10: // DM3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 123; + data_header = 2; + data_crc = TRUE; + break; + + case 11: // DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 185; + data_header = 2; + data_crc = TRUE; + break; + + case 14: // DM5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 226; + data_header = 2; + data_crc = TRUE; + break; + + case 15: // DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 341; + data_header = 2; + data_crc = TRUE; + break; + + default: + break; + } + } else if (payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 2: // FHS + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 0; + data_crc = TRUE; + decrypted = TRUE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + case 4: // 2-DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 56; + data_header = 2; + data_crc = TRUE; + break; + + case 8: // 3-DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 85; + data_header = 2; + data_crc = TRUE; + break; + + case 9: // AUX1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 30; + data_header = 1; + data_crc = FALSE; + break; + + case 10: // 2-DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 369; + data_header = 2; + data_crc = TRUE; + break; + + case 11: // 3-DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 554; + data_header = 2; + data_crc = TRUE; + break; + + case 14: // 2-DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 681; + data_header = 2; + data_crc = TRUE; + break; + + case 15: // 3-DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 1023; + data_header = 2; + data_crc = TRUE; + break; + + default: + break; + } + } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_BR)) { + switch (packet_type) { + case 0: // NULL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + case 4: // DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 28; + data_header = 1; + data_crc = TRUE; + break; + + case 10: // DM3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 123; + data_header = 2; + data_crc = TRUE; + break; + + case 11: // DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 185; + data_header = 2; + data_crc = TRUE; + break; + + case 14: // DM5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 226; + data_header = 2; + data_crc = TRUE; + break; + + case 15: // DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 341; + data_header = 2; + data_crc = TRUE; + break; + + default: + break; + } + } else if (payload_and_transport == (TRANSPORT_CSB | PAYLOAD_EDR_2) || payload_and_transport == (TRANSPORT_ACL | PAYLOAD_EDR_3)) { + switch (packet_type) { + case 0: // NULL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + case 4: // 2-DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 56; + data_header = 2; + data_crc = TRUE; + break; + + case 8: // 3-DH1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 85; + data_header = 2; + data_crc = TRUE; + break; + + case 10: // 2-DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 369; + data_header = 2; + data_crc = TRUE; + break; + + case 11: // 3-DH3 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 554; + data_header = 2; + data_crc = TRUE; + break; + + case 14: // 2-DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 681; + data_header = 2; + data_crc = TRUE; + break; + + case 15: // 3-DH5 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 1023; + data_header = 2; + data_crc = TRUE; + break; + + default: + break; + } + } else if ((payload_and_transport >> 4) == TRANSPORT_ANY) { + switch (packet_type) { + case 0: // NULL + case 1: // POLL + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 0; + data_header = 0; + data_crc = FALSE; + break; + + case 2: // FHS + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 0; + data_crc = TRUE; + decrypted = TRUE; + break; + + case 3: // DM1 + isochronous_length = 0; + isochronous_crc = FALSE; + data_length = 18; + data_header = 1; + data_crc = TRUE; + break; + + default: + break; + } + } + + if (flags & FLAGS_BR_EDR_DATA_PRESENT) { + if (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED) { + if (decrypted) { + tvbuff_t *next_tvb; + + next_tvb = tvb_new_subset_remaining(tvb, offset); + if (packet_type_table && packet_type > PACKET_TYPE_UNKNOWN && + dissector_try_uint_new(packet_type_table, packet_type, next_tvb, pinfo, tree, TRUE, bluetooth_data)) { + offset = tvb_reported_length(tvb); + } else { + if (isochronous_length > 0 && + (!isochronous_crc || (flags & (FLAGS_CRC_PASS | FLAGS_CRC_CHECKED)) == (FLAGS_CRC_PASS | FLAGS_CRC_CHECKED))) { + gint len = tvb_captured_length_remaining(tvb, offset); + if (isochronous_crc) + len -= 2; + if (isochronous_length > len) + isochronous_length = len; + if (isochronous_length > 0) { + //next_tvb = tvb_new_subset_length(tvb, offset, isochronous_length); + proto_item *iso_item = proto_tree_add_item(btbredr_rf_tree, hf_isochronous_data, tvb, offset, isochronous_length, ENC_NA); + if (isochronous_crc) { + proto_item *crc_item = NULL; + crc_item = proto_tree_add_item(btbredr_rf_tree, hf_crc, tvb, offset + isochronous_length, 2, ENC_LITTLE_ENDIAN); + if ((flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) && !check_crc(uap, tvb, offset, isochronous_length + 2)) + expert_add_info(pinfo, crc_item, &ei_incorrect_crc); + offset += 2; + } + offset += isochronous_length; + if (connection_info) { + if (connection_info->esco != isochronous_esco) + expert_add_info(pinfo, iso_item, &ei_esco_incorrect_ltaddr); + if (direction >= 0 && connection_info->esco && + connection_info->escosize[direction] != isochronous_length) + expert_add_info(pinfo, iso_item, &ei_esco_incorrect_length); + } + } + } + if (data_length > 0 && + (!data_crc || (flags & (FLAGS_CRC_PASS | FLAGS_CRC_CHECKED)) == (FLAGS_CRC_PASS | FLAGS_CRC_CHECKED))) { + gint len = tvb_captured_length_remaining(tvb, offset); + gboolean error = FALSE; + gint llid = -1; + if (data_crc) + len -= 2; + if (data_length > len) + data_length = len; + if (data_header > 0) { + if (len < data_header) { + error = TRUE; + } else if (data_header == 1) { + guint8 hdr = tvb_get_guint8(tvb, offset); + llid = hdr & 3; + hdr >>= 3; + hdr &= 0x1f; + ++hdr; + if (hdr > len) + error = TRUE; + else + data_length = hdr; + } else if (data_header == 2) { + guint16 hdr = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); + llid = hdr & 3; + hdr >>= 3; + hdr &= 0x3ff; + hdr += 2; + if (hdr > len) + error = TRUE; + else + data_length = hdr; + } else { + error = TRUE; + } + } + if (data_length > 0 && !error) { + gboolean handled = FALSE; + fragment_head *frag_l2cap_msg = NULL; + if (data_header == 1) { + proto_item *pheader_item = proto_tree_add_item(btbredr_rf_tree, hf_payload_header1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree *pheader_tree = proto_item_add_subtree(pheader_item, ett_payload_header); + proto_tree_add_item(pheader_tree, hf_payload_header1_llid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pheader_tree, hf_payload_header1_flow, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pheader_tree, hf_payload_header1_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } else if (data_header == 2) { + proto_item *pheader_item = proto_tree_add_item(btbredr_rf_tree, hf_payload_header2, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree *pheader_tree = proto_item_add_subtree(pheader_item, ett_payload_header); + proto_tree_add_item(pheader_tree, hf_payload_header2_llid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pheader_tree, hf_payload_header2_flow, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pheader_tree, hf_payload_header2_length, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(pheader_tree, hf_payload_header2_rfu, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + if (!pinfo->fd->visited) { + frame_info = wmem_new0(wmem_file_scope(), btbredr_frame_info_t); + p_add_proto_data(wmem_file_scope(), pinfo, proto_btbredr_rf, pinfo->curr_layer_num, frame_info); + if (connection_info && direction >= 0) { + frame_info->retransmit = (seqn == connection_info->reassembly[direction].seqn); + frame_info->ack = arqn; + frame_info->l2cap_index = pinfo->num; + connection_info->reassembly[direction].seqn = seqn; + } + } else { + frame_info = (btbredr_frame_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_btbredr_rf, pinfo->curr_layer_num); + } + if (packet_type == 2) { + // FHS + next_tvb = tvb_new_subset_length(tvb, offset + data_header, data_length - data_header); + if (next_tvb) { + btbredr_fhs_data_t *fhs_data = wmem_new0(wmem_packet_scope(), btbredr_fhs_data_t); + fhs_data->bluetooth_data = bluetooth_data; + fhs_data->device_info = device_info; + fhs_data->connection_info = connection_info; + call_dissector_with_data(btbredr_fhs_handle, next_tvb, pinfo, tree, fhs_data); + handled = TRUE; + } + } + switch (llid) { + case 0x03: // LMP + if (!btlmp_handle) + break; + next_tvb = tvb_new_subset_length(tvb, offset + data_header, data_length - data_header); + if (!next_tvb) + break; + call_dissector_with_data(btlmp_handle, next_tvb, pinfo, tree, connection_info); + handled = TRUE; + break; + + case 0x02: // Start of or complete L2CAP message + if (!btl2cap_handle) + break; + if (frame_info && data_length > data_header) { + guint pdu_len = data_length - data_header; + guint l2cap_len = tvb_get_letohs(tvb, offset + data_header); + if (l2cap_len + 4 <= pdu_len) { + bthci_acl_data_t *acl_data = wmem_new(wmem_packet_scope(), bthci_acl_data_t); + acl_data->interface_id = interface_id; + acl_data->adapter_id = adapter_id; + acl_data->chandle = 0; /* No connection handle at this layer */ + acl_data->remote_bd_addr_oui = 0; + acl_data->remote_bd_addr_id = 0; + acl_data->is_btle = TRUE; + acl_data->is_btle_retransmit = FALSE; + acl_data->adapter_disconnect_in_frame = &max_disconnect_in_frame; + acl_data->disconnect_in_frame = &max_disconnect_in_frame; + next_tvb = tvb_new_subset_length(tvb, offset + data_header, pdu_len); + call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data); + handled = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); + if (!pinfo->fd->visited && connection_info && direction >= 0) { + connection_info->reassembly[direction].l2cap_index = pinfo->num; + connection_info->reassembly[direction].segment_len_rem = 0; + } + break; + } + pinfo->fragmented = TRUE; + if (!frame_info->retransmit && connection_info && direction >= 0) { + if (!pinfo->fd->visited) { + connection_info->reassembly[direction].l2cap_index = pinfo->num; + connection_info->reassembly[direction].segment_len_rem = l2cap_len + 4 - pdu_len; + frame_info->more_fragments = 1; + } + frag_l2cap_msg = fragment_add_seq_next(&l2cap_msg_reassembly_table, + tvb, offset + data_header, + pinfo, + frame_info->l2cap_index, /* guint32 ID for fragments belonging together */ + NULL, /* data* */ + pdu_len, /* Fragment length */ + frame_info->more_fragments); /* More fragments */ + process_reassembled_data(tvb, offset + data_header, pinfo, + "Reassembled L2CAP", + frag_l2cap_msg, + &l2cap_msg_frag_items, + NULL, + btbredr_rf_tree); + } + proto_tree_add_item(btbredr_rf_tree, hf_l2cap_fragment, tvb, offset + data_header, pdu_len, ENC_NA); + handled = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment Start"); + } + break; + + case 0x01: /* Continuation fragment of an L2CAP message, or an Empty PDU */ + if (!btl2cap_handle) + break; + if (!frame_info || data_length <= data_header) { + col_set_str(pinfo->cinfo, COL_INFO, "Empty PDU"); + break; + } + pinfo->fragmented = TRUE; + if (!frame_info->retransmit && connection_info && direction >= 0) { + guint pdu_len = data_length - data_header; + if (!pinfo->fd->visited) { + if (connection_info->reassembly[direction].segment_len_rem > 0) { + if (connection_info->reassembly[direction].segment_len_rem >= pdu_len) { + connection_info->reassembly[direction].segment_len_rem -= pdu_len; + frame_info->l2cap_index = connection_info->reassembly[direction].l2cap_index; + } else { + /* + * Missing fragment for previous L2CAP and fragment start for this. + * Set more_fragments and increase l2cap_index to avoid reassembly. + */ + frame_info->more_fragments = 1; + frame_info->missing_start = 1; + connection_info->reassembly[direction].l2cap_index = pinfo->num; + connection_info->reassembly[direction].segment_len_rem = 0; + } + frame_info->more_fragments = (connection_info->reassembly[direction].segment_len_rem > 0); + } else { + /* + * Missing fragment start. + * Set more_fragments and increase l2cap_index to avoid reassembly. + */ + frame_info->more_fragments = 1; + frame_info->missing_start = 1; + connection_info->reassembly[direction].l2cap_index = pinfo->num; + connection_info->reassembly[direction].segment_len_rem = 0; + } + } + frag_l2cap_msg = fragment_add_seq_next(&l2cap_msg_reassembly_table, + tvb, offset + data_header, + pinfo, + frame_info->l2cap_index, /* guint32 ID for fragments belonging together */ + NULL, /* data* */ + pdu_len, /* Fragment length */ + frame_info->more_fragments); /* More fragments */ + next_tvb = process_reassembled_data(tvb, offset, pinfo, + "Reassembled L2CAP", + frag_l2cap_msg, + &l2cap_msg_frag_items, + NULL, + btbredr_rf_tree); + } + if (next_tvb) { + bthci_acl_data_t *acl_data = wmem_new(wmem_packet_scope(), bthci_acl_data_t); + acl_data->interface_id = interface_id; + acl_data->adapter_id = adapter_id; + acl_data->chandle = 0; /* No connection handle at this layer */ + acl_data->remote_bd_addr_oui = 0; + acl_data->remote_bd_addr_id = 0; + acl_data->is_btle = TRUE; + acl_data->is_btle_retransmit = FALSE; + acl_data->adapter_disconnect_in_frame = &max_disconnect_in_frame; + acl_data->disconnect_in_frame = &max_disconnect_in_frame; + call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data); + handled = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); + } else { + proto_item *item = proto_tree_add_item(btbredr_rf_tree, hf_l2cap_fragment, tvb, offset + data_header, data_length - data_header, ENC_NA); + if (frame_info->missing_start) + expert_add_info(pinfo, item, &ei_missing_fragment_start); + handled = TRUE; + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment"); + } + break; + + default: + break; + } + if (!handled) + proto_tree_add_item(btbredr_rf_tree, hf_asynchronous_data, tvb, offset + data_header, data_length - data_header, ENC_NA); + if (data_crc) { + proto_item *crc_item = NULL; + crc_item = proto_tree_add_item(btbredr_rf_tree, hf_crc, tvb, offset + data_length, 2, ENC_LITTLE_ENDIAN); + if ((flags & FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID) && !check_crc(uap, tvb, offset, data_length + 2)) + expert_add_info(pinfo, crc_item, &ei_incorrect_crc); + offset += 2; + } + offset += data_length; + } + } + if (tvb_captured_length_remaining(tvb, offset) > 0) + proto_tree_add_item(btbredr_rf_tree, hf_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + } + } else { + proto_tree_add_item(btbredr_rf_tree, hf_encrypted_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + offset = tvb_reported_length(tvb); + } + } else { + proto_tree_add_item(btbredr_rf_tree, hf_whitened_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + offset = tvb_reported_length(tvb); + } + } else { + if (tvb_captured_length_remaining(tvb, offset) > 0) + proto_tree_add_expert(btbredr_rf_tree, pinfo, &ei_unexpected_data, tvb, offset, tvb_captured_length_remaining(tvb, offset)); + offset = tvb_reported_length(tvb); + } + + if (!pinfo->fd->visited) { + address *addr; + + addr = (address *) wmem_memdup(wmem_file_scope(), &pinfo->dl_src, sizeof(address)); + addr->data = wmem_memdup(wmem_file_scope(), pinfo->dl_src.data, pinfo->dl_src.len); + p_add_proto_data(wmem_file_scope(), pinfo, proto_bluetooth, BLUETOOTH_DATA_SRC, addr); + + addr = (address *) wmem_memdup(wmem_file_scope(), &pinfo->dl_dst, sizeof(address)); + addr->data = wmem_memdup(wmem_file_scope(), pinfo->dl_dst.data, pinfo->dl_dst.len); + p_add_proto_data(wmem_file_scope(), pinfo, proto_bluetooth, BLUETOOTH_DATA_DST, addr); + } + + return offset; +} + +static gint +dissect_btbredr_fhs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + proto_item *btbredr_fhs_item; + proto_tree *btbredr_fhs_tree; + gint offset = 0; + guint32 interface_id; + guint32 adapter_id; + guint64 parity_lap_eir_sp_sr; + guint32 lap; + guint8 uap; + guint16 nap; + guint32 ltaddr_clk_pgscan; + guint32 ltaddr; + device_info_t *device_info = NULL; + connection_info_t *connection_info = NULL; + btbredr_fhs_data_t *fhs_data = (btbredr_fhs_data_t *) data; + + btbredr_fhs_item = proto_tree_add_item(tree, proto_btbredr_fhs, tvb, offset, -1, ENC_NA); + btbredr_fhs_tree = proto_item_add_subtree(btbredr_fhs_item, ett_btbredr_fhs); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT BR/EDR FHS"); + + if (fhs_data->bluetooth_data) + interface_id = fhs_data->bluetooth_data->interface_id; + else if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) + interface_id = pinfo->rec->rec_header.packet_header.interface_id; + else + interface_id = HCI_INTERFACE_DEFAULT; + + if (fhs_data->bluetooth_data) + adapter_id = fhs_data->bluetooth_data->adapter_id; + else + adapter_id = HCI_ADAPTER_DEFAULT; + + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_parity, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_lap, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_eir, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_reserved, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_sr, tvb, offset, 8, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_sp, tvb, offset, 8, ENC_LITTLE_ENDIAN); + parity_lap_eir_sp_sr = tvb_get_guint64(tvb, offset, ENC_LITTLE_ENDIAN); + lap = (parity_lap_eir_sp_sr >> 34) & 0xffffff; + offset += 8; + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_uap, tvb, offset, 1, ENC_LITTLE_ENDIAN); + uap = tvb_get_guint8(tvb, offset); + offset += 1; + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_nap, tvb, offset, 2, ENC_LITTLE_ENDIAN); + nap = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_class, tvb, offset, 3, ENC_LITTLE_ENDIAN); + offset += 3; + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_ltaddr, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_clk, tvb, offset, 4, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btbredr_fhs_tree, hf_fhs_pagescanmode, tvb, offset, 4, ENC_LITTLE_ENDIAN); + ltaddr_clk_pgscan = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); + offset += 4; + ltaddr = ltaddr_clk_pgscan & 0x00000007; + + { + wmem_tree_key_t key[4]; + key[0].length = 1; + key[0].key = &interface_id; + key[1].length = 1; + key[1].key = &adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 0; + key[3].key = NULL; + + device_info = (device_info_t *) wmem_tree_lookup32_array(device_info_tree, key); + if (!device_info && !pinfo->fd->visited) { + device_info = wmem_new0(wmem_file_scope(), device_info_t); + device_info->interface_id = interface_id; + device_info->adapter_id = adapter_id; + device_info->bd_addr[0] = nap >> 8; + device_info->bd_addr[1] = nap >> 0; + device_info->bd_addr[2] = uap; + device_info->bd_addr[3] = lap >> 16; + device_info->bd_addr[4] = lap >> 8; + device_info->bd_addr[5] = lap; + device_info->dir = pinfo->p2p_dir; + wmem_tree_insert32_array(device_info_tree, key, device_info); + } + } + if (ltaddr) { + connection_info = lookup_connection_info(interface_id, adapter_id, lap, ltaddr, pinfo->num); + if (!pinfo->fd->visited) { + if (connection_info && fhs_data->device_info && + !memcmp(connection_info->bd_addr[BDADDR_SLAVE], null_bd_addr, 6)) + memcpy(connection_info->bd_addr[BDADDR_SLAVE], fhs_data->device_info->bd_addr, 6); + if (!connection_info && device_info) { + wmem_tree_key_t key[6]; + key[0].length = 1; + key[0].key = &interface_id; + key[1].length = 1; + key[1].key = &adapter_id; + key[2].length = 1; + key[2].key = ⪅ + key[3].length = 1; + key[3].key = <addr; + key[4].length = 1; + key[4].key = &pinfo->num; + key[5].length = 0; + key[5].key = NULL; + connection_info = wmem_new0(wmem_file_scope(), connection_info_t); + connection_info->interface_id = interface_id; + connection_info->adapter_id = adapter_id; + connection_info->lt_addr = ltaddr; + connection_info->timestamp = pinfo->abs_ts; + connection_info->btclock = (ltaddr_clk_pgscan >> 3) & 0x3ffffff; + memcpy(connection_info->bd_addr[BDADDR_MASTER], device_info->bd_addr, 6); + if (fhs_data->device_info) + memcpy(connection_info->bd_addr[BDADDR_SLAVE], fhs_data->device_info->bd_addr, 6); + wmem_tree_insert32_array(connection_info_tree, key, connection_info); + } + } + } + if (device_info) { + set_address(&pinfo->dl_src, AT_ETHER, sizeof(device_info->bd_addr), device_info->bd_addr); + set_address(&pinfo->net_src, AT_ETHER, sizeof(device_info->bd_addr), device_info->bd_addr); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + } + if (fhs_data->device_info) { + set_address(&pinfo->dl_dst, AT_ETHER, sizeof(fhs_data->device_info->bd_addr), fhs_data->device_info->bd_addr); + set_address(&pinfo->net_dst, AT_ETHER, sizeof(fhs_data->device_info->bd_addr), fhs_data->device_info->bd_addr); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + } return offset; } @@ -688,91 +2068,161 @@ proto_register_btbredr_rf(void) FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL } }, + { &hf_invalid_packet_header, + { "Invalid Packet Header", "btbredr_rf.invalid.packet_header", + FT_UINT32, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, { &hf_packet_header, { "Packet Header", "btbredr_rf.packet_header", FT_UINT32, BASE_HEX, NULL, 0x00, NULL, HFILL } }, + { &hf_packet_header_lt_addr, + { "LT_ADDR", "btbredr_rf.packet_header.lt_addr", + FT_UINT32, BASE_HEX, NULL, 0x00000007, + NULL, HFILL } + }, + { &hf_packet_header_type, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, NULL, 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_any, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_any_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_sco_br, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_sco_br_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_esco_br, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_esco_br_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_esco_edr, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_esco_edr_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_acl_br, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_acl_br_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_acl_edr, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_acl_edr_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_csb_br, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_csb_br_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_type_csb_edr, + { "Type", "btbredr_rf.packet_header.type", + FT_UINT32, BASE_HEX, VALS(packet_type_csb_edr_vals), 0x00000078, + NULL, HFILL } + }, + { &hf_packet_header_flow_control, + { "Flow Control", "btbredr_rf.packet_header.flow_control", + FT_BOOLEAN, 32, NULL, 0x00000080, + NULL, HFILL } + }, + { &hf_packet_header_acknowledge_indication, + { "ARQN", "btbredr_rf.packet_header.arqn", + FT_BOOLEAN, 32, NULL, 0x00000100, + "Acknowledge Indication", HFILL } + }, + { &hf_packet_header_sequence_number, + { "SEQN", "btbredr_rf.packet_header.seqn", + FT_BOOLEAN, 32, NULL, 0x00000200, + "Sequence Number", HFILL } + }, + { &hf_packet_header_header_error_check, + { "HEC", "btbredr_rf.packet_header.hec", + FT_UINT32, BASE_HEX, NULL, 0x0003FC00, + "Header Error Check", HFILL } + }, { &hf_packet_header_reserved, { "Reserved", "btbredr_rf.packet_header.reserved", FT_UINT32, BASE_HEX, NULL, 0xFFFC0000, NULL, HFILL } }, - { &hf_packet_header_lt_addr, + { &hf_packet_header_broken_lt_addr, { "LT_ADDR", "btbredr_rf.packet_header.lt_addr", FT_UINT32, BASE_HEX, NULL, 0x00038000, NULL, HFILL } }, - { &hf_packet_header_type, + { &hf_packet_header_broken_type, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, NULL, 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_any, + { &hf_packet_header_broken_type_any, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_any_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_sco_br, + { &hf_packet_header_broken_type_sco_br, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_sco_br_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_esco_br, + { &hf_packet_header_broken_type_esco_br, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_esco_br_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_esco_edr, + { &hf_packet_header_broken_type_esco_edr, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_esco_edr_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_acl_br, + { &hf_packet_header_broken_type_acl_br, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_acl_br_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_acl_edr, + { &hf_packet_header_broken_type_acl_edr, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_acl_edr_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_csb_br, + { &hf_packet_header_broken_type_csb_br, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_csb_br_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_type_csb_edr, + { &hf_packet_header_broken_type_csb_edr, { "Type", "btbredr_rf.packet_header.type", FT_UINT32, BASE_HEX, VALS(packet_type_csb_edr_vals), 0x00007800, NULL, HFILL } }, - { &hf_packet_header_flow_control, + { &hf_packet_header_broken_flow_control, { "Flow Control", "btbredr_rf.packet_header.flow_control", FT_BOOLEAN, 32, NULL, 0x00000400, NULL, HFILL } }, - { &hf_packet_header_acknowledge_indication, + { &hf_packet_header_broken_acknowledge_indication, { "ARQN", "btbredr_rf.packet_header.arqn", FT_BOOLEAN, 32, NULL, 0x00000200, "Acknowledge Indication", HFILL } }, - { &hf_packet_header_sequence_number, + { &hf_packet_header_broken_sequence_number, { "SEQN", "btbredr_rf.packet_header.seqn", FT_BOOLEAN, 32, NULL, 0x00000100, "Sequence Number", HFILL } }, - { &hf_packet_header_header_error_check, + { &hf_packet_header_broken_header_error_check, { "HEC", "btbredr_rf.packet_header.hec", FT_UINT32, BASE_HEX, NULL, 0x000000FF, "Header Error Check", HFILL } }, - { &hf_flags, - { "Flags", "btbredr_rf.flags", - FT_UINT16, BASE_HEX, NULL, 0x00, - NULL, HFILL } - }, { &hf_whitened_data, { "Whitened Data", "btbredr_rf.whitened.data", FT_NONE, BASE_NONE, NULL, 0x00, @@ -788,6 +2238,31 @@ proto_register_btbredr_rf(void) FT_NONE, BASE_NONE, NULL, 0x00, NULL, HFILL } }, + { &hf_isochronous_data, + { "Isochronous Data", "btbredr_rf.isochronous_data", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_asynchronous_data, + { "Asynchronous Data", "btbredr_rf.asynchronous_data", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_fragment, + { "L2CAP Fragment", "btbredr_rf.l2cap_data", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_crc, + { "CRC", "btbredr_rf.crc", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_flags, + { "Flags", "btbredr_rf.flags", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, { &hf_flags_reserved_15_14, { "Reserved", "btbredr_rf.flags.reserved.15_14", FT_UINT16, BASE_HEX, NULL, 0xC000, @@ -862,6 +2337,164 @@ proto_register_btbredr_rf(void) { "Packet Header and BR/EDR Payload Dewhitened", "btbredr_rf.flags.pkt_hdr_and_br_edr_payload_dewhitened", FT_BOOLEAN, 16, NULL, 0x0001, NULL, HFILL } + }, + { &hf_payload_header2, + { "Payload Header", "btbredr_rf.payload_header", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_payload_header2_llid, + { "LLID", "btbredr_rf.payload_header.llid", + FT_UINT16, BASE_HEX, NULL, 0x0003, + NULL, HFILL } + }, + { &hf_payload_header2_flow, + { "Flow", "btbredr_rf.payload_header.flow", + FT_UINT16, BASE_HEX, NULL, 0x0004, + NULL, HFILL } + }, + { &hf_payload_header2_length, + { "Length", "btbredr_rf.payload_header.length", + FT_UINT16, BASE_HEX, NULL, 0x1ff8, + NULL, HFILL } + }, + { &hf_payload_header2_rfu, + { "RFU", "btbredr_rf.payload_header.rfu", + FT_UINT16, BASE_HEX, NULL, 0xe000, + NULL, HFILL } + }, + { &hf_payload_header1, + { "Payload Header", "btbredr_rf.payload_header", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_payload_header1_llid, + { "LLID", "btbredr_rf.payload_header.llid", + FT_UINT8, BASE_HEX, NULL, 0x03, + NULL, HFILL } + }, + { &hf_payload_header1_flow, + { "Flow", "btbredr_rf.payload_header.flow", + FT_UINT8, BASE_HEX, NULL, 0x04, + NULL, HFILL } + }, + { &hf_payload_header1_length, + { "Length", "btbredr_rf.payload_header.length", + FT_UINT8, BASE_HEX, NULL, 0xf8, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragments, + { "L2CAP fragments", "btbredr_rf.l2cap.fragments", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment, + { "L2CAP fragment", "btbredr_rf.l2cap.fragment", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_overlap, + { "L2CAP fragment overlap", "btbredr_rf.l2cap.fragment.overlap", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_overlap_conflicts, + { "L2CAP fragment overlapping with conflicting data", "btbredr_rf.l2cap.fragment.overlap.conflicts", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_multiple_tails, + { "L2CAP has multiple tail fragments", "btbredr_rf.l2cap.fragment.multiple_tails", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_too_long_fragment, + { "L2CAP fragment too long", "btbredr_rf.l2cap.fragment.too_long_fragment", + FT_BOOLEAN, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_error, + { "L2CAP defragmentation error", "btbredr_rf.l2cap.fragment.error", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_msg_fragment_count, + { "L2CAP fragment count", "btbredr_rf.l2cap.fragment.count", + FT_UINT32, BASE_DEC, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_msg_reassembled_in, + { "Reassembled in", "btbredr_rf.l2cap.reassembled.in", + FT_FRAMENUM, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_l2cap_msg_reassembled_length, + { "Reassembled L2CAP length", "btbredr_rf.l2cap.reassembled.length", + FT_UINT32, BASE_DEC, NULL, 0x00, + NULL, HFILL } + } + }; + + static hf_register_info hf_fhs[] = { + { &hf_fhs_parity, + { "Parity Bits", "btbredr_fhs.parity", + FT_UINT64, BASE_HEX, NULL, 0x00000003ffffffff, + NULL, HFILL } + }, + { &hf_fhs_lap, + { "Lower Address Part", "btbredr_fhs.lap", + FT_UINT64, BASE_HEX, NULL, 0x03fffffc00000000, + NULL, HFILL } + }, + { &hf_fhs_eir, + { "Extended Inquiry Response", "btbredr_fhs.eir", + FT_UINT64, BASE_DEC, NULL, 0x0400000000000000, + NULL, HFILL } + }, + { &hf_fhs_reserved, + { "Reserved", "btbredr_fhs.reserved", + FT_UINT64, BASE_DEC, NULL, 0x0800000000000000, + NULL, HFILL } + }, + { &hf_fhs_sr, + { "Scan Repetition", "btbredr_fhs.sr", + FT_UINT64, BASE_DEC|BASE_VAL64_STRING, VALS64(fhs_scan_repetition_vals), 0x3000000000000000, + NULL, HFILL } + }, + { &hf_fhs_sp, + { "SP", "btbredr_fhs.sp", + FT_UINT64, BASE_DEC, NULL, 0xc000000000000000, + "shall be set to 10", HFILL } + }, + { &hf_fhs_uap, + { "Upper Address Part", "btbredr_fhs.uap", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_fhs_nap, + { "Non-Significant Address Part", "btbredr_fhs.nap", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_fhs_class, + { "Class of Device", "btbredr_fhs.class", + FT_UINT24, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_fhs_ltaddr, + { "LT_ADDR", "btbredr_fhs.ltaddr", + FT_UINT32, BASE_DEC, NULL, 0x00000007, + NULL, HFILL } + }, + { &hf_fhs_clk, + { "CLK", "btbredr_fhs.clk", + FT_UINT32, BASE_HEX, NULL, 0x1ffffff8, + NULL, HFILL } + }, + { &hf_fhs_pagescanmode, + { "Page Scan Mode", "btbredr_fhs.pagescanmode", + FT_UINT32, BASE_DEC, VALS(fhs_page_scan_mode_vals), 0xe0000000, + NULL, HFILL } } }; @@ -870,7 +2503,11 @@ proto_register_btbredr_rf(void) &ett_flags, &ett_payload_transport_rate, &ett_packet_header, - &ett_bluetooth_header + &ett_bluetooth_header, + &ett_payload_header, + &ett_l2cap_msg_fragment, + &ett_l2cap_msg_fragments, + &ett_btbredr_fhs }; static ei_register_info ei[] = { @@ -878,13 +2515,25 @@ proto_register_btbredr_rf(void) { &ei_reserved_not_zero, { "btbredr_rf.reserved_not_zero", PI_PROTOCOL, PI_WARN, "Reserved values are not zeros", EXPFILL }}, { &ei_incorrect_packet_header_or_hec, { "btbredr_rf.incorrect_packet_header_or_hec", PI_PROTOCOL, PI_WARN, "Incorrect Packet Header or HEC", EXPFILL }}, { &ei_packet_header_with_hec_not_checked, { "btbredr_rf.packet_header_with_hec_not_checked", PI_PROTOCOL, PI_NOTE, "Packet Header with HEC is not checked", EXPFILL }}, + { &ei_broken_packet_header_format, { "btbredr_rf.broken_packet_header_format", PI_PROTOCOL, PI_WARN, "Broken Packet Header Format", EXPFILL }}, + { &ei_incorrect_crc, { "btbredr_rf.incorrect_crc", PI_PROTOCOL, PI_WARN, "Incorrect CRC", EXPFILL }}, + { &ei_missing_fragment_start, { "btbredr_rf.missing_fragment_start", PI_SEQUENCE, PI_WARN, "Missing Fragment Start", EXPFILL }}, + { &ei_esco_incorrect_ltaddr, { "btbredr_rf.esco_incorrect_ltaddr", PI_PROTOCOL, PI_WARN, "Incorrect (e)SCO LT_ADDR", EXPFILL }}, + { &ei_esco_incorrect_length, { "btbredr_rf.esco_incorrect_length", PI_PROTOCOL, PI_WARN, "Incorrect eSCO Packet Length", EXPFILL }} }; + connection_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + device_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + proto_btbredr_rf = proto_register_protocol("Bluetooth Pseudoheader for BR/EDR", "BT BR/EDR RF", "btbredr_rf"); proto_register_field_array(proto_btbredr_rf, hf, array_length(hf)); proto_register_subtree_array(ett, array_length(ett)); btbredr_rf_handle = register_dissector("btbredr_rf", dissect_btbredr_rf, proto_btbredr_rf); + proto_btbredr_fhs = proto_register_protocol("Bluetooth BR/EDR FHS", "BT BR/EDR FHS", "btbredr_fhs"); + proto_register_field_array(proto_btbredr_fhs, hf_fhs, array_length(hf_fhs)); + btbredr_fhs_handle = register_dissector("btbredr_fhs", dissect_btbredr_fhs, proto_btbredr_fhs); + packet_type_sco_br_table = register_dissector_table("btbredr_rf.packet_type.sco.br", "BT Packet Type for SCO BR", proto_btbredr_rf, FT_UINT8, BASE_HEX); packet_type_esco_br_table = register_dissector_table("btbredr_rf.packet_type.esco.br", "BT Packet Type for eSCO BR", proto_btbredr_rf, FT_UINT8, BASE_HEX); packet_type_esco_edr_table = register_dissector_table("btbredr_rf.packet_type.esco.edr", "BT Packet Type for eSCO EDR", proto_btbredr_rf, FT_UINT8, BASE_HEX); @@ -900,6 +2549,8 @@ proto_register_btbredr_rf(void) void proto_reg_handoff_btbredr_rf(void) { + btlmp_handle = find_dissector_add_dependency("btlmp", proto_btbredr_rf); + btl2cap_handle = find_dissector_add_dependency("btl2cap", proto_btbredr_rf); dissector_add_uint("bluetooth.encap", WTAP_ENCAP_BLUETOOTH_BREDR_BB, btbredr_rf_handle); } diff --git a/epan/dissectors/packet-btlmp.c b/epan/dissectors/packet-btlmp.c new file mode 100644 index 0000000000..e6338cf7e9 --- /dev/null +++ b/epan/dissectors/packet-btlmp.c @@ -0,0 +1,2469 @@ +/* packet-btlmp.c + * Routines for the Bluetooth Link Manager Protocol + * + * Copyright 2020, Thomas Sailer + * + * Wireshark - Network traffic analyzer + * By Gerald Combs + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "config.h" + +#include +#include + +#include + +#include "packet-bluetooth.h" + +struct _connection_info_t; + +extern struct _connection_info_t * +btbredr_rf_add_esco_link(struct _connection_info_t *cinfo, packet_info *pinfo, guint8 handle, guint32 ltaddr, guint16 pktszms, guint16 pktszsm); + +extern void +btbredr_rf_remove_esco_link(struct _connection_info_t *cinfo, packet_info *pinfo, guint8 handle); + + + +static int proto_btlmp = -1; + +static int hf_opcode[3] = { -1, -1, -1 }; +static int hf_escopcode[4] = { -1, -1, -1, -1 }; +static int hf_accept_opcode = -1; +static int hf_accept_escopcode[4] = { -1, -1, -1, -1 }; +static int hf_errorcode = -1; +static int hf_param_feature_page0_byte0[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte1[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte2[7] = { -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte3[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte4[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte5[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte6[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page0_byte7[6] = { -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page1_byte0[6] = { -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page2_byte0[9] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_feature_page2_byte1[6] = { -1, -1, -1, -1, -1, -1 }; +static int hf_param_features_page = -1; +static int hf_param_max_supported_page = -1; +static int hf_param_versnr = -1; +static int hf_param_compid = -1; +static int hf_param_subversnr = -1; +static int hf_param_namelength = -1; +static int hf_param_nameoffset = -1; +static int hf_param_namefragment = -1; +static int hf_param_afh_mode = -1; +static int hf_param_afh_instant = -1; +static int hf_param_afh_channelmap[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +static int hf_param_afh_reportingmode = -1; +static int hf_param_afh_mininterval = -1; +static int hf_param_afh_maxinterval = -1; +static int hf_param_afh_channelclass[10][4] = { { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, + { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 }, { -1, -1, -1, -1 } }; +static int hf_param_rand = -1; +static int hf_param_key = -1; +static int hf_param_clockoffset = -1; +static int hf_param_authresp = -1; +static int hf_param_encryptionmode = -1; +static int hf_param_encryptionkeysize = -1; +static int hf_param_switchinstant = -1; +static int hf_param_holdtime = -1; +static int hf_param_holdinstant = -1; +static int hf_param_dsniff = -1; +static int hf_param_tsniff = -1; +static int hf_param_sniffattempt = -1; +static int hf_param_snifftimeout = -1; +static int hf_param_timingcontrolflags[5] = { -1, -1, -1, -1, -1 }; +static int hf_param_futureuse1 = -1; +static int hf_param_datarate[6] = { -1, -1, -1, -1, -1, -1 }; +static int hf_param_pollinterval = -1; +static int hf_param_nbc = -1; +static int hf_param_scohandle = -1; +static int hf_param_dsco = -1; +static int hf_param_tsco = -1; +static int hf_param_scopacket = -1; +static int hf_param_airmode = -1; +static int hf_param_slots = -1; +static int hf_param_tmgacc_drift = -1; +static int hf_param_tmgacc_jitter = -1; +static int hf_param_slotoffset = -1; +static int hf_param_bdaddr = -1; +static int hf_param_pagingscheme = -1; +static int hf_param_pagingschemesettings = -1; +static int hf_param_supervisiontimeout = -1; +static int hf_param_testscenario = -1; +static int hf_param_testhoppingmode = -1; +static int hf_param_testtxfrequency = -1; +static int hf_param_testrxfrequency = -1; +static int hf_param_testpowercontrolmode = -1; +static int hf_param_testpollperiod = -1; +static int hf_param_testpackettype = -1; +static int hf_param_testdatalength = -1; +static int hf_param_keysizemask = -1; +static int hf_param_encapsulatedmajor = -1; +static int hf_param_encapsulatedminor = -1; +static int hf_param_encapsulatedlength = -1; +static int hf_param_encapsulateddata = -1; +static int hf_param_simplepaircommit = -1; +static int hf_param_simplepairnonce = -1; +static int hf_param_dhkeyconfirm = -1; +static int hf_param_clkadjid = -1; +static int hf_param_clkadjinstant = -1; +static int hf_param_clkadjus = -1; +static int hf_param_clkadjslots = -1; +static int hf_param_clkadjmode = -1; +static int hf_param_clkadjclk = -1; +static int hf_param_clkadjperiod = -1; +static int hf_param_packettypetable = -1; +static int hf_param_escohandle = -1; +static int hf_param_escoltaddr = -1; +static int hf_param_escod = -1; +static int hf_param_escot = -1; +static int hf_param_escow = -1; +static int hf_param_escopackettypems = -1; +static int hf_param_escopackettypesm = -1; +static int hf_param_escopacketlengthms = -1; +static int hf_param_escopacketlengthsm = -1; +static int hf_param_negostate = -1; +static int hf_param_maxsniffsubrate = -1; +static int hf_param_minsniffmodetimeout = -1; +static int hf_param_sniffsubratinginstant = -1; +static int hf_param_iocapcap = -1; +static int hf_param_iocapoobauthdata = -1; +static int hf_param_iocapauthreq = -1; +static int hf_param_keypressnotificationtype = -1; +static int hf_param_poweradjreq = -1; +static int hf_param_poweradjresp[5] = { -1, -1, -1, -1, -1 }; +static int hf_param_samindex = -1; +static int hf_param_samtsm = -1; +static int hf_param_samnsm = -1; +static int hf_param_samsubmaps = -1; +static int hf_param_samupdatemode = -1; +static int hf_param_samtype0submap = -1; +static int hf_param_samd = -1; +static int hf_param_saminstant = -1; +static int hf_params = -1; + +static gint ett_btlmp = -1; + +static dissector_handle_t btlmp_handle; + +static const value_string opcode_vals[] = { + { 1, "LMP_name_req" }, + { 2, "LMP_name_res" }, + { 3, "LMP_accepted" }, + { 4, "LMP_not_accepted" }, + { 5, "LMP_clkoffset_req" }, + { 6, "LMP_clkoffset_res" }, + { 7, "LMP_detach" }, + { 8, "LMP_in_rand" }, + { 9, "LMP_comb_key" }, + { 10, "LMP_unit_key" }, + { 11, "LMP_au_rand" }, + { 12, "LMP_sres" }, + { 13, "LMP_temp_rand" }, + { 14, "LMP_temp_key" }, + { 15, "LMP_encryption_mode_req" }, + { 16, "LMP_encryption_key_size_req" }, + { 17, "LMP_start_encryption_req" }, + { 18, "LMP_stop_encryption_req" }, + { 19, "LMP_switch_req" }, + { 20, "LMP_hold" }, + { 21, "LMP_hold_req" }, + { 23, "LMP_sniff_req" }, + { 24, "LMP_unsniff_req" }, + { 31, "LMP_incr_power_req" }, + { 32, "LMP_decr_power_req" }, + { 33, "LMP_max_power" }, + { 34, "LMP_min_power" }, + { 35, "LMP_auto_rate" }, + { 36, "LMP_preferred_rate" }, + { 37, "LMP_version_req" }, + { 38, "LMP_version_res" }, + { 39, "LMP_features_req" }, + { 40, "LMP_features_res" }, + { 41, "LMP_quality_of_service" }, + { 42, "LMP_quality_of_service_req" }, + { 43, "LMP_SCO_link_req" }, + { 44, "LMP_remove_SCO_link_req" }, + { 45, "LMP_max_slot" }, + { 46, "LMP_max_slot_req" }, + { 47, "LMP_timing_accuracy_req" }, + { 48, "LMP_timing_accuracy_res" }, + { 49, "LMP_setup_complete" }, + { 50, "LMP_use_semi_permanent_key" }, + { 51, "LMP_host_connection_req" }, + { 52, "LMP_slot_offset" }, + { 53, "LMP_page_mode_req" }, + { 54, "LMP_page_scan_mode_req" }, + { 55, "LMP_supervision_timeout" }, + { 56, "LMP_test_activate" }, + { 57, "LMP_test_control" }, + { 58, "LMP_encryption_key_size_mask_req" }, + { 59, "LMP_encryption_key_size_mask_res" }, + { 60, "LMP_set_AFH" }, + { 61, "LMP_encapsulated_header" }, + { 62, "LMP_encapsulated_payload" }, + { 63, "LMP_Simple_Pairing_Confirm" }, + { 64, "LMP_Simple_Pairing_Number" }, + { 65, "LMP_DHkey_Check" }, + { 66, "LMP_pause_encryption_aes_req" }, + { 124, "Escape 1" }, + { 125, "Escape 2" }, + { 126, "Escape 3" }, + { 127, "Escape 4" }, + { 0, NULL } +}; + +static const value_string escape1_opcode_vals[] = { + { 0x00, "Mandatory Scan Mode" }, + { 0, NULL } +}; + +static const value_string escape2_opcode_vals[] = { + { 0x00, "Mandatory Scan Mode" }, + { 0, NULL } +}; + +static const value_string escape3_opcode_vals[] = { + { 0x00, "Mandatory Scan Mode" }, + { 0, NULL } +}; + +static const value_string escape4_opcode_vals[] = { + { 1, "LMP_accepted_ext" }, + { 2, "LMP_not_accepted_ext" }, + { 3, "LMP_features_req_ext" }, + { 4, "LMP_features_res_ext" }, + { 5, "LMP_clk_adj" }, + { 6, "LMP_clk_adj_ack" }, + { 7, "LMP_clk_adj_req" }, + { 11, "LMP_packet_type_table_req" }, + { 12, "LMP_eSCO_link_req" }, + { 13, "LMP_remove_eSCO_link_req" }, + { 16, "LMP_channel_classification_req" }, + { 17, "LMP_channel_classification" }, + { 21, "LMP_sniff_subrating_req" }, + { 22, "LMP_sniff_subrating_res" }, + { 23, "LMP_pause_encryption_req" }, + { 24, "LMP_resume_encryption_req" }, + { 25, "LMP_IO_Capability_req" }, + { 26, "LMP_IO_Capability_res" }, + { 27, "LMP_numeric_comparison_failed" }, + { 28, "LMP_passkey_failed" }, + { 29, "LMP_oob_failed" }, + { 30, "LMP_keypress_notification" }, + { 31, "LMP_power_control_req" }, + { 32, "LMP_power_control_res" }, + { 33, "LMP_ping_req" }, + { 34, "LMP_ping_res" }, + { 35, "LMP_SAM_set_type0" }, + { 36, "LMP_SAM_define_map" }, + { 37, "LMP_SAM_switch" }, + { 0, NULL } +}; + +static const value_string errorcode_vals[] = { + { 0x00, "Success" }, + { 0x01, "Unknown HCI Command" }, + { 0x02, "Unknown Connection Identifier" }, + { 0x03, "Hardware Failure" }, + { 0x04, "Page Timeout" }, + { 0x05, "Authentication Failure" }, + { 0x06, "PIN or Key Missing" }, + { 0x07, "Memory Capacity Exceeded" }, + { 0x08, "Connection Timeout" }, + { 0x09, "Connection Limit Exceeded" }, + { 0x0A, "Synchronous Connection Limit To A Device Exceeded" }, + { 0x0B, "Connection Already Exists" }, + { 0x0C, "Command Disallowed" }, + { 0x0D, "Connection Rejected due to Limited Resources" }, + { 0x0E, "Connection Rejected Due To Security Reasons" }, + { 0x0F, "Connection Rejected due to Unacceptable BD_ADDR" }, + { 0x10, "Connection Accept Timeout Exceeded" }, + { 0x11, "Unsupported Feature or Parameter Value" }, + { 0x12, "Invalid HCI Command Parameters" }, + { 0x13, "Remote User Terminated Connection" }, + { 0x14, "Remote Device Terminated Connection due to Low Resources" }, + { 0x15, "Remote Device Terminated Connection due to Power Off" }, + { 0x16, "Connection Terminated By Local Host" }, + { 0x17, "Repeated Attempts" }, + { 0x18, "Pairing Not Allowed" }, + { 0x19, "Unknown LMP PDU" }, + { 0x1A, "Unsupported Remote Feature / Unsupported LMP Feature" }, + { 0x1B, "SCO Offset Rejected" }, + { 0x1C, "SCO Interval Rejected" }, + { 0x1D, "SCO Air Mode Rejected" }, + { 0x1E, "Invalid LMP Parameters / Invalid LL Parameters" }, + { 0x1F, "Unspecified Error" }, + { 0x20, "Unsupported LMP Parameter Value / Unsupported LL Parameter Value" }, + { 0x21, "Role Change Not Allowed" }, + { 0x22, "LMP Response Timeout / LL Response Timeout" }, + { 0x23, "LMP Error Transaction Collision / LL Procedure Collision" }, + { 0x24, "LMP PDU Not Allowed" }, + { 0x25, "Encryption Mode Not Acceptable" }, + { 0x26, "Link Key cannot be Changed" }, + { 0x27, "Requested QoS Not Supported" }, + { 0x28, "Instant Passed" }, + { 0x29, "Pairing With Unit Key Not Supported" }, + { 0x2A, "Different Transaction Collision" }, + { 0x2B, "Reserved for future use" }, + { 0x2C, "QoS Unacceptable Parameter" }, + { 0x2D, "QoS Rejected" }, + { 0x2E, "Channel Classification Not Supported" }, + { 0x2F, "Insufficient Security" }, + { 0x30, "Parameter Out Of Mandatory Range" }, + { 0x31, "Reserved for future use" }, + { 0x32, "Role Switch Pending" }, + { 0x33, "Reserved for future use" }, + { 0x34, "Reserved Slot Violation" }, + { 0x35, "Role Switch Failed" }, + { 0x36, "Extended Inquiry Response Too Large" }, + { 0x37, "Secure Simple Pairing Not Supported By Host" }, + { 0x38, "Host Busy - Pairing" }, + { 0x39, "Connection Rejected due to No Suitable Channel Found" }, + { 0x3A, "Controller Busy" }, + { 0x3B, "Unacceptable Connection Parameters" }, + { 0x3C, "Advertising Timeout" }, + { 0x3D, "Connection Terminated due to MIC Failure" }, + { 0x3E, "Connection Failed to be Established / Synchronization Timeout" }, + { 0x3F, "MAC Connection Failed" }, + { 0x40, "Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock" }, + { 0x41, "Type0 Submap Not Defined" }, + { 0x42, "Unknown Advertising Identifier" }, + { 0x43, "Limit Reached" }, + { 0x44, "Operation Cancelled by Host" }, + { 0x45, "Packet Too Long" }, + { 0x00, NULL } +}; + +static const value_string afh_mode_vals[] = { + { 0x00, "AFH disabled" }, + { 0x01, "AFH enabled" }, + { 0x00, NULL } +}; + +static const value_string afh_reportingmode_vals[] = { + { 0x00, "AFH reporting disabled" }, + { 0x01, "AFH reporting enabled" }, + { 0x00, NULL } +}; + +static const value_string afh_channelclass_vals[] = { + { 0x00, "unknown" }, + { 0x01, "good" }, + { 0x02, "reserved" }, + { 0x03, "bad" }, + { 0x00, NULL } +}; + +static const value_string encryptionmode_vals[] = { + { 0x00, "no encryption" }, + { 0x01, "encryption" }, + { 0x02, "encryption" }, + { 0x00, NULL } +}; + +static const value_string timingcontrol_timingchange_vals[] = { + { 0x00, "no timing change" }, + { 0x01, "timing change" }, + { 0x00, NULL } +}; + +static const value_string timingcontrol_useinit2[] = { + { 0x00, "use initialization 1" }, + { 0x01, "use initialization 2" }, + { 0x00, NULL } +}; + +static const value_string timingcontrol_noaccesswindow[] = { + { 0x00, "access window" }, + { 0x01, "no access window" }, + { 0x00, NULL } +}; + +static const value_string dataratenofec_vals[] = { + { 0x00, "use FEC" }, + { 0x01, "do not use FEC" }, + { 0x00, NULL } +}; + +static const value_string dataratepacketsizepreference_vals[] = { + { 0x00, "no packet size preference" }, + { 0x01, "use 1-slot packets" }, + { 0x02, "use 3-slot packets" }, + { 0x02, "use 5-slot packets" }, + { 0x00, NULL } +}; + +static const value_string dataratedrpreference_vals[] = { + { 0x00, "use DM1 packets" }, + { 0x01, "use 2Mb/s packets" }, + { 0x02, "use 3Mb/s packets" }, + { 0x00, NULL } +}; + +static const value_string scopacket_vals[] = { + { 0x00, "HV1" }, + { 0x01, "HV2" }, + { 0x02, "HV3" }, + { 0x00, NULL } +}; + +static const value_string airmode_vals[] = { + { 0x00, "ulaw log" }, + { 0x01, "Alaw log" }, + { 0x02, "CVSD" }, + { 0x03, "transparent data" }, + { 0x00, NULL } +}; + +static const value_string pagingscheme_vals[] = { + { 0x00, "mandatory scheme" }, + { 0x00, NULL } +}; + +static const value_string pagingschemesettings_vals[] = { + { 0x00, "R0" }, + { 0x01, "R1" }, + { 0x02, "R2" }, + { 0x00, NULL } +}; + +static const value_string encapsulatedmajor_vals[] = { + { 0x01, "public key" }, + { 0x00, NULL } +}; + +static const value_string encapsulatedminor_vals[] = { + { 0x01, "P-192 public key" }, + { 0x02, "P-256 public key" }, + { 0x00, NULL } +}; + +static const value_string clkadjmode_vals[] = { + { 0x00, "before instant" }, + { 0x01, "after instant" }, + { 0x00, NULL } +}; + +static const value_string packettypetable_vals[] = { + { 0x00, "1Mb/s only" }, + { 0x01, "2/3Mb/s" }, + { 0x00, NULL } +}; + +static const value_string escopackettypems_vals[] = { + { 0x00, "POLL" }, + { 0x07, "EV3" }, + { 0x0c, "EV4" }, + { 0x0d, "EV5" }, + { 0x26, "2-EV3" }, + { 0x2c, "2-EV5" }, + { 0x37, "3-EV3" }, + { 0x3d, "3-EV5" }, + { 0x00, NULL } +}; + +static const value_string escopackettypesm_vals[] = { + { 0x00, "NULL" }, + { 0x07, "EV3" }, + { 0x0c, "EV4" }, + { 0x0d, "EV5" }, + { 0x26, "2-EV3" }, + { 0x2c, "2-EV5" }, + { 0x37, "3-EV3" }, + { 0x3d, "3-EV5" }, + { 0x00, NULL } +}; + +static const value_string negostate_vals[] = { + { 0, "initiate negotiation" }, + { 1, "the latest received set of negotiable parameters were possible but these parameters are preferred" }, + { 2, "the latest received set of negotiable parameters would cause a reserved slot violation" }, + { 3, "the latest received set of negotiable parameters would cause a latency violation" }, + { 4, "the latest received set of negotiable parameters are not supported" }, + { 0, NULL } +}; + +static const value_string iocapcap_vals[] = { + { 0x00, "Display Only" }, + { 0x01, "Display Yes/No" }, + { 0x02, "Keyboard Only" }, + { 0x03, "No Input No Output" }, + { 0x00, NULL } +}; + +static const value_string iocapoobauthdata_vals[] = { + { 0x00, "No OOB Authentication Data received" }, + { 0x01, "OOB Authentication Data received" }, + { 0x00, NULL } +}; + +static const value_string iocapauthreq_vals[] = { + { 0x00, "MITM Protection Not Required - No Bonding" }, + { 0x01, "MITM Protection Required - No Bonding" }, + { 0x02, "MITM Protection Not Required - Dedicated Bonding" }, + { 0x03, "MITM Protection Required - Dedicated Bonding" }, + { 0x04, "MITM Protection Not Required - General Bonding" }, + { 0x05, "MITM Protection Required - General Bonding" }, + { 0x00, NULL } +}; + +static const value_string keypressnotificationtype_vals[] = { + { 0x00, "passkey entry started" }, + { 0x01, "passkey digit entered" }, + { 0x02, "passkey digit erased" }, + { 0x03, "passkey cleared" }, + { 0x04, "passkey entry completed" }, + { 0x00, NULL } +}; + +static const value_string poweradjreq_vals[] = { + { 0x00, "decrement power one step" }, + { 0x01, "increment power one step" }, + { 0x02, "increase to maximum power" }, + { 0x00, NULL } +}; + +static const value_string poweradjresp_vals[] = { + { 0x00, "not supported" }, + { 0x01, "changed one step" }, + { 0x02, "max power" }, + { 0x03, "min power" }, + { 0x00, NULL } +}; + +static const value_string samupdatemode_vals[] = { + { 0, "Existing SAM slot maps containing any type 0 submaps are invalidated" }, + { 1, "The defined type 0 submap takes effect immediately" }, + { 2, "The defined type 0 submap takes effect at the start of the next sub-interval" }, + { 0, NULL } +}; + +static const unit_name_string units_ppm = { " ppm", NULL }; + +static const unit_name_string units_slots = { " slot", " slots" }; + +static const unit_name_string units_slotpairs = { " slot pair", " slot pairs" }; + + + + +static void decode_uint8_binary(gchar *s, guint8 value) +{ + for (guint i = 0; i < 8 && i + 1 < ITEM_LABEL_LENGTH; ++i, value <<= 1) + *s++ = '0' + ((value >> 7) & 1); + *s = 0; +} + +void proto_register_btlmp(void); +void proto_reg_handoff_btlmp(void); + +static gint +dissect_btlmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + proto_item *btlmp_item; + proto_tree *btlmp_tree; + gint offset = 0; + guint16 opcode; + struct _connection_info_t *connection_info = (struct _connection_info_t *)data; + + btlmp_item = proto_tree_add_item(tree, proto_btlmp, tvb, offset, -1, ENC_NA); + btlmp_tree = proto_item_add_subtree(btlmp_item, ett_btlmp); + + col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT LMP"); + + for (guint i = 0; i < array_length(hf_opcode); ++i) + proto_tree_add_item(btlmp_tree, hf_opcode[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + opcode = tvb_get_guint8(tvb, offset) >> 1; + offset += 1; + if (opcode >= 0x7c) { + opcode &= 3; + proto_tree_add_item(btlmp_tree, hf_escopcode[opcode], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++opcode; + opcode <<= 8; + opcode |= tvb_get_guint8(tvb, offset); + offset += 1; + } + switch (opcode) { + case 0x001: // LMP_name_req + break; + + case 0x002: // LMP_name_res + proto_tree_add_item(btlmp_tree, hf_param_namelength, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_nameoffset, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + if (tvb_captured_length_remaining(tvb, offset) <= 0) + break; + proto_tree_add_item(btlmp_tree, hf_param_namefragment, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + offset = tvb_reported_length(tvb); + break; + + case 0x003: // LMP_accepted + proto_tree_add_item(btlmp_tree, hf_accept_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x004: // LMP_not_accepted + proto_tree_add_item(btlmp_tree, hf_accept_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_errorcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x005: // LMP_clkoffset_req + break; + + case 0x006: // LMP_clkoffset_res + proto_tree_add_item(btlmp_tree, hf_param_clockoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x007: // LMP_detach + proto_tree_add_item(btlmp_tree, hf_errorcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x008: // LMP_in_rand + case 0x009: // LMP_comb_key + case 0x00b: // LMP_au_rand + case 0x00d: // LMP_temp_rand + case 0x011: // LMP_start_encryption_req + case 0x042: // LMP_pause_encryption_aes_req + proto_tree_add_item(btlmp_tree, hf_param_rand, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x00a: // LMP_unit_key + case 0x00e: // LMP_temp_key + proto_tree_add_item(btlmp_tree, hf_param_key, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x00c: // LMP_sres + proto_tree_add_item(btlmp_tree, hf_param_authresp, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + case 0x00f: // LMP_encryption_mode_req + proto_tree_add_item(btlmp_tree, hf_param_encryptionmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x010: // LMP_encryption_key_size_req + proto_tree_add_item(btlmp_tree, hf_param_encryptionkeysize, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x012: // LMP_stop_encryption_req + break; + + case 0x013: // LMP_switch_req + proto_tree_add_item(btlmp_tree, hf_param_switchinstant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + case 0x014: // LMP_hold + case 0x015: // LMP_hold_req + proto_tree_add_item(btlmp_tree, hf_param_holdtime, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_holdinstant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + case 0x017: // LMP_sniff_req + for (guint i = 0; i < array_length(hf_param_timingcontrolflags); ++i) + proto_tree_add_item(btlmp_tree, hf_param_timingcontrolflags[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_dsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_tsniff, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_sniffattempt, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_snifftimeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x018: // LMP_unsniff_req + break; + + case 0x01f: // LMP_incr_power_req + case 0x020: // LMP_decr_power_req + proto_tree_add_item(btlmp_tree, hf_param_futureuse1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x021: // LMP_max_power + case 0x022: // LMP_min_power + case 0x023: // LMP_auto_rate + break; + + case 0x024: // LMP_preferred_rate + for (guint i = 0; i < array_length(hf_param_datarate); ++i) + proto_tree_add_item(btlmp_tree, hf_param_datarate[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + + case 0x025: // LMP_version_req + case 0x026: // LMP_version_res + proto_tree_add_item(btlmp_tree, hf_param_versnr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_compid, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_subversnr, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x027: // LMP_features_req + case 0x028: // LMP_features_res + for (guint i = 0; i < array_length(hf_param_feature_page0_byte0); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte0[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte1); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte1[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte2); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte2[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte3); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte3[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte4); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte4[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte5); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte5[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte6); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte6[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte7); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte7[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x029: // LMP_quality_of_service + case 0x02a: // LMP_quality_of_service_req + proto_tree_add_item(btlmp_tree, hf_param_pollinterval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_nbc, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x02b: // LMP_SCO_link_req + proto_tree_add_item(btlmp_tree, hf_param_scohandle, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_timingcontrolflags); ++i) + proto_tree_add_item(btlmp_tree, hf_param_timingcontrolflags[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_dsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_tsco, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_scopacket, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x02c: // LMP_remove_SCO_link_req + proto_tree_add_item(btlmp_tree, hf_param_scohandle, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_errorcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x02d: // LMP_max_slot + case 0x02e: // LMP_max_slot_req + proto_tree_add_item(btlmp_tree, hf_param_slots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x02f: // LMP_timing_accuracy_req + break; + + case 0x030: // LMP_timing_accuracy_res + proto_tree_add_item(btlmp_tree, hf_param_tmgacc_drift, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_tmgacc_jitter, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x031: // LMP_setup_complete + case 0x032: // LMP_use_semi_permanent_key + case 0x033: // LMP_host_connection_req + break; + + case 0x034: // LMP_slot_offset + proto_tree_add_item(btlmp_tree, hf_param_slotoffset, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_bdaddr, tvb, offset, 6, ENC_NA); + offset += 6; + break; + + case 0x035: // LMP_page_mode_req + case 0x036: // LMP_page_scan_mode_req + proto_tree_add_item(btlmp_tree, hf_param_pagingscheme, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_pagingschemesettings, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x037: // LMP_supervision_timeout + proto_tree_add_item(btlmp_tree, hf_param_supervisiontimeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x038: // LMP_test_activate + break; + + case 0x039: // LMP_test_control + proto_tree_add_item(btlmp_tree, hf_param_testscenario, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testhoppingmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testtxfrequency, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testrxfrequency, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testpowercontrolmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testpollperiod, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testpackettype, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_testdatalength, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x03a: // LMP_encryption_key_size_mask_req + break; + + case 0x03b: // LMP_encryption_key_size_mask_res + proto_tree_add_item(btlmp_tree, hf_param_keysizemask, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x03c: // LMP_set_AFH + proto_tree_add_item(btlmp_tree, hf_param_afh_instant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(btlmp_tree, hf_param_afh_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_afh_channelmap); ++i, ++offset) + proto_tree_add_item(btlmp_tree, hf_param_afh_channelmap[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + + case 0x03d: // LMP_encapsulated_header + proto_tree_add_item(btlmp_tree, hf_param_encapsulatedmajor, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_encapsulatedminor, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_encapsulatedlength, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x03e: // LMP_encapsulated_payload + proto_tree_add_item(btlmp_tree, hf_param_encapsulateddata, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x03f: // LMP_Simple_Pairing_Confirm + proto_tree_add_item(btlmp_tree, hf_param_simplepaircommit, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x040: // LMP_Simple_Pairing_Number + proto_tree_add_item(btlmp_tree, hf_param_simplepairnonce, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x041: // LMP_DHkey_Check + proto_tree_add_item(btlmp_tree, hf_param_dhkeyconfirm, tvb, offset, 16, ENC_NA); + offset += 16; + break; + + case 0x401: // LMP_accepted_ext + proto_tree_add_item(btlmp_tree, hf_accept_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_accept_escopcode[tvb_get_guint8(tvb, offset - 1) & 3], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x402: // LMP_not_accepted_ext + proto_tree_add_item(btlmp_tree, hf_accept_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_accept_escopcode[tvb_get_guint8(tvb, offset - 1) & 3], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_errorcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x403: // LMP_features_req_ext + case 0x404: // LMP_features_res_ext + proto_tree_add_item(btlmp_tree, hf_param_features_page, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_max_supported_page, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + switch (tvb_get_guint8(tvb, offset - 2)) { + case 0: + for (guint i = 0; i < array_length(hf_param_feature_page0_byte0); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte0[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte1); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte1[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte2); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte2[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte3); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte3[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte4); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte4[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte5); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte5[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte6); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte6[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page0_byte7); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page0_byte7[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 1: + for (guint i = 0; i < array_length(hf_param_feature_page1_byte0); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page1_byte0[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 2: + for (guint i = 0; i < array_length(hf_param_feature_page2_byte0); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page2_byte0[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_feature_page2_byte1); ++i) + proto_tree_add_item(btlmp_tree, hf_param_feature_page2_byte1[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + default: + break; + } + break; + + case 0x405: // LMP_clk_adj + proto_tree_add_item(btlmp_tree, hf_param_clkadjid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_clkadjinstant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + proto_tree_add_item(btlmp_tree, hf_param_clkadjus, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_clkadjslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_clkadjmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_clkadjclk, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + case 0x406: // LMP_clk_adj_ack + proto_tree_add_item(btlmp_tree, hf_param_clkadjid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x407: // LMP_clk_adj_req + proto_tree_add_item(btlmp_tree, hf_param_clkadjus, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_clkadjslots, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_clkadjperiod, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x40b: // LMP_packet_type_table_req + proto_tree_add_item(btlmp_tree, hf_param_packettypetable, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x40c: // LMP_eSCO_link_req + btbredr_rf_add_esco_link(connection_info, pinfo, tvb_get_guint8(tvb, offset), tvb_get_guint8(tvb, offset + 1), + tvb_get_guint16(tvb, offset + 8, ENC_LITTLE_ENDIAN), tvb_get_guint16(tvb, offset + 10, ENC_LITTLE_ENDIAN)); + proto_tree_add_item(btlmp_tree, hf_param_escohandle, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escoltaddr, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_timingcontrolflags); ++i) + proto_tree_add_item(btlmp_tree, hf_param_timingcontrolflags[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escod, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escot, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escow, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escopackettypems, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escopackettypesm, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_escopacketlengthms, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_escopacketlengthsm, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_airmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_negostate, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x40d: // LMP_remove_eSCO_link_req + btbredr_rf_remove_esco_link(connection_info, pinfo, tvb_get_guint8(tvb, offset)); + proto_tree_add_item(btlmp_tree, hf_param_escohandle, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_errorcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x410: // LMP_channel_classification_req + proto_tree_add_item(btlmp_tree, hf_param_afh_reportingmode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_afh_mininterval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_afh_maxinterval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + + case 0x411: // LMP_channel_classification + for (guint i = 0; i < array_length(hf_param_afh_channelclass); ++i) + for (guint j = 0; j < array_length(hf_param_afh_channelclass[0]); ++j) + proto_tree_add_item(btlmp_tree, hf_param_afh_channelclass[i][j], tvb, offset + i, 1, ENC_LITTLE_ENDIAN); + offset += array_length(hf_param_afh_channelclass); + break; + + case 0x415: // LMP_sniff_subrating_req + case 0x416: // LMP_sniff_subrating_res + proto_tree_add_item(btlmp_tree, hf_param_maxsniffsubrate, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_minsniffmodetimeout, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + proto_tree_add_item(btlmp_tree, hf_param_sniffsubratinginstant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + case 0x417: // LMP_pause_encryption_req + case 0x418: // LMP_resume_encryption_req + break; + + case 0x419: // LMP_IO_Capability_req + case 0x41a: // LMP_IO_Capability_res + proto_tree_add_item(btlmp_tree, hf_param_iocapcap, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_iocapoobauthdata, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_iocapauthreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x41b: // LMP_numeric_comparison_failed + case 0x41c: // LMP_passkey_failed + case 0x41d: // LMP_oob_failed + break; + + case 0x41e: // LMP_keypress_notification + proto_tree_add_item(btlmp_tree, hf_param_keypressnotificationtype, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x41f: // LMP_power_control_req + proto_tree_add_item(btlmp_tree, hf_param_poweradjreq, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x420: // LMP_power_control_res + for (guint i = 0; i < array_length(hf_param_poweradjresp); ++i) + proto_tree_add_item(btlmp_tree, hf_param_poweradjresp[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + break; + + case 0x421: // LMP_ping_req + case 0x422: // LMP_ping_res + break; + + case 0x423: // LMP_SAM_set_type0 + proto_tree_add_item(btlmp_tree, hf_param_samupdatemode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_samtype0submap, tvb, offset, 14, ENC_NA); + offset += 14; + break; + + case 0x424: // LMP_SAM_define_map + proto_tree_add_item(btlmp_tree, hf_param_samindex, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_samtsm, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_samnsm, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_samsubmaps, tvb, offset, 12, ENC_NA); + offset += 12; + break; + + case 0x425: // LMP_SAM_switch + proto_tree_add_item(btlmp_tree, hf_param_samindex, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + for (guint i = 0; i < array_length(hf_param_timingcontrolflags); ++i) + proto_tree_add_item(btlmp_tree, hf_param_timingcontrolflags[i], tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_samd, tvb, offset, 1, ENC_LITTLE_ENDIAN); + ++offset; + proto_tree_add_item(btlmp_tree, hf_param_saminstant, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + break; + + default: + break; + } + if (tvb_captured_length_remaining(tvb, offset) > 0) { + proto_tree_add_item(btlmp_tree, hf_params, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + offset = tvb_reported_length(tvb); + } + return offset; +} + +void +proto_register_btlmp(void) +{ + static hf_register_info hf[] = { + { &hf_opcode[0], + { "Opcode", "btlmp.opcode.byte0", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_opcode[1], + { "TID", "btlmp.opcode.tid", + FT_UINT8, BASE_HEX, NULL, 0x01, + NULL, HFILL } + }, + { &hf_opcode[2], + { "Opcode", "btlmp.opcode.opcode", + FT_UINT8, BASE_DEC_HEX, VALS(opcode_vals), 0xfe, + NULL, HFILL } + }, + { &hf_escopcode[0], + { "Escape 1 Opcode", "btlmp.opcode.escaped", + FT_UINT16, BASE_DEC_HEX, VALS(escape1_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_escopcode[1], + { "Escape 2 Opcode", "btlmp.opcode.escaped", + FT_UINT16, BASE_DEC_HEX, VALS(escape2_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_escopcode[2], + { "Escape 3 Opcode", "btlmp.opcode.escaped", + FT_UINT16, BASE_DEC_HEX, VALS(escape3_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_escopcode[3], + { "Escape 4 Opcode", "btlmp.opcode.escaped", + FT_UINT16, BASE_DEC_HEX, VALS(escape4_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_accept_opcode, + { "Opcode", "btlmp.accept_opcode", + FT_UINT8, BASE_DEC_HEX, VALS(opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_accept_escopcode[0], + { "Escape 1 Opcode", "btlmp.accept_opcode1", + FT_UINT16, BASE_DEC_HEX, VALS(escape1_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_accept_escopcode[1], + { "Escape 2 Opcode", "btlmp.accept_opcode2", + FT_UINT16, BASE_DEC_HEX, VALS(escape2_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_accept_escopcode[2], + { "Escape 3 Opcode", "btlmp.accept_opcode3", + FT_UINT16, BASE_DEC_HEX, VALS(escape3_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_accept_escopcode[3], + { "Escape 4 Opcode", "btlmp.accept_opcode4", + FT_UINT16, BASE_DEC_HEX, VALS(escape4_opcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_errorcode, + { "Error Code", "btlmp.errorcode", + FT_UINT8, BASE_DEC_HEX, VALS(errorcode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[0], + { "Feature Page 0 Byte 0", "btlmp.feature.page0.byte0", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[1], + { "3 slot packets", "btlmp.feature.page0.3slotpackets", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[2], + { "5 slot packets", "btlmp.feature.page0.5slotpackets", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[3], + { "Encryption", "btlmp.feature.page0.encryption", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[4], + { "Slot offset", "btlmp.feature.page0.slotoffset", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[5], + { "Timing accuracy", "btlmp.feature.page0.timingaccuracy", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[6], + { "Role switch", "btlmp.feature.page0.roleswitch", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[7], + { "Hold mode", "btlmp.feature.page0.holdmode", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte0[8], + { "Sniff mode", "btlmp.feature.page0.sniffmode", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[0], + { "Feature Page 0 Byte 1", "btlmp.feature.page0.byte1", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[1], + { "Reserved", "btlmp.feature.page0.reserved1", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[2], + { "Power control requests", "btlmp.feature.page0.powercontrolrequests", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[3], + { "Channel quality driven data rate (CQDDR)", "btlmp.feature.page0.cqddr", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[4], + { "SCO link", "btlmp.feature.page0.scolink", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[5], + { "HV2 packets", "btlmp.feature.page0.hv2packets", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[6], + { "HV3 packets", "btlmp.feature.page0.hv3packets", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[7], + { "u-law log synchronous data", "btlmp.feature.page0.ulaw", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte1[8], + { "A-law log synchronous data", "btlmp.feature.page0.alaw", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[0], + { "Feature Page 0 Byte 2", "btlmp.feature.page0.byte2", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[1], + { "CVSD synchronous data", "btlmp.feature.page0.cvsd", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[2], + { "Paging parameter negotiation", "btlmp.feature.page0.pagingparameter", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[3], + { "Power control", "btlmp.feature.page0.powercontrol", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[4], + { "Transparent synchronous data", "btlmp.feature.page0.transparentsynchronous", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[5], + { "Flow control lag (least significant bit)", "btlmp.feature.page0.flowcontrollag", + FT_UINT8, BASE_DEC, NULL, 0x70, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte2[6], + { "Broadcast Encryption", "btlmp.feature.page0.broadcastencryption", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[0], + { "Feature Page 0 Byte 3", "btlmp.feature.page0.byte3", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[1], + { "Reserved", "btlmp.feature.page0.reserved2", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[2], + { "Enhanced Data Rate ACL 2 Mb/s mode", "btlmp.feature.page0.edracl2", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[3], + { "Enhanced Data Rate ACL 3 Mb/s mode", "btlmp.feature.page0.edracl3", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[4], + { "Enhanced inquiry scan", "btlmp.feature.page0.enhinqscan", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[5], + { "Interlaced inquiry scan", "btlmp.feature.page0.interlacedinqscan", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[6], + { "Interlaced page scan", "btlmp.feature.page0.interlacedpgscan", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[7], + { "RSSI with inquiry results", "btlmp.feature.page0.inqrssi", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte3[8], + { "Extended SCO link (EV3 packets)", "btlmp.feature.page0.escolink", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[0], + { "Feature Page 0 Byte 4", "btlmp.feature.page0.byte4", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[1], + { "EV4 packets", "btlmp.feature.page0.ev4", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[2], + { "EV5 packets", "btlmp.feature.page0.ev5", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[3], + { "Reserved", "btlmp.feature.page0.reserved3", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[4], + { "AFH capable slave", "btlmp.feature.page0.afhcapableslave", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[5], + { "AFH classification slave", "btlmp.feature.page0.afhclassificationslave", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[6], + { "BR/EDR Not Supported", "btlmp.feature.page0.bredrnotsupp", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[7], + { "LE Supported (Controller)", "btlmp.feature.page0.lesuppcontroller", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte4[8], + { "3-slot Enhanced Data Rate ACL packets", "btlmp.feature.page0.3slotedracl", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[0], + { "Feature Page 0 Byte 5", "btlmp.feature.page0.byte5", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[1], + { "5-slot Enhanced Data Rate ACL packets", "btlmp.feature.page0.5slotedracl", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[2], + { "Sniff subrating", "btlmp.feature.page0.sniffsubrating", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[3], + { "Pause encryption", "btlmp.feature.page0.pauseencrypt", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[4], + { "AFH capable master", "btlmp.feature.page0.afhcapablemaster", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[5], + { "AFH classification master", "btlmp.feature.page0.afhclassificationmaster", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[6], + { "Enhanced Data Rate eSCO 2 Mb/s mode", "btlmp.feature.page0.edresco2", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[7], + { "Enhanced Data Rate eSCO 3 Mb/s mode", "btlmp.feature.page0.edresco3", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte5[8], + { "3-slot Enhanced Data Rate eSCO packets", "btlmp.feature.page0.3slotedresco", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[0], + { "Feature Page 0 Byte 6", "btlmp.feature.page0.byte6", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[1], + { "Extended Inquiry Response", "btlmp.feature.page0.extinqresp", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[2], + { "Simultaneous LE and BR/EDR to Same Device Capable (Controller)", "btlmp.feature.page0.simullebredrcontroller", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[3], + { "Reserved", "btlmp.feature.page0.reserved4", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[4], + { "Secure Simple Pairing (Controller Support)", "btlmp.feature.page0.securesimplepaircontroller", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[5], + { "Encapsulated PDU", "btlmp.feature.page0.encpdu", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[6], + { "Erroneous Data Reporting", "btlmp.feature.page0.errdatareport", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[7], + { "Non-flushable Packet Boundary Flag", "btlmp.feature.page0.nonflushboundary", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte6[8], + { "Reserved", "btlmp.feature.page0.reserved5", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[0], + { "Feature Page 0 Byte 1", "btlmp.feature.page0.byte7", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[1], + { "HCI Link Supervision Timeout Changed event", "btlmp.feature.page0.hcilinksupervisiontimeoutchgevt", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[2], + { "Variable Inquiry TX Power Level", "btlmp.feature.page0.varinqtxpwr", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[3], + { "Enhanced Power Control", "btlmp.feature.page0.enhpowercontrol", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[4], + { "Reserved", "btlmp.feature.page0.reserved6", + FT_UINT8, BASE_DEC, NULL, 0x78, + NULL, HFILL } + }, + { &hf_param_feature_page0_byte7[5], + { "Extended features", "btlmp.feature.page0.extftr", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[0], + { "Feature Page 1 Byte 0", "btlmp.feature.page1.byte0", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[1], + { "Secure Simple Pairing (Host Support)", "btlmp.feature.page1.securesimplepairhost", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[2], + { "LE Supported (Host)", "btlmp.feature.page1.lesupphost", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[3], + { "Simultaneous LE and BR/EDR to Same Device Capable (Host)", "btlmp.feature.page1.simullebredrhost", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[4], + { "Secure Connections (Host Support)", "btlmp.feature.page1.secureconnhost", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page1_byte0[5], + { "Reserved", "btlmp.feature.page1.reserved1", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[0], + { "Feature Page 2 Byte 0", "btlmp.feature.page2.byte0", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[1], + { "Connectionless Slave Broadcast - Master", "btlmp.feature.page2.csbmaster", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[2], + { "Connectionless Slave Broadcast - Slave", "btlmp.feature.page2.csbslave", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[3], + { "Synchronization Train", "btlmp.feature.page2.synctrain", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[4], + { "Synchronization Scan", "btlmp.feature.page2.syncscan", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[5], + { "HCI_Inquiry_Response_Notification event", "btlmp.feature.page2.hciinqrespnotifevt", + FT_UINT8, BASE_DEC, NULL, 0x10, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[6], + { "Generalized interlaced scan", "btlmp.feature.page2.generalinterlacedscan", + FT_UINT8, BASE_DEC, NULL, 0x20, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[7], + { "Coarse Clock Adjustment", "btlmp.feature.page2.coarseclockadj", + FT_UINT8, BASE_DEC, NULL, 0x40, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte0[8], + { "Reserved", "btlmp.feature.page2.reserved1", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[0], + { "Feature Page 2 Byte 1", "btlmp.feature.page2.byte1", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[1], + { "Secure Connections (Controller Support)", "btlmp.feature.page2.secureconncontroller", + FT_UINT8, BASE_DEC, NULL, 0x01, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[2], + { "Ping", "btlmp.feature.page2.ping", + FT_UINT8, BASE_DEC, NULL, 0x02, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[3], + { "Slot Availability Mask", "btlmp.feature.page2.slotavailabilitymask", + FT_UINT8, BASE_DEC, NULL, 0x04, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[4], + { "Train nudging", "btlmp.feature.page2.trainnudging", + FT_UINT8, BASE_DEC, NULL, 0x08, + NULL, HFILL } + }, + { &hf_param_feature_page2_byte1[5], + { "Reserved", "btlmp.feature.page2.reserved2", + FT_UINT8, BASE_DEC, NULL, 0xf0, + NULL, HFILL } + }, + { &hf_param_features_page, + { "Feature Page", "btlmp.feature.features_page", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_max_supported_page, + { "Max Supported Page", "btlmp.feature.max_supported_page", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_versnr, + { "VersNr", "btlmp.version.versnr", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_compid, + { "CompId", "btlmp.version.CompId", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_subversnr, + { "SubVersNr", "btlmp.version.SubVersNr", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_namelength, + { "Name Length", "btlmp.name.length", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_nameoffset, + { "Name Offset", "btlmp.name.offset", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_namefragment, + { "Name Fragment", "btlmp.name.fragment", + FT_STRINGZPAD, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_afh_mode, + { "AFH Mode", "btlmp.afh.mode", + FT_UINT8, BASE_HEX, VALS(afh_mode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_instant, + { "AFH Instant", "btlmp.afh.instant", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[0], + { "AFH Channel Map 0", "btlmp.afh.channelmap0", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[1], + { "AFH Channel Map 1", "btlmp.afh.channelmap1", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[2], + { "AFH Channel Map 2", "btlmp.afh.channelmap2", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[3], + { "AFH Channel Map 3", "btlmp.afh.channelmap3", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[4], + { "AFH Channel Map 4", "btlmp.afh.channelmap4", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[5], + { "AFH Channel Map 5", "btlmp.afh.channelmap5", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[6], + { "AFH Channel Map 6", "btlmp.afh.channelmap6", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[7], + { "AFH Channel Map 7", "btlmp.afh.channelmap7", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[8], + { "AFH Channel Map 8", "btlmp.afh.channelmap8", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelmap[9], + { "AFH Channel Map 9", "btlmp.afh.channelmap9", + FT_UINT32, BASE_CUSTOM, CF_FUNC(decode_uint8_binary), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_reportingmode, + { "AFH Reporting Mode", "btlmp.afh.reportingmode", + FT_UINT8, BASE_HEX, VALS(afh_reportingmode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_afh_mininterval, + { "AFH Min Interval", "btlmp.afh.mininterval", + FT_UINT16, BASE_HEX_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_afh_maxinterval, + { "AFH Max Interval", "btlmp.afh.maxinterval", + FT_UINT16, BASE_HEX_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[0][0], + { "AFH Channel 0-1 Classification", "btlmp.afh.channelclass0", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[0][1], + { "AFH Channel 2-3 Classification", "btlmp.afh.channelclass2", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[0][2], + { "AFH Channel 4-5 Classification", "btlmp.afh.channelclass4", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[0][3], + { "AFH Channel 6-7 Classification", "btlmp.afh.channelclass6", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[1][0], + { "AFH Channel 8-9 Classification", "btlmp.afh.channelclass8", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[1][1], + { "AFH Channel 10-11 Classification", "btlmp.afh.channelclass10", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[1][2], + { "AFH Channel 12-13 Classification", "btlmp.afh.channelclass12", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[1][3], + { "AFH Channel 14-15 Classification", "btlmp.afh.channelclass14", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[2][0], + { "AFH Channel 16-17 Classification", "btlmp.afh.channelclass16", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[2][1], + { "AFH Channel 18-19 Classification", "btlmp.afh.channelclass18", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[2][2], + { "AFH Channel 20-21 Classification", "btlmp.afh.channelclass20", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[2][3], + { "AFH Channel 22-23 Classification", "btlmp.afh.channelclass22", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[3][0], + { "AFH Channel 24-25 Classification", "btlmp.afh.channelclass24", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[3][1], + { "AFH Channel 26-27 Classification", "btlmp.afh.channelclass26", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[3][2], + { "AFH Channel 28-29 Classification", "btlmp.afh.channelclass28", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[3][3], + { "AFH Channel 30-31 Classification", "btlmp.afh.channelclass30", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[4][0], + { "AFH Channel 32-33 Classification", "btlmp.afh.channelclass32", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[4][1], + { "AFH Channel 34-35 Classification", "btlmp.afh.channelclass34", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[4][2], + { "AFH Channel 36-37 Classification", "btlmp.afh.channelclass36", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[4][3], + { "AFH Channel 38-39 Classification", "btlmp.afh.channelclass38", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[5][0], + { "AFH Channel 40-41 Classification", "btlmp.afh.channelclass40", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[5][1], + { "AFH Channel 42-43 Classification", "btlmp.afh.channelclass42", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[5][2], + { "AFH Channel 44-45 Classification", "btlmp.afh.channelclass44", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[5][3], + { "AFH Channel 46-47 Classification", "btlmp.afh.channelclass46", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[6][0], + { "AFH Channel 48-49 Classification", "btlmp.afh.channelclass48", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[6][1], + { "AFH Channel 50-51 Classification", "btlmp.afh.channelclass50", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[6][2], + { "AFH Channel 52-53 Classification", "btlmp.afh.channelclass52", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[6][3], + { "AFH Channel 54-55 Classification", "btlmp.afh.channelclass54", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[7][0], + { "AFH Channel 56-57 Classification", "btlmp.afh.channelclass56", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[7][1], + { "AFH Channel 58-59 Classification", "btlmp.afh.channelclass58", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[7][2], + { "AFH Channel 60-61 Classification", "btlmp.afh.channelclass60", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[7][3], + { "AFH Channel 62-63 Classification", "btlmp.afh.channelclass62", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[8][0], + { "AFH Channel 64-65 Classification", "btlmp.afh.channelclass64", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[8][1], + { "AFH Channel 66-67 Classification", "btlmp.afh.channelclass66", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[8][2], + { "AFH Channel 68-69 Classification", "btlmp.afh.channelclass68", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[8][3], + { "AFH Channel 70-71 Classification", "btlmp.afh.channelclass70", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[9][0], + { "AFH Channel 72-73 Classification", "btlmp.afh.channelclass72", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[9][1], + { "AFH Channel 74-75 Classification", "btlmp.afh.channelclass74", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[9][2], + { "AFH Channel 76-77 Classification", "btlmp.afh.channelclass76", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_afh_channelclass[9][3], + { "AFH Channel 78 Classification", "btlmp.afh.channelclass78", + FT_UINT8, BASE_HEX, VALS(afh_channelclass_vals), 0xC0, + NULL, HFILL } + }, + { &hf_param_rand, + { "Random Number", "btlmp.randomnumber", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_key, + { "Key", "btlmp.key", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_clockoffset, + { "Clock Offset", "btlmp.clockoffset", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slotpairs, 0x00, + NULL, HFILL } + }, + { &hf_param_authresp, + { "Authentication Response", "btlmp.authenticationresponse", + FT_UINT32, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_encryptionmode, + { "Encryption Mode", "btlmp.encryptionmode", + FT_UINT8, BASE_HEX, VALS(encryptionmode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_encryptionkeysize, + { "Encryption Key Size", "btlmp.encryptionkeysize", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_switchinstant, + { "Switch Instant", "btlmp.switchinstant", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_holdtime, + { "Hold Time", "btlmp.holdtime", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_holdinstant, + { "Hold Instant", "btlmp.holdinstant", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_dsniff, + { "Dsniff", "btlmp.sniff.d", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_tsniff, + { "Tsniff", "btlmp.sniff.t", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_sniffattempt, + { "Sniff Attempt", "btlmp.sniff.attempt", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_snifftimeout, + { "Sniff Timeout", "btlmp.sniff.timeout", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_timingcontrolflags[0], + { "Timing Control Flags", "btlmp.timingcontrol.flags", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_timingcontrolflags[1], + { "Timing Change", "btlmp.timingcontrol.timingchange", + FT_UINT8, BASE_DEC, VALS(timingcontrol_timingchange_vals), 0x01, + NULL, HFILL } + }, + { &hf_param_timingcontrolflags[2], + { "Use Initialization 2", "btlmp.timingcontrol.useinit2", + FT_UINT8, BASE_DEC, VALS(timingcontrol_useinit2), 0x02, + NULL, HFILL } + }, + { &hf_param_timingcontrolflags[3], + { "No Access Window", "btlmp.timingcontrol.noaccesswindow", + FT_UINT8, BASE_DEC, VALS(timingcontrol_noaccesswindow), 0x04, + NULL, HFILL } + }, + { &hf_param_timingcontrolflags[4], + { "Reserved", "btlmp.timingcontrol.reserved", + FT_UINT8, BASE_HEX, NULL, 0xf8, + NULL, HFILL } + }, + { &hf_param_futureuse1, + { "Future Use", "btlmp.futureuse1", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_datarate[0], + { "Datarate", "btlmp.datarate.flags", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_datarate[1], + { "Do not use FEC", "btlmp.datarate.nofec", + FT_UINT8, BASE_DEC, VALS(dataratenofec_vals), 0x01, + NULL, HFILL } + }, + { &hf_param_datarate[2], + { "Basic Rate Packet Size Preference", "btlmp.datarate.brpacketsizepreference", + FT_UINT8, BASE_DEC, VALS(dataratepacketsizepreference_vals), 0x06, + NULL, HFILL } + }, + { &hf_param_datarate[3], + { "Enhanced Data Rate Datarate Preference", "btlmp.datarate.edrdataratepreference", + FT_UINT8, BASE_DEC, VALS(dataratedrpreference_vals), 0x18, + NULL, HFILL } + }, + { &hf_param_datarate[4], + { "Enhanced Data Rate Packet Size Preference", "btlmp.datarate.edrpacketsizepreference", + FT_UINT8, BASE_DEC, VALS(dataratepacketsizepreference_vals), 0x60, + NULL, HFILL } + }, + { &hf_param_datarate[5], + { "Reserved", "btlmp.datarate.reserved", + FT_UINT8, BASE_DEC, NULL, 0x80, + NULL, HFILL } + }, + { &hf_param_pollinterval, + { "Poll Interval", "btlmp.qos.pollinterval", + FT_UINT16, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_nbc, + { "NBC", "btlmp.qos.nbc", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_scohandle, + { "SCO Handle", "btlmp.sco.handle", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_dsco, + { "Dsco", "btlmp.sco.d", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_tsco, + { "Tsco", "btlmp.sco.t", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_scopacket, + { "SCO packet", "btlmp.sco.packet", + FT_UINT8, BASE_HEX, VALS(scopacket_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_airmode, + { "Air Mode", "btlmp.sco.airmode", + FT_UINT8, BASE_HEX, VALS(airmode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_slots, + { "Slots", "btlmp.slots", + FT_UINT8, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_tmgacc_drift, + { "Drift", "btlmp.timingaccuracy.drift", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_ppm, 0x00, + NULL, HFILL } + }, + { &hf_param_tmgacc_jitter, + { "Jitter", "btlmp.timingaccuracy.jitter", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_microsecond_microseconds, 0x00, + NULL, HFILL } + }, + { &hf_param_slotoffset, + { "Slot Offset", "btlmp.slotoffset", + FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_microsecond_microseconds, 0x00, + NULL, HFILL } + }, + { &hf_param_bdaddr, + { "Address", "btlmp.bd_addr", + FT_ETHER, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_pagingscheme, + { "Paging Scheme", "btlmp.paging.scheme", + FT_UINT8, BASE_HEX, VALS(pagingscheme_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_pagingschemesettings, + { "Paging Scheme Settings", "btlmp.paging.schemesettings", + FT_UINT8, BASE_HEX, VALS(pagingschemesettings_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_supervisiontimeout, + { "Supervision Timeout", "btlmp.supervisiontimeout", + FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_testscenario, + { "Scenario", "btlmp.test.scenario", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testhoppingmode, + { "Hopping Mode", "btlmp.test.hoppingmode", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testtxfrequency, + { "TX frequency", "btlmp.test.txfrequency", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testrxfrequency, + { "RX frequency", "btlmp.test.rxfrequency", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testpowercontrolmode, + { "Power Control Mode", "btlmp.test.powercontrolmode", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testpollperiod, + { "Poll Period", "btlmp.test.pollperiod", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testpackettype, + { "Packet Type", "btlmp.test.packettype", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_testdatalength, + { "Length of Test Data", "btlmp.test.datalength", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_keysizemask, + { "Key Size Mask", "btlmp.keysizemask", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_encapsulatedmajor, + { "Encapsulated Major Type", "btlmp.encapsulated.major", + FT_UINT8, BASE_HEX, VALS(encapsulatedmajor_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_encapsulatedminor, + { "Encapsulated Minor Type", "btlmp.encapsulated.minor", + FT_UINT8, BASE_HEX, VALS(encapsulatedminor_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_encapsulatedlength, + { "Encapsulated Payload Length", "btlmp.encapsulated.payloadlength", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_encapsulateddata, + { "Encapsulated Data", "btlmp.encapsulated.data", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_simplepaircommit, + { "Commitment Value", "btlmp.simplepair.commit", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_simplepairnonce, + { "Nonce Value", "btlmp.simplepair.nonce", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_dhkeyconfirm, + { "Confirmation Value", "btlmp.dhkey.confirm", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjid, + { "Clock Adjust ID", "btlmp.clkadj.id", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjinstant, + { "Clock Adjust Instant", "btlmp.clkadj.instant", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjus, + { "Clock Adjust Microseconds", "btlmp.clkadj.us", + FT_INT16, BASE_DEC | BASE_UNIT_STRING, &units_microsecond_microseconds, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjslots, + { "Clock Adjust Slots", "btlmp.clkadj.slots", + FT_UINT8, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjmode, + { "Clock Adjust Mode", "btlmp.clkadj.mode", + FT_UINT8, BASE_HEX, VALS(clkadjmode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjclk, + { "Clock Adjust Clock", "btlmp.clkadj.clk", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slotpairs, 0x00, + NULL, HFILL } + }, + { &hf_param_clkadjperiod, + { "Clock Adjust Period", "btlmp.clkadj.period", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_packettypetable, + { "Packet Type Table", "btlmp.packettypetable", + FT_UINT8, BASE_HEX, VALS(packettypetable_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_escohandle, + { "eSCO Handle", "btlmp.esco.handle", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_escoltaddr, + { "eSCO LT_ADDR", "btlmp.esco.ltaddr", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_escod, + { "Desco", "btlmp.esco.d", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_escot, + { "Tesco", "btlmp.esco.t", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_escow, + { "Wesco", "btlmp.esco.w", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_escopackettypems, + { "eSCO Packet Type M->S", "btlmp.esco.packettypems", + FT_UINT8, BASE_HEX, VALS(escopackettypems_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_escopackettypesm, + { "eSCO Packet Type S->M", "btlmp.esco.packettypesm", + FT_UINT8, BASE_HEX, VALS(escopackettypesm_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_escopacketlengthms, + { "eSCO Packet Length M->S", "btlmp.esco.packetlengthms", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_escopacketlengthsm, + { "eSCO Packet Length S->M", "btlmp.esco.packetlengthsm", + FT_UINT16, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_negostate, + { "Negotiation State", "btlmp.negotiationstate", + FT_UINT8, BASE_HEX, VALS(negostate_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_maxsniffsubrate, + { "Max Sniff Subrate", "btlmp.sniffsubrate.max", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_minsniffmodetimeout, + { "Min Sniff Mode Timeout", "btlmp.sniffsubrate.minmodetimeout", + FT_UINT16, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_sniffsubratinginstant, + { "Sniff Subrating Instant", "btlmp.sniffsubrate.instant", + FT_UINT32, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_iocapcap, + { "IO Capabilities", "btlmp.iocap.cap", + FT_UINT8, BASE_HEX, VALS(iocapcap_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_iocapoobauthdata, + { "OOB Authentication Data", "btlmp.iocap.oobauthdata", + FT_UINT8, BASE_HEX, VALS(iocapoobauthdata_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_iocapauthreq, + { "Authentication Requirement", "btlmp.iocap.authreq", + FT_UINT8, BASE_HEX, VALS(iocapauthreq_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_keypressnotificationtype, + { "Notification Type", "btlmp.keypress.notificationtype", + FT_UINT8, BASE_HEX, VALS(keypressnotificationtype_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_poweradjreq, + { "Power Adjustment Request", "btlmp.poweradj.request", + FT_UINT8, BASE_HEX, VALS(poweradjreq_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_poweradjresp[0], + { "Power Adjustment Response", "btlmp.poweradj.response", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_poweradjresp[1], + { "GFSK", "btlmp.poweradj.gfsk", + FT_UINT8, BASE_HEX, VALS(poweradjresp_vals), 0x03, + NULL, HFILL } + }, + { &hf_param_poweradjresp[2], + { "Pi/4-DQPSK", "btlmp.poweradj.pi4dqsk", + FT_UINT8, BASE_HEX, VALS(poweradjresp_vals), 0x0C, + NULL, HFILL } + }, + { &hf_param_poweradjresp[3], + { "8DPSK", "btlmp.poweradj.8dpsk", + FT_UINT8, BASE_HEX, VALS(poweradjresp_vals), 0x30, + NULL, HFILL } + }, + { &hf_param_poweradjresp[4], + { "Reserved", "btlmp.poweradj.reserved", + FT_UINT8, BASE_HEX, NULL, 0xC0, + NULL, HFILL } + }, + { &hf_param_samindex, + { "SAM Index", "btlmp.sam.index", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_samtsm, + { "Tsam-sm", "btlmp.sam.tsm", + FT_UINT8, BASE_DEC | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_param_samnsm, + { "Nsam-sm", "btlmp.sam.nsm", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_samsubmaps, + { "SAM Submaps", "btlmp.sam.submaps", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_samupdatemode, + { "Update Mode", "btlmp.sam.updatemode", + FT_UINT8, BASE_HEX, VALS(samupdatemode_vals), 0x00, + NULL, HFILL } + }, + { &hf_param_samtype0submap, + { "SAM Type 0 Submap", "btlmp.sam.type0submap", + FT_BYTES, BASE_NONE, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_samd, + { "Dsam", "btlmp.sam.d", + FT_UINT8, BASE_HEX, NULL, 0x00, + NULL, HFILL } + }, + { &hf_param_saminstant, + { "SAM Instant", "btlmp.sam.instant", + FT_UINT32, BASE_HEX | BASE_UNIT_STRING, &units_slots, 0x00, + NULL, HFILL } + }, + { &hf_params, + { "Parameters", "btlmp.parameters", + FT_NONE, BASE_NONE, NULL, 0x00, + NULL, HFILL } + } + }; + + static gint *ett[] = { + &ett_btlmp + }; + + proto_btlmp = proto_register_protocol("Bluetooth LMP Protocol", "BT LMP", "btlmp"); + proto_register_field_array(proto_btlmp, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + btlmp_handle = register_dissector("btlmp", dissect_btlmp, proto_btlmp); +} + +void +proto_reg_handoff_btlmp(void) +{ +} + +/* + * Editor modelines - https://www.wireshark.org/tools/modelines.html + * + * Local variables: + * c-basic-offset: 4 + * tab-width: 8 + * indent-tabs-mode: nil + * End: + * + * vi: set shiftwidth=4 tabstop=8 expandtab: + * :indentSize=4:tabSize=8:noTabs=true: + */