wireshark/epan/dissectors/packet-btbredr_rf.c

2551 lines
107 KiB
C

/* packet-btbredr_rf.c
* Routines for Bluetooth Pseudoheader for BR/EDR Baseband
*
* Copyright 2020, Thomas Sailer <t.sailer@alumni.ethz.ch>
* Copyright 2014, Michal Labedzki for Tieto Corporation
* Copyright 2014, Dominic Spill <dominicgs@gmail.com>
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "config.h"
#include <epan/packet.h>
#include <epan/expert.h>
#include <epan/proto_data.h>
#include <epan/reassemble.h>
#include <wiretap/wtap.h>
#include "packet-bluetooth.h"
#include "packet-btbredr_rf.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;
static int hf_signal_power = -1;
static int hf_invalid_signal_power = -1;
static int hf_noise_power = -1;
static int hf_invalid_noise_power = -1;
static int hf_access_address_offenses = -1;
static int hf_payload_transport_rate = -1;
static int hf_payload_transport_rate_payload = -1;
static int hf_payload_transport_rate_transport = -1;
static int hf_payload_transport_rate_ignored = -1;
static int hf_corrected_header_bits = -1;
static int hf_corrected_payload_bits = -1;
static int hf_lower_address_part = -1;
static int hf_reference_lower_address_part = -1;
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;
static int hf_packet_header_type = -1;
static int hf_packet_header_type_any = -1;
static int hf_packet_header_type_sco_br = -1;
static int hf_packet_header_type_esco_br = -1;
static int hf_packet_header_type_esco_edr = -1;
static int hf_packet_header_type_acl_br = -1;
static int hf_packet_header_type_acl_edr = -1;
static int hf_packet_header_type_csb_br = -1;
static int hf_packet_header_type_csb_edr = -1;
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;
static int hf_flags_mic_checked = -1;
static int hf_flags_crc_pass = -1;
static int hf_flags_crc_checked = -1;
static int hf_flags_hec_pass = -1;
static int hf_flags_hec_checked = -1;
static int hf_flags_reference_upper_addres_part_valid = -1;
static int hf_flags_rf_channel_aliasing = -1;
static int hf_flags_br_edr_data_present = -1;
static int hf_flags_reference_lower_address_part_valid = -1;
static int hf_flags_bredr_payload_decrypted = -1;
static int hf_flags_noise_power_valid = -1;
static int hf_flags_signal_power_valid = -1;
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
#define FLAGS_CRC_PASS 0x0800
#define FLAGS_CRC_CHECKED 0x0400
#define FLAGS_HEC_PASS 0x0200
#define FLAGS_HEC_CHECKED 0x0100
#define FLAGS_REFERENCE_UPPER_ADDRES_PART_VALID 0x0080
#define FLAGS_RF_CHANNEL_ALIASING 0x0040
#define FLAGS_BR_EDR_DATA_PRESENT 0x0020
#define FLAGS_REFERENCE_LOWER_ADDRESS_PART_VALID 0x0010
#define FLAGS_BREDR_PAYLOAD_DECRYPTED 0x0008
#define FLAGS_NOISE_POWER_VALID 0x0004
#define FLAGS_SIGNAL_POWER_VALID 0x0002
#define FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED 0x0001
static int * const hfx_payload_transport_rate[] = {
&hf_payload_transport_rate_payload,
&hf_payload_transport_rate_transport,
NULL
};
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;
static dissector_table_t packet_type_esco_edr_table;
static dissector_table_t packet_type_acl_br_table;
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;
#define BDADDR_MASTER 0
#define BDADDR_SLAVE 1
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" },
{ 0x01, "SCO" },
{ 0x02, "eSCO" },
{ 0x03, "ACL" },
{ 0x04, "CSB" },
{ 0, NULL }
};
#define TRANSPORT_ANY 0x00
#define TRANSPORT_SCO 0x10
#define TRANSPORT_eSCO 0x20
#define TRANSPORT_ACL 0x30
#define TRANSPORT_CSB 0x40
static const value_string payload_transport_rate_payload_vals[] = {
{ 0x00, "Basic Rate with GFSK demodulation" },
{ 0x01, "Enhanced Data Rate with PI/2-DQPSK demodulation" },
{ 0x02, "Enhanced Data Rate with 8DPSK demodulation" },
{ 0, NULL }
};
static const value_string payload_transport_rate_payload_abbrev_vals[] = {
{ 0x00, "BR 1Mbps" },
{ 0x01, "EDR 2Mbps" },
{ 0x02, "EDR 3Mbps" },
{ 0, NULL }
};
#define PAYLOAD_BR 0x00
#define PAYLOAD_EDR_2 0x01
#define PAYLOAD_EDR_3 0x02
#define PACKET_TYPE_UNKNOWN -1
static const value_string packet_type_any_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "FHS" },
{ 0x03, "DM1" },
{ 0x04, "DH1/2-DH1" },
{ 0x05, "HV1" },
{ 0x06, "HV2/2-EV3" },
{ 0x07, "HV3/EV3/3-EV3" },
{ 0x08, "DV/3-DH1" },
{ 0x09, "AUX1" },
{ 0x0A, "DM3/2-DH3" },
{ 0x0B, "DH3/3-DH3" },
{ 0x0C, "EV4/2-EV5" },
{ 0x0D, "EV5/3-EV5" },
{ 0x0E, "DM5/2-DH5" },
{ 0x0F, "DH5/3-DH5" },
{ 0, NULL }
};
static const value_string packet_type_sco_br_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "FHS" },
{ 0x03, "DM1" },
{ 0x04, "undefined" },
{ 0x05, "HV1" },
{ 0x06, "HV2" },
{ 0x07, "HV3" },
{ 0x08, "DV" },
{ 0x09, "undefined" },
{ 0x0A, "undefined" },
{ 0x0B, "undefined" },
{ 0x0C, "undefined" },
{ 0x0D, "undefined" },
{ 0x0E, "undefined" },
{ 0x0F, "undefined" },
{ 0, NULL }
};
static const value_string packet_type_esco_br_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "reserved" },
{ 0x03, "reserved" },
{ 0x04, "undefined" },
{ 0x05, "undefined" },
{ 0x06, "undefined" },
{ 0x07, "EV3" },
{ 0x08, "undefined" },
{ 0x09, "undefined" },
{ 0x0A, "undefined" },
{ 0x0B, "undefined" },
{ 0x0C, "EV4" },
{ 0x0D, "EV5" },
{ 0x0E, "undefined" },
{ 0x0F, "undefined" },
{ 0, NULL }
};
static const value_string packet_type_esco_edr_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "reserved" },
{ 0x03, "reserved" },
{ 0x04, "undefined" },
{ 0x05, "undefined" },
{ 0x06, "2-EV3" },
{ 0x07, "3-EV3" },
{ 0x08, "undefined" },
{ 0x09, "undefined" },
{ 0x0A, "undefined" },
{ 0x0B, "undefined" },
{ 0x0C, "2-EV5" },
{ 0x0D, "3-EV5" },
{ 0x0E, "undefined" },
{ 0x0F, "undefined" },
{ 0, NULL }
};
static const value_string packet_type_acl_br_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "FHS" },
{ 0x03, "DM1" },
{ 0x04, "DH1" },
{ 0x05, "undefined" },
{ 0x06, "undefined" },
{ 0x07, "undefined" },
{ 0x08, "undefined" },
{ 0x09, "AUX1" },
{ 0x0A, "DM3" },
{ 0x0B, "DH3" },
{ 0x0C, "undefined" },
{ 0x0D, "undefined" },
{ 0x0E, "DM5" },
{ 0x0F, "DH5" },
{ 0, NULL }
};
static const value_string packet_type_acl_edr_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "POLL" },
{ 0x02, "FHS" },
{ 0x03, "DM1" },
{ 0x04, "2-DH1" },
{ 0x05, "undefined" },
{ 0x06, "undefined" },
{ 0x07, "undefined" },
{ 0x08, "3-DH1" },
{ 0x09, "AUX1" },
{ 0x0A, "2-DH3" },
{ 0x0B, "3-DH3" },
{ 0x0C, "undefined" },
{ 0x0D, "undefined" },
{ 0x0E, "2-DH5" },
{ 0x0F, "3-DH5" },
{ 0, NULL }
};
static const value_string packet_type_csb_br_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "reserved" },
{ 0x02, "reserved" },
{ 0x03, "DM1" },
{ 0x04, "DH1" },
{ 0x05, "undefined" },
{ 0x06, "undefined" },
{ 0x07, "undefined" },
{ 0x08, "undefined" },
{ 0x09, "undefined" },
{ 0x0A, "DM3" },
{ 0x0B, "DH3" },
{ 0x0C, "undefined" },
{ 0x0D, "undefined" },
{ 0x0E, "DM5" },
{ 0x0F, "DH5" },
{ 0, NULL }
};
static const value_string packet_type_csb_edr_vals[] = {
{ 0x00, "NULL" },
{ 0x01, "reserved" },
{ 0x02, "reserved" },
{ 0x03, "DM1" },
{ 0x04, "2-DH1" },
{ 0x05, "undefined" },
{ 0x06, "undefined" },
{ 0x07, "undefined" },
{ 0x08, "3-DH1" },
{ 0x09, "undefined" },
{ 0x0A, "2-DH3" },
{ 0x0B, "3-DH3" },
{ 0x0C, "undefined" },
{ 0x0D, "undefined" },
{ 0x0E, "2-DH5" },
{ 0x0F, "3-DH5" },
{ 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)
{
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
broken_check_hec(guint8 uap, guint32 header)
{
guint8 hec;
guint16 header_data;
guint8 lfsr;
gint8 i;
hec = header & 0xFF;
header_data = (header >> 8) & 0x3F;
lfsr = uap;
for (i = 9; i >= 0; i -= 1) {
if (lfsr & 0x80)
lfsr ^= 0x65;
lfsr = (lfsr << 1) | (((lfsr >> 7) ^ (header_data >> i)) & 0x01);
}
lfsr = reverse_bits(lfsr);
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 = &lap;
key[3].length = 1;
key[3].key = &ltaddr;
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 = &lap;
key[3].length = 1;
key[3].key = &ltaddr;
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 = &lap;
key[3].length = 1;
key[3].key = &ltaddr;
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 = 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);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "BT BR/EDR RF");
if (tvb_captured_length(tvb) >= 21) {
flags = tvb_get_guint16(tvb, 20, ENC_LITTLE_ENDIAN);
} else {
flags = 0;
}
if (flags & FLAGS_RF_CHANNEL_ALIASING)
hf_x = hf_uncertain_rf_channel;
else
hf_x = hf_rf_channel;
proto_tree_add_item(btbredr_rf_tree, hf_x, tvb, offset, 1, ENC_NA);
offset += 1;
if (flags & FLAGS_SIGNAL_POWER_VALID)
hf_x = hf_signal_power;
else
hf_x = hf_invalid_signal_power;
proto_tree_add_item(btbredr_rf_tree, hf_x, tvb, offset, 1, ENC_NA);
offset += 1;
if (flags & FLAGS_NOISE_POWER_VALID)
hf_x = hf_noise_power;
else
hf_x = hf_invalid_noise_power;
proto_tree_add_item(btbredr_rf_tree, hf_x, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(btbredr_rf_tree, hf_access_address_offenses, tvb, offset, 1, ENC_NA);
offset += 1;
payload_and_transport = tvb_get_guint8(tvb, offset);
col_add_fstr(pinfo->cinfo, COL_INFO, "Transport: %s (%s), RF Channel: %s%2u",
val_to_str_const(payload_and_transport >> 4, payload_transport_rate_transport_vals, "Unknown"),
val_to_str_const(payload_and_transport & 0xF, payload_transport_rate_payload_abbrev_vals, "Unknown"),
(flags & FLAGS_RF_CHANNEL_ALIASING) ? "~" : "",
tvb_get_guint8(tvb, 0));
if (payload_and_transport == 0xFF)
proto_tree_add_item(btbredr_rf_tree, hf_payload_transport_rate_ignored, tvb, offset, 1, ENC_NA);
else
proto_tree_add_bitmask(btbredr_rf_tree, tvb, offset, hf_payload_transport_rate, ett_payload_transport_rate, hfx_payload_transport_rate, ENC_LITTLE_ENDIAN);
offset += 1;
proto_tree_add_item(btbredr_rf_tree, hf_corrected_header_bits, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(btbredr_rf_tree, hf_corrected_payload_bits, tvb, offset, 2, ENC_LITTLE_ENDIAN);
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 = &lap;
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
hf_x = hf_invalid_reference_lower_address_part;
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) {
hf_x = hf_reference_upper_addres_part;
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;
{
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_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_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_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_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_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_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_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_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_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);
}
proto_tree_add_item(header_tree, hf_packet_header_flow_control, tvb, offset, 4, ENC_LITTLE_ENDIAN);
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);
}
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);
flags_tree = proto_item_add_subtree(flags_item, ett_flags);
flags = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
reserved_item = proto_tree_add_item(flags_tree, hf_flags_reserved_15_14, tvb, offset, 2, ENC_LITTLE_ENDIAN);
if (flags & 0xC000) {
expert_add_info(pinfo, reserved_item, &ei_reserved_not_zero);
}
proto_tree_add_item(flags_tree, hf_flags_mic_pass, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_mic_checked, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_crc_pass, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_crc_checked, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_hec_pass, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_hec_checked, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_reference_upper_addres_part_valid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_rf_channel_aliasing, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_br_edr_data_present, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_reference_lower_address_part_valid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_bredr_payload_decrypted, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_noise_power_valid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_signal_power_valid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(flags_tree, hf_flags_packet_header_and_br_edr_payload_dewhitened, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if ((flags & (FLAGS_SIGNAL_POWER_VALID | FLAGS_NOISE_POWER_VALID)) == (FLAGS_SIGNAL_POWER_VALID | FLAGS_NOISE_POWER_VALID)) {
col_append_fstr(pinfo->cinfo, COL_INFO, " (SP: %4i, NP: %4i)",
(gint)tvb_get_gint8(tvb, 1), (gint)tvb_get_gint8(tvb, 2));
} else if (flags & FLAGS_SIGNAL_POWER_VALID) {
col_append_fstr(pinfo->cinfo, COL_INFO, " (SP: %4i)",
(gint)tvb_get_gint8(tvb, 1));
} else if (flags & FLAGS_NOISE_POWER_VALID) {
col_append_fstr(pinfo->cinfo, COL_INFO, " (NP: %4i)",
(gint)tvb_get_gint8(tvb, 2));
}
if (flags & FLAGS_PACKET_HEADER_AND_BR_EDR_PAYLOAD_DEWHITENED)
col_append_fstr(pinfo->cinfo, COL_INFO, ", Packet Type: %s", packet_type_str);
// 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;
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 (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(pinfo->pool, 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(pinfo->pool, 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 = &bluetooth_max_disconnect_in_frame;
acl_data->disconnect_in_frame = &bluetooth_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(pinfo->pool, 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 = &bluetooth_max_disconnect_in_frame;
acl_data->disconnect_in_frame = &bluetooth_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 = &lap;
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 = &lap;
key[3].length = 1;
key[3].key = &ltaddr;
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;
}
void
proto_register_btbredr_rf(void)
{
expert_module_t *expert_module;
static hf_register_info hf[] = {
{ &hf_rf_channel,
{ "RF Channel", "btbredr_rf.rf_channel",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_uncertain_rf_channel,
{ "Uncertain RF Channel", "btbredr_rf.uncertain_rf_channel",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_signal_power,
{ "Signal Power", "btbredr_rf.signal_power",
FT_INT8, BASE_DEC, NULL, 0x00,
"Signal Power in dBm", HFILL }
},
{ &hf_invalid_signal_power,
{ "Invalid Signal Power", "btbredr_rf.invalid.signal_power",
FT_INT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_noise_power,
{ "Noise Power", "btbredr_rf.noise_power",
FT_INT8, BASE_DEC, NULL, 0x00,
"Noise Power in dBm", HFILL }
},
{ &hf_invalid_noise_power,
{ "Invalid Noise Power", "btbredr_rf.invalid.noise_power",
FT_INT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_access_address_offenses,
{ "Access Address Offenses", "btbredr_rf.access_address_offenses",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_payload_transport_rate,
{ "Payload Transport Rate", "btbredr_rf.payload_transport_rate",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_payload_transport_rate_ignored,
{ "Payload Transport Rate: Ignored", "btbredr_rf.payload_transport_rate.ignored",
FT_UINT8, BASE_HEX, NULL, 0x00,
"BT Packet Header is ignored and there is no payload", HFILL }
},
{ &hf_payload_transport_rate_transport,
{ "Transport", "btbredr_rf.payload_transport_rate.transport",
FT_UINT8, BASE_HEX, VALS(payload_transport_rate_transport_vals), 0xF0,
NULL, HFILL }
},
{ &hf_payload_transport_rate_payload,
{ "Payload", "btbredr_rf.payload_transport_rate.payload",
FT_UINT8, BASE_HEX, VALS(payload_transport_rate_payload_vals), 0x0F,
NULL, HFILL }
},
{ &hf_corrected_header_bits,
{ "Corrected Header Bits", "btbredr_rf.corrected_header_bits",
FT_UINT8, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_corrected_payload_bits,
{ "Corrected Payload Bits", "btbredr_rf.corrected_payload_bits",
FT_INT16, BASE_DEC, NULL, 0x00,
NULL, HFILL }
},
{ &hf_lower_address_part,
{ "Lower Address Part", "btbredr_rf.lower_address_part",
FT_UINT32, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_reference_lower_address_part,
{ "Reference Lower Address Part", "btbredr_rf.reference_lower_address_part",
FT_UINT24, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_invalid_reference_lower_address_part,
{ "Invalid Reference Lower Address Part", "btbredr_rf.invalid.reference_lower_address_part",
FT_UINT24, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_reference_upper_addres_part,
{ "Reference Upper Address Part", "btbredr_rf.reference_upper_addres_part",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_invalid_reference_upper_addres_part,
{ "Invalid Reference Upper Address Part", "btbredr_rf.invalid.reference_upper_addres_part",
FT_UINT8, BASE_HEX, NULL, 0x00,
NULL, HFILL }
},
{ &hf_whitened_packet_header,
{ "Whitened Packet Header", "btbredr_rf.whitened.packet_header",
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_broken_lt_addr,
{ "LT_ADDR", "btbredr_rf.packet_header.lt_addr",
FT_UINT32, BASE_HEX, NULL, 0x00038000,
NULL, HFILL }
},
{ &hf_packet_header_broken_type,
{ "Type", "btbredr_rf.packet_header.type",
FT_UINT32, BASE_HEX, NULL, 0x00007800,
NULL, HFILL }
},
{ &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_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_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_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_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_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_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_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_broken_flow_control,
{ "Flow Control", "btbredr_rf.packet_header.flow_control",
FT_BOOLEAN, 32, NULL, 0x00000400,
NULL, HFILL }
},
{ &hf_packet_header_broken_acknowledge_indication,
{ "ARQN", "btbredr_rf.packet_header.arqn",
FT_BOOLEAN, 32, NULL, 0x00000200,
"Acknowledge Indication", HFILL }
},
{ &hf_packet_header_broken_sequence_number,
{ "SEQN", "btbredr_rf.packet_header.seqn",
FT_BOOLEAN, 32, NULL, 0x00000100,
"Sequence Number", HFILL }
},
{ &hf_packet_header_broken_header_error_check,
{ "HEC", "btbredr_rf.packet_header.hec",
FT_UINT32, BASE_HEX, NULL, 0x000000FF,
"Header Error Check", HFILL }
},
{ &hf_whitened_data,
{ "Whitened Data", "btbredr_rf.whitened.data",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_encrypted_data,
{ "Encrypted Data", "btbredr_rf.encrypted.data",
FT_NONE, BASE_NONE, NULL, 0x00,
NULL, HFILL }
},
{ &hf_data,
{ "Data", "btbredr_rf.data",
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,
NULL, HFILL }
},
{ &hf_flags_mic_pass,
{ "MIC Pass", "btbredr_rf.flags.mic_pass",
FT_BOOLEAN, 16, NULL, 0x2000,
NULL, HFILL }
},
{ &hf_flags_mic_checked,
{ "MIC Checked", "btbredr_rf.flags.mic_check",
FT_BOOLEAN, 16, NULL, 0x1000,
NULL, HFILL }
},
{ &hf_flags_crc_pass,
{ "CRC Pass", "btbredr_rf.flags.crc_pass",
FT_BOOLEAN, 16, NULL, 0x0800,
NULL, HFILL }
},
{ &hf_flags_crc_checked,
{ "CRC Checked", "btbredr_rf.flags.crc_check",
FT_BOOLEAN, 16, NULL, 0x0400,
NULL, HFILL }
},
{ &hf_flags_hec_pass,
{ "HEC Pass", "btbredr_rf.flags.hec_pass",
FT_BOOLEAN, 16, NULL, 0x0200,
NULL, HFILL }
},
{ &hf_flags_hec_checked,
{ "HEC Checked", "btbredr_rf.flags.hec_check",
FT_BOOLEAN, 16, NULL, 0x0100,
NULL, HFILL }
},
{ &hf_flags_reference_upper_addres_part_valid,
{ "Reference Upper Address Part Valid", "btbredr_rf.flags.reference_upper_addres_part_valid",
FT_BOOLEAN, 16, NULL, 0x0080,
NULL, HFILL }
},
{ &hf_flags_rf_channel_aliasing,
{ "RF Channel Aliasing", "btbredr_rf.flags.rf_channel_aliasing",
FT_BOOLEAN, 16, NULL, 0x0040,
NULL, HFILL }
},
{ &hf_flags_br_edr_data_present,
{ "BR or EDR Data Present", "btbredr_rf.flags.bredr_data_present",
FT_BOOLEAN, 16, NULL, 0x0020,
NULL, HFILL }
},
{ &hf_flags_reference_lower_address_part_valid,
{ "Reference Lower Address Part Valid", "btbredr_rf.flags.reference_lower_address_part_valid",
FT_BOOLEAN, 16, NULL, 0x0010,
NULL, HFILL }
},
{ &hf_flags_bredr_payload_decrypted,
{ "BR or EDR Payload Decrypted", "btbredr_rf.flags.bredr_payload_decrypted",
FT_BOOLEAN, 16, NULL, 0x0008,
NULL, HFILL }
},
{ &hf_flags_noise_power_valid,
{ "Noise Power Valid", "btbredr_rf.flags.noise_power_valid",
FT_BOOLEAN, 16, NULL, 0x0004,
NULL, HFILL }
},
{ &hf_flags_signal_power_valid,
{ "Signal Power Valid", "btbredr_rf.flags.signal_power_valid",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL }
},
{ &hf_flags_packet_header_and_br_edr_payload_dewhitened,
{ "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 }
}
};
static gint *ett[] = {
&ett_btbredr_rf,
&ett_flags,
&ett_payload_transport_rate,
&ett_packet_header,
&ett_bluetooth_header,
&ett_payload_header,
&ett_l2cap_msg_fragment,
&ett_l2cap_msg_fragments,
&ett_btbredr_fhs
};
static ei_register_info ei[] = {
{ &ei_unexpected_data, { "btbredr_rf.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected data, BR or EDR Data Present flag is set to False", EXPFILL }},
{ &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);
packet_type_acl_br_table = register_dissector_table("btbredr_rf.packet_type.acl.br", "BT Packet Type for ACL BR", proto_btbredr_rf, FT_UINT8, BASE_HEX);
packet_type_acl_edr_table = register_dissector_table("btbredr_rf.packet_type.acl.edr", "BT Packet Type for ACL EDR", proto_btbredr_rf, FT_UINT8, BASE_HEX);
packet_type_csb_br_table = register_dissector_table("btbredr_rf.packet_type.csb.br", "BT Packet Type for CSB BR", proto_btbredr_rf, FT_UINT8, BASE_HEX);
packet_type_csb_edr_table = register_dissector_table("btbredr_rf.packet_type.csb.edr", "BT Packet Type for CSB EDR", proto_btbredr_rf, FT_UINT8, BASE_HEX);
expert_module = expert_register_protocol(proto_btbredr_rf);
expert_register_field_array(expert_module, ei, array_length(ei));
}
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);
}
/*
* 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:
*/