diff options
author | Michal Labedzki <michal.labedzki@tieto.com> | 2014-12-23 14:57:45 +0100 |
---|---|---|
committer | Michal Labedzki <michal.labedzki@tieto.com> | 2015-01-10 15:35:39 +0000 |
commit | d6e040989280e9999ddbe0a2b41f9fd80c746dbd (patch) | |
tree | d4990f08ec610aa06bc060a081af1bd3893113a0 /epan | |
parent | c69b2ab32001fecb510ffb2b6799b60068872f99 (diff) | |
download | wireshark-d6e040989280e9999ddbe0a2b41f9fd80c746dbd.tar.gz |
Bluetooth: Add HCI Vendor Broadcom dissector
Since those command/events are vendor specific and proprietary
not all commands/events are implemented. All implemented commands can be
found in Open Source implementations for Broadcom chip. If you found more,
please let me know.
Change-Id: Ie68d3737c88a8cef39260a9d93192cfc81871d6c
Reviewed-on: https://code.wireshark.org/review/6406
Reviewed-by: Michal Labedzki <michal.labedzki@tieto.com>
Tested-by: Michal Labedzki <michal.labedzki@tieto.com>
Diffstat (limited to 'epan')
-rw-r--r-- | epan/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/dissectors/Makefile.common | 1 | ||||
-rw-r--r-- | epan/dissectors/packet-bluetooth.c | 52 | ||||
-rw-r--r-- | epan/dissectors/packet-bluetooth.h | 5 | ||||
-rw-r--r-- | epan/dissectors/packet-bthci_cmd.c | 63 | ||||
-rw-r--r-- | epan/dissectors/packet-bthci_evt.c | 8 | ||||
-rw-r--r-- | epan/dissectors/packet-bthci_vendor.c | 1418 |
7 files changed, 1490 insertions, 58 deletions
diff --git a/epan/CMakeLists.txt b/epan/CMakeLists.txt index cb78652da3..f8f870f6fd 100644 --- a/epan/CMakeLists.txt +++ b/epan/CMakeLists.txt @@ -432,6 +432,7 @@ set(DISSECTOR_SRC dissectors/packet-bthci_cmd.c dissectors/packet-bthci_evt.c dissectors/packet-bthci_sco.c + dissectors/packet-bthci_vendor.c dissectors/packet-bthcrp.c dissectors/packet-bthfp.c dissectors/packet-bthid.c diff --git a/epan/dissectors/Makefile.common b/epan/dissectors/Makefile.common index da681faa25..8660afce7d 100644 --- a/epan/dissectors/Makefile.common +++ b/epan/dissectors/Makefile.common @@ -347,6 +347,7 @@ DISSECTOR_SRC = \ packet-bthci_cmd.c \ packet-bthci_evt.c \ packet-bthci_sco.c \ + packet-bthci_vendor.c \ packet-bthcrp.c \ packet-bthfp.c \ packet-bthid.c \ diff --git a/epan/dissectors/packet-bluetooth.c b/epan/dissectors/packet-bluetooth.c index a16bc5073f..b5cb9f0cf6 100644 --- a/epan/dissectors/packet-bluetooth.c +++ b/epan/dissectors/packet-bluetooth.c @@ -1031,6 +1031,58 @@ dissect_bd_addr(gint hf_bd_addr, proto_tree *tree, tvbuff_t *tvb, gint offset, g } +void +save_local_device_name_from_eir_ad(tvbuff_t *tvb, gint offset, packet_info *pinfo, + guint8 size, bluetooth_data_t *bluetooth_data) +{ + gint i = 0; + guint8 length; + wmem_tree_key_t key[4]; + guint32 k_interface_id; + guint32 k_adapter_id; + guint32 k_frame_number; + gchar *name; + localhost_name_entry_t *localhost_name_entry; + + if (!(!pinfo->fd->flags.visited && bluetooth_data)) return; + + while (i < size) { + length = tvb_get_guint8(tvb, offset + i); + if (length == 0) break; + + switch(tvb_get_guint8(tvb, offset + i + 1)) { + case 0x08: /* Device Name, shortened */ + case 0x09: /* Device Name, full */ + name = tvb_get_string_enc(wmem_packet_scope(), tvb, offset + i + 2, length - 1, ENC_ASCII); + + k_interface_id = bluetooth_data->interface_id; + k_adapter_id = bluetooth_data->adapter_id; + k_frame_number = pinfo->fd->num; + + key[0].length = 1; + key[0].key = &k_interface_id; + key[1].length = 1; + key[1].key = &k_adapter_id; + key[2].length = 1; + key[2].key = &k_frame_number; + key[3].length = 0; + key[3].key = NULL; + + localhost_name_entry = (localhost_name_entry_t *) wmem_new(wmem_file_scope(), localhost_name_entry_t); + localhost_name_entry->interface_id = k_interface_id; + localhost_name_entry->adapter_id = k_adapter_id; + localhost_name_entry->name = wmem_strdup(wmem_file_scope(), name); + + wmem_tree_insert32_array(bluetooth_data->localhost_name, key, localhost_name_entry); + + break; + } + + i += length + 1; + } +} + + static const char* bluetooth_conv_get_filter_type(conv_item_t* conv _U_, conv_filter_type_e filter) { if (filter == CONV_FT_SRC_ADDRESS) diff --git a/epan/dissectors/packet-bluetooth.h b/epan/dissectors/packet-bluetooth.h index b4e7c2c926..29a737afd4 100644 --- a/epan/dissectors/packet-bluetooth.h +++ b/epan/dissectors/packet-bluetooth.h @@ -82,6 +82,8 @@ extern const value_string bthci_cmd_page_scan_repetition_modes[]; extern const value_string bthci_cmd_page_scan_period_modes[]; extern const value_string bthci_cmd_notification_types[]; +extern value_string_ext bthci_evt_evt_code_vals_ext; + /* We support Bluetooth over various interfaces, interface_id and adapter_id is used to decode further payload. Case: there is a host. Host has X @@ -186,6 +188,9 @@ extern guint32 max_disconnect_in_frame; extern gint dissect_bd_addr(gint hf_bd_addr, proto_tree *tree, tvbuff_t *tvb, gint offset, guint8 *bdaddr); +extern void save_local_device_name_from_eir_ad(tvbuff_t *tvb, gint offset, + packet_info *pinfo, guint8 size, bluetooth_data_t *bluetooth_data); + #endif /* diff --git a/epan/dissectors/packet-bthci_cmd.c b/epan/dissectors/packet-bthci_cmd.c index b26e3026e2..4ad4b6d3db 100644 --- a/epan/dissectors/packet-bthci_cmd.c +++ b/epan/dissectors/packet-bthci_cmd.c @@ -1445,57 +1445,6 @@ static gpointer bthci_cmd_vendor_value(packet_info *pinfo _U_) return NULL; } -static void -save_local_device_name(tvbuff_t *tvb, gint offset, packet_info *pinfo, - guint8 size, bluetooth_data_t *bluetooth_data) -{ - gint i = 0; - guint8 length; - wmem_tree_key_t key[4]; - guint32 k_interface_id; - guint32 k_adapter_id; - guint32 k_frame_number; - gchar *name; - localhost_name_entry_t *localhost_name_entry; - - if (!(!pinfo->fd->flags.visited && bluetooth_data)) return; - - while (i < size) { - length = tvb_get_guint8(tvb, offset + i); - if (length == 0) break; - - switch(tvb_get_guint8(tvb, offset + i + 1)) { - case 0x08: /* Device Name, shortened */ - case 0x09: /* Device Name, full */ - name = tvb_get_string_enc(wmem_packet_scope(), tvb, offset + i + 2, length - 1, ENC_ASCII); - - k_interface_id = bluetooth_data->interface_id; - k_adapter_id = bluetooth_data->adapter_id; - k_frame_number = pinfo->fd->num; - - key[0].length = 1; - key[0].key = &k_interface_id; - key[1].length = 1; - key[1].key = &k_adapter_id; - key[2].length = 1; - key[2].key = &k_frame_number; - key[3].length = 0; - key[3].key = NULL; - - localhost_name_entry = (localhost_name_entry_t *) wmem_new(wmem_file_scope(), localhost_name_entry_t); - localhost_name_entry->interface_id = k_interface_id; - localhost_name_entry->adapter_id = k_adapter_id; - localhost_name_entry->name = wmem_strdup(wmem_file_scope(), name); - - wmem_tree_insert32_array(bluetooth_data->localhost_name, key, localhost_name_entry); - - break; - } - - i += length + 1; - } -} - static int dissect_bthci_cmd_cod_mask(tvbuff_t *tvb, int offset, packet_info *pinfo _U_, proto_tree *tree) { @@ -2556,7 +2505,7 @@ dissect_host_controller_baseband_cmd(tvbuff_t *tvb, int offset, packet_info *pin offset++; call_dissector(btcommon_eir_handle, tvb_new_subset_length(tvb, offset, 240), pinfo, tree); - save_local_device_name(tvb, offset, pinfo, 240, bluetooth_data); + save_local_device_name_from_eir_ad(tvb, offset, pinfo, 240, bluetooth_data); offset += 240; break; @@ -2899,7 +2848,7 @@ dissect_le_cmd(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, offset++; call_dissector(btcommon_ad_handle, tvb_new_subset_length(tvb, offset, 31), pinfo, tree); - save_local_device_name(tvb, offset, pinfo, 31, bluetooth_data); + save_local_device_name_from_eir_ad(tvb, offset, pinfo, 31, bluetooth_data); offset += 31; break; @@ -3081,6 +3030,7 @@ dissect_bthci_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat proto_tree *opcode_tree; gint hfx; bluetooth_data_t *bluetooth_data; + const gchar *unknown_format; /* Reject the packet if data is NULL */ if (data == NULL) @@ -3125,7 +3075,12 @@ dissect_bthci_cmd(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat ocf = opcode & 0x03ff; ogf = (guint8) (opcode >> 10); - proto_item_append_text(ti_cmd," - %s", val_to_str_ext(opcode, &bthci_cmd_opcode_vals_ext, "Unknown 0x%04x")); + if (ogf == HCI_OGF_VENDOR_SPECIFIC) + unknown_format = "Vendor Command 0x%04x"; + else + unknown_format = "Unknown 0x%04x"; + + proto_item_append_text(ti_cmd," - %s", val_to_str_ext(opcode, &bthci_cmd_opcode_vals_ext, unknown_format)); col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_CMD"); diff --git a/epan/dissectors/packet-bthci_evt.c b/epan/dissectors/packet-bthci_evt.c index 9f3a1e54b7..121529e402 100644 --- a/epan/dissectors/packet-bthci_evt.c +++ b/epan/dissectors/packet-bthci_evt.c @@ -445,7 +445,7 @@ static const value_string evt_code_vals[] = { {0xff, "Vendor-Specific"}, {0, NULL} }; -static value_string_ext evt_code_vals_ext = VALUE_STRING_EXT_INIT(evt_code_vals); +value_string_ext bthci_evt_evt_code_vals_ext = VALUE_STRING_EXT_INIT(evt_code_vals); static const value_string bthci_cmd_status_pending_vals[] = { {0x00, "Pending"}, @@ -3380,7 +3380,7 @@ dissect_bthci_evt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat evt_code = tvb_get_guint8(tvb, offset); proto_tree_add_item(bthci_evt_tree, hf_bthci_evt_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_item_append_text(bthci_evt_tree, " - %s", val_to_str_ext_const(evt_code, &evt_code_vals_ext, "Unknown 0x%08x")); + proto_item_append_text(bthci_evt_tree, " - %s", val_to_str_ext_const(evt_code, &bthci_evt_evt_code_vals_ext, "Unknown 0x%08x")); offset += 1; param_length = tvb_get_guint8(tvb, offset); @@ -3390,7 +3390,7 @@ dissect_bthci_evt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *dat col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_EVT"); - col_append_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(evt_code, &evt_code_vals_ext, "Unknown 0x%08x")); + col_append_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(evt_code, &bthci_evt_evt_code_vals_ext, "Unknown 0x%08x")); if (param_length > 0) { switch(evt_code) { @@ -3704,7 +3704,7 @@ proto_register_bthci_evt(void) static hf_register_info hf[] = { { &hf_bthci_evt_code, { "Event Code", "bthci_evt.code", - FT_UINT8, BASE_HEX | BASE_EXT_STRING, &evt_code_vals_ext, 0x0, + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &bthci_evt_evt_code_vals_ext, 0x0, NULL, HFILL } }, { &hf_bthci_evt_param_length, diff --git a/epan/dissectors/packet-bthci_vendor.c b/epan/dissectors/packet-bthci_vendor.c new file mode 100644 index 0000000000..259b2f1deb --- /dev/null +++ b/epan/dissectors/packet-bthci_vendor.c @@ -0,0 +1,1418 @@ +/* packet-bthci_vendor.c + * Routines for the Bluetooth HCI Vendors Commands/Events + * + * Copyright 2014, Michal Labedzki for Tieto Corporation + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include <epan/packet.h> +#include <epan/expert.h> + +#include "packet-bluetooth.h" + +static int proto_bthci_vendor_broadcom = -1; + +static int hf_opcode = -1; +static int hf_opcode_ogf = -1; +static int hf_opcode_ocf = -1; +static int hf_parameter_length = -1; +static int hf_number_of_allowed_command_packets = -1; +static int hf_event_code = -1; +static int hf_le_advertising_filter_subcode = -1; +static int hf_le_scan_condition = -1; +static int hf_le_filter_index = -1; +static int hf_le_number_of_available_filters = -1; +static int hf_firmware = -1; +static int hf_firmware_address = -1; +static int hf_baudrate = -1; +static int hf_status = -1; +static int hf_bd_addr = -1; +static int hf_max_advertising_instance = -1; +static int hf_resolvable_private_address_offloading = -1; +static int hf_total_scan_results = -1; +static int hf_max_irk_list = -1; +static int hf_filter_support = -1; +static int hf_max_filter = -1; +static int hf_energy_support = -1; +static int hf_connection_handle = -1; +static int hf_connection_priority = -1; +static int hf_sleep_mode = -1; +static int hf_host_stack_idle_threshold = -1; +static int hf_host_controller_idle_threshold = -1; +static int hf_wake_polarity = -1; +static int hf_host_wake_polarity = -1; +static int hf_allow_host_sleep_during_sco = -1; +static int hf_combine_sleep_mode_and_lpm = -1; +static int hf_enable_uart_txd_tri_state = -1; +static int hf_sleep_guard_time = -1; +static int hf_wakeup_guard_time = -1; +static int hf_txd_config = -1; +static int hf_pulsed_host_wake = -1; +static int hf_uart_clock = -1; +static int hf_codec_state = -1; +static int hf_codec = -1; +static int hf_sco_pcm_routing = -1; +static int hf_sco_pcm_interface_clock_rate = -1; +static int hf_sco_pcm_interface_frame_type = -1; +static int hf_sco_pcm_interface_sync_mode = -1; +static int hf_sco_pcm_interface_clock_mode = -1; +static int hf_pcm_shift_mode = -1; +static int hf_pcm_fill_bits = -1; +static int hf_pcm_fill_method = -1; +static int hf_pcm_fill_number_of_bits = -1; +static int hf_pcm_justify_mode = -1; +static int hf_sco_i2s_pcm_interface_mode = -1; +static int hf_sco_i2s_pcm_interface_role = -1; +static int hf_sco_i2s_pcm_interface_sample_rate = -1; +static int hf_sco_i2s_pcm_interface_clock_rate = -1; +static int hf_le_energy_total_rx_time = -1; +static int hf_le_energy_total_tx_time = -1; +static int hf_le_energy_total_idle_time = -1; +static int hf_le_energy_total_energy_used = -1; +static int hf_le_batch_scan_subcode = -1; +static int hf_le_batch_scan_report_format = -1; +static int hf_le_batch_scan_number_of_records = -1; +static int hf_le_batch_scan_mode = -1; +static int hf_le_batch_scan_enable = -1; +static int hf_le_batch_scan_full_max = -1; +static int hf_le_batch_scan_truncate_max = -1; +static int hf_le_batch_scan_notify_threshold = -1; +static int hf_le_batch_scan_window = -1; +static int hf_le_batch_scan_interval = -1; +static int hf_le_batch_scan_address_type = -1; +static int hf_le_batch_scan_discard_rule = -1; +static int hf_le_multi_advertising_subcode = -1; +static int hf_le_multi_advertising_enable = -1; +static int hf_le_multi_advertising_instance_id = -1; +static int hf_le_multi_advertising_type = -1; +static int hf_le_multi_advertising_min_interval = -1; +static int hf_le_multi_advertising_max_interval = -1; +static int hf_le_multi_advertising_address_type = -1; +static int hf_le_multi_advertising_filter_policy = -1; +static int hf_le_multi_advertising_tx_power = -1; +static int hf_le_multi_advertising_channel_map = -1; +static int hf_le_multi_advertising_channel_map_reserved; +static int hf_le_multi_advertising_channel_map_39 = -1; +static int hf_le_multi_advertising_channel_map_38 = -1; +static int hf_le_multi_advertising_channel_map_37 = -1; +static int hf_data = -1; + +static const int *hfx_le_multi_advertising_channel_map[] = { + &hf_le_multi_advertising_channel_map_reserved, + &hf_le_multi_advertising_channel_map_39, + &hf_le_multi_advertising_channel_map_38, + &hf_le_multi_advertising_channel_map_37, + NULL +}; + +static gint ett_bthci_vendor_broadcom = -1; +static gint ett_opcode = -1; +static gint ett_channel_map = -1; + +static expert_field ei_undecoded = EI_INIT; +static expert_field ei_unexpected_parameter = EI_INIT; +static expert_field ei_unexpected_data = EI_INIT; + +static dissector_handle_t bthci_vendor_broadcom_handle; +static dissector_handle_t btcommon_ad_handle; + +static const value_string opcode_ocf_vals[] = { +/* Bluetooth Core 4.0 */ + { 0x0001, "Write BD ADDR" }, + { 0x0018, "Update Baudrate" }, + { 0x001C, "Write SCO PCM INT Parameter" }, + { 0x001E, "Write PCM Data Format Parameter" }, + { 0x0027, "Write Sleep Mode" }, + { 0x002E, "Download MiniDrv" }, + { 0x0045, "Write UART Clock Setting" }, + { 0x004C, "Write Firmware" }, /* Unknown name, but it is part of firmware, + which is set of this command and one + "Launch RAM" at the end of file. + Procedure of load firmware seems to be + initiated by command "Download MiniDrv" */ + { 0x004E, "Launch RAM" }, + { 0x0057, "Set ACL Priority" }, + { 0x006D, "Write I2S PCM Interface Parameter" }, + { 0x007E, "Enable WBS" }, + { 0x0102, "Enable WBS Modified" }, + { 0x0111, "Set ConnectionLess Broadcast Stream" }, + { 0x0112, "Receive ConnectionLess Broadcast Stream" }, + { 0x0113, "Write ConnectionLess Broadcast Stream Data" }, + { 0x0114, "ConnectionLess Broadcast Stream Flush" }, + { 0x0153, "LE Get Vendor Capabilities" }, + { 0x0154, "LE Multi Adveritising" }, + { 0x0156, "LE Batch Scan" }, + { 0x0157, "LE Advertising Filter" }, + { 0x0158, "LE Tracking Advertising" }, + { 0x0159, "LE Energy Info" }, + { 0, NULL } +}; + +static value_string opcode_vals[array_length(opcode_ocf_vals)]; + +static const value_string le_subcode_advertising_filter_vals[] = { + { 0x00, "Enable" }, + { 0x01, "Feature Select" }, + { 0x02, "BDADDR" }, + { 0x03, "UUID" }, + { 0x04, "Solicitate UUID" }, + { 0x05, "Local Name" }, + { 0x06, "Manufacturer Data" }, + { 0x07, "Service Data" }, + { 0x08, "All" }, + { 0, NULL } +}; + +static const value_string le_scan_condition_vals[] = { + { 0x00, "Add" }, + { 0x01, "Delete" }, + { 0x02, "Clear" }, + { 0, NULL } +}; + +static const value_string uart_clock_vals[] = { + { 0x01, "48 MHz" }, + { 0x02, "24 HHz" }, + { 0, NULL } +}; + +static const value_string sleep_mode_vals[] = { + { 0x01, "disable" }, + { 0x02, "UART" }, + { 0x09, "H5" }, + { 0, NULL } +}; + +static const value_string wake_polarity_vals[] = { + { 0x00, "Active Low" }, + { 0x01, "Active High" }, + { 0, NULL } +}; + +static const value_string connection_priority_vals[] = { + { 0x00, "Normal" }, + { 0xFF, "High" }, + { 0, NULL } +}; + +static const value_string codec_state_vals[] = { + { 0x00, "Disable" }, + { 0x01, "Enable" }, + { 0, NULL } +}; + +static const value_string codec_vals[] = { + { 0x00, "None" }, + { 0x01, "CVSD" }, + { 0x01, "mSBC" }, + { 0, NULL } +}; + +static const value_string sco_pcm_routing_vals[] = { + { 0x00, "PCM" }, + { 0x01, "Transport" }, + { 0x02, "Codec" }, + { 0x03, "I2S" }, + { 0, NULL } +}; + +static const value_string sco_pcm_interface_clock_rate_vals[] = { + { 0x00, "128k" }, + { 0x01, "256k" }, + { 0x02, "512k" }, + { 0x03, "1024k" }, + { 0x04, "2048k" }, + { 0, NULL } +}; + +static const value_string sco_pcm_interface_frame_type_vals[] = { + { 0x00, "Short" }, + { 0x01, "Long" }, + { 0, NULL } +}; + +static const value_string mode_slave_master_vals[] = { + { 0x00, "Slave" }, + { 0x01, "Master" }, + { 0, NULL } +}; + +static const value_string pcm_shift_mode_vals[] = { + { 0x00, "MSB" }, + { 0x01, "LSB" }, + { 0, NULL } +}; + +static const value_string pcm_fill_method_vals[] = { + { 0x00, "0's" }, + { 0x01, "1's" }, + { 0x02, "Signed" }, + { 0x03, "Programmable" }, + { 0, NULL } +}; + +static const value_string pcm_justify_mode_vals[] = { + { 0x00, "Left" }, + { 0x01, "Right" }, + { 0, NULL } +}; + +static const value_string sco_i2s_pcm_interface_mode_vals[] = { + { 0x00, "Disable" }, + { 0x01, "Enable" }, + { 0, NULL } +}; + +static const value_string sco_i2s_pcm_interface_sample_rate_vals[] = { + { 0x00, "8k" }, + { 0x01, "16k" }, + { 0x02, "4k" }, + { 0, NULL } +}; + +static const value_string sco_i2s_pcm_interface_clock_rate_vals[] = { + { 0x00, "128k" }, + { 0x01, "256k" }, + { 0x02, "512k" }, + { 0x03, "1024k" }, + { 0x04, "2048k" }, + { 0, NULL } +}; + +static const value_string le_subcode_batch_scan_vals[] = { + { 0x01, "Enable/Disable Customer Feature" }, + { 0x02, "Set Storage Parameter" }, + { 0x03, "Set Parameter" }, + { 0x04, "Read Results" }, + { 0, NULL } +}; + +static const value_string batch_scan_mode_vals[] = { + { 0x00, "Disable" }, + { 0x01, "Pass" }, + { 0x02, "ACTI" }, + { 0x03, "Pass ACTI" }, + { 0, NULL } +}; + +static const value_string address_type_vals[] = { + { 0x00, "Public" }, + { 0x01, "Random" }, + { 0, NULL } +}; + +static const value_string batch_scan_discard_rule_vals[] = { + { 0x00, "Old Items" }, + { 0x01, "Lower RSSI Items" }, + { 0, NULL } +}; + +static const value_string disable_enable_vals[] = { + { 0x00, "Disable" }, + { 0x01, "Enable" }, + { 0, NULL } +}; + +static const value_string le_subcode_multi_advertising_vals[] = { + { 0x01, "Set Parameter" }, + { 0x02, "Write Advertising Data" }, + { 0x03, "Write Scan Response Data" }, + { 0x04, "Set Random Address" }, + { 0x05, "MultiAdvertising Enable/Disable Customer Feature" }, + { 0, NULL } +}; + +static const value_string le_filter_policy_vals[] = { + { 0x00, "All Connections" }, + { 0x01, "Whitelist Connections All" }, + { 0x02, "All Connections Whitelist" }, + { 0x03, "Whitelist Connections" }, + { 0, NULL } +}; + +#define STATUS_SUCCESS 0x00 + +void proto_register_bthci_vendor_broadcom(void); +void proto_reg_handoff_bthci_vendor_broadcom(void); + + +static gint +dissect_bthci_vendor_broadcom(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + proto_item *main_item; + proto_tree *main_tree; + proto_item *opcode_item; + proto_tree *opcode_tree; + proto_item *sub_item; + bluetooth_data_t *bluetooth_data; + gint offset = 0; + guint16 opcode; + guint16 ocf; + const gchar *description; + guint8 length; + guint8 event_code; + guint8 bd_addr[6]; + guint8 status; + guint8 subcode; + guint8 condition; + + bluetooth_data = (bluetooth_data_t *) data; + + main_item = proto_tree_add_item(tree, proto_bthci_vendor_broadcom, tvb, 0, tvb_captured_length(tvb), ENC_NA); + main_tree = proto_item_add_subtree(main_item, ett_bthci_vendor_broadcom); + + switch (pinfo->p2p_dir) { + + case P2P_DIR_SENT: + col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_CMD_BROADCOM"); + col_add_fstr(pinfo->cinfo, COL_INFO, "Sent Broadcom "); + + opcode_item = proto_tree_add_item(main_tree, hf_opcode, tvb, offset, 2, ENC_LITTLE_ENDIAN); + opcode_tree = proto_item_add_subtree(opcode_item, ett_opcode); + opcode = tvb_get_letohs(tvb, offset); + proto_tree_add_item(opcode_tree, hf_opcode_ogf, tvb, offset, 2, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(opcode_tree, hf_opcode_ocf, tvb, offset, 2, ENC_LITTLE_ENDIAN); + ocf = opcode & 0x03ff; + offset+=2; + + description = val_to_str_const(ocf, opcode_ocf_vals, "unknown"); + if (g_strcmp0(description, "unknown") != 0) + col_append_fstr(pinfo->cinfo, COL_INFO, "%s", description); + else + col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown Command 0x%04X (opcode 0x%04X)", ocf, opcode); + + proto_tree_add_item(main_tree, hf_parameter_length, tvb, offset, 1, ENC_NA); + length = tvb_get_guint8(tvb, offset); + offset += 1; + + switch(ocf) { + case 0x0001: /* Write BDADDR */ + offset = dissect_bd_addr(hf_bd_addr, main_tree, tvb, offset, bd_addr); + +/* TODO: This is command, but in respose (event Command Complete) there is a status for that, + so write bdaddr can fail, but we store bdaddr as valid for now... */ + if (!pinfo->fd->flags.visited && bluetooth_data) { + wmem_tree_key_t key[4]; + guint32 frame_number; + localhost_bdaddr_entry_t *localhost_bdaddr_entry; + + frame_number = pinfo->fd->num; + + key[0].length = 1; + key[0].key = &bluetooth_data->interface_id; + key[1].length = 1; + key[1].key = &bluetooth_data->adapter_id; + key[2].length = 1; + key[2].key = &frame_number; + key[3].length = 0; + key[3].key = NULL; + + localhost_bdaddr_entry = (localhost_bdaddr_entry_t *) wmem_new(wmem_file_scope(), localhost_bdaddr_entry_t); + localhost_bdaddr_entry->interface_id = bluetooth_data->interface_id; + localhost_bdaddr_entry->adapter_id = bluetooth_data->adapter_id; + memcpy(localhost_bdaddr_entry->bd_addr, bd_addr, 6); + wmem_tree_insert32_array(bluetooth_data->localhost_bdaddr, key, localhost_bdaddr_entry); + } + break; + case 0x0018: /* Update Baudrate */ +/* TODO: Implement - two unknown parameters... */ + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, 1, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += 1; + + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, 1, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += 1; + + proto_tree_add_item(main_tree, hf_baudrate, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + break; + case 0x001C: /* Write SCO PCM INT Parameter */ + proto_tree_add_item(main_tree, hf_sco_pcm_routing, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_pcm_interface_clock_rate, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_pcm_interface_frame_type, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_pcm_interface_sync_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_pcm_interface_clock_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x001E: /* Write PCM Data Format Parameter */ + proto_tree_add_item(main_tree, hf_pcm_shift_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_pcm_fill_bits, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_pcm_fill_method, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_pcm_fill_number_of_bits, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_pcm_justify_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x0027: /* Write Sleep Mode */ + proto_tree_add_item(main_tree, hf_sleep_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_host_stack_idle_threshold, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_host_controller_idle_threshold, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_wake_polarity, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_host_wake_polarity, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_allow_host_sleep_during_sco, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_combine_sleep_mode_and_lpm, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_enable_uart_txd_tri_state, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sleep_guard_time, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_wakeup_guard_time, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_txd_config, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_pulsed_host_wake, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x0045: /* Write UART Clock Setting */ + proto_tree_add_item(main_tree, hf_uart_clock, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x004C: /* Write Firmware*/ + proto_tree_add_item(main_tree, hf_firmware_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(main_tree, hf_firmware, tvb, offset, length - 4, ENC_NA); + offset += length - 4; + break; + case 0x004E: /* Launch RAM */ + proto_tree_add_item(main_tree, hf_firmware_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + break; + case 0x0057: /* Set ACL Priority */ + proto_tree_add_item(main_tree, hf_connection_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(main_tree, hf_connection_priority, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x006D: /* Write I2S PCM Interface Parameter */ + proto_tree_add_item(main_tree, hf_sco_i2s_pcm_interface_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_i2s_pcm_interface_role, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_i2s_pcm_interface_sample_rate, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_sco_i2s_pcm_interface_clock_rate, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x007E: /* Enable WBS */ + proto_tree_add_item(main_tree, hf_codec_state, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_codec, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + break; + case 0x0154: /* LE Multi Adveritising */ + proto_tree_add_item(main_tree, hf_le_multi_advertising_subcode, tvb, offset, 1, ENC_NA); + subcode = tvb_get_guint8(tvb, offset); + offset += 1; + + switch (subcode) { + case 0x01: /* Set Parameter */ + proto_tree_add_item(main_tree, hf_le_multi_advertising_min_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_max_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_type, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_address_type, tvb, offset, 1, ENC_NA); + offset += 1; + + offset = dissect_bd_addr(hf_bd_addr, main_tree, tvb, offset, NULL); + + proto_tree_add_item(main_tree, hf_le_multi_advertising_address_type, tvb, offset, 1, ENC_NA); + offset += 1; + + offset = dissect_bd_addr(hf_bd_addr, main_tree, tvb, offset, NULL); + + proto_tree_add_bitmask(main_tree, tvb, offset, hf_le_multi_advertising_channel_map, ett_channel_map, hfx_le_multi_advertising_channel_map, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_filter_policy, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_instance_id, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_tx_power, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x02: /* Write Advertising Data */ + case 0x03: /* Write Scan Response Data */ + call_dissector(btcommon_ad_handle, tvb_new_subset_length(tvb, offset, 31), pinfo, tree); + save_local_device_name_from_eir_ad(tvb, offset, pinfo, 31, bluetooth_data); + offset += 31; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_instance_id, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x04: /* Set Random Address */ + offset = dissect_bd_addr(hf_bd_addr, main_tree, tvb, offset, NULL); + + proto_tree_add_item(main_tree, hf_le_multi_advertising_instance_id, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x05: /* MultiAdvertising Enable/Disable Customer Feature */ + proto_tree_add_item(main_tree, hf_le_multi_advertising_enable, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_multi_advertising_instance_id, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + } + + break; + case 0x0156: /* LE Batch Scan */ + proto_tree_add_item(main_tree, hf_le_batch_scan_subcode, tvb, offset, 1, ENC_NA); + subcode = tvb_get_guint8(tvb, offset); + offset += 1; + + switch (subcode) { + case 0x01: /* Enable/Disable Customer Feature */ + proto_tree_add_item(main_tree, hf_le_batch_scan_enable, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x02: /* Set Storage Parameter */ + proto_tree_add_item(main_tree, hf_le_batch_scan_full_max, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_batch_scan_truncate_max, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_batch_scan_notify_threshold, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x03: /* Set Parameter */ + proto_tree_add_item(main_tree, hf_le_batch_scan_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_batch_scan_window, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(main_tree, hf_le_batch_scan_interval, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; + + proto_tree_add_item(main_tree, hf_le_batch_scan_address_type, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_batch_scan_discard_rule, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x04: /* Read Results */ + proto_tree_add_item(main_tree, hf_le_batch_scan_mode, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + } + + break; + case 0x0157: /* LE Advertising Filter */ + proto_tree_add_item(main_tree, hf_le_advertising_filter_subcode, tvb, offset, 1, ENC_NA); + subcode = tvb_get_guint8(tvb, offset); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_scan_condition, tvb, offset, 1, ENC_NA); + condition = tvb_get_guint8(tvb, offset); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_filter_index, tvb, offset, 1, ENC_NA); + offset += 1; + + if (condition == 0x00) { /* Add */ + switch (subcode) { + case 0x00: /* Enable */ + case 0x01: /* Feature Select */ + case 0x02: /* BDADDR */ + case 0x03: /* UUID */ + case 0x04: /* Solicitate UUID */ + case 0x05: /* Local Name */ + case 0x06: /* Manufacturer Data */ + case 0x07: /* Service Data */ + case 0x08: /* All */ +/* TODO */ + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length - 3, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += length - 3; + + break; + default: + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length - 3, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_unexpected_data); + offset += length - 3; + } + } + + break; + case 0x0102: /* Enable WBS Modified */ + case 0x0111: /* Set ConnectionLess Broadcast Stream */ + case 0x0112: /* Receive ConnectionLess Broadcast Stream */ + case 0x0113: /* Write ConnectionLess Broadcast Stream Data */ + case 0x0114: /* ConnectionLess Broadcast Stream Flush */ + case 0x0158: /* LE Tracking Advertising */ + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += length; + + break; + + case 0x002E: /* Download MiniDrv */ + case 0x0153: /* LE Get Vendor Capabilities */ + case 0x0159: /* LE Energy Info */ + if (tvb_captured_length_remaining(tvb, offset) > 0) { + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_unexpected_parameter); + } + break; + default: + if (length > 0) { + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += length; + } + } + + break; + case P2P_DIR_RECV: + col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_EVT_BROADCOM"); + col_add_fstr(pinfo->cinfo, COL_INFO, "Rcvd Broadcom "); + + event_code = tvb_get_guint8(tvb, offset); + col_append_str(pinfo->cinfo, COL_INFO, val_to_str_ext_const(event_code, &bthci_evt_evt_code_vals_ext, "Unknown 0x%08x")); + proto_tree_add_item(main_tree, hf_event_code, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_parameter_length, tvb, offset, 1, ENC_NA); + length = tvb_get_guint8(tvb, offset); + offset += 1; + + switch (event_code) { + case 0x0e: /* Command Complete */ + proto_tree_add_item(main_tree, hf_number_of_allowed_command_packets, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + opcode_item = proto_tree_add_item(main_tree, hf_opcode, tvb, offset, 2, ENC_LITTLE_ENDIAN); + opcode_tree = proto_item_add_subtree(opcode_item, ett_opcode); + opcode = tvb_get_letohs(tvb, offset); + proto_tree_add_item(opcode_tree, hf_opcode_ogf, tvb, offset, 2, ENC_LITTLE_ENDIAN); + + proto_tree_add_item(opcode_tree, hf_opcode_ocf, tvb, offset, 2, ENC_LITTLE_ENDIAN); + ocf = opcode & 0x03ff; + offset += 2; + + description = val_to_str_const(ocf, opcode_ocf_vals, "unknown"); + if (g_strcmp0(description, "unknown") != 0) + col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)", description); + else + col_append_fstr(pinfo->cinfo, COL_INFO, " (Unknown Command 0x%04X [opcode 0x%04X])", ocf, opcode); + + proto_tree_add_item(main_tree, hf_status, tvb, offset, 1, ENC_NA); + status = tvb_get_guint8(tvb, offset); + offset += 1; + + switch (ocf) { + case 0x0153: /* LE Get Vendor Capabilities */ + if (status != STATUS_SUCCESS) + break; + proto_tree_add_item(main_tree, hf_max_advertising_instance, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_resolvable_private_address_offloading, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_total_scan_results, tvb, offset, 2, ENC_NA); + offset += 2; + + proto_tree_add_item(main_tree, hf_max_irk_list, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_filter_support, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_max_filter, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_energy_support, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x0154: /* LE Multi Adveritising */ + proto_tree_add_item(main_tree, hf_le_multi_advertising_subcode, tvb, offset, 1, ENC_NA); + offset += 1; + + break; + case 0x0156: /* LE Batch Scan */ + proto_tree_add_item(main_tree, hf_le_batch_scan_subcode, tvb, offset, 1, ENC_NA); + subcode = tvb_get_guint8(tvb, offset); + offset += 1; + + if (subcode == 0x04 && status == STATUS_SUCCESS) { /* Read Results*/ + proto_tree_add_item(main_tree, hf_le_batch_scan_report_format, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_batch_scan_number_of_records, tvb, offset, 1, ENC_NA); + offset += 1; + } + + + break; + case 0x0157: /* LE Advertising Filter */ + proto_tree_add_item(main_tree, hf_le_advertising_filter_subcode, tvb, offset, 1, ENC_NA); + offset += 1; + + if (status == STATUS_SUCCESS) { + proto_tree_add_item(main_tree, hf_le_scan_condition, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_number_of_available_filters, tvb, offset, 1, ENC_NA); + offset += 1; + } + + break; + case 0x0159: /* LE Energy Info */ + if (status == STATUS_SUCCESS) { + proto_tree_add_item(main_tree, hf_le_energy_total_rx_time, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_energy_total_tx_time, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_energy_total_idle_time, tvb, offset, 1, ENC_NA); + offset += 1; + + proto_tree_add_item(main_tree, hf_le_energy_total_energy_used, tvb, offset, 1, ENC_NA); + offset += 1; + } + + break; + case 0x0102: /* Enable WBS Modified */ + case 0x0111: /* Set ConnectionLess Broadcast Stream */ + case 0x0112: /* Receive ConnectionLess Broadcast Stream */ + case 0x0113: /* Write ConnectionLess Broadcast Stream Data */ + case 0x0114: /* ConnectionLess Broadcast Stream Flush */ + case 0x0158: /* LE Tracking Advertising */ +/* TODO: Implement - parameters not known */ + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += length; + + break; + case 0x0001: /* Write BDADDR */ + case 0x0018: /* Update Baudrate */ + case 0x001C: /* Write SCO PCM INT Parameter */ + case 0x001E: /* Write PCM Data Format Parameter */ + case 0x0027: /* Write Sleep Mode */ + case 0x002E: /* Download MiniDrv */ + case 0x0045: /* Write UART Clock Setting */ + case 0x004C: /* Write Firmware*/ + case 0x004E: /* Launch RAM */ + case 0x0057: /* Set ACL Priority */ + case 0x006D: /* Write I2S PCM Interface Parameter */ + case 0x007E: /* Enable WBS */ + default: + if (tvb_captured_length_remaining(tvb, offset) > 0) { + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_unexpected_parameter); + offset += tvb_captured_length_remaining(tvb, offset); + } + } + + break; + default: + if (length > 0) { + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, length, ENC_NA); + expert_add_info(pinfo, sub_item, &ei_undecoded); + offset += length; + } + } + + + break; + + case P2P_DIR_UNKNOWN: + default: + col_set_str(pinfo->cinfo, COL_PROTOCOL, "HCI_BROADCOM"); + col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d Broadcom ", + pinfo->p2p_dir); + + if (tvb_captured_length_remaining(tvb, offset) > 0) { + proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + offset += tvb_captured_length_remaining(tvb, offset); + } + break; + } + + if (tvb_captured_length_remaining(tvb, offset) > 0) { + sub_item = proto_tree_add_item(main_tree, hf_data, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA); + expert_add_info(pinfo, sub_item, &ei_unexpected_data); + offset += tvb_captured_length_remaining(tvb, offset); + } + + return offset; +} + +void +proto_register_bthci_vendor_broadcom(void) +{ + guint i_opcode = 0; + guint i_array; + guint i_string_array; + expert_module_t *expert_module; + + static hf_register_info hf[] = { + { &hf_opcode, + { "Command Opcode", "bthci_vendor.broadcom.opcode", + FT_UINT16, BASE_HEX, VALS(opcode_vals), 0x0, + "HCI Command Opcode", HFILL } + }, + { &hf_opcode_ogf, + { "Opcode Group Field", "bthci_vendor.broadcom.opcode.ogf", + FT_UINT16, BASE_HEX|BASE_EXT_STRING, &bthci_ogf_vals_ext, 0xfc00, + NULL, HFILL } + }, + { &hf_opcode_ocf, + { "Opcode Command Field", "bthci_vendor.broadcom.opcode.ocf", + FT_UINT16, BASE_HEX, VALS(opcode_ocf_vals), 0x03ff, + NULL, HFILL } + }, + { &hf_parameter_length, + { "Parameter Total Length", "bthci_vendor.broadcom.parameter_length", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_event_code, + { "Event Code", "bthci_vendor.broadcom.event_code", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &bthci_evt_evt_code_vals_ext, 0x0, + NULL, HFILL } + }, + { &hf_number_of_allowed_command_packets, + { "Number of Allowed Command Packets", "bthci_vendor.broadcom.number_of_allowed_command_packets", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_advertising_filter_subcode, + { "Subcode", "bthci_vendor.broadcom.le.advertising_filter.subcode", + FT_UINT8, BASE_HEX, VALS(le_subcode_advertising_filter_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_scan_condition, + { "Scan Condition", "bthci_vendor.broadcom.le.scan_condition", + FT_UINT8, BASE_HEX, VALS(le_scan_condition_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_filter_index, + { "Filter Index", "bthci_vendor.broadcom.le.filter_index", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_number_of_available_filters, + { "Number of Available Filters", "bthci_vendor.broadcom.le.number_of_available_filters", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_firmware_address, + { "Address", "bthci_vendor.broadcom.firmware.address", + FT_UINT32, BASE_HEX_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_firmware, + { "Firmware", "bthci_vendor.broadcom.firmware.data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + { &hf_baudrate, + { "Baudrate", "bthci_vendor.broadcom.baudrate", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_bd_addr, + { "BD_ADDR", "bthci_vendor.broadcom.bd_addr", + FT_ETHER, BASE_NONE, NULL, 0x0, + "Bluetooth Device Address", HFILL} + }, + { &hf_max_advertising_instance, + { "Max Advertising Instance", "bthci_vendor.broadcom.max_advertising_instance", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_resolvable_private_address_offloading, + { "Resolvable Private Address Offloading", "bthci_vendor.broadcom.resolvable_private_address_offloading", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_total_scan_results, + { "Total Scan Results", "bthci_vendor.broadcom.total_scan_results", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_max_irk_list, + { "Max IRK List", "bthci_vendor.broadcom.max_irk_list", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_filter_support, + { "Filter Support", "bthci_vendor.broadcom.filter_support", + FT_BOOLEAN, 8, NULL, 0x0, + NULL, HFILL } + }, + { &hf_max_filter, + { "Max Filter", "bthci_vendor.broadcom.max_filter", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_energy_support, + { "Energy Support", "bthci_vendor.broadcom.energy_support", + FT_BOOLEAN, 8, NULL, 0x0, + NULL, HFILL } + }, + { &hf_uart_clock, + { "UART Clock", "bthci_vendor.broadcom.uart_clock", + FT_UINT8, BASE_HEX, VALS(uart_clock_vals), 0x0, + NULL, HFILL } + }, + { &hf_connection_handle, + { "Connection Handle", "bthci_vendor.broadcom.connection_handle", + FT_UINT16, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_connection_priority, + { "Connection Priority", "bthci_vendor.broadcom.connection_priority", + FT_UINT8, BASE_HEX, VALS(connection_priority_vals), 0x0, + NULL, HFILL } + }, + { &hf_sleep_mode, + { "Sleep Mode", "bthci_vendor.broadcom.sleep_mode", + FT_UINT8, BASE_HEX, VALS(sleep_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_host_stack_idle_threshold, + { "Host Stack Idle Threshold", "bthci_vendor.broadcom.host_stack_idle_threshold", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_host_controller_idle_threshold, + { "Host Controller Idle Threshold", "bthci_vendor.broadcom.host_controller_idle_threshold", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_wake_polarity, + { "Wake Polarity", "bthci_vendor.broadcom.wake_polarity", + FT_UINT8, BASE_HEX, VALS(wake_polarity_vals), 0x0, + NULL, HFILL } + }, + { &hf_host_wake_polarity, + { "Host Wake Polarity", "bthci_vendor.broadcom.host_wake_polarity", + FT_UINT8, BASE_HEX, VALS(wake_polarity_vals), 0x0, + NULL, HFILL } + }, + { &hf_allow_host_sleep_during_sco, + { "Allow Host Sleep During SCO", "bthci_vendor.broadcom.allow_host_sleep_during_sco", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_combine_sleep_mode_and_lpm, + { "Combine Sleep Mode and LPM", "bthci_vendor.broadcom.combine_sleep_mode_and_lpm", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_enable_uart_txd_tri_state, + { "Enable UART TXD Tri-state", "bthci_vendor.broadcom.enable_uart_txd_tri_state", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_sleep_guard_time, + { "Sleep Guard Time", "bthci_vendor.broadcom.sleep_guard_time", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_wakeup_guard_time, + { "Wakeup Guard Time", "bthci_vendor.broadcom.wakeup_guard_time", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_txd_config, + { "TXD Config", "bthci_vendor.broadcom.txd_config", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pulsed_host_wake, + { "Pulsed Host Wake", "bthci_vendor.broadcom.pulsed_host_wake", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_codec_state, + { "Codec State", "bthci_vendor.broadcom.codec_state", + FT_UINT8, BASE_HEX, VALS(codec_state_vals), 0x0, + NULL, HFILL } + }, + { &hf_codec, + { "Codec", "bthci_vendor.broadcom.codec", + FT_UINT16, BASE_HEX, VALS(codec_vals), 0x0, + NULL, HFILL } + }, + { &hf_status, + { "Status", "bthci_vendor.broadcom.status", + FT_UINT8, BASE_HEX|BASE_EXT_STRING, &bthci_cmd_status_vals_ext, 0x0, + NULL, HFILL } + }, + { &hf_sco_pcm_routing, + { "SCO PCM Routing", "bthci_vendor.broadcom.sco.pcm_routing", + FT_UINT8, BASE_HEX, VALS(sco_pcm_routing_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_pcm_interface_clock_rate, + { "SCO PCM Interface Clock Rate", "bthci_vendor.broadcom.sco.interface.clock_rate", + FT_UINT8, BASE_HEX, VALS(sco_pcm_interface_clock_rate_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_pcm_interface_frame_type, + { "SCO PCM Interface Frame Type", "bthci_vendor.broadcom.sco.interface.frame_type", + FT_UINT8, BASE_HEX, VALS(sco_pcm_interface_frame_type_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_pcm_interface_sync_mode, + { "SCO PCM Interface Sync Mode", "bthci_vendor.broadcom.sco.interface.sync_mode", + FT_UINT8, BASE_HEX, VALS(mode_slave_master_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_pcm_interface_clock_mode, + { "SCO PCM Interface Clock Mode", "bthci_vendor.broadcom.sco.interface.", + FT_UINT8, BASE_HEX, VALS(mode_slave_master_vals), 0x0, + NULL, HFILL } + }, + { &hf_pcm_shift_mode, + { "PCM shift_mode", "bthci_vendor.broadcom.pcm.shift_mode", + FT_UINT8, BASE_HEX, VALS(pcm_shift_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_pcm_fill_bits, + { "PCM Fill Bits", "bthci_vendor.broadcom.pcm.fill_bits", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pcm_fill_method, + { "PCM Fill Method", "bthci_vendor.broadcom.pcm.fill_method", + FT_UINT8, BASE_HEX, VALS(pcm_fill_method_vals), 0x0, + NULL, HFILL } + }, + { &hf_pcm_fill_number_of_bits, + { "PCM fill_number_of_bits", "bthci_vendor.broadcom.pcm.fill_number_of_bits", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_pcm_justify_mode, + { "PCM Justify Mode", "bthci_vendor.broadcom.pcm.justify_mode", + FT_UINT8, BASE_HEX, VALS(pcm_justify_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_i2s_pcm_interface_mode, + { "SCO I2S PCM Interface Mode", "bthci_vendor.broadcom.pcm.i2s_pcm_interface.mode", + FT_UINT8, BASE_HEX, VALS(sco_i2s_pcm_interface_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_i2s_pcm_interface_role, + { "SCO I2S PCM Interface Role", "bthci_vendor.broadcom.pcm.i2s_pcm_interface.role", + FT_UINT8, BASE_HEX, VALS(mode_slave_master_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_i2s_pcm_interface_sample_rate, + { "SCO I2S PCM Interface Sample_Rate", "bthci_vendor.broadcom.sco.i2s_pcm_interface.sample_rate", + FT_UINT8, BASE_HEX, VALS(sco_i2s_pcm_interface_sample_rate_vals), 0x0, + NULL, HFILL } + }, + { &hf_sco_i2s_pcm_interface_clock_rate, + { "SCO I2S PCM Interface Clock Rate", "bthci_vendor.broadcom.pcm.i2s_pcm_interface.clock_rate", + FT_UINT8, BASE_HEX, VALS(sco_i2s_pcm_interface_clock_rate_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_energy_total_rx_time, + { "Total RX Time", "bthci_vendor.broadcom.le.total_rx_time", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_energy_total_tx_time, + { "Total TX Time", "bthci_vendor.broadcom.le.total_tx_time", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_energy_total_idle_time, + { "Total Idle Time", "bthci_vendor.broadcom.le.total_idle_time", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_energy_total_energy_used, + { "Total Energy Used Time", "bthci_vendor.broadcom.le.total_energy_used", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_subcode, + { "Subcode", "bthci_vendor.broadcom.le.batch_scan.subcode", + FT_UINT8, BASE_HEX, VALS(le_subcode_batch_scan_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_report_format, + { "Report Format", "bthci_vendor.broadcom.le.batch_scan.report_format", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_number_of_records, + { "Number of Records", "bthci_vendor.broadcom.le.batch_scan.number_of_records", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_mode, + { "Mode", "bthci_vendor.broadcom.le.batch_scan.mode", + FT_UINT8, BASE_HEX, VALS(batch_scan_mode_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_enable, + { "Enable", "bthci_vendor.broadcom.le.batch_scan.enable", + FT_UINT8, BASE_HEX, VALS(disable_enable_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_full_max, + { "Full Max", "bthci_vendor.broadcom.le.batch_scan.full_max", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_truncate_max, + { "Truncate Max", "bthci_vendor.broadcom.le.batch_scan.truncate_max", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_notify_threshold, + { "notify_threshold", "bthci_vendor.broadcom.le.batch_scan.notify_threshold", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_window, + { "Window", "bthci_vendor.broadcom.le.batch_scan.window", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_interval, + { "Interval", "bthci_vendor.broadcom.le.batch_scan.interval", + FT_UINT32, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_address_type, + { "Address Type", "bthci_vendor.broadcom.le.batch_scan.address_type", + FT_UINT8, BASE_HEX, VALS(address_type_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_batch_scan_discard_rule, + { "Discard Rule", "bthci_vendor.broadcom.le.batch_scan.discard_rule", + FT_UINT8, BASE_HEX, VALS(batch_scan_discard_rule_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_subcode, + { "Subcode", "bthci_vendor.broadcom.le.multi_advertising.subcode", + FT_UINT8, BASE_HEX, VALS(le_subcode_multi_advertising_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_enable, + { "Enable", "bthci_vendor.broadcom.le.multi_advertising.enable", + FT_UINT8, BASE_HEX, VALS(disable_enable_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_instance_id, + { "Full Max", "bthci_vendor.broadcom.le.multi_advertising.instance_id", + FT_UINT8, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_min_interval, + { "Min Interval", "bthci_vendor.broadcom.le.multi_advertising.min_interval", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_max_interval, + { "Max Interval", "bthci_vendor.broadcom.le.multi_advertising.max_interval", + FT_UINT16, BASE_DEC, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_address_type, + { "Address Type", "bthci_vendor.broadcom.le.multi_advertising.address_type", + FT_UINT8, BASE_HEX, VALS(address_type_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_type, + { "Type", "bthci_vendor.broadcom.le.multi_advertising.type", + FT_UINT8, BASE_HEX | BASE_EXT_STRING, &bthci_cmd_eir_data_type_vals_ext, 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_channel_map, + { "Channel Map", "bthci_vendor.broadcom.le.multi_advertising.channel_map", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_channel_map_reserved, + { "Reserved", "bthci_vendor.broadcom.le.multi_advertising.channel_map.reserved", + FT_UINT8, BASE_HEX, NULL, 0xF8, + NULL, HFILL } + }, + { &hf_le_multi_advertising_channel_map_39, + { "Channel 39", "bthci_vendor.broadcom.le.multi_advertising.channel_map.39", + FT_UINT8, BASE_HEX, NULL, 0x04, + NULL, HFILL } + }, + { &hf_le_multi_advertising_channel_map_38, + { "Channel 39", "bthci_vendor.broadcom.le.multi_advertising.channel_map.38", + FT_UINT8, BASE_HEX, NULL, 0x02, + NULL, HFILL } + }, + { &hf_le_multi_advertising_channel_map_37, + { "Channel 39", "bthci_vendor.broadcom.le.multi_advertising.channel_map.37", + FT_UINT8, BASE_HEX, NULL, 0x01, + NULL, HFILL } + }, + { &hf_le_multi_advertising_filter_policy, + { "Filter Policy", "bthci_vendor.broadcom.le.multi_advertising.filter_policy", + FT_UINT8, BASE_HEX, VALS(le_filter_policy_vals), 0x0, + NULL, HFILL } + }, + { &hf_le_multi_advertising_tx_power, + { "Tx power", "bthci_vendor.broadcom.le.multi_advertising.tx_power", + FT_UINT8, BASE_HEX, NULL, 0x0, + NULL, HFILL } + }, + { &hf_data, + { "Data", "bthci_vendor.broadcom.data", + FT_NONE, BASE_NONE, NULL, 0x0, + NULL, HFILL } + }, + }; + + static gint *ett[] = { + &ett_bthci_vendor_broadcom, + &ett_opcode, + &ett_channel_map + }; + + static ei_register_info ei[] = { + { &ei_undecoded, { "bthci_vendor.broadcom.undecoded", PI_PROTOCOL, PI_UNDECODED, "Undecoded", EXPFILL }}, + { &ei_unexpected_parameter, { "bthci_vendor.broadcom.unexpected_parameter", PI_PROTOCOL, PI_WARN, "Unexpected parameter", EXPFILL }}, + { &ei_unexpected_data, { "bthci_vendor.broadcom.unexpected_data", PI_PROTOCOL, PI_WARN, "Unexpected data", EXPFILL }}, + }; + + static const struct _opcode_value_string_arrays { + guint ogf; + const value_string *string_array; + guint length; + } opcode_value_string_arrays[] = { + { 0x3F, opcode_ocf_vals, array_length(opcode_vals) }, + }; + + for (i_array = 0; i_array < array_length(opcode_value_string_arrays); i_array += 1) { + for (i_string_array = 0; i_string_array < opcode_value_string_arrays[i_array].length - 1; i_string_array += 1) { + opcode_vals[i_opcode].value = opcode_value_string_arrays[i_array].string_array[i_string_array].value | (opcode_value_string_arrays[i_array].ogf << 10); + opcode_vals[i_opcode].strptr = opcode_value_string_arrays[i_array].string_array[i_string_array].strptr; + i_opcode += 1; + } + } + opcode_vals[i_opcode].value = 0; + opcode_vals[i_opcode].strptr = NULL; + + proto_bthci_vendor_broadcom = proto_register_protocol("Bluetooth Broadcom HCI Command", + "HCI BROADCOM", "bthci_vendor.broadcom"); + + bthci_vendor_broadcom_handle = new_register_dissector("bthci_vendor.broadcom", dissect_bthci_vendor_broadcom, proto_bthci_vendor_broadcom); + + proto_register_field_array(proto_bthci_vendor_broadcom, hf, array_length(hf)); + proto_register_subtree_array(ett, array_length(ett)); + + expert_module = expert_register_protocol(proto_bthci_vendor_broadcom); + expert_register_field_array(expert_module, ei, array_length(ei)); +} + +void +proto_reg_handoff_bthci_vendor_broadcom(void) +{ + btcommon_ad_handle = find_dissector("btcommon.eir_ad.ad"); + dissector_add_for_decode_as("bthci_cmd.vendor", bthci_vendor_broadcom_handle); +} + +/* + * Editor modelines - http://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: + */ |