diff options
Diffstat (limited to 'epan/dissectors/packet-btle.c')
-rw-r--r-- | epan/dissectors/packet-btle.c | 5584 |
1 files changed, 2887 insertions, 2697 deletions
diff --git a/epan/dissectors/packet-btle.c b/epan/dissectors/packet-btle.c index 00017448..29476de3 100644 --- a/epan/dissectors/packet-btle.c +++ b/epan/dissectors/packet-btle.c @@ -22,6 +22,8 @@ #include <epan/expert.h> #include <epan/proto_data.h> #include <epan/reassemble.h> +#include <epan/tfs.h> +#include <epan/unit_strings.h> #include <wiretap/wtap.h> @@ -29,339 +31,339 @@ #include "packet-bthci_cmd.h" #include "packet-bthci_acl.h" -static int proto_btle = -1; -static int proto_btle_rf = -1; -static int proto_nordic_ble = -1; - -static int hf_access_address = -1; -static int hf_coding_indicator = -1; -static int hf_crc = -1; -static int hf_master_bd_addr = -1; -static int hf_slave_bd_addr = -1; -static int hf_length = -1; -static int hf_advertising_header = -1; -static int hf_advertising_header_pdu_type = -1; -static int hf_advertising_header_ch_sel = -1; -static int hf_advertising_header_rfu_1 = -1; -static int hf_advertising_header_rfu_2 = -1; -static int hf_advertising_header_rfu_3 = -1; -static int hf_advertising_header_rfu_4 = -1; -static int hf_advertising_header_randomized_tx = -1; -static int hf_advertising_header_randomized_rx = -1; -static int hf_advertising_header_length = -1; -static int hf_advertising_address = -1; -static int hf_initiator_addresss = -1; -static int hf_target_addresss = -1; -static int hf_scanning_address = -1; -static int hf_scan_response_data = -1; -static int hf_link_layer_data = -1; -static int hf_link_layer_data_access_address = -1; -static int hf_link_layer_data_crc_init = -1; -static int hf_link_layer_data_window_size = -1; -static int hf_link_layer_data_window_offset = -1; -static int hf_link_layer_data_interval = -1; -static int hf_link_layer_data_latency = -1; -static int hf_link_layer_data_timeout = -1; -static int hf_link_layer_data_channel_map = -1; -static int hf_link_layer_data_hop = -1; -static int hf_link_layer_data_sleep_clock_accuracy = -1; -static int hf_extended_advertising_header = -1; -static int hf_extended_advertising_header_length = -1; -static int hf_extended_advertising_mode = -1; -static int hf_extended_advertising_flags = -1; -static int hf_extended_advertising_flags_adva = -1; -static int hf_extended_advertising_flags_targeta = -1; -static int hf_extended_advertising_flags_cte_info = -1; -static int hf_extended_advertising_flags_advdatainfo = -1; -static int hf_extended_advertising_flags_aux_ptr = -1; -static int hf_extended_advertising_flags_sync_info = -1; -static int hf_extended_advertising_flags_tx_power = -1; -static int hf_extended_advertising_flags_reserved = -1; -static int hf_extended_advertising_cte_info = -1; -static int hf_extended_advertising_cte_info_time = -1; -static int hf_extended_advertising_cte_info_rfu = -1; -static int hf_extended_advertising_cte_info_type = -1; -static int hf_extended_advertising_data_info = -1; -static int hf_extended_advertising_data_info_did = -1; -static int hf_extended_advertising_data_info_sid = -1; -static int hf_extended_advertising_aux_ptr = -1; -static int hf_extended_advertising_aux_ptr_channel = -1; -static int hf_extended_advertising_aux_ptr_ca = -1; -static int hf_extended_advertising_aux_ptr_offset_units = -1; -static int hf_extended_advertising_aux_ptr_aux_offset = -1; -static int hf_extended_advertising_aux_ptr_aux_phy = -1; -static int hf_extended_advertising_sync_info = -1; -static int hf_extended_advertising_sync_info_offset = -1; -static int hf_extended_advertising_sync_info_offset_units = -1; -static int hf_extended_advertising_sync_info_offset_adjust = -1; -static int hf_extended_advertising_sync_info_reserved = -1; -static int hf_extended_advertising_sync_info_interval = -1; -static int hf_extended_advertising_sync_info_channel_map = -1; -static int hf_extended_advertising_sync_info_sleep_clock_accuracy = -1; -static int hf_extended_advertising_sync_info_access_address = -1; -static int hf_extended_advertising_sync_info_crc_init = -1; -static int hf_extended_advertising_sync_info_event_counter = -1; -static int hf_extended_advertising_tx_power = -1; -static int hf_extended_advertising_header_acad = -1; -static int hf_extended_advertising_had_fragment = -1; -static int hf_data_header = -1; -static int hf_data_header_length = -1; -static int hf_data_header_rfu = -1; -static int hf_data_header_llid = -1; -static int hf_data_header_llid_connectediso = -1; -static int hf_data_header_llid_broadcastiso = -1; -static int hf_data_header_more_data = -1; -static int hf_data_header_cte_info_present = -1; -static int hf_data_header_sequence_number = -1; -static int hf_data_header_next_expected_sequence_number = -1; -static int hf_data_header_rfu_57 = -1; -static int hf_data_header_rfu_67 = -1; -static int hf_data_header_close_isochronous_event = -1; -static int hf_data_header_null_pdu_indicator = -1; -static int hf_data_header_control_subevent_sequence_number = -1; -static int hf_data_header_control_subevent_transmission_flag = -1; -static int hf_data_header_cte_info = -1; -static int hf_data_header_cte_info_time = -1; -static int hf_data_header_cte_info_rfu = -1; -static int hf_data_header_cte_info_type = -1; -static int hf_control_opcode = -1; -static int hf_l2cap_index = -1; -static int hf_l2cap_fragment = -1; -static int hf_connection_parameters_in = -1; -static int hf_control_reject_opcode = -1; -static int hf_control_error_code = -1; -static int hf_control_unknown_type = -1; -static int hf_control_version_number = -1; -static int hf_control_company_id = -1; -static int hf_control_subversion_number = -1; -static int hf_control_feature_set = -1; -static int hf_control_feature_set_le_encryption = -1; -static int hf_control_feature_set_connection_parameters_request_procedure = -1; -static int hf_control_feature_set_extended_reject_indication = -1; -static int hf_control_feature_set_slave_initiated_features_exchange = -1; -static int hf_control_feature_set_le_ping = -1; -static int hf_control_feature_set_le_pkt_len_ext = -1; -static int hf_control_feature_set_ll_privacy = -1; -static int hf_control_feature_set_ext_scan_flt_pol = -1; -static int hf_control_feature_set_le_2m_phy = -1; -static int hf_control_feature_set_stable_modulation_index_transmitter = -1; -static int hf_control_feature_set_stable_modulation_index_receiver = -1; -static int hf_control_feature_set_le_coded_phy = -1; -static int hf_control_feature_set_le_extended_advertising = -1; -static int hf_control_feature_set_le_periodic_advertising = -1; -static int hf_control_feature_set_channel_selection_algorithm_2 = -1; -static int hf_control_feature_set_le_power_class_1 = -1; -static int hf_control_feature_set_minimum_number_of_used_channels_procedure = -1; -static int hf_control_feature_set_connection_cte_request = -1; -static int hf_control_feature_set_connection_cte_response = -1; -static int hf_control_feature_set_connectionless_cte_tx = -1; -static int hf_control_feature_set_connectionless_cte_rx = -1; -static int hf_control_feature_set_antenna_switching_tx_aod = -1; -static int hf_control_feature_set_antenna_switching_rx_aoa = -1; -static int hf_control_feature_set_cte_rx = -1; -static int hf_control_feature_set_past_sender = -1; -static int hf_control_feature_set_past_receiver = -1; -static int hf_control_feature_set_sca_updates = -1; -static int hf_control_feature_set_remote_public_key_validation = -1; -static int hf_control_feature_set_cis_central = -1; -static int hf_control_feature_set_cis_peripheral = -1; -static int hf_control_feature_set_iso_broadcast = -1; -static int hf_control_feature_set_synchronized_receiver = -1; -static int hf_control_feature_set_connected_iso_host_support = -1; -static int hf_control_feature_set_le_power_control_request1 = -1; -static int hf_control_feature_set_le_power_control_request2 = -1; -static int hf_control_feature_set_le_path_loss_monitoring = -1; -static int hf_control_feature_set_le_periodic_adv_adi_support = -1; -static int hf_control_feature_set_connection_subrating = -1; -static int hf_control_feature_set_connection_subrating_host_support = -1; -static int hf_control_feature_set_channel_classification = -1; -static int hf_control_feature_set_adv_coding_selection = -1; -static int hf_control_feature_set_adv_coding_selection_host_support = -1; -static int hf_control_feature_set_periodic_adv_with_responses_advertiser = -1; -static int hf_control_feature_set_periodic_adv_with_responses_scanner = -1; -static int hf_control_feature_set_reserved_bits = -1; -static int hf_control_feature_set_reserved = -1; -static int hf_control_window_size = -1; -static int hf_control_window_offset = -1; -static int hf_control_interval = -1; -static int hf_control_latency = -1; -static int hf_control_timeout = -1; -static int hf_control_instant = -1; -static int hf_control_rfu_5 = -1; -static int hf_control_interval_min = -1; -static int hf_control_interval_max = -1; -static int hf_control_preferred_periodicity = -1; -static int hf_control_reference_connection_event_count = -1; -static int hf_control_offset_0 = -1; -static int hf_control_offset_1 = -1; -static int hf_control_offset_2 = -1; -static int hf_control_offset_3 = -1; -static int hf_control_offset_4 = -1; -static int hf_control_offset_5 = -1; -static int hf_control_channel_map = -1; -static int hf_control_random_number = -1; -static int hf_control_encrypted_diversifier = -1; -static int hf_control_master_session_key_diversifier = -1; -static int hf_control_master_session_initialization_vector = -1; -static int hf_control_slave_session_key_diversifier = -1; -static int hf_control_slave_session_initialization_vector = -1; -static int hf_control_max_rx_octets = -1; -static int hf_control_max_rx_time = -1; -static int hf_control_max_tx_octets = -1; -static int hf_control_max_tx_time = -1; -static int hf_control_phys_sender_le_1m_phy = -1; -static int hf_control_phys_sender_le_2m_phy = -1; -static int hf_control_phys_sender_le_coded_phy = -1; -static int hf_control_phys_update_le_1m_phy = -1; -static int hf_control_phys_update_le_2m_phy = -1; -static int hf_control_phys_update_le_coded_phy = -1; -static int hf_control_phys_reserved_bits = -1; -static int hf_control_tx_phys = -1; -static int hf_control_rx_phys = -1; -static int hf_control_m_to_s_phy = -1; -static int hf_control_m_to_s_phy_le_1m_phy = -1; -static int hf_control_m_to_s_phy_le_2m_phy = -1; -static int hf_control_m_to_s_phy_le_coded_phy = -1; -static int hf_control_m_to_s_phy_reserved_bits = -1; -static int hf_control_s_to_m_phy = -1; -static int hf_control_s_to_m_phy_le_1m_phy = -1; -static int hf_control_s_to_m_phy_le_2m_phy = -1; -static int hf_control_s_to_m_phy_le_coded_phy = -1; -static int hf_control_s_to_m_phy_reserved_bits = -1; -static int hf_control_phys = -1; -static int hf_control_phys_le_1m_phy = -1; -static int hf_control_phys_le_2m_phy = -1; -static int hf_control_phys_le_coded_phy = -1; -static int hf_control_min_used_channels = -1; -static int hf_control_cte_min_len_req = -1; -static int hf_control_cte_rfu = -1; -static int hf_control_cte_type_req = -1; -static int hf_control_sync_id = -1; -static int hf_control_sync_info_offset = -1; -static int hf_control_sync_info_offset_units = -1; -static int hf_control_sync_info_offset_adjust = -1; -static int hf_control_sync_info_reserved = -1; -static int hf_control_sync_info_interval = -1; -static int hf_control_sync_info_channel_map = -1; -static int hf_control_sync_info_sleep_clock_accuracy = -1; -static int hf_control_sync_info_access_address = -1; -static int hf_control_sync_info_crc_init = -1; -static int hf_control_sync_info_event_counter = -1; -static int hf_control_sync_conn_event_count = -1; -static int hf_control_sync_last_pa_event_counter = -1; -static int hf_control_sync_sid = -1; -static int hf_control_sync_atype = -1; -static int hf_control_sync_sleep_clock_accuracy = -1; -static int hf_control_sync_sync_conn_event_counter = -1; -static int hf_control_sleep_clock_accuracy = -1; -static int hf_control_cig_id = -1; -static int hf_control_cis_id = -1; -static int hf_control_max_sdu_m_to_s = -1; -static int hf_control_rfu_1 = -1; -static int hf_control_framed = -1; -static int hf_control_max_sdu_s_to_m = -1; -static int hf_control_rfu_2 = -1; -static int hf_control_sdu_interval_m_to_s = -1; -static int hf_control_rfu_3 = -1; -static int hf_control_sdu_interval_s_to_m = -1; -static int hf_control_rfu_4 = -1; -static int hf_control_max_pdu_m_to_s = -1; -static int hf_control_max_pdu_s_to_m = -1; -static int hf_control_num_sub_events = -1; -static int hf_control_sub_interval = -1; -static int hf_control_bn_m_to_s = -1; -static int hf_control_bn_s_to_m = -1; -static int hf_control_ft_m_to_s = -1; -static int hf_control_ft_s_to_m = -1; -static int hf_control_iso_interval = -1; -static int hf_control_cis_offset_min = -1; -static int hf_control_cis_offset_max = -1; -static int hf_control_conn_event_count = -1; -static int hf_control_access_address = -1; -static int hf_control_cis_offset = -1; -static int hf_control_cig_sync_delay = -1; -static int hf_control_cis_sync_delay = -1; -static int hf_control_pwr_phy = -1; -static int hf_control_pwr_phy_le_1m_phy = -1; -static int hf_control_pwr_phy_le_2m_phy = -1; -static int hf_control_pwr_phy_le_coded_s8_phy = -1; -static int hf_control_pwr_phy_le_coded_s2_phy = -1; -static int hf_control_pwr_phy_reserved_bits = -1; -static int hf_control_delta = -1; -static int hf_control_txpwr = -1; -static int hf_control_pwrflags = -1; -static int hf_control_pwrflags_min = -1; -static int hf_control_pwrflags_max = -1; -static int hf_control_pwrflags_reserved_bits = -1; -static int hf_control_acceptable_power_reduction = -1; -static int hf_control_subrate_factor_min = -1; -static int hf_control_subrate_factor_max = -1; -static int hf_control_max_latency = -1; -static int hf_control_continuation_number = -1; -static int hf_control_subrate_factor = -1; -static int hf_control_subrate_base_event = -1; -static int hf_control_channel_reporting_enable = -1; -static int hf_control_channel_reporting_min_spacing = -1; -static int hf_control_channel_reporting_max_delay = -1; -static int hf_control_channel_classification = -1; -static int hf_control_sync_info_rsp_access_address = -1; -static int hf_control_sync_info_num_subevents = -1; -static int hf_control_sync_info_subevent_interval = -1; -static int hf_control_sync_info_response_slot_delay = -1; -static int hf_control_sync_info_response_slot_spacing = -1; -static int hf_big_control_opcode = -1; -static int hf_isochronous_data = -1; -static int hf_btle_l2cap_msg_fragments = -1; -static int hf_btle_l2cap_msg_fragment = -1; -static int hf_btle_l2cap_msg_fragment_overlap = -1; -static int hf_btle_l2cap_msg_fragment_overlap_conflicts = -1; -static int hf_btle_l2cap_msg_fragment_multiple_tails = -1; -static int hf_btle_l2cap_msg_fragment_too_long_fragment = -1; -static int hf_btle_l2cap_msg_fragment_error = -1; -static int hf_btle_l2cap_msg_fragment_count = -1; -static int hf_btle_l2cap_msg_reassembled_in = -1; -static int hf_btle_l2cap_msg_reassembled_length = -1; -static int hf_btle_ea_host_advertising_data_fragments = -1; -static int hf_btle_ea_host_advertising_data_fragment = -1; -static int hf_btle_ea_host_advertising_data_fragment_overlap = -1; -static int hf_btle_ea_host_advertising_data_fragment_overlap_conflicts = -1; -static int hf_btle_ea_host_advertising_data_fragment_multiple_tails = -1; -static int hf_btle_ea_host_advertising_data_fragment_too_long_fragment = -1; -static int hf_btle_ea_host_advertising_data_fragment_error = -1; -static int hf_btle_ea_host_advertising_data_fragment_count = -1; -static int hf_btle_ea_host_advertising_data_reassembled_in = -1; -static int hf_btle_ea_host_advertising_data_reassembled_length = -1; - -static int hf_request_in_frame = -1; -static int hf_response_in_frame = -1; - -static gint ett_btle = -1; -static gint ett_advertising_header = -1; -static gint ett_link_layer_data = -1; -static gint ett_data_header = -1; -static gint ett_data_header_cte_info = -1; -static gint ett_features = -1; -static gint ett_tx_phys = -1; -static gint ett_rx_phys = -1; -static gint ett_m_to_s_phy = -1; -static gint ett_s_to_m_phy = -1; -static gint ett_phys = -1; -static gint ett_pwr_phy = -1; -static gint ett_cte = -1; -static gint ett_channel_map = -1; -static gint ett_scan_response_data = -1; -static gint ett_pwrflags = -1; -static gint ett_btle_l2cap_msg_fragment = -1; -static gint ett_btle_l2cap_msg_fragments = -1; -static gint ett_btle_ea_host_advertising_data_fragment = -1; -static gint ett_btle_ea_host_advertising_data_fragments = -1; -static gint ett_extended_advertising_header = -1; -static gint ett_extended_advertising_flags = -1; -static gint ett_extended_advertising_cte_info = -1; -static gint ett_extended_advertising_data_info = -1; -static gint ett_extended_advertising_aux_pointer = -1; -static gint ett_extended_advertising_sync_info = -1; -static gint ett_extended_advertising_acad = -1; +static int proto_btle; +static int proto_btle_rf; +static int proto_nordic_ble; + +static int hf_access_address; +static int hf_coding_indicator; +static int hf_crc; +static int hf_central_bd_addr; +static int hf_peripheral_bd_addr; +static int hf_length; +static int hf_advertising_header; +static int hf_advertising_header_pdu_type; +static int hf_advertising_header_ch_sel; +static int hf_advertising_header_rfu_1; +static int hf_advertising_header_rfu_2; +static int hf_advertising_header_rfu_3; +static int hf_advertising_header_rfu_4; +static int hf_advertising_header_randomized_tx; +static int hf_advertising_header_randomized_rx; +static int hf_advertising_header_length; +static int hf_advertising_address; +static int hf_initiator_addresss; +static int hf_target_addresss; +static int hf_scanning_address; +static int hf_scan_response_data; +static int hf_link_layer_data; +static int hf_link_layer_data_access_address; +static int hf_link_layer_data_crc_init; +static int hf_link_layer_data_window_size; +static int hf_link_layer_data_window_offset; +static int hf_link_layer_data_interval; +static int hf_link_layer_data_latency; +static int hf_link_layer_data_timeout; +static int hf_link_layer_data_channel_map; +static int hf_link_layer_data_hop; +static int hf_link_layer_data_sleep_clock_accuracy; +static int hf_extended_advertising_header; +static int hf_extended_advertising_header_length; +static int hf_extended_advertising_mode; +static int hf_extended_advertising_flags; +static int hf_extended_advertising_flags_adva; +static int hf_extended_advertising_flags_targeta; +static int hf_extended_advertising_flags_cte_info; +static int hf_extended_advertising_flags_advdatainfo; +static int hf_extended_advertising_flags_aux_ptr; +static int hf_extended_advertising_flags_sync_info; +static int hf_extended_advertising_flags_tx_power; +static int hf_extended_advertising_flags_reserved; +static int hf_extended_advertising_cte_info; +static int hf_extended_advertising_cte_info_time; +static int hf_extended_advertising_cte_info_rfu; +static int hf_extended_advertising_cte_info_type; +static int hf_extended_advertising_data_info; +static int hf_extended_advertising_data_info_did; +static int hf_extended_advertising_data_info_sid; +static int hf_extended_advertising_aux_ptr; +static int hf_extended_advertising_aux_ptr_channel; +static int hf_extended_advertising_aux_ptr_ca; +static int hf_extended_advertising_aux_ptr_offset_units; +static int hf_extended_advertising_aux_ptr_aux_offset; +static int hf_extended_advertising_aux_ptr_aux_phy; +static int hf_extended_advertising_sync_info; +static int hf_extended_advertising_sync_info_offset; +static int hf_extended_advertising_sync_info_offset_units; +static int hf_extended_advertising_sync_info_offset_adjust; +static int hf_extended_advertising_sync_info_reserved; +static int hf_extended_advertising_sync_info_interval; +static int hf_extended_advertising_sync_info_channel_map; +static int hf_extended_advertising_sync_info_sleep_clock_accuracy; +static int hf_extended_advertising_sync_info_access_address; +static int hf_extended_advertising_sync_info_crc_init; +static int hf_extended_advertising_sync_info_event_counter; +static int hf_extended_advertising_tx_power; +static int hf_extended_advertising_header_acad; +static int hf_extended_advertising_had_fragment; +static int hf_data_header; +static int hf_data_header_length; +static int hf_data_header_rfu; +static int hf_data_header_llid; +static int hf_data_header_llid_connectediso; +static int hf_data_header_llid_broadcastiso; +static int hf_data_header_more_data; +static int hf_data_header_cte_info_present; +static int hf_data_header_sequence_number; +static int hf_data_header_next_expected_sequence_number; +static int hf_data_header_rfu_57; +static int hf_data_header_rfu_67; +static int hf_data_header_close_isochronous_event; +static int hf_data_header_null_pdu_indicator; +static int hf_data_header_control_subevent_sequence_number; +static int hf_data_header_control_subevent_transmission_flag; +static int hf_data_header_cte_info; +static int hf_data_header_cte_info_time; +static int hf_data_header_cte_info_rfu; +static int hf_data_header_cte_info_type; +static int hf_control_opcode; +static int hf_l2cap_index; +static int hf_l2cap_fragment; +static int hf_connection_parameters_in; +static int hf_control_reject_opcode; +static int hf_control_error_code; +static int hf_control_unknown_type; +static int hf_control_version_number; +static int hf_control_company_id; +static int hf_control_subversion_number; +static int hf_control_feature_set; +static int hf_control_feature_set_le_encryption; +static int hf_control_feature_set_connection_parameters_request_procedure; +static int hf_control_feature_set_extended_reject_indication; +static int hf_control_feature_set_peripheral_initiated_features_exchange; +static int hf_control_feature_set_le_ping; +static int hf_control_feature_set_le_pkt_len_ext; +static int hf_control_feature_set_ll_privacy; +static int hf_control_feature_set_ext_scan_flt_pol; +static int hf_control_feature_set_le_2m_phy; +static int hf_control_feature_set_stable_modulation_index_transmitter; +static int hf_control_feature_set_stable_modulation_index_receiver; +static int hf_control_feature_set_le_coded_phy; +static int hf_control_feature_set_le_extended_advertising; +static int hf_control_feature_set_le_periodic_advertising; +static int hf_control_feature_set_channel_selection_algorithm_2; +static int hf_control_feature_set_le_power_class_1; +static int hf_control_feature_set_minimum_number_of_used_channels_procedure; +static int hf_control_feature_set_connection_cte_request; +static int hf_control_feature_set_connection_cte_response; +static int hf_control_feature_set_connectionless_cte_tx; +static int hf_control_feature_set_connectionless_cte_rx; +static int hf_control_feature_set_antenna_switching_tx_aod; +static int hf_control_feature_set_antenna_switching_rx_aoa; +static int hf_control_feature_set_cte_rx; +static int hf_control_feature_set_past_sender; +static int hf_control_feature_set_past_receiver; +static int hf_control_feature_set_sca_updates; +static int hf_control_feature_set_remote_public_key_validation; +static int hf_control_feature_set_cis_central; +static int hf_control_feature_set_cis_peripheral; +static int hf_control_feature_set_iso_broadcast; +static int hf_control_feature_set_synchronized_receiver; +static int hf_control_feature_set_connected_iso_host_support; +static int hf_control_feature_set_le_power_control_request1; +static int hf_control_feature_set_le_power_control_request2; +static int hf_control_feature_set_le_path_loss_monitoring; +static int hf_control_feature_set_le_periodic_adv_adi_support; +static int hf_control_feature_set_connection_subrating; +static int hf_control_feature_set_connection_subrating_host_support; +static int hf_control_feature_set_channel_classification; +static int hf_control_feature_set_adv_coding_selection; +static int hf_control_feature_set_adv_coding_selection_host_support; +static int hf_control_feature_set_periodic_adv_with_responses_advertiser; +static int hf_control_feature_set_periodic_adv_with_responses_scanner; +static int hf_control_feature_set_reserved_bits; +static int hf_control_feature_set_reserved; +static int hf_control_window_size; +static int hf_control_window_offset; +static int hf_control_interval; +static int hf_control_latency; +static int hf_control_timeout; +static int hf_control_instant; +static int hf_control_rfu_5; +static int hf_control_interval_min; +static int hf_control_interval_max; +static int hf_control_preferred_periodicity; +static int hf_control_reference_connection_event_count; +static int hf_control_offset_0; +static int hf_control_offset_1; +static int hf_control_offset_2; +static int hf_control_offset_3; +static int hf_control_offset_4; +static int hf_control_offset_5; +static int hf_control_channel_map; +static int hf_control_random_number; +static int hf_control_encrypted_diversifier; +static int hf_control_central_session_key_diversifier; +static int hf_control_central_session_initialization_vector; +static int hf_control_peripheral_session_key_diversifier; +static int hf_control_peripheral_session_initialization_vector; +static int hf_control_max_rx_octets; +static int hf_control_max_rx_time; +static int hf_control_max_tx_octets; +static int hf_control_max_tx_time; +static int hf_control_phys_sender_le_1m_phy; +static int hf_control_phys_sender_le_2m_phy; +static int hf_control_phys_sender_le_coded_phy; +static int hf_control_phys_update_le_1m_phy; +static int hf_control_phys_update_le_2m_phy; +static int hf_control_phys_update_le_coded_phy; +static int hf_control_phys_reserved_bits; +static int hf_control_tx_phys; +static int hf_control_rx_phys; +static int hf_control_c_to_p_phy; +static int hf_control_c_to_p_phy_le_1m_phy; +static int hf_control_c_to_p_phy_le_2m_phy; +static int hf_control_c_to_p_phy_le_coded_phy; +static int hf_control_c_to_p_phy_reserved_bits; +static int hf_control_p_to_c_phy; +static int hf_control_p_to_c_phy_le_1m_phy; +static int hf_control_p_to_c_phy_le_2m_phy; +static int hf_control_p_to_c_phy_le_coded_phy; +static int hf_control_p_to_c_phy_reserved_bits; +static int hf_control_phys; +static int hf_control_phys_le_1m_phy; +static int hf_control_phys_le_2m_phy; +static int hf_control_phys_le_coded_phy; +static int hf_control_min_used_channels; +static int hf_control_cte_min_len_req; +static int hf_control_cte_rfu; +static int hf_control_cte_type_req; +static int hf_control_sync_id; +static int hf_control_sync_info_offset; +static int hf_control_sync_info_offset_units; +static int hf_control_sync_info_offset_adjust; +static int hf_control_sync_info_reserved; +static int hf_control_sync_info_interval; +static int hf_control_sync_info_channel_map; +static int hf_control_sync_info_sleep_clock_accuracy; +static int hf_control_sync_info_access_address; +static int hf_control_sync_info_crc_init; +static int hf_control_sync_info_event_counter; +static int hf_control_sync_conn_event_count; +static int hf_control_sync_last_pa_event_counter; +static int hf_control_sync_sid; +static int hf_control_sync_atype; +static int hf_control_sync_sleep_clock_accuracy; +static int hf_control_sync_sync_conn_event_counter; +static int hf_control_sleep_clock_accuracy; +static int hf_control_cig_id; +static int hf_control_cis_id; +static int hf_control_max_sdu_c_to_p; +static int hf_control_rfu_1; +static int hf_control_framed; +static int hf_control_max_sdu_p_to_c; +static int hf_control_rfu_2; +static int hf_control_sdu_interval_c_to_p; +static int hf_control_rfu_3; +static int hf_control_sdu_interval_p_to_c; +static int hf_control_rfu_4; +static int hf_control_max_pdu_c_to_p; +static int hf_control_max_pdu_p_to_c; +static int hf_control_num_sub_events; +static int hf_control_sub_interval; +static int hf_control_bn_c_to_p; +static int hf_control_bn_p_to_c; +static int hf_control_ft_c_to_p; +static int hf_control_ft_p_to_c; +static int hf_control_iso_interval; +static int hf_control_cis_offset_min; +static int hf_control_cis_offset_max; +static int hf_control_conn_event_count; +static int hf_control_access_address; +static int hf_control_cis_offset; +static int hf_control_cig_sync_delay; +static int hf_control_cis_sync_delay; +static int hf_control_pwr_phy; +static int hf_control_pwr_phy_le_1m_phy; +static int hf_control_pwr_phy_le_2m_phy; +static int hf_control_pwr_phy_le_coded_s8_phy; +static int hf_control_pwr_phy_le_coded_s2_phy; +static int hf_control_pwr_phy_reserved_bits; +static int hf_control_delta; +static int hf_control_txpwr; +static int hf_control_pwrflags; +static int hf_control_pwrflags_min; +static int hf_control_pwrflags_max; +static int hf_control_pwrflags_reserved_bits; +static int hf_control_acceptable_power_reduction; +static int hf_control_subrate_factor_min; +static int hf_control_subrate_factor_max; +static int hf_control_max_latency; +static int hf_control_continuation_number; +static int hf_control_subrate_factor; +static int hf_control_subrate_base_event; +static int hf_control_channel_reporting_enable; +static int hf_control_channel_reporting_min_spacing; +static int hf_control_channel_reporting_max_delay; +static int hf_control_channel_classification; +static int hf_control_sync_info_rsp_access_address; +static int hf_control_sync_info_num_subevents; +static int hf_control_sync_info_subevent_interval; +static int hf_control_sync_info_response_slot_delay; +static int hf_control_sync_info_response_slot_spacing; +static int hf_big_control_opcode; +static int hf_isochronous_data; +static int hf_btle_l2cap_msg_fragments; +static int hf_btle_l2cap_msg_fragment; +static int hf_btle_l2cap_msg_fragment_overlap; +static int hf_btle_l2cap_msg_fragment_overlap_conflicts; +static int hf_btle_l2cap_msg_fragment_multiple_tails; +static int hf_btle_l2cap_msg_fragment_too_long_fragment; +static int hf_btle_l2cap_msg_fragment_error; +static int hf_btle_l2cap_msg_fragment_count; +static int hf_btle_l2cap_msg_reassembled_in; +static int hf_btle_l2cap_msg_reassembled_length; +static int hf_btle_ea_host_advertising_data_fragments; +static int hf_btle_ea_host_advertising_data_fragment; +static int hf_btle_ea_host_advertising_data_fragment_overlap; +static int hf_btle_ea_host_advertising_data_fragment_overlap_conflicts; +static int hf_btle_ea_host_advertising_data_fragment_multiple_tails; +static int hf_btle_ea_host_advertising_data_fragment_too_long_fragment; +static int hf_btle_ea_host_advertising_data_fragment_error; +static int hf_btle_ea_host_advertising_data_fragment_count; +static int hf_btle_ea_host_advertising_data_reassembled_in; +static int hf_btle_ea_host_advertising_data_reassembled_length; + +static int hf_request_in_frame; +static int hf_response_in_frame; + +static int ett_btle; +static int ett_advertising_header; +static int ett_link_layer_data; +static int ett_data_header; +static int ett_data_header_cte_info; +static int ett_features; +static int ett_tx_phys; +static int ett_rx_phys; +static int ett_c_to_p_phy; +static int ett_p_to_c_phy; +static int ett_phys; +static int ett_pwr_phy; +static int ett_cte; +static int ett_channel_map; +static int ett_scan_response_data; +static int ett_pwrflags; +static int ett_btle_l2cap_msg_fragment; +static int ett_btle_l2cap_msg_fragments; +static int ett_btle_ea_host_advertising_data_fragment; +static int ett_btle_ea_host_advertising_data_fragments; +static int ett_extended_advertising_header; +static int ett_extended_advertising_flags; +static int ett_extended_advertising_cte_info; +static int ett_extended_advertising_data_info; +static int ett_extended_advertising_aux_pointer; +static int ett_extended_advertising_sync_info; +static int ett_extended_advertising_acad; static int * const hfx_extended_advertising_flags[] = { &hf_extended_advertising_flags_adva, @@ -379,7 +381,7 @@ static int * const hfx_control_feature_set_1[] = { &hf_control_feature_set_le_encryption, &hf_control_feature_set_connection_parameters_request_procedure, &hf_control_feature_set_extended_reject_indication, - &hf_control_feature_set_slave_initiated_features_exchange, + &hf_control_feature_set_peripheral_initiated_features_exchange, &hf_control_feature_set_le_ping, &hf_control_feature_set_le_pkt_len_ext, &hf_control_feature_set_ll_privacy, @@ -460,19 +462,19 @@ static int * const hfx_control_phys_update[] = { NULL }; -static int * const hfx_control_m_to_s_phy[] = { - &hf_control_m_to_s_phy_le_1m_phy, - &hf_control_m_to_s_phy_le_2m_phy, - &hf_control_m_to_s_phy_le_coded_phy, - &hf_control_m_to_s_phy_reserved_bits, +static int * const hfx_control_c_to_p_phy[] = { + &hf_control_c_to_p_phy_le_1m_phy, + &hf_control_c_to_p_phy_le_2m_phy, + &hf_control_c_to_p_phy_le_coded_phy, + &hf_control_c_to_p_phy_reserved_bits, NULL }; -static int * const hfx_control_s_to_m_phy[] = { - &hf_control_s_to_m_phy_le_1m_phy, - &hf_control_s_to_m_phy_le_2m_phy, - &hf_control_s_to_m_phy_le_coded_phy, - &hf_control_s_to_m_phy_reserved_bits, +static int * const hfx_control_p_to_c_phy[] = { + &hf_control_p_to_c_phy_le_1m_phy, + &hf_control_p_to_c_phy_le_2m_phy, + &hf_control_p_to_c_phy_le_coded_phy, + &hf_control_p_to_c_phy_reserved_bits, NULL }; @@ -514,19 +516,19 @@ static int * const hfx_control_pwrflags[] = { NULL }; -static expert_field ei_unknown_data = EI_INIT; -static expert_field ei_access_address_matched = EI_INIT; -static expert_field ei_access_address_bit_errors = EI_INIT; -static expert_field ei_access_address_illegal = EI_INIT; -static expert_field ei_crc_cannot_be_determined = EI_INIT; -static expert_field ei_crc_incorrect = EI_INIT; -static expert_field ei_missing_fragment_start = EI_INIT; -static expert_field ei_retransmit = EI_INIT; -static expert_field ei_nack = EI_INIT; -static expert_field ei_control_proc_overlapping = EI_INIT; -static expert_field ei_control_proc_invalid_collision = EI_INIT; -static expert_field ei_control_proc_wrong_seq = EI_INIT; -static expert_field ei_control_proc_invalid_conflict_resolution = EI_INIT; +static expert_field ei_unknown_data; +static expert_field ei_access_address_matched; +static expert_field ei_access_address_bit_errors; +static expert_field ei_access_address_illegal; +static expert_field ei_crc_cannot_be_determined; +static expert_field ei_crc_incorrect; +static expert_field ei_missing_fragment_start; +static expert_field ei_retransmit; +static expert_field ei_nack; +static expert_field ei_control_proc_overlapping; +static expert_field ei_control_proc_invalid_collision; +static expert_field ei_control_proc_wrong_seq; +static expert_field ei_control_proc_invalid_conflict_resolution; static dissector_handle_t btle_handle; static dissector_handle_t btcommon_ad_handle; @@ -534,10 +536,11 @@ static dissector_handle_t btcommon_le_channel_map_handle; static dissector_handle_t btl2cap_handle; static wmem_tree_t *connection_info_tree; +static wmem_tree_t *periodic_adv_info_tree; static wmem_tree_t *broadcastiso_connection_info_tree; static wmem_tree_t *connection_parameter_info_tree; static wmem_tree_t *adi_to_first_frame_tree; -static guint32 l2cap_index; +static uint32_t l2cap_index; /* Reassembly */ static reassembly_table btle_l2cap_msg_reassembly_table; @@ -592,8 +595,8 @@ static const fragment_items btle_ea_host_advertising_data_frag_items = { }; typedef struct _ae_had_info_t { - guint fragment_counter; - guint32 first_frame_num; + unsigned fragment_counter; + uint32_t first_frame_num; address adv_addr; } ae_had_info_t; @@ -602,10 +605,10 @@ typedef struct _control_proc_info_t { * The first entry corresponds to the request, the remaining frames are responses. * The longest sequence is needed for the encryption start procedure, * which consists of 5 frames. */ - guint frames[5]; + unsigned frames[5]; /* Opcode of the first control procedure packet. */ - guint8 proc_opcode; + uint8_t proc_opcode; /* The frame where the procedure completes. Set to 0 when not yet known. * This is used to avoid adding another frame to the control procedure @@ -614,69 +617,70 @@ typedef struct _control_proc_info_t { * This frame number may be ignored in the case where an LL_UNKNOWN_RSP is * received after a procedure involving only one packet, like the * LL_MIN_USED_CHANNELS_IND. */ - guint last_frame; + unsigned last_frame; /* The frame number of the packet containing the instant value. * If set to 0, there is no such frame. * * We need to store this frame number, as any event counter is * a valid instant. */ - guint frame_with_instant_value; + unsigned frame_with_instant_value; /* The event counter corresponding to the instant of the control procedure. */ - guint16 instant; + uint16_t instant; } control_proc_info_t; /* Store information about a connection direction */ typedef struct _direction_info_t { - guint prev_seq_num : 1; /* Previous sequence number for this direction */ - guint segmentation_started : 1; /* 0 = No, 1 = Yes */ - guint segment_len_rem; /* The remaining segment length, used to find last segment */ - guint32 l2cap_index; /* Unique identifier for each L2CAP message */ + unsigned prev_seq_num : 1; /* Previous sequence number for this direction */ + unsigned segmentation_started : 1; /* 0 = No, 1 = Yes */ + unsigned segment_len_rem; /* The remaining segment length, used to find last segment */ + uint32_t l2cap_index; /* Unique identifier for each L2CAP message */ wmem_tree_t *control_procs; /* Control procedures initiated from this direction. */ } direction_info_t; typedef struct _connection_parameter_info_t { - guint32 parameters_frame; + uint32_t parameters_frame; } connection_parameter_info_t; /* Store information about a connection */ typedef struct _connection_info_t { /* Address information */ - guint32 interface_id; - guint32 adapter_id; - guint32 access_address; + uint32_t interface_id; + uint32_t adapter_id; + uint32_t access_address; + uint32_t crc_init; - guint8 master_bd_addr[6]; - guint8 slave_bd_addr[6]; + uint8_t central_bd_addr[6]; + uint8_t peripheral_bd_addr[6]; - guint16 connection_parameter_update_instant; + uint16_t connection_parameter_update_instant; connection_parameter_info_t *connection_parameter_update_info; /* Connection information */ /* Data used on the first pass to get info from previous frame, result will be in per_packet_data */ - guint first_data_frame_seen : 1; - direction_info_t direction_info[3]; /* UNKNOWN, MASTER_SLAVE and SLAVE_MASTER */ + unsigned first_data_frame_seen : 1; + direction_info_t direction_info[3]; /* UNKNOWN, CENTRAL_PERIPHERAL and PERIPHERAL_CENTRAL */ } connection_info_t; /* Store information about a broadcast isochronous connection */ typedef struct _broadcastiso_connection_info_t { /* Address information */ - guint32 interface_id; - guint32 adapter_id; - guint32 access_address; + uint32_t interface_id; + uint32_t adapter_id; + uint32_t access_address; - guint8 master_bd_addr[6]; + uint8_t central_bd_addr[6]; } broadcastiso_connection_info_t; /* */ typedef struct _btle_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 */ + unsigned retransmit : 1; /* 0 = No, 1 = Retransmitted frame */ + unsigned ack : 1; /* 0 = Nack, 1 = Ack */ + unsigned more_fragments : 1; /* 0 = Last fragment, 1 = More fragments */ + unsigned missing_start : 1; /* 0 = No, 1 = Missing fragment start */ + uint32_t l2cap_index; /* Unique identifier for each L2CAP message */ } btle_frame_info_t; static const value_string pdu_type_vals[] = { @@ -774,7 +778,7 @@ typedef enum LL_CTRL_OPCODE_PAUSE_ENC_RSP = 0x0B, LL_CTRL_OPCODE_VERSION_IND = 0x0C, LL_CTRL_OPCODE_REJECT_IND = 0x0D, - LL_CTRL_OPCODE_SLAVE_FEATURE_REQ = 0x0E, + LL_CTRL_OPCODE_PERIPHERAL_FEATURE_REQ = 0x0E, LL_CTRL_OPCODE_CONNECTION_PARAM_REQ = 0x0F, LL_CTRL_OPCODE_CONNECTION_PARAM_RSP = 0x10, LL_CTRL_OPCODE_REJECT_EXT_IND = 0x11, @@ -820,7 +824,7 @@ static const value_string control_opcode_vals[] = { { LL_CTRL_OPCODE_PAUSE_ENC_RSP, "LL_PAUSE_ENC_RSP" }, { LL_CTRL_OPCODE_VERSION_IND, "LL_VERSION_IND" }, { LL_CTRL_OPCODE_REJECT_IND, "LL_REJECT_IND" }, - { LL_CTRL_OPCODE_SLAVE_FEATURE_REQ, "LL_SLAVE_FEATURE_REQ" }, + { LL_CTRL_OPCODE_PERIPHERAL_FEATURE_REQ, "LL_PERIPHERAL_FEATURE_REQ" }, { LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, "LL_CONNECTION_PARAM_REQ" }, { LL_CTRL_OPCODE_CONNECTION_PARAM_RSP, "LL_CONNECTION_PARAM_RSP" }, { LL_CTRL_OPCODE_REJECT_EXT_IND, "LL_REJECT_EXT_IND" }, @@ -932,7 +936,7 @@ static const true_false_string tfs_random_public = { void proto_register_btle(void); void proto_reg_handoff_btle(void); -static gboolean btle_detect_retransmit = TRUE; +static bool btle_detect_retransmit = true; static void btle_init(void) @@ -950,10 +954,10 @@ btle_init(void) * This implementation operates on nibbles and is therefore * endian-neutral. */ -static guint32 -btle_crc(tvbuff_t *tvb, const guint8 payload_len, const guint32 crc_init) +static uint32_t +btle_crc(tvbuff_t *tvb, const uint8_t payload_len, const uint32_t crc_init) { - static const guint16 btle_crc_next_state_flips[256] = { + static const uint16_t btle_crc_next_state_flips[256] = { 0x0000, 0x32d8, 0x196c, 0x2bb4, 0x0cb6, 0x3e6e, 0x15da, 0x2702, 0x065b, 0x3483, 0x1f37, 0x2def, 0x0aed, 0x3835, 0x1381, 0x2159, 0x065b, 0x3483, 0x1f37, 0x2def, 0x0aed, 0x3835, 0x1381, 0x2159, @@ -987,13 +991,13 @@ btle_crc(tvbuff_t *tvb, const guint8 payload_len, const guint32 crc_init) 0x2159, 0x1381, 0x3835, 0x0aed, 0x2def, 0x1f37, 0x3483, 0x065b, 0x2702, 0x15da, 0x3e6e, 0x0cb6, 0x2bb4, 0x196c, 0x32d8, 0x0000 }; - gint offset = 4; /* skip AA, CRC applies over PDU */ - guint32 state = crc_init; - guint8 bytes_to_go = 2+payload_len; /* PDU includes header and payload */ + int offset = 4; /* skip AA, CRC applies over PDU */ + uint32_t state = crc_init; + uint8_t bytes_to_go = 2+payload_len; /* PDU includes header and payload */ while( bytes_to_go-- ) { - guint8 byte = tvb_get_guint8(tvb, offset++); - guint8 nibble = (byte & 0xf); - guint8 byte_index = ((state >> 16) & 0xf0) | nibble; + uint8_t byte = tvb_get_uint8(tvb, offset++); + uint8_t nibble = (byte & 0xf); + uint8_t byte_index = ((state >> 16) & 0xf0) | nibble; state = ((state << 4) ^ btle_crc_next_state_flips[byte_index]) & 0xffffff; nibble = ((byte >> 4) & 0xf); byte_index = ((state >> 16) & 0xf0) | nibble; @@ -1002,9 +1006,11 @@ btle_crc(tvbuff_t *tvb, const guint8 payload_len, const guint32 crc_init) return state; } -static const gchar * adv_pdu_type_str_get(const btle_context_t *btle_context, guint32 pdu_type) +static const char * adv_pdu_type_str_get(const btle_context_t *btle_context, uint32_t pdu_type, bool is_periodic_adv) { - if (!btle_context || !(btle_context->channel < 37)) { + if (is_periodic_adv) { + return "AUX_SYNC_IND"; + } else if (!btle_context || !(btle_context->channel < 37)) { return val_to_str_ext_const(pdu_type, &pdu_type_vals_ext, "Unknown"); } else if (pdu_type == 0x07 && btle_context->aux_pdu_type_valid) { return val_to_str_ext_const(btle_context->aux_pdu_type, &aux_pdu_common_vals_ext, "Unknown"); @@ -1020,26 +1026,26 @@ static const gchar * adv_pdu_type_str_get(const btle_context_t *btle_context, gu * to the rest of the BTLE packet. See BT spec, Vol 6, Part B, * Section 1.2. */ -static guint32 -reverse_bits_per_byte(const guint32 val) +static uint32_t +reverse_bits_per_byte(const uint32_t val) { - const guint8 nibble_rev[16] = { + static const uint8_t nibble_rev[16] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - guint32 retval = 0; + uint32_t retval = 0; unsigned byte_index; for (byte_index=0; byte_index<4; byte_index++) { - guint shiftA = byte_index*8; - guint shiftB = shiftA+4; + unsigned shiftA = byte_index*8; + unsigned shiftB = shiftA+4; retval |= (nibble_rev[((val >> shiftA) & 0xf)] << shiftB); retval |= (nibble_rev[((val >> shiftB) & 0xf)] << shiftA); } return retval; } -static gint -dissect_feature_set(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_feature_set(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_item *sub_item; proto_tree *sub_tree; @@ -1071,8 +1077,8 @@ dissect_feature_set(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_conn_param_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_conn_param_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_interval_min, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -1113,8 +1119,8 @@ dissect_conn_param_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_length_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_length_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_max_rx_octets, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -1131,8 +1137,8 @@ dissect_length_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_phy_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_phy_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_tx_phys, ett_tx_phys, hfx_control_phys_sender, ENC_NA); offset += 1; @@ -1143,13 +1149,13 @@ dissect_phy_req_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_periodic_sync_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, packet_info *pinfo, guint32 interface_id, guint32 adapter_id) +static int +dissect_periodic_sync_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset, packet_info *pinfo, uint32_t interface_id, uint32_t adapter_id) { - guint32 sync_offset, interval; - gint reserved_offset; - guint16 sf; - guint8 bd_addr[6]; + uint32_t sync_offset, interval; + int reserved_offset; + uint16_t sf; + uint8_t bd_addr[6]; proto_item *item; proto_item *sub_item; proto_tree *sub_tree; @@ -1159,7 +1165,7 @@ dissect_periodic_sync_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, pac offset += 2; /* Sync Info */ - sf = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); + sf = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN); item = proto_tree_add_item_ret_uint(btle_tree, hf_control_sync_info_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &sync_offset); proto_tree_add_item(btle_tree, hf_control_sync_info_offset_units, tvb, offset, 2, ENC_LITTLE_ENDIAN); @@ -1205,7 +1211,7 @@ dissect_periodic_sync_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, pac proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_phys, ett_phys, hfx_control_phys, ENC_NA); offset += 1; - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, bd_addr); + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, bd_addr); proto_tree_add_item(btle_tree, hf_control_sync_sync_conn_event_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -1213,10 +1219,10 @@ dissect_periodic_sync_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, pac return offset; } -static gint -dissect_cis_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_cis_req(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { - guint32 interval; + uint32_t interval; proto_item *item; proto_tree_add_item(btle_tree, hf_control_cig_id, tvb, offset, 1, ENC_NA); @@ -1225,33 +1231,33 @@ dissect_cis_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) proto_tree_add_item(btle_tree, hf_control_cis_id, tvb, offset, 1, ENC_NA); offset += 1; - proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_m_to_s_phy, ett_m_to_s_phy, hfx_control_m_to_s_phy, ENC_NA); + proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_c_to_p_phy, ett_c_to_p_phy, hfx_control_c_to_p_phy, ENC_NA); offset += 1; - proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_s_to_m_phy, ett_s_to_m_phy, hfx_control_s_to_m_phy, ENC_NA); + proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_p_to_c_phy, ett_p_to_c_phy, hfx_control_p_to_c_phy, ENC_NA); offset += 1; - proto_tree_add_item(btle_tree, hf_control_max_sdu_m_to_s, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_max_sdu_c_to_p, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(btle_tree, hf_control_rfu_1, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(btle_tree, hf_control_framed, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(btle_tree, hf_control_max_sdu_s_to_m, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_max_sdu_p_to_c, tvb, offset, 2, ENC_LITTLE_ENDIAN); proto_tree_add_item(btle_tree, hf_control_rfu_2, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(btle_tree, hf_control_sdu_interval_m_to_s, tvb, offset, 3, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_sdu_interval_c_to_p, tvb, offset, 3, ENC_LITTLE_ENDIAN); proto_tree_add_item(btle_tree, hf_control_rfu_3, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; - proto_tree_add_item(btle_tree, hf_control_sdu_interval_s_to_m, tvb, offset, 3, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_sdu_interval_p_to_c, tvb, offset, 3, ENC_LITTLE_ENDIAN); proto_tree_add_item(btle_tree, hf_control_rfu_4, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; - proto_tree_add_item(btle_tree, hf_control_max_pdu_m_to_s, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_max_pdu_c_to_p, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; - proto_tree_add_item(btle_tree, hf_control_max_pdu_s_to_m, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(btle_tree, hf_control_max_pdu_p_to_c, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; proto_tree_add_item(btle_tree, hf_control_num_sub_events, tvb, offset, 1, ENC_NA); @@ -1260,14 +1266,14 @@ dissect_cis_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) proto_tree_add_item(btle_tree, hf_control_sub_interval, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; - proto_tree_add_item(btle_tree, hf_control_bn_m_to_s, tvb, offset, 1, ENC_NA); - proto_tree_add_item(btle_tree, hf_control_bn_s_to_m, tvb, offset, 1, ENC_NA); + proto_tree_add_item(btle_tree, hf_control_bn_c_to_p, tvb, offset, 1, ENC_NA); + proto_tree_add_item(btle_tree, hf_control_bn_p_to_c, tvb, offset, 1, ENC_NA); offset += 1; - proto_tree_add_item(btle_tree, hf_control_ft_m_to_s, tvb, offset, 1, ENC_NA); + proto_tree_add_item(btle_tree, hf_control_ft_c_to_p, tvb, offset, 1, ENC_NA); offset += 1; - proto_tree_add_item(btle_tree, hf_control_ft_s_to_m, tvb, offset, 1, ENC_NA); + proto_tree_add_item(btle_tree, hf_control_ft_p_to_c, tvb, offset, 1, ENC_NA); offset += 1; item = proto_tree_add_item_ret_uint(btle_tree, hf_control_iso_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &interval); @@ -1286,8 +1292,8 @@ dissect_cis_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_cis_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_cis_rsp(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_cis_offset_min, tvb, offset, 3, ENC_LITTLE_ENDIAN); offset += 3; @@ -1301,8 +1307,8 @@ dissect_cis_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_cis_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_cis_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); offset += 4; @@ -1322,8 +1328,8 @@ dissect_cis_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_cis_terminate_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_cis_terminate_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_cig_id, tvb, offset, 1, ENC_NA); offset += 1; @@ -1337,8 +1343,8 @@ dissect_cis_terminate_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_power_control_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_power_control_req(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_pwr_phy, ett_pwr_phy, hfx_control_pwr_phy, ENC_NA); offset += 1; @@ -1353,8 +1359,8 @@ dissect_power_control_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) } -static gint -dissect_power_control_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_power_control_rsp(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_pwrflags, ett_pwrflags, hfx_control_pwrflags, ENC_NA); offset += 1; @@ -1371,8 +1377,8 @@ dissect_power_control_rsp(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_power_control_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_power_control_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_pwr_phy, ett_pwr_phy, hfx_control_pwr_phy, ENC_NA); offset += 1; @@ -1389,8 +1395,8 @@ dissect_power_control_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_subrate_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_subrate_req(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_subrate_factor_min, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -1410,8 +1416,8 @@ dissect_subrate_req(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_subrate_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_subrate_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_subrate_factor, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; @@ -1431,8 +1437,8 @@ dissect_subrate_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_channel_reporting_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_channel_reporting_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_channel_reporting_enable, tvb, offset, 1, ENC_NA); offset += 1; @@ -1446,8 +1452,8 @@ dissect_channel_reporting_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) return offset; } -static gint -dissect_channel_status_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) +static int +dissect_channel_status_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset) { proto_tree_add_item(btle_tree, hf_control_channel_classification, tvb, offset, 10, ENC_NA); offset += 10; @@ -1456,8 +1462,8 @@ dissect_channel_status_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset) } -static gint -dissect_periodic_sync_wr_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, packet_info *pinfo, guint32 interface_id, guint32 adapter_id) +static int +dissect_periodic_sync_wr_ind(tvbuff_t *tvb, proto_tree *btle_tree, int offset, packet_info *pinfo, uint32_t interface_id, uint32_t adapter_id) { /* The first part of LL_PERIODIC_SYNC_WR_IND is identical to LL_PERIODIC_SYNC_IND */ offset += dissect_periodic_sync_ind(tvb, btle_tree, offset, pinfo, interface_id, adapter_id); @@ -1480,8 +1486,8 @@ dissect_periodic_sync_wr_ind(tvbuff_t *tvb, proto_tree *btle_tree, gint offset, return offset; } -static gint -dissect_ctrl_pdu_without_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btle_tree, gint offset) +static int +dissect_ctrl_pdu_without_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btle_tree, int offset) { if (tvb_reported_length_remaining(tvb, offset) > 3) { proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); @@ -1491,6 +1497,45 @@ dissect_ctrl_pdu_without_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btl return offset; } +static int +dissect_crc(tvbuff_t *tvb, + proto_tree *btle_tree, + int offset, + packet_info *pinfo, + uint32_t length, + const connection_info_t *connection_info, + const btle_context_t *btle_context, + uint32_t access_address) +{ + /* BT spec Vol 6, Part B, Section 1.2: CRC is big endian and bits in byte are flipped */ + uint32_t packet_crc = reverse_bits_per_byte(tvb_get_ntoh24(tvb, offset)); + proto_item *sub_item = proto_tree_add_uint(btle_tree, hf_crc, tvb, offset, 3, packet_crc); + + if (btle_context && btle_context->crc_checked_at_capture) { + if (!btle_context->crc_valid_at_capture) { + expert_add_info(pinfo, sub_item, &ei_crc_incorrect); + } + } else if ((access_address == ACCESS_ADDRESS_ADVERTISING) || connection_info) { + /* CRC can be calculated */ + uint32_t crc_init; + + if (access_address == ACCESS_ADDRESS_ADVERTISING) { + crc_init = 0x555555; + } else { + crc_init = connection_info->crc_init; + } + + uint32_t crc = btle_crc(tvb, length, crc_init); + if (packet_crc != crc) { + expert_add_info(pinfo, sub_item, &ei_crc_incorrect); + } + } else { + expert_add_info(pinfo, sub_item, &ei_crc_cannot_be_determined); + } + + return 3; +} + /* Checks if it is possible to add the frame at the given index * to the given control procedure context. * @@ -1498,26 +1543,26 @@ dissect_ctrl_pdu_without_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btl * Therefore this function can be used to add an LL_UNKNOWN_RSP to * a completed connection parameter update procedure. */ -static gboolean +static bool control_proc_can_add_frame_even_if_complete(packet_info *pinfo, control_proc_info_t *last_control_proc_info, - guint8 proc_opcode, - guint frame_num) + uint8_t proc_opcode, + unsigned frame_num) { if (frame_num == 0) - return FALSE; /* This function must be used to add a frame to an ongoing procedure */ + return false; /* This function must be used to add a frame to an ongoing procedure */ /* We need to check if the control procedure has been initiated. */ if (!last_control_proc_info) - return FALSE; + return false; /* And that the new frame belongs to this control procedure */ if (last_control_proc_info->proc_opcode != proc_opcode) - return FALSE; + return false; /* Previous frame has not yet been added. */ if (last_control_proc_info->frames[frame_num - 1] == 0) - return FALSE; + return false; /* We need to check if we can add this frame at this index * in the control procedure sequence. */ @@ -1525,48 +1570,48 @@ control_proc_can_add_frame_even_if_complete(packet_info *pinfo, /* The first time we visit the frame, we just need to check that the * spot is empty. */ if (!pinfo->fd->visited && last_control_proc_info->frames[frame_num]) - return FALSE; /* Another opcode has already been added to the procedure at this index */ + return false; /* Another opcode has already been added to the procedure at this index */ /* At later visits, we need to check that we are not replacing the frame with * another frame. */ if (pinfo->fd->visited && (last_control_proc_info->frames[frame_num] != pinfo->num)) - return FALSE; + return false; - return TRUE; + return true; } -static gboolean -control_proc_is_complete(guint32 frame_num, control_proc_info_t const *last_control_proc_info) +static bool +control_proc_is_complete(uint32_t frame_num, control_proc_info_t const *last_control_proc_info) { if (last_control_proc_info->last_frame != 0 && frame_num > last_control_proc_info->last_frame) - return TRUE; + return true; - return FALSE; + return false; } -static gboolean +static bool control_proc_can_add_frame(packet_info *pinfo, control_proc_info_t *last_control_proc_info, - guint8 proc_opcode, - guint frame_num) + uint8_t proc_opcode, + unsigned frame_num) { if (!control_proc_can_add_frame_even_if_complete(pinfo, last_control_proc_info, proc_opcode, frame_num)) - return FALSE; + return false; /* We check that we are not adding a frame to a completed procedure. */ if (control_proc_is_complete(pinfo->num, last_control_proc_info)) - return FALSE; + return false; - return TRUE; + return true; } static void -control_proc_complete_if_instant_reached(guint frame_num, - guint16 event_counter, +control_proc_complete_if_instant_reached(unsigned frame_num, + uint16_t event_counter, control_proc_info_t *last_control_proc_info) { /* We need to check if the control procedure has been initiated. */ @@ -1588,8 +1633,8 @@ control_proc_complete_if_instant_reached(guint frame_num, } } -static gboolean -control_proc_contains_instant(guint8 proc_opcode) +static bool +control_proc_contains_instant(uint8_t proc_opcode) { switch (proc_opcode) { @@ -1597,30 +1642,30 @@ control_proc_contains_instant(guint8 proc_opcode) case LL_CTRL_OPCODE_CHANNEL_MAP_IND: case LL_CTRL_OPCODE_CONNECTION_PARAM_REQ: case LL_CTRL_OPCODE_PHY_REQ: - return TRUE; + return true; default: - return FALSE; + return false; } } /* Returns true if this frame contains an collision violating the specification. * * See Core_v5.2, Vol 6, Part B, Section 5.3 */ -static gboolean +static bool control_proc_invalid_collision(packet_info const *pinfo, control_proc_info_t const *control_proc_other, - guint8 proc_opcode) + uint8_t proc_opcode) { if (!control_proc_other) - return FALSE; + return false; if (control_proc_is_complete(pinfo->num, control_proc_other)) - return FALSE; + return false; /* Both procedures must contain an instant to be marked as incompatible. */ if (!control_proc_contains_instant(control_proc_other->proc_opcode) || !control_proc_contains_instant(proc_opcode)) - return FALSE; + return false; /* From the Core Spec: * @@ -1632,9 +1677,9 @@ control_proc_invalid_collision(packet_info const *pinfo, * time, there is a procedure violation. */ if (control_proc_other->frames[1] && (control_proc_other->frames[1] < pinfo->num)) - return TRUE; + return true; else - return FALSE; + return false; } /* Mark the start of a new control procedure. @@ -1653,7 +1698,7 @@ control_proc_start(tvbuff_t *tvb, proto_item *control_proc_item, wmem_tree_t *control_proc_tree, control_proc_info_t const *control_proc_other_direction, - guint8 opcode) + uint8_t opcode) { if (control_proc_invalid_collision(pinfo, control_proc_other_direction, @@ -1682,7 +1727,7 @@ control_proc_start(tvbuff_t *tvb, if (proc_info && proc_info->proc_opcode == opcode) { proto_item *sub_item; - for (guint i = 1; i < sizeof(proc_info->frames)/sizeof(proc_info->frames[0]); i++) { + for (unsigned i = 1; i < array_length(proc_info->frames); i++) { if (proc_info->frames[i]) { sub_item = proto_tree_add_uint(btle_tree, hf_response_in_frame, tvb, 0, 0, proc_info->frames[i]); proto_item_set_generated(sub_item); @@ -1704,11 +1749,11 @@ control_proc_start(tvbuff_t *tvb, static void control_proc_add_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btle_tree, - guint8 opcode, - guint32 direction, + uint8_t opcode, + uint32_t direction, control_proc_info_t *last_control_proc_info, control_proc_info_t const *control_proc_other_direction, - guint frame_num) + unsigned frame_num) { proto_item *item; @@ -1722,7 +1767,7 @@ static void control_proc_add_frame(tvbuff_t *tvb, !control_proc_is_complete(pinfo->num, control_proc_other_direction) && control_proc_contains_instant(last_control_proc_info->proc_opcode) && control_proc_contains_instant(control_proc_other_direction->proc_opcode)) { - if (direction == BTLE_DIR_MASTER_SLAVE && + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL && opcode != LL_CTRL_OPCODE_REJECT_IND && opcode != LL_CTRL_OPCODE_REJECT_EXT_IND) { /* Continuing a control procedure when the peer has initiated an incompatible control procedure. @@ -1739,11 +1784,11 @@ static void control_proc_add_frame(tvbuff_t *tvb, static void control_proc_add_last_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btle_tree, - guint8 opcode, - guint32 direction, + uint8_t opcode, + uint32_t direction, control_proc_info_t *last_control_proc_info, control_proc_info_t const *control_proc_other_direction, - guint frame_num) + unsigned frame_num) { control_proc_add_frame(tvb, pinfo, @@ -1762,12 +1807,12 @@ static void control_proc_add_frame_with_instant(tvbuff_t *tvb, packet_info *pinfo, proto_tree *btle_tree, const btle_context_t *btle_context, - guint8 opcode, - guint32 direction, + uint8_t opcode, + uint32_t direction, control_proc_info_t *last_control_proc_info, control_proc_info_t const *control_proc_other_direction, - guint frame_num, - guint16 instant) + unsigned frame_num, + uint16_t instant) { if (btle_context && btle_context->event_counter_valid) { control_proc_add_frame(tvb, @@ -1794,7 +1839,7 @@ static void control_proc_add_frame_with_instant(tvbuff_t *tvb, } static void -dissect_ad_eir(tvbuff_t *tvb, guint32 interface_id, guint32 adapter_id, guint32 frame_number, guint8 *src_bd_addr, packet_info *pinfo, proto_tree *tree) +dissect_ad_eir(tvbuff_t *tvb, uint32_t interface_id, uint32_t adapter_id, uint32_t frame_number, uint8_t *src_bd_addr, packet_info *pinfo, proto_tree *tree) { bluetooth_eir_ad_data_t *ad_data = wmem_new0(pinfo->pool, bluetooth_eir_ad_data_t); ad_data->interface_id = interface_id; @@ -1802,23 +1847,23 @@ dissect_ad_eir(tvbuff_t *tvb, guint32 interface_id, guint32 adapter_id, guint32 call_dissector_with_data(btcommon_ad_handle, tvb, pinfo, tree, ad_data); if (pinfo->fd->visited) return; - for (gint offset = 0;; ) { - guint remain = tvb_reported_length_remaining(tvb, offset); - guint length; - guint8 opcode; + for (int offset = 0;; ) { + unsigned remain = tvb_reported_length_remaining(tvb, offset); + unsigned length; + uint8_t opcode; if (remain < 1) break; - length = tvb_get_guint8(tvb, offset); + length = tvb_get_uint8(tvb, offset); ++offset; if (length <= 0) continue; --remain; if (remain < length) break; - opcode = tvb_get_guint8(tvb, offset); + opcode = tvb_get_uint8(tvb, offset); if (opcode == 0x2c && length >= 34) { - guint seed_access_address = tvb_get_guint32(tvb, offset + 14, ENC_LITTLE_ENDIAN); - guint32 trunc_seed_access_address = seed_access_address & 0x0041ffff; + unsigned seed_access_address = tvb_get_uint32(tvb, offset + 14, ENC_LITTLE_ENDIAN); + uint32_t trunc_seed_access_address = seed_access_address & 0x0041ffff; broadcastiso_connection_info_t *nconnection_info; wmem_tree_key_t key[5]; @@ -1839,7 +1884,7 @@ dissect_ad_eir(tvbuff_t *tvb, guint32 interface_id, guint32 adapter_id, guint32 nconnection_info->access_address = seed_access_address; if (src_bd_addr) - memcpy(nconnection_info->master_bd_addr, src_bd_addr, 6); + memcpy(nconnection_info->central_bd_addr, src_bd_addr, 6); wmem_tree_insert32_array(broadcastiso_connection_info_tree, key, nconnection_info); } @@ -1847,44 +1892,65 @@ dissect_ad_eir(tvbuff_t *tvb, guint32 interface_id, guint32 adapter_id, guint32 } } -static gint -dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +static uint8_t +guess_btle_pdu_type_from_access(uint32_t interface_id, + uint32_t adapter_id, + uint32_t access_address) { - proto_item *btle_item; - proto_tree *btle_tree; - proto_item *sub_item; - proto_tree *sub_tree; - gint offset = 0; - guint32 access_address, length; - tvbuff_t *next_tvb; - guint8 *dst_bd_addr; - guint8 *src_bd_addr; - static const guint8 broadcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - connection_info_t *connection_info = NULL; - wmem_tree_t *wmem_tree; - wmem_tree_key_t key[5], ae_had_key[4]; - guint32 interface_id; - guint32 adapter_id; - guint32 connection_access_address; - guint32 frame_number; - enum {CRC_INDETERMINATE, - CRC_CAN_BE_CALCULATED, - CRC_INCORRECT, - CRC_CORRECT} crc_status = CRC_INDETERMINATE; - guint32 crc_init = 0x555555; /* default to advertising channel's value */ - guint32 packet_crc; - const btle_context_t *btle_context = NULL; - bluetooth_data_t *bluetooth_data = NULL; - ubertooth_data_t *ubertooth_data = NULL; - gint previous_proto; - wmem_list_frame_t *list_data; - proto_item *item; - guint item_value; - guint8 btle_pdu_type = BTLE_PDU_TYPE_UNKNOWN; + wmem_tree_key_t key[5]; + wmem_tree_t *wmem_tree; + uint32_t broadcast_iso_seed_access_address = access_address & 0x0041ffff; + + /* No context to provide us with physical channel pdu type, make an assumption from the access address */ + if (access_address == ACCESS_ADDRESS_ADVERTISING) { + return BTLE_PDU_TYPE_ADVERTISING; + } + + /* Check if it is a connection context. */ + 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 = &access_address; + key[3].length = 0; + key[3].key = NULL; + + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_info_tree, key); + if (wmem_tree) { + /* Connection. */ + return BTLE_PDU_TYPE_DATA; + } - list_data = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(periodic_adv_info_tree, key); + if (wmem_tree) { + /* Periodic advertiser. */ + return BTLE_PDU_TYPE_ADVERTISING; + } + + key[2].key = &broadcast_iso_seed_access_address; + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(broadcastiso_connection_info_tree, key); + if (wmem_tree) { + /* Broadcast ISO. */ + return BTLE_PDU_TYPE_BROADCASTISO; + } + + /* Default to data. */ + return BTLE_PDU_TYPE_DATA; +} + +static const btle_context_t * get_btle_context(packet_info *pinfo, + void *data, + uint32_t *adapter_id_out, + uint32_t *interface_id_out) +{ + const btle_context_t * btle_context = NULL; + bluetooth_data_t *bluetooth_data = NULL; + ubertooth_data_t *ubertooth_data = NULL; + + wmem_list_frame_t * list_data = wmem_list_frame_prev(wmem_list_tail(pinfo->layers)); if (list_data) { - previous_proto = GPOINTER_TO_INT(wmem_list_frame_data(list_data)); + int previous_proto = GPOINTER_TO_INT(wmem_list_frame_data(list_data)); if ((previous_proto == proto_btle_rf)||(previous_proto == proto_nordic_ble)) { btle_context = (const btle_context_t *) data; @@ -1898,363 +1964,522 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) } } - src_bd_addr = (guint8 *) wmem_alloc(pinfo->pool, 6); - dst_bd_addr = (guint8 *) wmem_alloc(pinfo->pool, 6); + if (bluetooth_data) + *interface_id_out = bluetooth_data->interface_id; + else if (pinfo->rec->presence_flags & WTAP_HAS_INTERFACE_ID) + *interface_id_out = pinfo->rec->rec_header.packet_header.interface_id; + else + *interface_id_out = HCI_INTERFACE_DEFAULT; + + if (ubertooth_data) + *adapter_id_out = ubertooth_data->bus_id << 8 | ubertooth_data->device_address; + else if (bluetooth_data) + *adapter_id_out = bluetooth_data->adapter_id; + else + *adapter_id_out = HCI_ADAPTER_DEFAULT; - if (btle_context && btle_context->crc_checked_at_capture) { - crc_status = btle_context->crc_valid_at_capture ? CRC_CORRECT : CRC_INCORRECT; - } + return btle_context; +} - col_set_str(pinfo->cinfo, COL_PROTOCOL, "LE LL"); +static int +dissect_btle_adv(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *btle_tree, + const btle_context_t *btle_context, + uint32_t adapter_id, + uint32_t interface_id, + uint32_t access_address) +{ + proto_item *sub_item; + proto_tree *sub_tree; + int offset = 0; + uint32_t length; + tvbuff_t *next_tvb; + uint8_t *dst_bd_addr; + uint8_t *src_bd_addr; + static const uint8_t broadcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + connection_info_t *connection_info = NULL; + wmem_tree_t *wmem_tree; + wmem_tree_key_t key[5], ae_had_key[4]; - btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, ENC_NA); - btle_tree = proto_item_add_subtree(btle_item, ett_btle); + uint32_t connection_access_address; - sub_item = proto_tree_add_item(btle_tree, hf_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); - access_address = tvb_get_letohl(tvb, offset); - if (btle_context) { - switch(btle_context->aa_category) { - case E_AA_MATCHED: - expert_add_info(pinfo, sub_item, &ei_access_address_matched); - break; - case E_AA_ILLEGAL: - expert_add_info(pinfo, sub_item, &ei_access_address_illegal); - break; - case E_AA_BIT_ERRORS: - expert_add_info(pinfo, sub_item, &ei_access_address_bit_errors); - break; - default: - break; + proto_item *item; + unsigned item_value; + + proto_item *advertising_header_item; + proto_tree *advertising_header_tree; + proto_item *link_layer_data_item; + proto_tree *link_layer_data_tree; + uint8_t header, pdu_type; + bool ch_sel_valid = false, tx_add_valid = false, rx_add_valid = false; + bool is_periodic_adv = false; + + src_bd_addr = (uint8_t *) wmem_alloc(pinfo->pool, 6); + dst_bd_addr = (uint8_t *) wmem_alloc(pinfo->pool, 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 = &access_address; + key[3].length = 0; + key[3].key = NULL; + + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_info_tree, key); + if (!wmem_tree) { + /* Check periodic advertising tree */ + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(periodic_adv_info_tree, key); + if (wmem_tree) { + is_periodic_adv = true; } } - offset += 4; - if (btle_context && btle_context->phy == LE_CODED_PHY) { - proto_tree_add_item(btle_tree, hf_coding_indicator, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + if (wmem_tree) { + connection_info = (connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); + if (connection_info) { + set_address(&pinfo->net_src, AT_ETHER, 6, connection_info->central_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + memcpy(src_bd_addr, connection_info->central_bd_addr, 6); + } } - 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; + advertising_header_item = proto_tree_add_item(btle_tree, hf_advertising_header, tvb, offset, 2, ENC_LITTLE_ENDIAN); + advertising_header_tree = proto_item_add_subtree(advertising_header_item, ett_advertising_header); - if (ubertooth_data) - adapter_id = ubertooth_data->bus_id << 8 | ubertooth_data->device_address; - else if (bluetooth_data) - adapter_id = bluetooth_data->adapter_id; - else - adapter_id = HCI_ADAPTER_DEFAULT; + header = tvb_get_uint8(tvb, offset); + pdu_type = header & 0x0F; - frame_number = pinfo->num; + switch (pdu_type) { + case 0x00: /* ADV_IND */ + ch_sel_valid = true; + /* Fallthrough */ + case 0x02: /* ADV_NONCONN_IND */ + case 0x06: /* ADV_SCAN_IND */ + case 0x04: /* SCAN_RSP */ + tx_add_valid = true; + break; + case 0x07: /* ADV_EXT_IND / AUX_ADV_IND / AUX_SYNC_IND / AUX_CHAIN_IND / AUX_SCAN_RSP */ + case 0x08: /* AUX_CONNECT_RSP */ + { + /* 0 + header, 1 = len, 2 = ext_len/adv-mode, 3 = flags */ + uint8_t ext_header_flags = tvb_get_uint8(tvb, offset + 3); - if (btle_context) { - btle_pdu_type = btle_context->pdu_type; + ch_sel_valid = false; + tx_add_valid = (ext_header_flags & 0x01) != 0; + rx_add_valid = (ext_header_flags & 0x02) != 0; + break; + } + case 0x01: /* ADV_DIRECT_IND */ + case 0x05: /* CONNECT_IND or AUX_CONNECT_REQ */ + if (btle_context && btle_context->channel >= 37) { + /* CONNECT_IND */ + ch_sel_valid = true; + } + /* Fallthrough */ + case 0x03: /* SCAN_REQ or AUX_SCAN_REQ */ + tx_add_valid = true; + rx_add_valid = true; + break; } - if (btle_pdu_type == BTLE_PDU_TYPE_UNKNOWN) { - /* No context to provide us with physical channel pdu type, make an assumption from the access address */ - btle_pdu_type = access_address == ACCESS_ADDRESS_ADVERTISING ? BTLE_PDU_TYPE_ADVERTISING : BTLE_PDU_TYPE_DATA; + proto_item_append_text(advertising_header_item, " (PDU Type: %s", adv_pdu_type_str_get(btle_context, pdu_type, is_periodic_adv)); + item = proto_tree_add_item(advertising_header_tree, hf_advertising_header_pdu_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_item_append_text(item, " %s", adv_pdu_type_str_get(btle_context, pdu_type, is_periodic_adv)); + proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + + if (ch_sel_valid) { + proto_item_append_text(advertising_header_item, ", ChSel: %s", + tfs_get_string(header & 0x20, &tfs_ch_sel)); + proto_tree_add_item(advertising_header_tree, hf_advertising_header_ch_sel, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } else { + proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_2, tvb, offset, 1, ENC_LITTLE_ENDIAN); } - if (btle_pdu_type == BTLE_PDU_TYPE_ADVERTISING) { - proto_item *advertising_header_item; - proto_tree *advertising_header_tree; - proto_item *link_layer_data_item; - proto_tree *link_layer_data_tree; - guint8 header, pdu_type; - gboolean ch_sel_valid = FALSE, tx_add_valid = FALSE, rx_add_valid = FALSE; - - if (crc_status == CRC_INDETERMINATE) { - /* Advertising channel CRCs can aways be calculated, because CRCInit is always known. */ - crc_status = CRC_CAN_BE_CALCULATED; - } + if (tx_add_valid) { + proto_item_append_text(advertising_header_item, ", TxAdd: %s", + tfs_get_string(header & 0x40, &tfs_random_public)); + proto_tree_add_item(advertising_header_tree, hf_advertising_header_randomized_tx, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } else { + proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } - 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 = &access_address; - key[3].length = 0; - key[3].key = NULL; + if (rx_add_valid) { + proto_item_append_text(advertising_header_item, ", RxAdd: %s", + tfs_get_string(header & 0x80, &tfs_random_public)); + proto_tree_add_item(advertising_header_tree, hf_advertising_header_randomized_rx, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } else { + proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } - wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_info_tree, key); - if (wmem_tree) { - connection_info = (connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); - if (connection_info) { - set_address(&pinfo->net_src, AT_ETHER, 6, connection_info->master_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); - memcpy(src_bd_addr, connection_info->master_bd_addr, 6); - } - } + proto_item_append_text(advertising_header_item, ")"); - advertising_header_item = proto_tree_add_item(btle_tree, hf_advertising_header, tvb, offset, 2, ENC_LITTLE_ENDIAN); - advertising_header_tree = proto_item_add_subtree(advertising_header_item, ett_advertising_header); + col_set_str(pinfo->cinfo, COL_INFO, adv_pdu_type_str_get(btle_context, pdu_type, is_periodic_adv)); - header = tvb_get_guint8(tvb, offset); - pdu_type = header & 0x0F; + offset += 1; - switch (pdu_type) { - case 0x00: /* ADV_IND */ - ch_sel_valid = TRUE; - /* Fallthrough */ - case 0x02: /* ADV_NONCONN_IND */ - case 0x06: /* ADV_SCAN_IND */ - case 0x04: /* SCAN_RSP */ - tx_add_valid = TRUE; - break; - case 0x07: /* ADV_EXT_IND / AUX_ADV_IND / AUX_SYNC_IND / AUX_CHAIN_IND / AUX_SCAN_RSP */ - case 0x08: /* AUX_CONNECT_RSP */ - { - /* 0 + header, 1 = len, 2 = ext_len/adv-mode, 3 = flags */ - guint8 ext_header_flags = tvb_get_guint8(tvb, offset + 3); + proto_tree_add_item(advertising_header_tree, hf_advertising_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + proto_item_set_hidden(item); + offset += 1; - ch_sel_valid = FALSE; - tx_add_valid = (ext_header_flags & 0x01) != 0; - rx_add_valid = (ext_header_flags & 0x02) != 0; - break; + switch (pdu_type) { + case 0x00: /* ADV_IND */ + case 0x02: /* ADV_NONCONN_IND */ + case 0x06: /* ADV_SCAN_IND */ + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, src_bd_addr); + + set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + + set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + + 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); } - case 0x01: /* ADV_DIRECT_IND */ - case 0x05: /* CONNECT_IND or AUX_CONNECT_REQ */ - if (btle_context && btle_context->channel >= 37) { - /* CONNECT_IND */ - ch_sel_valid = TRUE; - } - /* Fallthrough */ - case 0x03: /* SCAN_REQ or AUX_SCAN_REQ */ - tx_add_valid = TRUE; - rx_add_valid = TRUE; - break; + + if (tvb_reported_length_remaining(tvb, offset) > 3) { + next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + dissect_ad_eir(next_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, btle_tree); } - proto_item_append_text(advertising_header_item, " (PDU Type: %s", adv_pdu_type_str_get(btle_context, pdu_type)); - item = proto_tree_add_item(advertising_header_tree, hf_advertising_header_pdu_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_item_append_text(item, " %s", adv_pdu_type_str_get(btle_context, pdu_type)); - proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_1, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += tvb_reported_length_remaining(tvb, offset) - 3; - if (ch_sel_valid) { - proto_item_append_text(advertising_header_item, ", ChSel: %s", - tfs_get_string(header & 0x20, &tfs_ch_sel)); - proto_tree_add_item(advertising_header_tree, hf_advertising_header_ch_sel, tvb, offset, 1, ENC_LITTLE_ENDIAN); - } else { - proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_2, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case 0x01: /* ADV_DIRECT_IND */ + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, src_bd_addr); + offset = dissect_bd_addr(hf_target_addresss, pinfo, btle_tree, tvb, offset, false, interface_id, adapter_id, dst_bd_addr); + + set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + + set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + + 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); } - if (tx_add_valid) { - proto_item_append_text(advertising_header_item, ", TxAdd: %s", - tfs_get_string(header & 0x40, &tfs_random_public)); - proto_tree_add_item(advertising_header_tree, hf_advertising_header_randomized_tx, tvb, offset, 1, ENC_LITTLE_ENDIAN); - } else { - proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_3, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case 0x03: /* SCAN_REQ */ + offset = dissect_bd_addr(hf_scanning_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, src_bd_addr); + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, false, interface_id, adapter_id, dst_bd_addr); + + set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + + set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + + 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); } - if (rx_add_valid) { - proto_item_append_text(advertising_header_item, ", RxAdd: %s", - tfs_get_string(header & 0x80, &tfs_random_public)); - proto_tree_add_item(advertising_header_tree, hf_advertising_header_randomized_rx, tvb, offset, 1, ENC_LITTLE_ENDIAN); - } else { - proto_tree_add_item(advertising_header_tree, hf_advertising_header_rfu_4, tvb, offset, 1, ENC_LITTLE_ENDIAN); + break; + case 0x04: /* SCAN_RSP */ + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, src_bd_addr); + + set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + + set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + + 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); } - proto_item_append_text(advertising_header_item, ")"); + sub_item = proto_tree_add_item(btle_tree, hf_scan_response_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_scan_response_data); - col_set_str(pinfo->cinfo, COL_INFO, adv_pdu_type_str_get(btle_context, pdu_type)); + if (tvb_reported_length_remaining(tvb, offset) > 3) { + next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + dissect_ad_eir(next_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, sub_tree); + } - offset += 1; + offset += tvb_reported_length_remaining(tvb, offset) - 3; - proto_tree_add_item(advertising_header_tree, hf_advertising_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); - item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); - proto_item_set_hidden(item); - offset += 1; + break; + case 0x05: /* CONNECT_IND */ + { + uint32_t connect_ind_crc_init; - switch (pdu_type) { - case 0x00: /* ADV_IND */ - case 0x02: /* ADV_NONCONN_IND */ - case 0x06: /* ADV_SCAN_IND */ - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, src_bd_addr); + offset = dissect_bd_addr(hf_initiator_addresss, pinfo, btle_tree, tvb, offset, false, interface_id, adapter_id, src_bd_addr); + offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, true, interface_id, adapter_id, dst_bd_addr); - set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); + set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); + copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); - set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - if (!pinfo->fd->visited) { - address *addr; + 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_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); - } + 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); + } - if (tvb_reported_length_remaining(tvb, offset) > 3) { - next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - dissect_ad_eir(next_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, btle_tree); - } + link_layer_data_item = proto_tree_add_item(btle_tree, hf_link_layer_data, tvb, offset, 22, ENC_NA); + link_layer_data_tree = proto_item_add_subtree(link_layer_data_item, ett_link_layer_data); - offset += tvb_reported_length_remaining(tvb, offset) - 3; + proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + connection_access_address = tvb_get_letohl(tvb, offset); + offset += 4; - break; - case 0x01: /* ADV_DIRECT_IND */ - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, src_bd_addr); - offset = dissect_bd_addr(hf_target_addresss, pinfo, btle_tree, tvb, offset, FALSE, interface_id, adapter_id, dst_bd_addr); + proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_crc_init, tvb, offset, 3, ENC_LITTLE_ENDIAN, &connect_ind_crc_init); + offset += 3; - set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); + item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_window_size, tvb, offset, 1, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 1; - set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_window_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 2; - if (!pinfo->fd->visited) { - address *addr; + item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 2; - 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); + proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_latency, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; - 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); - } + item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%u msec)", item_value*10); + offset += 2; - break; - case 0x03: /* SCAN_REQ */ - offset = dissect_bd_addr(hf_scanning_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, src_bd_addr); - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, FALSE, interface_id, adapter_id, dst_bd_addr); + sub_item = proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_channel_map, tvb, offset, 5, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); - set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); + call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); + offset += 5; - set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_hop, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_sleep_clock_accuracy, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - if (!pinfo->fd->visited) { - address *addr; + if (!pinfo->fd->visited) { + connection_parameter_info_t *connection_parameter_info; - 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); + 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 = &connection_access_address; + key[3].length = 1; + key[3].key = &pinfo->num; + key[4].length = 0; + key[4].key = NULL; - 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); - } + connection_info = wmem_new0(wmem_file_scope(), connection_info_t); + connection_info->interface_id = interface_id; + connection_info->adapter_id = adapter_id; + connection_info->access_address = connection_access_address; + connection_info->crc_init = connect_ind_crc_init; - break; - case 0x04: /* SCAN_RSP */ - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, src_bd_addr); + memcpy(connection_info->central_bd_addr, src_bd_addr, 6); + memcpy(connection_info->peripheral_bd_addr, dst_bd_addr, 6); - set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); + /* We don't create control procedure context trees for BTLE_DIR_UNKNOWN, + * as the direction must be known for request/response matching. */ + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs = + wmem_tree_new(wmem_file_scope()); + connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs = + wmem_tree_new(wmem_file_scope()); - set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + wmem_tree_insert32_array(connection_info_tree, key, connection_info); - if (!pinfo->fd->visited) { - address *addr; + connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); + connection_parameter_info->parameters_frame = pinfo->num; - 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); + key[3].length = 1; + key[3].key = &pinfo->num; + wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); + } - 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); - } + break; + } + case 0x07: /* ADV_EXT_IND / AUX_ADV_IND / AUX_SYNC_IND / AUX_CHAIN_IND / AUX_SCAN_RSP */ + case 0x08: /* AUX_CONNECT_RSP */ + { + uint8_t tmp, ext_header_len, flags, acad_len; + proto_item *ext_header_item, *ext_flags_item; + proto_tree *ext_header_tree, *ext_flags_tree; + uint32_t adi; + bool adi_present = false; + bool aux_pointer_present = false; - sub_item = proto_tree_add_item(btle_tree, hf_scan_response_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_scan_response_data); + tmp = tvb_get_uint8(tvb, offset); + ext_header_len = acad_len = tmp & 0x3F; - if (tvb_reported_length_remaining(tvb, offset) > 3) { - next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - dissect_ad_eir(next_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, sub_tree); - } + ext_header_item = proto_tree_add_item(btle_tree, hf_extended_advertising_header, tvb, offset, ext_header_len + 1, ENC_NA); + ext_header_tree = proto_item_add_subtree(ext_header_item, ett_extended_advertising_header); - offset += tvb_reported_length_remaining(tvb, offset) - 3; + proto_tree_add_item(ext_header_tree, hf_extended_advertising_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(ext_header_tree, hf_extended_advertising_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - break; - case 0x05: /* CONNECT_IND */ - offset = dissect_bd_addr(hf_initiator_addresss, pinfo, btle_tree, tvb, offset, FALSE, interface_id, adapter_id, src_bd_addr); - offset = dissect_bd_addr(hf_advertising_address, pinfo, btle_tree, tvb, offset, TRUE, interface_id, adapter_id, dst_bd_addr); + if (ext_header_len > 0) { + ext_flags_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_flags, tvb, offset, 1, ENC_NA); + ext_flags_tree = proto_item_add_subtree(ext_flags_item, ett_extended_advertising_flags); + + proto_tree_add_bitmask_list(ext_flags_tree, tvb, offset, 1, hfx_extended_advertising_flags, ENC_NA); + flags = tvb_get_uint8(tvb, offset); + offset += 1; + + acad_len -= 1; + } else { + flags = 0; + } + if (flags & 0x01) { + /* Advertiser Address */ + offset = dissect_bd_addr(hf_advertising_address, pinfo, ext_header_tree, tvb, offset, true, interface_id, adapter_id, src_bd_addr); set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); copy_address_shallow(&pinfo->src, &pinfo->net_src); + acad_len -= 6; + } else if (!connection_info) { + const char * anon_str = "Anonymous"; + clear_address(&pinfo->dl_src); + set_address(&pinfo->net_src, AT_STRINGZ, sizeof(*anon_str), anon_str); + copy_address_shallow(&pinfo->src, &pinfo->net_src); + } + + if (flags & 0x02) { + /* Target Address */ + offset = dissect_bd_addr(hf_target_addresss, pinfo, ext_header_tree, tvb, offset, false, interface_id, adapter_id, dst_bd_addr); set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - 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); + acad_len -= 6; + } else { + set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + } - 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); - } + if (flags & 0x04) { + uint32_t cte_time; - link_layer_data_item = proto_tree_add_item(btle_tree, hf_link_layer_data, tvb, offset, 22, ENC_NA); - link_layer_data_tree = proto_item_add_subtree(link_layer_data_item, ett_link_layer_data); + /* CTE Info */ + sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_cte_info, tvb, offset, 1, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_cte_info); - proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); - connection_access_address = tvb_get_letohl(tvb, offset); - offset += 4; + item = proto_tree_add_item_ret_uint(sub_tree, hf_extended_advertising_cte_info_time, tvb, offset, 1, ENC_LITTLE_ENDIAN, &cte_time); + proto_item_append_text(item, " (%u usec)", cte_time * 8); + proto_tree_add_item(sub_tree, hf_extended_advertising_cte_info_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sub_tree, hf_extended_advertising_cte_info_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_crc_init, tvb, offset, 3, ENC_LITTLE_ENDIAN); - offset += 3; + acad_len -= 1; + } - item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_window_size, tvb, offset, 1, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); - offset += 1; + if (flags & 0x08) { + /* AdvDataInfo */ + sub_item = proto_tree_add_item_ret_uint(ext_header_tree, hf_extended_advertising_data_info, tvb, offset, 2, ENC_LITTLE_ENDIAN, &adi); + sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_data_info); - item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_window_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); + proto_tree_add_item(sub_tree, hf_extended_advertising_data_info_did, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sub_tree, hf_extended_advertising_data_info_sid, tvb, offset, 2, ENC_LITTLE_ENDIAN); offset += 2; + adi_present = true; - item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); - offset += 2; + acad_len -= 2; + } - proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_latency, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; + if (flags & 0x10) { + uint32_t aux_offset; - item = proto_tree_add_item_ret_uint(link_layer_data_tree, hf_link_layer_data_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%u msec)", item_value*10); + /* Aux Pointer */ + sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_aux_ptr, tvb, offset, 3, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_aux_pointer); + + proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_ca, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_offset_units, tvb, offset, 1, ENC_LITTLE_ENDIAN); + tmp = tvb_get_uint8(tvb, offset); + offset += 1; + + item = proto_tree_add_item_ret_uint(sub_tree, hf_extended_advertising_aux_ptr_aux_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &aux_offset); + proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_aux_phy, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_item_append_text(item, " (%u usec)", aux_offset * ((tmp & 0x80) != 0 ? 300 : 30)); offset += 2; + aux_pointer_present = true; - sub_item = proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_channel_map, tvb, offset, 5, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + acad_len -= 3; + } - call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); - offset += 5; + if (flags & 0x20) { + uint32_t sync_offset, interval; + proto_item *sync_info_item; + proto_tree *sync_info_tree; + int reserved_offset; + uint16_t sf; - proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_hop, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(link_layer_data_tree, hf_link_layer_data_sleep_clock_accuracy, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + /* Sync Info */ + sync_info_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_sync_info, tvb, offset, 18, ENC_NA); + sync_info_tree = proto_item_add_subtree(sync_info_item, ett_extended_advertising_sync_info); if (!pinfo->fd->visited) { connection_parameter_info_t *connection_parameter_info; + connection_access_address = tvb_get_uint32(tvb, offset + 9, ENC_LITTLE_ENDIAN); + key[0].length = 1; key[0].key = &interface_id; key[1].length = 1; @@ -2262,7 +2487,7 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) key[2].length = 1; key[2].key = &connection_access_address; key[3].length = 1; - key[3].key = &frame_number; + key[3].key = &pinfo->num; key[4].length = 0; key[4].key = NULL; @@ -2271,17 +2496,17 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) connection_info->adapter_id = adapter_id; connection_info->access_address = connection_access_address; - memcpy(connection_info->master_bd_addr, src_bd_addr, 6); - memcpy(connection_info->slave_bd_addr, dst_bd_addr, 6); + if (flags & 0x01) + memcpy(connection_info->central_bd_addr, src_bd_addr, 6); /* We don't create control procedure context trees for BTLE_DIR_UNKNOWN, - * as the direction must be known for request/response matching. */ - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs = - wmem_tree_new(wmem_file_scope()); - connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs = - wmem_tree_new(wmem_file_scope()); + * as the direction must be known for request/response matching. */ + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs = + wmem_tree_new(wmem_file_scope()); + connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs = + wmem_tree_new(wmem_file_scope()); - wmem_tree_insert32_array(connection_info_tree, key, connection_info); + wmem_tree_insert32_array(periodic_adv_info_tree, key, connection_info); connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); connection_parameter_info->parameters_frame = pinfo->num; @@ -2291,628 +2516,470 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); } - break; - case 0x07: /* ADV_EXT_IND / AUX_ADV_IND / AUX_SYNC_IND / AUX_CHAIN_IND / AUX_SCAN_RSP */ - case 0x08: /* AUX_CONNNECT_RSP */ - { - guint8 tmp, ext_header_len, flags, acad_len; - proto_item *ext_header_item, *ext_flags_item; - proto_tree *ext_header_tree, *ext_flags_tree; - guint32 adi; - gboolean adi_present = FALSE; - gboolean aux_pointer_present = FALSE; - - tmp = tvb_get_guint8(tvb, offset); - ext_header_len = acad_len = tmp & 0x3F; - - ext_header_item = proto_tree_add_item(btle_tree, hf_extended_advertising_header, tvb, offset, ext_header_len + 1, ENC_NA); - ext_header_tree = proto_item_add_subtree(ext_header_item, ett_extended_advertising_header); - - proto_tree_add_item(ext_header_tree, hf_extended_advertising_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(ext_header_tree, hf_extended_advertising_mode, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + sf = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN); - if (ext_header_len > 0) { - ext_flags_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_flags, tvb, offset, 1, ENC_NA); - ext_flags_tree = proto_item_add_subtree(ext_flags_item, ett_extended_advertising_flags); - - proto_tree_add_bitmask_list(ext_flags_tree, tvb, offset, 1, hfx_extended_advertising_flags, ENC_NA); - flags = tvb_get_guint8(tvb, offset); - offset += 1; - - acad_len -= 1; + item = proto_tree_add_item_ret_uint(sync_info_tree, hf_extended_advertising_sync_info_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &sync_offset); + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_offset_units, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_offset_adjust, tvb, offset, 2, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN); + if (sync_offset > 0) { + proto_item_append_text(item, " (%u usec)", sync_offset * ((sf & 0x2000) != 0 ? 300 : 30) + ((sf & 0x4000) != 0 ? 2457600 : 0)); } else { - flags = 0; + proto_item_append_text(item, " Cannot be represented"); } + offset += 2; - if (flags & 0x01) { - /* Advertiser Address */ - offset = dissect_bd_addr(hf_advertising_address, pinfo, ext_header_tree, tvb, offset, TRUE, interface_id, adapter_id, src_bd_addr); - set_address(&pinfo->net_src, AT_ETHER, 6, src_bd_addr); - copy_address_shallow(&pinfo->dl_src, &pinfo->net_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); - - acad_len -= 6; - } else if (!connection_info) { - const char * anon_str = "Anonymous"; - clear_address(&pinfo->dl_src); - set_address(&pinfo->net_src, AT_STRINGZ, sizeof(*anon_str), anon_str); - copy_address_shallow(&pinfo->src, &pinfo->net_src); - } - - if (flags & 0x02) { - /* Target Address */ - offset = dissect_bd_addr(hf_target_addresss, pinfo, ext_header_tree, tvb, offset, FALSE, interface_id, adapter_id, dst_bd_addr); - set_address(&pinfo->net_dst, AT_ETHER, 6, dst_bd_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - - acad_len -= 6; - } else { - set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - } + item = proto_tree_add_item_ret_uint(sync_info_tree, hf_extended_advertising_sync_info_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &interval); + proto_item_append_text(item, " (%g msec)", interval * 1.25); + offset += 2; - if (flags & 0x04) { - guint32 cte_time; + sub_item = proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_channel_map, tvb, offset, 5, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); - /* CTE Info */ - sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_cte_info, tvb, offset, 1, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_cte_info); + call_dissector_with_data(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree, &reserved_offset); + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_sleep_clock_accuracy, tvb, offset + reserved_offset, 1, ENC_LITTLE_ENDIAN); + offset += 5; - item = proto_tree_add_item_ret_uint(sub_tree, hf_extended_advertising_cte_info_time, tvb, offset, 1, ENC_LITTLE_ENDIAN, &cte_time); - proto_item_append_text(item, " (%u usec)", cte_time * 8); - proto_tree_add_item(sub_tree, hf_extended_advertising_cte_info_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sub_tree, hf_extended_advertising_cte_info_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; - acad_len -= 1; - } + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_crc_init, tvb, offset, 3, ENC_LITTLE_ENDIAN); + offset += 3; - if (flags & 0x08) { - /* AdvDataInfo */ - sub_item = proto_tree_add_item_ret_uint(ext_header_tree, hf_extended_advertising_data_info, tvb, offset, 2, ENC_LITTLE_ENDIAN, &adi); - sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_data_info); + proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_event_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; - proto_tree_add_item(sub_tree, hf_extended_advertising_data_info_did, tvb, offset, 2, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sub_tree, hf_extended_advertising_data_info_sid, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; - adi_present = TRUE; + acad_len -= 18; + } - acad_len -= 2; - } + if (flags & 0x40) { + /* Tx Power */ + proto_tree_add_item(ext_header_tree, hf_extended_advertising_tx_power, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - if (flags & 0x10) { - guint32 aux_offset; + acad_len -= 1; + } - /* Aux Pointer */ - sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_aux_ptr, tvb, offset, 3, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_aux_pointer); + if (acad_len > 0) { + sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_header_acad, tvb, offset, acad_len, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_acad); - proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_channel, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_ca, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_offset_units, tvb, offset, 1, ENC_LITTLE_ENDIAN); - tmp = tvb_get_guint8(tvb, offset); - offset += 1; + /* Additional Controller Advertising Data */ + next_tvb = tvb_new_subset_length(tvb, offset, acad_len); + dissect_ad_eir(next_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, sub_tree); - item = proto_tree_add_item_ret_uint(sub_tree, hf_extended_advertising_aux_ptr_aux_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &aux_offset); - proto_tree_add_item(sub_tree, hf_extended_advertising_aux_ptr_aux_phy, tvb, offset, 2, ENC_LITTLE_ENDIAN); - proto_item_append_text(item, " (%u usec)", aux_offset * ((tmp & 0x80) != 0 ? 300 : 30)); - offset += 2; - aux_pointer_present = TRUE; + offset += acad_len; + } + if (tvb_reported_length_remaining(tvb, offset) > 3) { + bool ad_processed = false; + if (btle_context && pdu_type == 0x07 && btle_context->aux_pdu_type_valid) { + bool ad_reassembled = false; + ae_had_info_t *ae_had_info = NULL; + + switch (btle_context->aux_pdu_type) { + case 0x00: /* AUX_ADV_IND */ + case 0x02: /* AUX_SYNC_IND */ + case 0x03: /* AUX_SCAN_RSP */ + if (aux_pointer_present) { + /* Beginning of new sequence of fragments */ + if (!pinfo->fd->visited && adi_present) { + ae_had_info = wmem_new0(wmem_file_scope(), ae_had_info_t); + ae_had_info->first_frame_num=pinfo->num; - acad_len -= 3; - } + if (flags & 0x01) { + /* Copy Advertiser Address to reassemble AUX_CHAIN_IND */ + copy_address_wmem(wmem_file_scope(), &ae_had_info->adv_addr, &pinfo->src); + } - if (flags & 0x20) { - guint32 sync_offset, interval; - proto_item *sync_info_item; - proto_tree *sync_info_tree; - gint reserved_offset; - guint16 sf; + ae_had_key[0].length = 1; + ae_had_key[0].key = &interface_id; + ae_had_key[1].length = 1; + ae_had_key[1].key = &adapter_id; + ae_had_key[2].length = 1; + ae_had_key[2].key = &adi; + ae_had_key[3].length = 0; + ae_had_key[3].key = NULL; - /* Sync Info */ - sync_info_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_sync_info, tvb, offset, 18, ENC_NA); - sync_info_tree = proto_item_add_subtree(sync_info_item, ett_extended_advertising_sync_info); + wmem_tree_insert32_array(adi_to_first_frame_tree, ae_had_key, ae_had_info); - if (!pinfo->fd->visited) { - connection_parameter_info_t *connection_parameter_info; + fragment_add_seq(&btle_ea_host_advertising_data_reassembly_table, + tvb, offset, pinfo, + ae_had_info->first_frame_num, NULL, + ae_had_info->fragment_counter, + tvb_captured_length_remaining(tvb, offset) - 3, + !ad_reassembled, 0); - connection_access_address = tvb_get_guint32(tvb, offset + 9, ENC_LITTLE_ENDIAN); + ae_had_info->fragment_counter++; + } + ad_processed = true; + } + break; + case 0x01: /* AUX_CHAIN_IND */ + if (!aux_pointer_present) { + /* Final fragment */ + ad_reassembled = true; + } + if (!pinfo->fd->visited && adi_present) { + + ae_had_key[0].length = 1; + ae_had_key[0].key = &interface_id; + ae_had_key[1].length = 1; + ae_had_key[1].key = &adapter_id; + ae_had_key[2].length = 1; + ae_had_key[2].key = &adi; + ae_had_key[3].length = 0; + ae_had_key[3].key = NULL; + + ae_had_info = (ae_had_info_t *) wmem_tree_lookup32_array(adi_to_first_frame_tree, ae_had_key); + + if (ae_had_info != NULL) { + if (!(flags & 0x01) && (ae_had_info->adv_addr.len > 0)) { + /* Copy Advertiser Address from AUX_ADV_IND if not present. */ + copy_address_shallow(&pinfo->src, &ae_had_info->adv_addr); + } - 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 = &connection_access_address; - key[3].length = 1; - key[3].key = &frame_number; - key[4].length = 0; - key[4].key = NULL; + fragment_add_seq(&btle_ea_host_advertising_data_reassembly_table, + tvb, offset, pinfo, + ae_had_info->first_frame_num, NULL, + ae_had_info->fragment_counter, + tvb_captured_length_remaining(tvb, offset) - 3, + !ad_reassembled, 0); - connection_info = wmem_new0(wmem_file_scope(), connection_info_t); - connection_info->interface_id = interface_id; - connection_info->adapter_id = adapter_id; - connection_info->access_address = connection_access_address; + ae_had_info->fragment_counter++; + if (ad_reassembled == true) { + p_add_proto_data(wmem_file_scope(), pinfo, proto_btle, (uint32_t)(pinfo->curr_layer_num) << 8, ae_had_info); + } + } + } + ad_processed = true; + break; + default: + /* This field is 2 bits long, no special action needed */ + break; + } + if (ad_processed) { + if (pinfo->fd->visited) { + /* Host Advertising Data fragment */ + proto_tree_add_item(btle_tree, hf_extended_advertising_had_fragment, tvb, offset, tvb_captured_length_remaining(tvb, offset) - 3, ENC_NA); + if (ad_reassembled) { + fragment_head *fd_head = NULL; + tvbuff_t *assembled_tvb = NULL; + + ae_had_info = (ae_had_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_btle, (uint32_t)(pinfo->curr_layer_num) << 8); + if (ae_had_info != NULL) { + col_append_str(pinfo->cinfo, COL_INFO, " (EA HAD Reassembled)"); + + if (!(flags & 0x01) && (ae_had_info->adv_addr.len > 0)) { + /* Copy Advertiser Address from AUX_ADV_IND if not present. */ + copy_address_shallow(&pinfo->src, &ae_had_info->adv_addr); + } - if (flags & 0x01) - memcpy(connection_info->master_bd_addr, src_bd_addr, 6); + fd_head = fragment_get(&btle_ea_host_advertising_data_reassembly_table, pinfo, ae_had_info->first_frame_num, NULL); + assembled_tvb = process_reassembled_data( + tvb, offset, pinfo, + "Reassembled Host Advertising Data", fd_head, + &btle_ea_host_advertising_data_frag_items, + NULL, btle_tree); - /* We don't create control procedure context trees for BTLE_DIR_UNKNOWN, - * as the direction must be known for request/response matching. */ - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs = - wmem_tree_new(wmem_file_scope()); - connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs = - wmem_tree_new(wmem_file_scope()); + if (assembled_tvb) { + dissect_ad_eir(assembled_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, btle_tree); + } + } + } + else { + col_append_str(pinfo->cinfo, COL_INFO, " (EA HAD Fragment)"); + } + offset += tvb_captured_length_remaining(tvb, offset) - 3; + } + } + } - wmem_tree_insert32_array(connection_info_tree, key, connection_info); + if (tvb_reported_length_remaining(tvb, offset) > 3) { + /* Host Advertising Data */ + next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); - connection_parameter_info->parameters_frame = pinfo->num; + if (btle_context && btle_context->aux_pdu_type_valid && btle_context->aux_pdu_type == 3) { + /* AUX_SCAN_RSP */ + sub_item = proto_tree_add_item(btle_tree, hf_scan_response_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_scan_response_data); - key[3].length = 1; - key[3].key = &pinfo->num; - wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); + dissect_ad_eir(next_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, sub_tree); } - - sf = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN); - - item = proto_tree_add_item_ret_uint(sync_info_tree, hf_extended_advertising_sync_info_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &sync_offset); - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_offset_units, tvb, offset, 2, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_offset_adjust, tvb, offset, 2, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_reserved, tvb, offset, 2, ENC_LITTLE_ENDIAN); - if (sync_offset > 0) { - proto_item_append_text(item, " (%u usec)", sync_offset * ((sf & 0x2000) != 0 ? 300 : 30) + ((sf & 0x4000) != 0 ? 2457600 : 0)); - } else { - proto_item_append_text(item, " Cannot be represented"); + else { + dissect_ad_eir(next_tvb, interface_id, adapter_id, pinfo->num, src_bd_addr, pinfo, btle_tree); } - offset += 2; - - item = proto_tree_add_item_ret_uint(sync_info_tree, hf_extended_advertising_sync_info_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &interval); - proto_item_append_text(item, " (%g msec)", interval * 1.25); - offset += 2; - sub_item = proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_channel_map, tvb, offset, 5, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + offset += tvb_reported_length_remaining(tvb, offset) - 3; + } + } + break; + } + default: + if (tvb_reported_length_remaining(tvb, offset) > 3) { + proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + offset += tvb_reported_length_remaining(tvb, offset) - 3; + } + } - call_dissector_with_data(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree, &reserved_offset); - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_sleep_clock_accuracy, tvb, offset + reserved_offset, 1, ENC_LITTLE_ENDIAN); - offset += 5; + return offset; +} - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; +static int +dissect_btle_acl_or_iso(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *tree, + proto_tree *btle_tree, + const btle_context_t *btle_context, + uint32_t adapter_id, + uint32_t interface_id, + uint32_t access_address, + uint8_t btle_pdu_type) +{ + proto_item *sub_item; + proto_tree *sub_tree; + int offset = 0; + uint32_t length; + tvbuff_t *next_tvb; + connection_info_t *connection_info = NULL; + wmem_tree_t *wmem_tree; + wmem_tree_key_t key[5]; - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_crc_init, tvb, offset, 3, ENC_LITTLE_ENDIAN); - offset += 3; + uint32_t connection_access_address; - proto_tree_add_item(sync_info_tree, hf_extended_advertising_sync_info_event_counter, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; + proto_item *item; + unsigned item_value; - acad_len -= 18; - } + proto_item *data_header_item, *seq_item, *control_proc_item; + proto_tree *data_header_tree; + uint8_t oct; + uint8_t llid; + uint8_t control_opcode; + uint32_t direction = BTLE_DIR_UNKNOWN; + uint8_t other_direction = BTLE_DIR_UNKNOWN; - if (flags & 0x40) { - /* Tx Power */ - proto_tree_add_item(ext_header_tree, hf_extended_advertising_tx_power, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + bool add_l2cap_index = false; + bool retransmit = false; + bool cte_info_present = false; - acad_len -= 1; - } + /* Holds the last initiated control procedures for a given direction. */ + control_proc_info_t *last_control_proc[3] = {0}; - if (acad_len > 0) { - sub_item = proto_tree_add_item(ext_header_tree, hf_extended_advertising_header_acad, tvb, offset, acad_len, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_extended_advertising_acad); - - /* Additional Controller Advertising Data */ - next_tvb = tvb_new_subset_length(tvb, offset, acad_len); - dissect_ad_eir(next_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, sub_tree); + if (btle_context) { + direction = btle_context->direction; + other_direction = (direction == BTLE_DIR_PERIPHERAL_CENTRAL) ? BTLE_DIR_CENTRAL_PERIPHERAL : BTLE_DIR_PERIPHERAL_CENTRAL; + } - offset += acad_len; + btle_frame_info_t *btle_frame_info = NULL; + fragment_head *frag_btl2cap_msg = NULL; + btle_frame_info_t empty_btle_frame_info = {0, 0, 0, 0, 0}; + + 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 = &access_address; + key[3].length = 0; + key[3].key = NULL; + + oct = tvb_get_uint8(tvb, offset); + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_info_tree, key); + if (wmem_tree) { + connection_info = (connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); + if (connection_info) { + char *str_addr_src, *str_addr_dst; + /* Holds "Peripheral_0x" (13 chars) + access_address (as %08x, 8 chars) + NULL, which is the longest string */ + int str_addr_len = 13 + 8 + 1; + + str_addr_src = (char *) wmem_alloc(pinfo->pool, str_addr_len); + str_addr_dst = (char *) wmem_alloc(pinfo->pool, str_addr_len); + + sub_item = proto_tree_add_ether(btle_tree, hf_central_bd_addr, tvb, 0, 0, connection_info->central_bd_addr); + proto_item_set_generated(sub_item); + + sub_item = proto_tree_add_ether(btle_tree, hf_peripheral_bd_addr, tvb, 0, 0, connection_info->peripheral_bd_addr); + proto_item_set_generated(sub_item); + + switch (direction) { + case BTLE_DIR_CENTRAL_PERIPHERAL: + snprintf(str_addr_src, str_addr_len, "Central_0x%08x", connection_info->access_address); + snprintf(str_addr_dst, str_addr_len, "Peripheral_0x%08x", connection_info->access_address); + set_address(&pinfo->dl_src, AT_ETHER, sizeof(connection_info->central_bd_addr), connection_info->central_bd_addr); + set_address(&pinfo->dl_dst, AT_ETHER, sizeof(connection_info->peripheral_bd_addr), connection_info->peripheral_bd_addr); + break; + case BTLE_DIR_PERIPHERAL_CENTRAL: + snprintf(str_addr_src, str_addr_len, "Peripheral_0x%08x", connection_info->access_address); + snprintf(str_addr_dst, str_addr_len, "Central_0x%08x", connection_info->access_address); + set_address(&pinfo->dl_src, AT_ETHER, sizeof(connection_info->peripheral_bd_addr), connection_info->peripheral_bd_addr); + set_address(&pinfo->dl_dst, AT_ETHER, sizeof(connection_info->central_bd_addr), connection_info->central_bd_addr); + break; + default: + /* BTLE_DIR_UNKNOWN */ + snprintf(str_addr_src, str_addr_len, "Unknown_0x%08x", connection_info->access_address); + snprintf(str_addr_dst, str_addr_len, "Unknown_0x%08x", connection_info->access_address); + clear_address(&pinfo->dl_src); + clear_address(&pinfo->dl_dst); + break; } - if (tvb_reported_length_remaining(tvb, offset) > 3) { - gboolean ad_processed = FALSE; - if (btle_context && pdu_type == 0x07 && btle_context->aux_pdu_type_valid) { - gboolean ad_reassembled = FALSE; - ae_had_info_t *ae_had_info = NULL; - - switch (btle_context->aux_pdu_type) { - case 0x00: /* AUX_ADV_IND */ - case 0x02: /* AUX_SYNC_IND */ - case 0x03: /* AUX_SCAN_RSP */ - if (aux_pointer_present) { - /* Begining of new sequence of fragments */ - if (!pinfo->fd->visited && adi_present) { - ae_had_info = wmem_new0(wmem_file_scope(), ae_had_info_t); - ae_had_info->first_frame_num=pinfo->num; - - if (flags & 0x01) { - /* Copy Advertiser Address to reassemble AUX_CHAIN_IND */ - copy_address_wmem(wmem_file_scope(), &ae_had_info->adv_addr, &pinfo->src); - } - - ae_had_key[0].length = 1; - ae_had_key[0].key = &interface_id; - ae_had_key[1].length = 1; - ae_had_key[1].key = &adapter_id; - ae_had_key[2].length = 1; - ae_had_key[2].key = &adi; - ae_had_key[3].length = 0; - ae_had_key[3].key = NULL; - - wmem_tree_insert32_array(adi_to_first_frame_tree, ae_had_key, ae_had_info); - - fragment_add_seq(&btle_ea_host_advertising_data_reassembly_table, - tvb, offset, pinfo, - ae_had_info->first_frame_num, NULL, - ae_had_info->fragment_counter, - tvb_captured_length_remaining(tvb, offset) - 3, - !ad_reassembled, 0); - - ae_had_info->fragment_counter++; - } - ad_processed = TRUE; - } - break; - case 0x01: /* AUX_CHAIN_IND */ - if (!aux_pointer_present) { - /* Final fragment */ - ad_reassembled = TRUE; - } - if (!pinfo->fd->visited && adi_present) { - ae_had_key[0].length = 1; - ae_had_key[0].key = &interface_id; - ae_had_key[1].length = 1; - ae_had_key[1].key = &adapter_id; - ae_had_key[2].length = 1; - ae_had_key[2].key = &adi; - ae_had_key[3].length = 0; - ae_had_key[3].key = NULL; - - ae_had_info = (ae_had_info_t *) wmem_tree_lookup32_array(adi_to_first_frame_tree, ae_had_key); - - if (ae_had_info != NULL) { - if (!(flags & 0x01) && (ae_had_info->adv_addr.len > 0)) { - /* Copy Advertiser Address from AUX_ADV_IND if not present. */ - copy_address_shallow(&pinfo->src, &ae_had_info->adv_addr); - } - - fragment_add_seq(&btle_ea_host_advertising_data_reassembly_table, - tvb, offset, pinfo, - ae_had_info->first_frame_num, NULL, - ae_had_info->fragment_counter, - tvb_captured_length_remaining(tvb, offset) - 3, - !ad_reassembled, 0); - - ae_had_info->fragment_counter++; - if (ad_reassembled == TRUE) { - p_add_proto_data(wmem_file_scope(), pinfo, proto_btle, (guint32)(pinfo->curr_layer_num) << 8, ae_had_info); - } - } - } - ad_processed = TRUE; - break; - default: - /* This field is 2 bits long, no special action needed */ - break; - } - if (ad_processed) { - if (pinfo->fd->visited) { - /* Host Advertising Data fragment */ - proto_tree_add_item(btle_tree, hf_extended_advertising_had_fragment, tvb, offset, tvb_captured_length_remaining(tvb, offset) - 3, ENC_NA); - if (ad_reassembled) { - fragment_head *fd_head = NULL; - tvbuff_t *assembled_tvb = NULL; - - ae_had_info = (ae_had_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_btle, (guint32)(pinfo->curr_layer_num) << 8); - if (ae_had_info != NULL) { - col_append_str(pinfo->cinfo, COL_INFO, " (EA HAD Reassembled)"); - - if (!(flags & 0x01) && (ae_had_info->adv_addr.len > 0)) { - /* Copy Advertiser Address from AUX_ADV_IND if not present. */ - copy_address_shallow(&pinfo->src, &ae_had_info->adv_addr); - } - - fd_head = fragment_get(&btle_ea_host_advertising_data_reassembly_table, pinfo, ae_had_info->first_frame_num, NULL); - assembled_tvb = process_reassembled_data( - tvb, offset, pinfo, - "Reassembled Host Advertising Data", fd_head, - &btle_ea_host_advertising_data_frag_items, - NULL, btle_tree); - - if (assembled_tvb) { - dissect_ad_eir(assembled_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, btle_tree); - } - } - } - else { - col_append_str(pinfo->cinfo, COL_INFO, " (EA HAD Fragment)"); - } - offset += tvb_captured_length_remaining(tvb, offset) - 3; - } - } - } - - if (tvb_reported_length_remaining(tvb, offset) > 3) { - /* Host Advertising Data */ - next_tvb = tvb_new_subset_length(tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - - if (btle_context && btle_context->aux_pdu_type_valid && btle_context->aux_pdu_type == 3) { - /* AUX_SCAN_RSP */ - sub_item = proto_tree_add_item(btle_tree, hf_scan_response_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_scan_response_data); + set_address(&pinfo->net_src, AT_STRINGZ, (int)strlen(str_addr_src)+1, str_addr_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); - dissect_ad_eir(next_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, sub_tree); - } - else { - dissect_ad_eir(next_tvb, interface_id, adapter_id, frame_number, src_bd_addr, pinfo, btle_tree); - } + set_address(&pinfo->net_dst, AT_STRINGZ, (int)strlen(str_addr_dst)+1, str_addr_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - offset += tvb_reported_length_remaining(tvb, offset) - 3; + /* Retrieve the last initiated control procedures. */ + if (btle_pdu_type == BTLE_PDU_TYPE_DATA) { + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL] = + (control_proc_info_t *)wmem_tree_lookup32_le(connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, pinfo->num); + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL] = + (control_proc_info_t *)wmem_tree_lookup32_le(connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs, pinfo->num); + + if (!pinfo->fd->visited && btle_context && btle_context->event_counter_valid) { + control_proc_complete_if_instant_reached(pinfo->num, + btle_context->event_counter, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL]); + control_proc_complete_if_instant_reached(pinfo->num, + btle_context->event_counter, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL]); } } - break; - } - default: - if (tvb_reported_length_remaining(tvb, offset) > 3) { - proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - offset += tvb_reported_length_remaining(tvb, offset) - 3; - } - } - } else if (btle_pdu_type == BTLE_PDU_TYPE_DATA || btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) { - proto_item *data_header_item, *seq_item, *control_proc_item; - proto_tree *data_header_tree; - guint8 oct; - guint8 llid; - guint8 control_opcode; - guint32 direction = BTLE_DIR_UNKNOWN; - guint8 other_direction = BTLE_DIR_UNKNOWN; - - gboolean add_l2cap_index = FALSE; - gboolean retransmit = FALSE; - gboolean cte_info_present = FALSE; - - /* Holds the last initiated control procedures for a given direction. */ - control_proc_info_t *last_control_proc[3] = {0}; - - if (btle_context) { - direction = btle_context->direction; - other_direction = (direction == BTLE_DIR_SLAVE_MASTER) ? BTLE_DIR_MASTER_SLAVE : BTLE_DIR_SLAVE_MASTER; - } - btle_frame_info_t *btle_frame_info = NULL; - fragment_head *frag_btl2cap_msg = NULL; - btle_frame_info_t empty_btle_frame_info = {0, 0, 0, 0, 0}; - - 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 = &access_address; - key[3].length = 0; - key[3].key = NULL; - - oct = tvb_get_guint8(tvb, offset); - wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_info_tree, key); - if (wmem_tree) { - connection_info = (connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); - if (connection_info) { - gchar *str_addr_src, *str_addr_dst; - /* Holds "unknown" + access_address + NULL, which is the longest string */ - int str_addr_len = 18 + 1; - - str_addr_src = (gchar *) wmem_alloc(pinfo->pool, str_addr_len); - str_addr_dst = (gchar *) wmem_alloc(pinfo->pool, str_addr_len); - - sub_item = proto_tree_add_ether(btle_tree, hf_master_bd_addr, tvb, 0, 0, connection_info->master_bd_addr); - proto_item_set_generated(sub_item); - - sub_item = proto_tree_add_ether(btle_tree, hf_slave_bd_addr, tvb, 0, 0, connection_info->slave_bd_addr); - proto_item_set_generated(sub_item); - - switch (direction) { - case BTLE_DIR_MASTER_SLAVE: - snprintf(str_addr_src, str_addr_len, "Master_0x%08x", connection_info->access_address); - snprintf(str_addr_dst, str_addr_len, "Slave_0x%08x", connection_info->access_address); - set_address(&pinfo->dl_src, AT_ETHER, sizeof(connection_info->master_bd_addr), connection_info->master_bd_addr); - set_address(&pinfo->dl_dst, AT_ETHER, sizeof(connection_info->slave_bd_addr), connection_info->slave_bd_addr); - break; - case BTLE_DIR_SLAVE_MASTER: - snprintf(str_addr_src, str_addr_len, "Slave_0x%08x", connection_info->access_address); - snprintf(str_addr_dst, str_addr_len, "Master_0x%08x", connection_info->access_address); - set_address(&pinfo->dl_src, AT_ETHER, sizeof(connection_info->slave_bd_addr), connection_info->slave_bd_addr); - set_address(&pinfo->dl_dst, AT_ETHER, sizeof(connection_info->master_bd_addr), connection_info->master_bd_addr); - break; - default: - /* BTLE_DIR_UNKNOWN */ - snprintf(str_addr_src, str_addr_len, "Unknown_0x%08x", connection_info->access_address); - snprintf(str_addr_dst, str_addr_len, "Unknown_0x%08x", connection_info->access_address); - clear_address(&pinfo->dl_src); - clear_address(&pinfo->dl_dst); - break; - } - - set_address(&pinfo->net_src, AT_STRINGZ, (int)strlen(str_addr_src)+1, str_addr_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); - - set_address(&pinfo->net_dst, AT_STRINGZ, (int)strlen(str_addr_dst)+1, str_addr_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - - /* Retrieve the last initiated control procedures. */ - if (btle_pdu_type == BTLE_PDU_TYPE_DATA) { - last_control_proc[BTLE_DIR_MASTER_SLAVE] = - (control_proc_info_t *)wmem_tree_lookup32_le(connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, pinfo->num); - last_control_proc[BTLE_DIR_SLAVE_MASTER] = - (control_proc_info_t *)wmem_tree_lookup32_le(connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs, pinfo->num); - - if (!pinfo->fd->visited && btle_context && btle_context->event_counter_valid) { - control_proc_complete_if_instant_reached(pinfo->num, - btle_context->event_counter, - last_control_proc[BTLE_DIR_MASTER_SLAVE]); - control_proc_complete_if_instant_reached(pinfo->num, - btle_context->event_counter, - last_control_proc[BTLE_DIR_SLAVE_MASTER]); - } - } + if (!pinfo->fd->visited) { + address *addr; - if (!pinfo->fd->visited) { - address *addr; + btle_frame_info = wmem_new0(wmem_file_scope(), btle_frame_info_t); + btle_frame_info->l2cap_index = connection_info->direction_info[direction].l2cap_index; - btle_frame_info = wmem_new0(wmem_file_scope(), btle_frame_info_t); - btle_frame_info->l2cap_index = connection_info->direction_info[direction].l2cap_index; + 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_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); - 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); + if (!connection_info->first_data_frame_seen) { + connection_info->first_data_frame_seen = 1; + btle_frame_info->retransmit = 0; + btle_frame_info->ack = 1; + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].prev_seq_num = 0; + connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].prev_seq_num = 1; + } + else { + uint8_t seq_num = !!(oct & 0x8), next_expected_seq_num = !!(oct & 0x4); - if (!connection_info->first_data_frame_seen) { - connection_info->first_data_frame_seen = 1; + if (seq_num != connection_info->direction_info[direction].prev_seq_num) { + /* SN is not equal to previous packet (in same direction) SN */ btle_frame_info->retransmit = 0; - btle_frame_info->ack = 1; - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].prev_seq_num = 0; - connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].prev_seq_num = 1; + } else { + btle_frame_info->retransmit = 1; } - else { - guint8 seq_num = !!(oct & 0x8), next_expected_seq_num = !!(oct & 0x4); + connection_info->direction_info[direction].prev_seq_num = seq_num; - if (seq_num != connection_info->direction_info[direction].prev_seq_num) { - /* SN is not equal to previous packet (in same direction) SN */ - btle_frame_info->retransmit = 0; - } else { - btle_frame_info->retransmit = 1; - } - connection_info->direction_info[direction].prev_seq_num = seq_num; - - if (next_expected_seq_num != connection_info->direction_info[other_direction].prev_seq_num) { - /* NESN is not equal to previous packet (in other direction) SN */ - btle_frame_info->ack = 1; - } else { - btle_frame_info->ack = 0; - } + if (next_expected_seq_num != connection_info->direction_info[other_direction].prev_seq_num) { + /* NESN is not equal to previous packet (in other direction) SN */ + btle_frame_info->ack = 1; + } else { + btle_frame_info->ack = 0; } - p_add_proto_data(wmem_file_scope(), pinfo, proto_btle, pinfo->curr_layer_num, btle_frame_info); - } - else { - /* Not the first pass */ - btle_frame_info = (btle_frame_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_btle, pinfo->curr_layer_num); } + p_add_proto_data(wmem_file_scope(), pinfo, proto_btle, pinfo->curr_layer_num, btle_frame_info); + } + else { + /* Not the first pass */ + btle_frame_info = (btle_frame_info_t *)p_get_proto_data(wmem_file_scope(), pinfo, proto_btle, pinfo->curr_layer_num); } } + } - if (btle_frame_info == NULL) { - btle_frame_info = &empty_btle_frame_info; - } + if (btle_frame_info == NULL) { + btle_frame_info = &empty_btle_frame_info; + } - if (btle_pdu_type == BTLE_PDU_TYPE_DATA) { - cte_info_present = (oct & 0x20) != 0; - } + if (btle_pdu_type == BTLE_PDU_TYPE_DATA) { + cte_info_present = (oct & 0x20) != 0; + } - data_header_item = proto_tree_add_item(btle_tree, hf_data_header, tvb, offset, 2 + cte_info_present, ENC_NA); - data_header_tree = proto_item_add_subtree(data_header_item, ett_data_header); + data_header_item = proto_tree_add_item(btle_tree, hf_data_header, tvb, offset, (cte_info_present) ? 3 : 2, ENC_NA); + data_header_tree = proto_item_add_subtree(data_header_item, ett_data_header); - proto_tree_add_item(data_header_tree, (btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) ? hf_data_header_llid_connectediso :hf_data_header_llid, tvb, offset, 1, ENC_LITTLE_ENDIAN); - seq_item = proto_tree_add_item(data_header_tree, hf_data_header_next_expected_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, (btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) ? hf_data_header_llid_connectediso :hf_data_header_llid, tvb, offset, 1, ENC_LITTLE_ENDIAN); + seq_item = proto_tree_add_item(data_header_tree, hf_data_header_next_expected_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); - if (direction != BTLE_DIR_UNKNOWN) { - /* Unable to check valid NESN without direction */ - if (btle_frame_info->ack == 1) { - proto_item_append_text(seq_item, " [ACK]"); - } else { - proto_item_append_text(seq_item, " [Request retransmit]"); - expert_add_info(pinfo, seq_item, &ei_nack); - } + if (direction != BTLE_DIR_UNKNOWN) { + /* Unable to check valid NESN without direction */ + if (btle_frame_info->ack == 1) { + proto_item_append_text(seq_item, " [ACK]"); + } else { + proto_item_append_text(seq_item, " [Request retransmit]"); + expert_add_info(pinfo, seq_item, &ei_nack); } + } - seq_item = proto_tree_add_item(data_header_tree, hf_data_header_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + seq_item = proto_tree_add_item(data_header_tree, hf_data_header_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); - if (direction != BTLE_DIR_UNKNOWN) { - /* Unable to check valid SN or retransmission without direction */ - if (btle_frame_info->retransmit == 0) { - proto_item_append_text(seq_item, " [OK]"); - } - else { - proto_item_append_text(seq_item, " [Retransmit]"); - if (btle_detect_retransmit) { - expert_add_info(pinfo, seq_item, &ei_retransmit); - retransmit = TRUE; - } + if (direction != BTLE_DIR_UNKNOWN) { + /* Unable to check valid SN or retransmission without direction */ + if (btle_frame_info->retransmit == 0) { + proto_item_append_text(seq_item, " [OK]"); + } + else { + proto_item_append_text(seq_item, " [Retransmit]"); + if (btle_detect_retransmit) { + expert_add_info(pinfo, seq_item, &ei_retransmit); + retransmit = true; } } + } - llid = oct & 0x03; - if (btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) { - proto_tree_add_item(data_header_tree, hf_data_header_close_isochronous_event, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_null_pdu_indicator, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_rfu_57, tvb, offset, 1, ENC_LITTLE_ENDIAN); - llid |= 0x04; - } else { - proto_tree_add_item(data_header_tree, hf_data_header_more_data, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_cte_info_present, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); - } - offset += 1; + llid = oct & 0x03; + if (btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) { + proto_tree_add_item(data_header_tree, hf_data_header_close_isochronous_event, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_null_pdu_indicator, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_rfu_57, tvb, offset, 1, ENC_LITTLE_ENDIAN); + llid |= 0x04; + } else { + proto_tree_add_item(data_header_tree, hf_data_header_more_data, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_cte_info_present, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); + } + offset += 1; - proto_tree_add_item(data_header_tree, hf_data_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); - item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); - proto_item_set_hidden(item); - offset += 1; + proto_tree_add_item(data_header_tree, hf_data_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + proto_item_set_hidden(item); + offset += 1; - if (cte_info_present) { - guint32 cte_time; + if (cte_info_present) { + uint32_t cte_time; - sub_item = proto_tree_add_item(data_header_tree, hf_data_header_cte_info, tvb, offset, 1, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_data_header_cte_info); + sub_item = proto_tree_add_item(data_header_tree, hf_data_header_cte_info, tvb, offset, 1, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_data_header_cte_info); - item = proto_tree_add_item_ret_uint(sub_tree, hf_data_header_cte_info_time, tvb, offset, 1, ENC_LITTLE_ENDIAN, &cte_time); - proto_item_append_text(item, " (%u usec)", cte_time * 8); - proto_tree_add_item(sub_tree, hf_data_header_cte_info_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(sub_tree, hf_data_header_cte_info_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - } + item = proto_tree_add_item_ret_uint(sub_tree, hf_data_header_cte_info_time, tvb, offset, 1, ENC_LITTLE_ENDIAN, &cte_time); + proto_item_append_text(item, " (%u usec)", cte_time * 8); + proto_tree_add_item(sub_tree, hf_data_header_cte_info_rfu, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(sub_tree, hf_data_header_cte_info_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + } - switch (llid) { - case 0x01: /* Continuation fragment of an L2CAP message, or an Empty PDU */ - if (length > 0) { - tvbuff_t *new_tvb = NULL; + switch (llid) { + case 0x01: /* Continuation fragment of an L2CAP message, or an Empty PDU */ + if (length > 0) { + tvbuff_t *new_tvb = NULL; - pinfo->fragmented = TRUE; - if (connection_info && !retransmit) { - if (!pinfo->fd->visited) { - if (connection_info->direction_info[direction].segmentation_started == 1) { - if (connection_info->direction_info[direction].segment_len_rem >= length) { - connection_info->direction_info[direction].segment_len_rem = connection_info->direction_info[direction].segment_len_rem - length; - } else { - /* - * Missing fragment for previous L2CAP and fragment start for this. - * Set more_fragments and increase l2cap_index to avoid reassembly. - */ - btle_frame_info->more_fragments = 1; - btle_frame_info->missing_start = 1; - btle_frame_info->l2cap_index = l2cap_index; - connection_info->direction_info[direction].l2cap_index = l2cap_index; - connection_info->direction_info[direction].segmentation_started = 0; - l2cap_index++; - } - if (connection_info->direction_info[direction].segment_len_rem > 0) { - btle_frame_info->more_fragments = 1; - } - else { - btle_frame_info->more_fragments = 0; - connection_info->direction_info[direction].segmentation_started = 0; - connection_info->direction_info[direction].segment_len_rem = 0; - } + pinfo->fragmented = true; + if (connection_info && !retransmit) { + if (!pinfo->fd->visited) { + if (connection_info->direction_info[direction].segmentation_started == 1) { + if (connection_info->direction_info[direction].segment_len_rem >= length) { + connection_info->direction_info[direction].segment_len_rem = connection_info->direction_info[direction].segment_len_rem - length; } else { /* - * Missing fragment start. - * Set more_fragments and increase l2cap_index to avoid reassembly. - */ + * Missing fragment for previous L2CAP and fragment start for this. + * Set more_fragments and increase l2cap_index to avoid reassembly. + */ btle_frame_info->more_fragments = 1; btle_frame_info->missing_start = 1; btle_frame_info->l2cap_index = l2cap_index; @@ -2920,19 +2987,110 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) connection_info->direction_info[direction].segmentation_started = 0; l2cap_index++; } + if (connection_info->direction_info[direction].segment_len_rem > 0) { + btle_frame_info->more_fragments = 1; + } + else { + btle_frame_info->more_fragments = 0; + connection_info->direction_info[direction].segmentation_started = 0; + connection_info->direction_info[direction].segment_len_rem = 0; + } + } else { + /* + * Missing fragment start. + * Set more_fragments and increase l2cap_index to avoid reassembly. + */ + btle_frame_info->more_fragments = 1; + btle_frame_info->missing_start = 1; + btle_frame_info->l2cap_index = l2cap_index; + connection_info->direction_info[direction].l2cap_index = l2cap_index; + connection_info->direction_info[direction].segmentation_started = 0; + l2cap_index++; } + } + + add_l2cap_index = true; + + frag_btl2cap_msg = fragment_add_seq_next(&btle_l2cap_msg_reassembly_table, + tvb, offset, + pinfo, + btle_frame_info->l2cap_index, /* uint32_t ID for fragments belonging together */ + NULL, /* data* */ + length, /* Fragment length */ + btle_frame_info->more_fragments); /* More fragments */ + + new_tvb = process_reassembled_data(tvb, offset, pinfo, + "Reassembled L2CAP", + frag_btl2cap_msg, + &btle_l2cap_msg_frag_items, + NULL, + btle_tree); + } - add_l2cap_index = TRUE; + if (new_tvb) { + bthci_acl_data_t *acl_data; + + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); + + 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 = retransmit; + 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, length); + if (next_tvb) { + call_dissector_with_data(btl2cap_handle, new_tvb, pinfo, tree, acl_data); + } + offset += length; + } + else { + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment"); + item = proto_tree_add_item(btle_tree, hf_l2cap_fragment, tvb, offset, length, ENC_NA); + if (btle_frame_info->missing_start) { + expert_add_info(pinfo, item, &ei_missing_fragment_start); + } + offset += length; + } + } else { + col_set_str(pinfo->cinfo, COL_INFO, "Empty PDU"); + } + + break; + case 0x02: /* Start of an L2CAP message or a complete L2CAP message with no fragmentation */ + if (length > 0) { + unsigned l2cap_len = tvb_get_letohs(tvb, offset); + if (l2cap_len + 4 > length) { /* L2CAP PDU Length excludes the 4 octets header */ + pinfo->fragmented = true; + if (connection_info && !retransmit) { + if (!pinfo->fd->visited) { + connection_info->direction_info[direction].segmentation_started = 1; + /* The first two octets in the L2CAP PDU contain the length of the entire + * L2CAP PDU in octets, excluding the Length and CID fields(4 octets). + */ + connection_info->direction_info[direction].segment_len_rem = l2cap_len + 4 - length; + connection_info->direction_info[direction].l2cap_index = l2cap_index; + btle_frame_info->more_fragments = 1; + btle_frame_info->l2cap_index = l2cap_index; + l2cap_index++; + } + + add_l2cap_index = true; frag_btl2cap_msg = fragment_add_seq_next(&btle_l2cap_msg_reassembly_table, tvb, offset, pinfo, - btle_frame_info->l2cap_index, /* guint32 ID for fragments belonging together */ + btle_frame_info->l2cap_index, /* uint32_t ID for fragments belonging together */ NULL, /* data* */ length, /* Fragment length */ btle_frame_info->more_fragments); /* More fragments */ - new_tvb = process_reassembled_data(tvb, offset, pinfo, + process_reassembled_data(tvb, offset, pinfo, "Reassembled L2CAP", frag_btl2cap_msg, &btle_l2cap_msg_frag_items, @@ -2940,1475 +3098,1506 @@ dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) btle_tree); } - if (new_tvb) { - bthci_acl_data_t *acl_data; - - col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); - - 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 = retransmit; - 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, length); - if (next_tvb) { - call_dissector_with_data(btl2cap_handle, new_tvb, pinfo, tree, acl_data); - } - offset += length; - } - else { - col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment"); - item = proto_tree_add_item(btle_tree, hf_l2cap_fragment, tvb, offset, length, ENC_NA); - if (btle_frame_info->missing_start) { - expert_add_info(pinfo, item, &ei_missing_fragment_start); - } - offset += length; - } + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment Start"); + proto_tree_add_item(btle_tree, hf_l2cap_fragment, tvb, offset, length, ENC_NA); + offset += length; } else { - col_set_str(pinfo->cinfo, COL_INFO, "Empty PDU"); - } - - break; - case 0x02: /* Start of an L2CAP message or a complete L2CAP message with no fragmentation */ - if (length > 0) { - guint l2cap_len = tvb_get_letohs(tvb, offset); - if (l2cap_len + 4 > length) { /* L2CAP PDU Length excludes the 4 octets header */ - pinfo->fragmented = TRUE; - if (connection_info && !retransmit) { - if (!pinfo->fd->visited) { - connection_info->direction_info[direction].segmentation_started = 1; - /* The first two octets in the L2CAP PDU contain the length of the entire - * L2CAP PDU in octets, excluding the Length and CID fields(4 octets). - */ - connection_info->direction_info[direction].segment_len_rem = l2cap_len + 4 - length; - connection_info->direction_info[direction].l2cap_index = l2cap_index; - btle_frame_info->more_fragments = 1; - btle_frame_info->l2cap_index = l2cap_index; - l2cap_index++; - } - - add_l2cap_index = TRUE; - - frag_btl2cap_msg = fragment_add_seq_next(&btle_l2cap_msg_reassembly_table, - tvb, offset, - pinfo, - btle_frame_info->l2cap_index, /* guint32 ID for fragments belonging together */ - NULL, /* data* */ - length, /* Fragment length */ - btle_frame_info->more_fragments); /* More fragments */ - - process_reassembled_data(tvb, offset, pinfo, - "Reassembled L2CAP", - frag_btl2cap_msg, - &btle_l2cap_msg_frag_items, - NULL, - btle_tree); - } - - col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Fragment Start"); - proto_tree_add_item(btle_tree, hf_l2cap_fragment, tvb, offset, length, ENC_NA); - offset += length; - } else { - bthci_acl_data_t *acl_data; - if (connection_info) { - /* Add a L2CAP index for completeness */ - if (!pinfo->fd->visited) { - btle_frame_info->l2cap_index = l2cap_index; - l2cap_index++; - } - - add_l2cap_index = TRUE; + bthci_acl_data_t *acl_data; + if (connection_info) { + /* Add a L2CAP index for completeness */ + if (!pinfo->fd->visited) { + btle_frame_info->l2cap_index = l2cap_index; + l2cap_index++; } - col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); - - 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 = retransmit; - 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, length); - call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data); - offset += length; + add_l2cap_index = true; } + + col_set_str(pinfo->cinfo, COL_INFO, "L2CAP Data"); + + 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 = retransmit; + 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, length); + call_dissector_with_data(btl2cap_handle, next_tvb, pinfo, tree, acl_data); + offset += length; } - break; - case 0x03: /* Control PDU */ - control_proc_item = proto_tree_add_item(btle_tree, hf_control_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); - control_opcode = tvb_get_guint8(tvb, offset); - offset += 1; + } + break; + case 0x03: /* Control PDU */ + control_proc_item = proto_tree_add_item(btle_tree, hf_control_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + control_opcode = tvb_get_uint8(tvb, offset); + offset += 1; - col_add_fstr(pinfo->cinfo, COL_INFO, "Control Opcode: %s", - val_to_str_ext_const(control_opcode, &control_opcode_vals_ext, "Unknown")); + col_add_fstr(pinfo->cinfo, COL_INFO, "Control Opcode: %s", + val_to_str_ext_const(control_opcode, &control_opcode_vals_ext, "Unknown")); - switch (control_opcode) { - case LL_CTRL_OPCODE_CONNECTION_UPDATE_IND: - item = proto_tree_add_item_ret_uint(btle_tree, hf_control_window_size, tvb, offset, 1, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); - offset += 1; + switch (control_opcode) { + case LL_CTRL_OPCODE_CONNECTION_UPDATE_IND: + item = proto_tree_add_item_ret_uint(btle_tree, hf_control_window_size, tvb, offset, 1, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 1; - item = proto_tree_add_item_ret_uint(btle_tree, hf_control_window_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); - offset += 2; + item = proto_tree_add_item_ret_uint(btle_tree, hf_control_window_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 2; - item = proto_tree_add_item_ret_uint(btle_tree, hf_control_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%g msec)", item_value*1.25); - offset += 2; + item = proto_tree_add_item_ret_uint(btle_tree, hf_control_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%g msec)", item_value*1.25); + offset += 2; - proto_tree_add_item(btle_tree, hf_control_latency, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; + proto_tree_add_item(btle_tree, hf_control_latency, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; - item = proto_tree_add_item_ret_uint(btle_tree, hf_control_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - proto_item_append_text(item, " (%u msec)", item_value*10); - offset += 2; + item = proto_tree_add_item_ret_uint(btle_tree, hf_control_timeout, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + proto_item_append_text(item, " (%u msec)", item_value*10); + offset += 2; - proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - offset += 2; + proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + offset += 2; - if (!pinfo->fd->visited) { - if (connection_info) { - connection_parameter_info_t *connection_parameter_info; + if (!pinfo->fd->visited) { + if (connection_info) { + connection_parameter_info_t *connection_parameter_info; - connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); - connection_parameter_info->parameters_frame = pinfo->num; + connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); + connection_parameter_info->parameters_frame = pinfo->num; - if (btle_context && btle_context->event_counter_valid) { - connection_info->connection_parameter_update_instant = item_value; - connection_info->connection_parameter_update_info = connection_parameter_info; - } else { - /* We don't have event counter information needed to determine the exact time the new - * connection parameters will be applied. - * Instead just set it as active immediately. - */ - 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 = &access_address; - key[3].length = 1; - key[3].key = &pinfo->num; - key[4].length = 0; - key[4].key = NULL; - wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); - } + if (btle_context && btle_context->event_counter_valid) { + connection_info->connection_parameter_update_instant = item_value; + connection_info->connection_parameter_update_info = connection_parameter_info; + } else { + /* We don't have event counter information needed to determine the exact time the new + * connection parameters will be applied. + * Instead just set it as active immediately. + */ + 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 = &access_address; + key[3].length = 1; + key[3].key = &pinfo->num; + key[4].length = 0; + key[4].key = NULL; + wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); } } + } - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_CONNECTION_UPDATE_IND can only be sent from master to slave. - * It can either be sent as the first packet of the connection update procedure, - * or as the last packet in the connection parameter request procedure. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 2)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - last_control_proc[BTLE_DIR_MASTER_SLAVE], - 1); - } else { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - - if (proc_info) { - if (btle_context && btle_context->event_counter_valid) { - proc_info->instant = item_value; - proc_info->frame_with_instant_value = pinfo->num; - } else { - /* Event counter is not available, assume the procedure completes now. */ - proc_info->last_frame = pinfo->num; - } - } + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_CONNECTION_UPDATE_IND can only be sent from central to peripheral. + * It can either be sent as the first packet of the connection update procedure, + * or as the last packet in the connection parameter request procedure. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 2)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + 1); + } else { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + if (proc_info) { + if (btle_context && btle_context->event_counter_valid) { + proc_info->instant = item_value; + proc_info->frame_with_instant_value = pinfo->num; + } else { + /* Event counter is not available, assume the procedure completes now. */ + proc_info->last_frame = pinfo->num; + } } - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); + } + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_CHANNEL_MAP_IND: - sub_item = proto_tree_add_item(btle_tree, hf_control_channel_map, tvb, offset, 5, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + break; + case LL_CTRL_OPCODE_CHANNEL_MAP_IND: + sub_item = proto_tree_add_item(btle_tree, hf_control_channel_map, tvb, offset, 5, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + + call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); + offset += 5; - call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); - offset += 5; + proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + offset += 2; - proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - offset += 2; - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_CHANNEL_MAP_REQ can only be sent from master to slave. - * It can either be sent as the first packet of the channel map update procedure, - * or as the last packet in the minimum number of used channels procedure. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - LL_CTRL_OPCODE_MIN_USED_CHANNELS_IND, 1)) { - control_proc_add_frame_with_instant(tvb, - pinfo, - btle_tree, - btle_context, - control_opcode, - direction, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - last_control_proc[BTLE_DIR_MASTER_SLAVE], - 1, - item_value); - } else { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - - if (proc_info) { - if (btle_context && btle_context->event_counter_valid) { - proc_info->instant = item_value; - proc_info->frame_with_instant_value = pinfo->num; - } else { - /* Event counter is not available, assume the procedure completes now. */ - proc_info->last_frame = pinfo->num; - } + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_CHANNEL_MAP_REQ can only be sent from central to peripheral. + * It can either be sent as the first packet of the channel map update procedure, + * or as the last packet in the minimum number of used channels procedure. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + LL_CTRL_OPCODE_MIN_USED_CHANNELS_IND, 1)) { + control_proc_add_frame_with_instant(tvb, + pinfo, + btle_tree, + btle_context, + control_opcode, + direction, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + 1, + item_value); + } else { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + + if (proc_info) { + if (btle_context && btle_context->event_counter_valid) { + proc_info->instant = item_value; + proc_info->frame_with_instant_value = pinfo->num; + } else { + /* Event counter is not available, assume the procedure completes now. */ + proc_info->last_frame = pinfo->num; } } - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_TERMINATE_IND: - proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + break; + case LL_CTRL_OPCODE_TERMINATE_IND: + proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - /* No need to mark procedure as started, as the procedure only consist - * of one packet which may be sent at any time, */ + /* No need to mark procedure as started, as the procedure only consist + * of one packet which may be sent at any time, */ - break; - case LL_CTRL_OPCODE_ENC_REQ: - proto_tree_add_item(btle_tree, hf_control_random_number, tvb, offset, 8, ENC_LITTLE_ENDIAN); - offset += 8; - - proto_tree_add_item(btle_tree, hf_control_encrypted_diversifier, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; - - proto_tree_add_item(btle_tree, hf_control_master_session_key_diversifier, tvb, offset, 8, ENC_LITTLE_ENDIAN); - offset += 8; - - proto_tree_add_item(btle_tree, hf_control_master_session_initialization_vector, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_ENC_REQ can only be sent from master to slave. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, - last_control_proc[other_direction], - control_opcode); - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + break; + case LL_CTRL_OPCODE_ENC_REQ: + proto_tree_add_item(btle_tree, hf_control_random_number, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; - break; - case LL_CTRL_OPCODE_ENC_RSP: - proto_tree_add_item(btle_tree, hf_control_slave_session_key_diversifier, tvb, offset, 8, ENC_LITTLE_ENDIAN); - offset += 8; - - proto_tree_add_item(btle_tree, hf_control_slave_session_initialization_vector, tvb, offset, 4, ENC_LITTLE_ENDIAN); - offset += 4; - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_ENC_REQ can only be sent from slave to master. */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 1)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + proto_tree_add_item(btle_tree, hf_control_encrypted_diversifier, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; - break; - case LL_CTRL_OPCODE_START_ENC_REQ: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_START_ENC_REQ can only be sent from slave to master. */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 2)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + proto_tree_add_item(btle_tree, hf_control_central_session_key_diversifier, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; - break; + proto_tree_add_item(btle_tree, hf_control_central_session_initialization_vector, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; - case LL_CTRL_OPCODE_START_ENC_RSP: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - /* This is either frame 4 or 5 of the procedure */ - if (direction == BTLE_DIR_MASTER_SLAVE && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 3)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 3); - } else if (direction == BTLE_DIR_SLAVE_MASTER && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 4)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 4); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_ENC_REQ can only be sent from central to peripheral. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, + last_control_proc[other_direction], + control_opcode); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; + break; + case LL_CTRL_OPCODE_ENC_RSP: + proto_tree_add_item(btle_tree, hf_control_peripheral_session_key_diversifier, tvb, offset, 8, ENC_LITTLE_ENDIAN); + offset += 8; - case LL_CTRL_OPCODE_UNKNOWN_RSP: - proto_tree_add_item(btle_tree, hf_control_unknown_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - /* LL_UNKNOWN_RSP can only be sent as the second frame of a procedure. */ - if (last_control_proc[other_direction] && - control_proc_can_add_frame_even_if_complete(pinfo, - last_control_proc[other_direction], - last_control_proc[other_direction]->proc_opcode, - 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + proto_tree_add_item(btle_tree, hf_control_peripheral_session_initialization_vector, tvb, offset, 4, ENC_LITTLE_ENDIAN); + offset += 4; - break; - case LL_CTRL_OPCODE_FEATURE_REQ: - offset = dissect_feature_set(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_FEATURE_REQ can only be sent from master to slave. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } else if (direction == BTLE_DIR_SLAVE_MASTER) { + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_ENC_REQ can only be sent from peripheral to central. */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 1)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_FEATURE_RSP: - offset = dissect_feature_set(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + break; + case LL_CTRL_OPCODE_START_ENC_REQ: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_START_ENC_REQ can only be sent from peripheral to central. */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_FEATURE_REQ, 1) || - control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_SLAVE_FEATURE_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 2)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_PAUSE_ENC_REQ: - if (tvb_reported_length_remaining(tvb, offset) > 3) { - proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - offset += tvb_reported_length_remaining(tvb, offset) - 3; - } - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_PAUSE_ENC_REQ can only be sent from master to slave. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, - last_control_proc[other_direction], - control_opcode); - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + break; - break; - case LL_CTRL_OPCODE_PAUSE_ENC_RSP: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (direction == BTLE_DIR_SLAVE_MASTER && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_PAUSE_ENC_REQ, 1)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else if (direction == BTLE_DIR_MASTER_SLAVE && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_PAUSE_ENC_REQ, 2)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + case LL_CTRL_OPCODE_START_ENC_RSP: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + /* This is either frame 4 or 5 of the procedure */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 3)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 3); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 4)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 4); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_VERSION_IND: - proto_tree_add_item(btle_tree, hf_control_version_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + break; - proto_tree_add_item(btle_tree, hf_control_company_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; + case LL_CTRL_OPCODE_UNKNOWN_RSP: + proto_tree_add_item(btle_tree, hf_control_unknown_type, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - proto_tree_add_item(btle_tree, hf_control_subversion_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); - offset += 2; + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + /* LL_UNKNOWN_RSP can only be sent as the second frame of a procedure. */ + if (last_control_proc[other_direction] && + control_proc_can_add_frame_even_if_complete(pinfo, + last_control_proc[other_direction], + last_control_proc[other_direction]->proc_opcode, + 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); + } + } - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - /* The LL_VERSION_IND can be sent as a request or response. - * We first check if it is a response. */ - if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_VERSION_IND, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } + break; + case LL_CTRL_OPCODE_FEATURE_REQ: + offset = dissect_feature_set(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_FEATURE_REQ can only be sent from central to peripheral. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_REJECT_IND: - proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - - /* LL_REJECT_IND my be sent as: - * - A response to the LL_ENQ_REQ from the master - * - After the LL_ENC_RSP from the slave */ - if (connection_info && !btle_frame_info->retransmit) { - if (direction == BTLE_DIR_SLAVE_MASTER) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 2)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + break; + case LL_CTRL_OPCODE_FEATURE_RSP: + offset = dissect_feature_set(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_FEATURE_REQ, 1) || + control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_PERIPHERAL_FEATURE_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_SLAVE_FEATURE_REQ: - offset = dissect_feature_set(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_SLAVE_FEATURE_REQ can only be sent from slave to master. */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + break; + case LL_CTRL_OPCODE_PAUSE_ENC_REQ: + if (tvb_reported_length_remaining(tvb, offset) > 3) { + proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + offset += tvb_reported_length_remaining(tvb, offset) - 3; + } + + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_PAUSE_ENC_REQ can only be sent from central to peripheral. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, + last_control_proc[other_direction], + control_opcode); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; + } - case LL_CTRL_OPCODE_CONNECTION_PARAM_REQ: - offset = dissect_conn_param_req_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (direction != BTLE_DIR_UNKNOWN) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } + break; + case LL_CTRL_OPCODE_PAUSE_ENC_RSP: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_PAUSE_ENC_REQ, 1)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_PAUSE_ENC_REQ, 2)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_CONNECTION_PARAM_RSP: - offset = dissect_conn_param_req_rsp(tvb, btle_tree, offset); - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_CONNECTION_PARAM_RSP can only be sent from slave to master - * as a response to a master initiated procedure */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + break; + case LL_CTRL_OPCODE_VERSION_IND: + proto_tree_add_item(btle_tree, hf_control_version_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(btle_tree, hf_control_company_id, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + proto_tree_add_item(btle_tree, hf_control_subversion_number, tvb, offset, 2, ENC_LITTLE_ENDIAN); + offset += 2; + + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + /* The LL_VERSION_IND can be sent as a request or response. + * We first check if it is a response. */ + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_VERSION_IND, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); } + } - break; - case LL_CTRL_OPCODE_REJECT_EXT_IND: - proto_tree_add_item(btle_tree, hf_control_reject_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - - proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - - /* LL_REJECT_EXT_IND my be sent as: - * - A response to the LL_ENQ_REQ from the master - * - After the LL_ENC_RSP from the slave - * - As a response to LL_CONNECTION_PARAM_REQ - * - As a response to LL_CONNECTION_PARAM_RSP - * - As a response during the phy update procedure. - * - As a response during the CTE request procedure. - * - As a response to LL_CIS_REQ - * - As a response to LL_CIS_RSP - * - As a response to LL_POWER_CONTROL_REQ - * - As a response to a LL_SUBRATE_REQ - */ - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (direction == BTLE_DIR_SLAVE_MASTER && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else if (direction == BTLE_DIR_SLAVE_MASTER && - control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_ENC_REQ, 2)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_PHY_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_CTE_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CIS_REQ, 1)) { + break; + case LL_CTRL_OPCODE_REJECT_IND: + proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + /* LL_REJECT_IND my be sent as: + * - A response to the LL_ENQ_REQ from the central + * - After the LL_ENC_RSP from the peripheral */ + if (connection_info && !btle_frame_info->retransmit) { + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 1)) { control_proc_add_last_frame(tvb, pinfo, btle_tree, control_opcode, direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], 1); } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CIS_REQ, 2)) { + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 2)) { control_proc_add_last_frame(tvb, pinfo, btle_tree, control_opcode, direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], 2); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_POWER_CONTROL_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - LL_CTRL_OPCODE_SUBRATE_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - last_control_proc[BTLE_DIR_MASTER_SLAVE], - 1); } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; - case LL_CTRL_OPCODE_PING_REQ: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + break; + case LL_CTRL_OPCODE_PERIPHERAL_FEATURE_REQ: + offset = dissect_feature_set(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_PERIPHERAL_FEATURE_REQ can only be sent from peripheral to central. */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } - break; - case LL_CTRL_OPCODE_PING_RSP: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_PING_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; + } + break; - case LL_CTRL_OPCODE_LENGTH_REQ: - dissect_length_req_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + case LL_CTRL_OPCODE_CONNECTION_PARAM_REQ: + offset = dissect_conn_param_req_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (direction != BTLE_DIR_UNKNOWN) { control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); } + } - break; - case LL_CTRL_OPCODE_LENGTH_RSP: - dissect_length_req_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + break; + case LL_CTRL_OPCODE_CONNECTION_PARAM_RSP: + offset = dissect_conn_param_req_rsp(tvb, btle_tree, offset); + + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_CONNECTION_PARAM_RSP can only be sent from peripheral to central + * as a response to a central initiated procedure */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_LENGTH_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_PHY_REQ: - dissect_phy_req_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } + } - break; - case LL_CTRL_OPCODE_PHY_RSP: - dissect_phy_req_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_PHY_RSP can only be sent from slave to master. */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_PHY_REQ, 1)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } + break; + case LL_CTRL_OPCODE_REJECT_EXT_IND: + proto_tree_add_item(btle_tree, hf_control_reject_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - break; - case LL_CTRL_OPCODE_PHY_UPDATE_IND: - { - guint64 phy_c_to_p, phy_p_to_c; + proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; - item = proto_tree_add_bitmask_ret_uint64(btle_tree, tvb, offset, hf_control_m_to_s_phy, ett_m_to_s_phy, hfx_control_phys_update, ENC_NA, &phy_c_to_p); - if (phy_c_to_p == 0) { - proto_item_append_text(item, ", No change"); + /* LL_REJECT_EXT_IND my be sent as: + * - A response to the LL_ENQ_REQ from the central + * - After the LL_ENC_RSP from the peripheral + * - As a response to LL_CONNECTION_PARAM_REQ + * - As a response to LL_CONNECTION_PARAM_RSP + * - As a response during the phy update procedure. + * - As a response during the CTE request procedure. + * - As a response to LL_CIS_REQ + * - As a response to LL_CIS_RSP + * - As a response to LL_POWER_CONTROL_REQ + * - As a response to a LL_SUBRATE_REQ + */ + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL && + control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_ENC_REQ, 2)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_CONNECTION_PARAM_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_PHY_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_CTE_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CIS_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CIS_REQ, 2)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_POWER_CONTROL_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + LL_CTRL_OPCODE_SUBRATE_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - offset += 1; + } - item = proto_tree_add_bitmask_ret_uint64(btle_tree, tvb, offset, hf_control_s_to_m_phy, ett_s_to_m_phy, hfx_control_phys_update, ENC_NA, &phy_p_to_c); - if (phy_p_to_c == 0) { - proto_item_append_text(item, ", No change"); + break; + case LL_CTRL_OPCODE_PING_REQ: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } + break; + case LL_CTRL_OPCODE_PING_RSP: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_PING_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - offset += 1; + } + break; + + case LL_CTRL_OPCODE_LENGTH_REQ: + dissect_length_req_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } - if (phy_c_to_p != 0 && phy_p_to_c != 0) { - proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + break; + case LL_CTRL_OPCODE_LENGTH_RSP: + dissect_length_req_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_LENGTH_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); } else { - /* If both the PHY_C_TO_P and PHY_P_TO_C fields are zero then there is no - * Instant and the Instant field is reserved for future use. - */ - proto_tree_add_item(btle_tree, hf_control_rfu_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - offset += 2; - - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_PHY_UPDATE_IND can only be sent from master to slave. */ - if (direction == BTLE_DIR_MASTER_SLAVE) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_PHY_REQ, 2)) { - control_proc_add_frame_with_instant(tvb, - pinfo, - btle_tree, - btle_context, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2, - item_value); - } else if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - LL_CTRL_OPCODE_PHY_REQ, 1)){ - control_proc_add_frame_with_instant(tvb, - pinfo, - btle_tree, - btle_context, - control_opcode, - direction, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - last_control_proc[BTLE_DIR_MASTER_SLAVE], - 1, - item_value); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } else if (direction == BTLE_DIR_SLAVE_MASTER) { + } + break; + case LL_CTRL_OPCODE_PHY_REQ: + dissect_phy_req_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } + + break; + case LL_CTRL_OPCODE_PHY_RSP: + dissect_phy_req_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_PHY_RSP can only be sent from peripheral to central. */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_PHY_REQ, 1)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } - break; + break; + case LL_CTRL_OPCODE_PHY_UPDATE_IND: + { + uint64_t phy_c_to_p, phy_p_to_c; + + item = proto_tree_add_bitmask_ret_uint64(btle_tree, tvb, offset, hf_control_c_to_p_phy, ett_c_to_p_phy, hfx_control_phys_update, ENC_NA, &phy_c_to_p); + if (phy_c_to_p == 0) { + proto_item_append_text(item, ", No change"); } - case LL_CTRL_OPCODE_MIN_USED_CHANNELS_IND: - proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_phys, ett_phys, hfx_control_phys, ENC_NA); - offset += 1; + offset += 1; - proto_tree_add_item(btle_tree, hf_control_min_used_channels, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + item = proto_tree_add_bitmask_ret_uint64(btle_tree, tvb, offset, hf_control_p_to_c_phy, ett_p_to_c_phy, hfx_control_phys_update, ENC_NA, &phy_p_to_c); + if (phy_p_to_c == 0) { + proto_item_append_text(item, ", No change"); + } + offset += 1; - if (connection_info && !btle_frame_info->retransmit) { - /* The LL_MIN_USED_CHANNELS_IND can only be sent from slave to master. */ - if (direction == BTLE_DIR_SLAVE_MASTER) { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + if (phy_c_to_p != 0 && phy_p_to_c != 0) { + proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + } else { + /* If both the PHY_C_TO_P and PHY_P_TO_C fields are zero then there is no + * Instant and the Instant field is reserved for future use. + */ + proto_tree_add_item(btle_tree, hf_control_rfu_5, tvb, offset, 2, ENC_LITTLE_ENDIAN); + } + offset += 2; - /* Procedure completes in the same frame. */ - if (proc_info) { - proc_info->last_frame = pinfo->num; - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_CTE_REQ: - proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_phys, ett_cte, hfx_control_cte, ENC_NA); - offset += 1; - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } - break; - case LL_CTRL_OPCODE_CTE_RSP: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_PHY_UPDATE_IND can only be sent from central to peripheral. */ + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_CTE_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_PHY_REQ, 2)) { + control_proc_add_frame_with_instant(tvb, + pinfo, + btle_tree, + btle_context, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2, + item_value); + } else if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + LL_CTRL_OPCODE_PHY_REQ, 1)){ + control_proc_add_frame_with_instant(tvb, + pinfo, + btle_tree, + btle_context, + control_opcode, + direction, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + 1, + item_value); } else { expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_PERIODIC_SYNC_IND: - offset = dissect_periodic_sync_ind(tvb, btle_tree, offset, pinfo, interface_id, adapter_id); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + } + + break; + } + case LL_CTRL_OPCODE_MIN_USED_CHANNELS_IND: + proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_phys, ett_phys, hfx_control_phys, ENC_NA); + offset += 1; + + proto_tree_add_item(btle_tree, hf_control_min_used_channels, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + if (connection_info && !btle_frame_info->retransmit) { + /* The LL_MIN_USED_CHANNELS_IND can only be sent from peripheral to central. */ + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { control_proc_info_t *proc_info; proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); /* Procedure completes in the same frame. */ if (proc_info) { proc_info->last_frame = pinfo->num; } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_CLOCK_ACCURACY_REQ: - proto_tree_add_item(btle_tree, hf_control_sleep_clock_accuracy, tvb, offset, 1, ENC_NA); - offset += 1; - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + } + break; + case LL_CTRL_OPCODE_CTE_REQ: + proto_tree_add_bitmask(btle_tree, tvb, offset, hf_control_phys, ett_cte, hfx_control_cte, ENC_NA); + offset += 1; + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } + break; + case LL_CTRL_OPCODE_CTE_RSP: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_CTE_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_CLOCK_ACCURACY_RSP: - proto_tree_add_item(btle_tree, hf_control_sleep_clock_accuracy, tvb, offset, 1, ENC_NA); - offset += 1; - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_CLOCK_ACCURACY_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + } + break; + case LL_CTRL_OPCODE_PERIODIC_SYNC_IND: + offset = dissect_periodic_sync_ind(tvb, btle_tree, offset, pinfo, interface_id, adapter_id); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + + /* Procedure completes in the same frame. */ + if (proc_info) { + proc_info->last_frame = pinfo->num; } - break; - case LL_CTRL_OPCODE_CIS_REQ: - offset = dissect_cis_req(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - control_opcode); - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + } + break; + case LL_CTRL_OPCODE_CLOCK_ACCURACY_REQ: + proto_tree_add_item(btle_tree, hf_control_sleep_clock_accuracy, tvb, offset, 1, ENC_NA); + offset += 1; + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } + break; + case LL_CTRL_OPCODE_CLOCK_ACCURACY_RSP: + proto_tree_add_item(btle_tree, hf_control_sleep_clock_accuracy, tvb, offset, 1, ENC_NA); + offset += 1; + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_CLOCK_ACCURACY_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_CIS_RSP: - offset = dissect_cis_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CIS_REQ, 1)) { - control_proc_add_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + } + break; + case LL_CTRL_OPCODE_CIS_REQ: + offset = dissect_cis_req(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + control_opcode); + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_CIS_IND: - if (!pinfo->fd->visited) { - connection_info_t *nconnection_info; - connection_parameter_info_t *connection_parameter_info; + } + break; + case LL_CTRL_OPCODE_CIS_RSP: + offset = dissect_cis_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CIS_REQ, 1)) { + control_proc_add_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); + } + } + break; + case LL_CTRL_OPCODE_CIS_IND: + if (!pinfo->fd->visited) { + connection_info_t *nconnection_info; + connection_parameter_info_t *connection_parameter_info; - connection_access_address = tvb_get_guint32(tvb, offset, ENC_LITTLE_ENDIAN); - - 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 = &connection_access_address; - key[3].length = 1; - key[3].key = &frame_number; - key[4].length = 0; - key[4].key = NULL; - - nconnection_info = wmem_new0(wmem_file_scope(), connection_info_t); - nconnection_info->interface_id = interface_id; - nconnection_info->adapter_id = adapter_id; - nconnection_info->access_address = connection_access_address; - - if (connection_info) { - memcpy(nconnection_info->master_bd_addr, connection_info->master_bd_addr, 6); - memcpy(nconnection_info->slave_bd_addr, connection_info->slave_bd_addr, 6); - } + connection_access_address = tvb_get_uint32(tvb, offset, ENC_LITTLE_ENDIAN); - /* We don't create control procedure context trees for BTLE_DIR_UNKNOWN, - * as the direction must be known for request/response matching. */ - nconnection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs = - wmem_tree_new(wmem_file_scope()); - nconnection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs = - wmem_tree_new(wmem_file_scope()); + 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 = &connection_access_address; + key[3].length = 1; + key[3].key = &pinfo->num; + key[4].length = 0; + key[4].key = NULL; - wmem_tree_insert32_array(connection_info_tree, key, nconnection_info); + nconnection_info = wmem_new0(wmem_file_scope(), connection_info_t); + nconnection_info->interface_id = interface_id; + nconnection_info->adapter_id = adapter_id; + nconnection_info->access_address = connection_access_address; - connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); - connection_parameter_info->parameters_frame = pinfo->num; + if (connection_info) { + memcpy(nconnection_info->central_bd_addr, connection_info->central_bd_addr, 6); + memcpy(nconnection_info->peripheral_bd_addr, connection_info->peripheral_bd_addr, 6); + } + + /* We don't create control procedure context trees for BTLE_DIR_UNKNOWN, + * as the direction must be known for request/response matching. */ + nconnection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs = + wmem_tree_new(wmem_file_scope()); + nconnection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs = + wmem_tree_new(wmem_file_scope()); + + wmem_tree_insert32_array(connection_info_tree, key, nconnection_info); + + connection_parameter_info = wmem_new0(wmem_file_scope(), connection_parameter_info_t); + connection_parameter_info->parameters_frame = pinfo->num; - key[3].length = 1; - key[3].key = &pinfo->num; - wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); + key[3].length = 1; + key[3].key = &pinfo->num; + wmem_tree_insert32_array(connection_parameter_info_tree, key, connection_parameter_info); + } + offset = dissect_cis_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + LL_CTRL_OPCODE_CIS_REQ, 2)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + 2); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - offset = dissect_cis_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - LL_CTRL_OPCODE_CIS_REQ, 2)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - last_control_proc[BTLE_DIR_SLAVE_MASTER], - 2); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } + } + break; + case LL_CTRL_OPCODE_CIS_TERMINATE_IND: + offset = dissect_cis_terminate_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + + /* Procedure completes in the same frame. */ + if (proc_info) { + proc_info->last_frame = pinfo->num; } - break; - case LL_CTRL_OPCODE_CIS_TERMINATE_IND: - offset = dissect_cis_terminate_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + } + break; + case LL_CTRL_OPCODE_POWER_CONTROL_REQ: + offset = dissect_power_control_req(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + } + break; + case LL_CTRL_OPCODE_POWER_CONTROL_RSP: + offset = dissect_power_control_rsp(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[other_direction], + LL_CTRL_OPCODE_POWER_CONTROL_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[other_direction], + last_control_proc[direction], + 1); + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); + } + } + break; + case LL_CTRL_OPCODE_POWER_CHANGE_IND: + offset = dissect_power_control_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + + /* Procedure completes in the same frame. */ + if (proc_info) { + proc_info->last_frame = pinfo->num; + } + } + break; + case LL_CTRL_OPCODE_SUBRATE_REQ: + offset = dissect_subrate_req(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + control_opcode); + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); + } + } + break; + case LL_CTRL_OPCODE_SUBRATE_IND: + offset = dissect_subrate_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (control_proc_can_add_frame(pinfo, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + LL_CTRL_OPCODE_SUBRATE_REQ, 1)) { + control_proc_add_last_frame(tvb, + pinfo, + btle_tree, + control_opcode, + direction, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + 1); + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { control_proc_info_t *proc_info; proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + control_opcode); /* Procedure completes in the same frame. */ if (proc_info) { proc_info->last_frame = pinfo->num; } + } else { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_POWER_CONTROL_REQ: - offset = dissect_power_control_req(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); - } - break; - case LL_CTRL_OPCODE_POWER_CONTROL_RSP: - offset = dissect_power_control_rsp(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[other_direction], - LL_CTRL_OPCODE_POWER_CONTROL_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[other_direction], - last_control_proc[direction], - 1); - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_POWER_CHANGE_IND: - offset = dissect_power_control_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + } + break; + case LL_CTRL_OPCODE_CHANNEL_REPORTING_IND: + offset = dissect_channel_reporting_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { control_proc_info_t *proc_info; proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + connection_info->direction_info[BTLE_DIR_CENTRAL_PERIPHERAL].control_procs, + last_control_proc[BTLE_DIR_PERIPHERAL_CENTRAL], + control_opcode); /* Procedure completes in the same frame. */ if (proc_info) { proc_info->last_frame = pinfo->num; } + } else if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - case LL_CTRL_OPCODE_SUBRATE_REQ: - offset = dissect_subrate_req(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (direction == BTLE_DIR_SLAVE_MASTER) { - control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - control_opcode); - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_SUBRATE_IND: - offset = dissect_subrate_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (control_proc_can_add_frame(pinfo, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - LL_CTRL_OPCODE_SUBRATE_REQ, 1)) { - control_proc_add_last_frame(tvb, - pinfo, - btle_tree, - control_opcode, - direction, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - last_control_proc[BTLE_DIR_MASTER_SLAVE], - 1); - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - control_opcode); - - /* Procedure completes in the same frame. */ - if (proc_info) { - proc_info->last_frame = pinfo->num; - } - } else { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_CHANNEL_REPORTING_IND: - offset = dissect_channel_reporting_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (direction == BTLE_DIR_MASTER_SLAVE) { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_MASTER_SLAVE].control_procs, - last_control_proc[BTLE_DIR_SLAVE_MASTER], - control_opcode); - - /* Procedure completes in the same frame. */ - if (proc_info) { - proc_info->last_frame = pinfo->num; - } - } else if (direction == BTLE_DIR_SLAVE_MASTER) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_CHANNEL_STATUS_IND: - offset = dissect_channel_status_ind(tvb, btle_tree, offset); - if (connection_info && !btle_frame_info->retransmit) { - if (direction == BTLE_DIR_SLAVE_MASTER) { - control_proc_info_t *proc_info; - proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[BTLE_DIR_SLAVE_MASTER].control_procs, - last_control_proc[BTLE_DIR_MASTER_SLAVE], - control_opcode); - - /* Procedure completes in the same frame. */ - if (proc_info) { - proc_info->last_frame = pinfo->num; - } - } else if (direction == BTLE_DIR_MASTER_SLAVE) { - expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); - } - } - break; - case LL_CTRL_OPCODE_PERIODIC_SYNC_WR_IND: - offset = dissect_periodic_sync_wr_ind(tvb, btle_tree, offset, pinfo, interface_id, adapter_id); - if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + } + break; + case LL_CTRL_OPCODE_CHANNEL_STATUS_IND: + offset = dissect_channel_status_ind(tvb, btle_tree, offset); + if (connection_info && !btle_frame_info->retransmit) { + if (direction == BTLE_DIR_PERIPHERAL_CENTRAL) { control_proc_info_t *proc_info; proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, - connection_info->direction_info[direction].control_procs, - last_control_proc[other_direction], - control_opcode); + connection_info->direction_info[BTLE_DIR_PERIPHERAL_CENTRAL].control_procs, + last_control_proc[BTLE_DIR_CENTRAL_PERIPHERAL], + control_opcode); /* Procedure completes in the same frame. */ if (proc_info) { proc_info->last_frame = pinfo->num; } + } else if (direction == BTLE_DIR_CENTRAL_PERIPHERAL) { + expert_add_info(pinfo, control_proc_item, &ei_control_proc_wrong_seq); } - break; - default: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - break; } - break; - - case 0x04: /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU */ - case 0x05: /* Unframed CIS Data PDU; start or continuation fragment of an SDU */ - case 0x06: /* Framed CIS Data PDU; one or more segments of an SDU */ - proto_tree_add_item(btle_tree, hf_isochronous_data, tvb, offset, length, ENC_NA); - offset += length; + case LL_CTRL_OPCODE_PERIODIC_SYNC_WR_IND: + offset = dissect_periodic_sync_wr_ind(tvb, btle_tree, offset, pinfo, interface_id, adapter_id); + if (connection_info && !btle_frame_info->retransmit && direction != BTLE_DIR_UNKNOWN) { + control_proc_info_t *proc_info; + proc_info = control_proc_start(tvb, pinfo, btle_tree, control_proc_item, + connection_info->direction_info[direction].control_procs, + last_control_proc[other_direction], + control_opcode); + + /* Procedure completes in the same frame. */ + if (proc_info) { + proc_info->last_frame = pinfo->num; + } + } break; - default: - if (tvb_reported_length_remaining(tvb, offset) > 3) { - proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - offset += tvb_reported_length_remaining(tvb, offset) - 3; - } + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + break; } - if (add_l2cap_index) { - item = proto_tree_add_uint(btle_tree, hf_l2cap_index, tvb, 0, 0, btle_frame_info->l2cap_index); - proto_item_set_generated(item); - } + break; - 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 = &access_address; - key[3].length = 0; - key[3].key = NULL; - wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_parameter_info_tree, key); - if (wmem_tree) { - connection_parameter_info_t *connection_parameter_info; + case 0x04: /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU */ + case 0x05: /* Unframed CIS Data PDU; start or continuation fragment of an SDU */ + case 0x06: /* Framed CIS Data PDU; one or more segments of an SDU */ + proto_tree_add_item(btle_tree, hf_isochronous_data, tvb, offset, length, ENC_NA); + offset += length; + break; - if (connection_info && connection_info->connection_parameter_update_info != NULL && - btle_context && btle_context->event_counter_valid) { - if ( ((gint16)btle_context->event_counter - connection_info->connection_parameter_update_instant) >= 0) { - wmem_tree_insert32(wmem_tree, pinfo->num, connection_info->connection_parameter_update_info); - connection_info->connection_parameter_update_info = NULL; - } - } + default: + if (tvb_reported_length_remaining(tvb, offset) > 3) { + proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + offset += tvb_reported_length_remaining(tvb, offset) - 3; + } + } + + if (add_l2cap_index) { + item = proto_tree_add_uint(btle_tree, hf_l2cap_index, tvb, 0, 0, btle_frame_info->l2cap_index); + proto_item_set_generated(item); + } - connection_parameter_info = (connection_parameter_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); - if (connection_parameter_info) { - item = proto_tree_add_uint(btle_tree, hf_connection_parameters_in, tvb, 0, 0, connection_parameter_info->parameters_frame); - proto_item_set_generated(item); + 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 = &access_address; + key[3].length = 0; + key[3].key = NULL; + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(connection_parameter_info_tree, key); + if (wmem_tree) { + connection_parameter_info_t *connection_parameter_info; + + if (connection_info && connection_info->connection_parameter_update_info != NULL && + btle_context && btle_context->event_counter_valid) { + if ( ((int16_t)btle_context->event_counter - connection_info->connection_parameter_update_instant) >= 0) { + wmem_tree_insert32(wmem_tree, pinfo->num, connection_info->connection_parameter_update_info); + connection_info->connection_parameter_update_info = NULL; } } - if ((crc_status == CRC_INDETERMINATE) && - btle_context && btle_context->connection_info_valid) { - /* the surrounding context has provided CRCInit */ - crc_init = btle_context->connection_info.CRCInit; - crc_status = CRC_CAN_BE_CALCULATED; + connection_parameter_info = (connection_parameter_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); + if (connection_parameter_info) { + item = proto_tree_add_uint(btle_tree, hf_connection_parameters_in, tvb, 0, 0, connection_parameter_info->parameters_frame); + proto_item_set_generated(item); } - } else if (btle_pdu_type == BTLE_PDU_TYPE_BROADCASTISO) { - broadcastiso_connection_info_t *broadcastiso_connection_info = NULL; - guint32 seed_access_address = access_address & 0x0041ffff; - proto_item *data_header_item; - proto_tree *data_header_tree; - guint8 llid; - guint8 control_opcode; - - 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 = &seed_access_address; - key[3].length = 0; - key[3].key = NULL; - - wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(broadcastiso_connection_info_tree, key); - if (wmem_tree) { - broadcastiso_connection_info = (broadcastiso_connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); - if (broadcastiso_connection_info) { - gchar *str_addr_src; - /* Holds "Master" + access_address + NULL, which is the longest string */ - int str_addr_len = 17 + 1; - - str_addr_src = (gchar *) wmem_alloc(pinfo->pool, str_addr_len); + } - sub_item = proto_tree_add_ether(btle_tree, hf_master_bd_addr, tvb, 0, 0, broadcastiso_connection_info->master_bd_addr); - proto_item_set_generated(sub_item); + return offset; +} - snprintf(str_addr_src, str_addr_len, "Master_0x%08x", broadcastiso_connection_info->access_address); - set_address(&pinfo->dl_src, AT_ETHER, sizeof(broadcastiso_connection_info->master_bd_addr), broadcastiso_connection_info->master_bd_addr); - clear_address(&pinfo->dl_dst); +static int +dissect_btle_broadcast_iso(tvbuff_t *tvb, + packet_info *pinfo, + proto_tree *btle_tree, + uint32_t adapter_id, + uint32_t interface_id, + uint32_t access_address) +{ + proto_item *sub_item; + proto_tree *sub_tree; + int offset = 0; + uint32_t length; + static const uint8_t broadcast_addr[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + wmem_tree_t *wmem_tree; + wmem_tree_key_t key[5]; - set_address(&pinfo->net_src, AT_STRINGZ, (int)strlen(str_addr_src)+1, str_addr_src); - copy_address_shallow(&pinfo->src, &pinfo->net_src); + proto_item *item; + unsigned item_value; + + broadcastiso_connection_info_t *broadcastiso_connection_info = NULL; + uint32_t seed_access_address = access_address & 0x0041ffff; + proto_item *data_header_item; + proto_tree *data_header_tree; + uint8_t llid; + uint8_t control_opcode; + + 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 = &seed_access_address; + key[3].length = 0; + key[3].key = NULL; + + wmem_tree = (wmem_tree_t *) wmem_tree_lookup32_array(broadcastiso_connection_info_tree, key); + if (wmem_tree) { + broadcastiso_connection_info = (broadcastiso_connection_info_t *) wmem_tree_lookup32_le(wmem_tree, pinfo->num); + if (broadcastiso_connection_info) { + char *str_addr_src; + /* Holds "Central" + access_address + NULL, which is the longest string */ + int str_addr_len = 17 + 1; + + str_addr_src = (char *) wmem_alloc(pinfo->pool, str_addr_len); + + sub_item = proto_tree_add_ether(btle_tree, hf_central_bd_addr, tvb, 0, 0, broadcastiso_connection_info->central_bd_addr); + proto_item_set_generated(sub_item); + + snprintf(str_addr_src, str_addr_len, "Central_0x%08x", broadcastiso_connection_info->access_address); + set_address(&pinfo->dl_src, AT_ETHER, sizeof(broadcastiso_connection_info->central_bd_addr), broadcastiso_connection_info->central_bd_addr); + clear_address(&pinfo->dl_dst); + + set_address(&pinfo->net_src, AT_STRINGZ, (int)strlen(str_addr_src)+1, str_addr_src); + copy_address_shallow(&pinfo->src, &pinfo->net_src); - if (!pinfo->fd->visited) { - address *addr; + 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_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); } } + } - set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); - copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); - copy_address_shallow(&pinfo->dst, &pinfo->net_dst); + set_address(&pinfo->net_dst, AT_ETHER, 6, broadcast_addr); + copy_address_shallow(&pinfo->dl_dst, &pinfo->net_dst); + copy_address_shallow(&pinfo->dst, &pinfo->net_dst); - data_header_item = proto_tree_add_item(btle_tree, hf_data_header, tvb, offset, 2, ENC_NA); - data_header_tree = proto_item_add_subtree(data_header_item, ett_data_header); + data_header_item = proto_tree_add_item(btle_tree, hf_data_header, tvb, offset, 2, ENC_NA); + data_header_tree = proto_item_add_subtree(data_header_item, ett_data_header); - proto_tree_add_item(data_header_tree, hf_data_header_llid_broadcastiso, tvb, offset, 1, ENC_LITTLE_ENDIAN); - llid = tvb_get_guint8(tvb, offset) & 0x03; - proto_tree_add_item(data_header_tree, hf_data_header_control_subevent_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_control_subevent_transmission_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN); - proto_tree_add_item(data_header_tree, hf_data_header_rfu_67, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; + proto_tree_add_item(data_header_tree, hf_data_header_llid_broadcastiso, tvb, offset, 1, ENC_LITTLE_ENDIAN); + llid = tvb_get_uint8(tvb, offset) & 0x03; + proto_tree_add_item(data_header_tree, hf_data_header_control_subevent_sequence_number, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_control_subevent_transmission_flag, tvb, offset, 1, ENC_LITTLE_ENDIAN); + proto_tree_add_item(data_header_tree, hf_data_header_rfu_67, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + + proto_tree_add_item(data_header_tree, hf_data_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); + item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); + proto_item_set_hidden(item); + offset += 1; - proto_tree_add_item(data_header_tree, hf_data_header_length, tvb, offset, 1, ENC_LITTLE_ENDIAN); - item = proto_tree_add_item_ret_uint(btle_tree, hf_length, tvb, offset, 1, ENC_LITTLE_ENDIAN, &length); - proto_item_set_hidden(item); + switch (llid) { + case 0x00: /* Unframed BIS Data PDU; end fragment of an SDU or a complete SDU */ + case 0x01: /* Unframed BIS Data PDU; start or continuation fragment of an SDU */ + case 0x02: /* Framed BIS Data PDU; one or more segments of an SDU */ + proto_tree_add_item(btle_tree, hf_isochronous_data, tvb, offset, length, ENC_NA); + offset += length; + break; + + case 0x03: /* BIG Control PDU */ + proto_tree_add_item(btle_tree, hf_big_control_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); + control_opcode = tvb_get_uint8(tvb, offset); offset += 1; - switch (llid) { - case 0x00: /* Unframed BIS Data PDU; end fragment of an SDU or a complete SDU */ - case 0x01: /* Unframed BIS Data PDU; start or continuation fragment of an SDU */ - case 0x02: /* Framed BIS Data PDU; one or more segments of an SDU */ - proto_tree_add_item(btle_tree, hf_isochronous_data, tvb, offset, length, ENC_NA); - offset += length; + col_add_fstr(pinfo->cinfo, COL_INFO, "BIG Control Opcode: %s", + val_to_str_ext_const(control_opcode, &big_control_opcode_vals_ext, "Unknown")); + + switch (control_opcode) { + case 0x00: /* BIG_CHANNEL_MAP_IND */ + sub_item = proto_tree_add_item(btle_tree, hf_control_channel_map, tvb, offset, 5, ENC_NA); + sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + + call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); + offset += 5; + + proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + offset += 2; break; - case 0x03: /* BIG Control PDU */ - proto_tree_add_item(btle_tree, hf_big_control_opcode, tvb, offset, 1, ENC_LITTLE_ENDIAN); - control_opcode = tvb_get_guint8(tvb, offset); + case 0x01: /* BIG_TERMINATE_IND */ + proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); offset += 1; + proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); + offset += 2; + break; + + default: + offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); + break; + } + break; - col_add_fstr(pinfo->cinfo, COL_INFO, "BIG Control Opcode: %s", - val_to_str_ext_const(control_opcode, &big_control_opcode_vals_ext, "Unknown")); + default: + if (tvb_reported_length_remaining(tvb, offset) > 3) { + proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); + offset += tvb_reported_length_remaining(tvb, offset) - 3; + } + } - switch (control_opcode) { - case 0x00: /* BIG_CHANNEL_MAP_IND */ - sub_item = proto_tree_add_item(btle_tree, hf_control_channel_map, tvb, offset, 5, ENC_NA); - sub_tree = proto_item_add_subtree(sub_item, ett_channel_map); + return offset; +} - call_dissector(btcommon_le_channel_map_handle, tvb_new_subset_length(tvb, offset, 5), pinfo, sub_tree); - offset += 5; +static int +dissect_btle(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) +{ + proto_item *btle_item; + proto_tree *btle_tree; + proto_item *sub_item; + int offset = 0; + uint32_t access_address, length; + tvbuff_t *next_tvb; + connection_info_t *connection_info = NULL; - proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - offset += 2; - break; + uint8_t btle_pdu_type = BTLE_PDU_TYPE_UNKNOWN; - case 0x01: /* BIG_TERMINATE_IND */ - proto_tree_add_item(btle_tree, hf_control_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN); - offset += 1; - proto_tree_add_item_ret_uint(btle_tree, hf_control_instant, tvb, offset, 2, ENC_LITTLE_ENDIAN, &item_value); - offset += 2; - break; + uint32_t interface_id; + uint32_t adapter_id; + const btle_context_t *btle_context = get_btle_context(pinfo, + data, + &adapter_id, + &interface_id); - default: - offset = dissect_ctrl_pdu_without_data(tvb, pinfo, btle_tree, offset); - break; - } - break; + col_set_str(pinfo->cinfo, COL_PROTOCOL, "LE LL"); + + btle_item = proto_tree_add_item(tree, proto_btle, tvb, offset, -1, ENC_NA); + btle_tree = proto_item_add_subtree(btle_item, ett_btle); + sub_item = proto_tree_add_item(btle_tree, hf_access_address, tvb, offset, 4, ENC_LITTLE_ENDIAN); + access_address = tvb_get_letohl(tvb, offset); + if (btle_context) { + switch(btle_context->aa_category) { + case E_AA_MATCHED: + expert_add_info(pinfo, sub_item, &ei_access_address_matched); + break; + case E_AA_ILLEGAL: + expert_add_info(pinfo, sub_item, &ei_access_address_illegal); + break; + case E_AA_BIT_ERRORS: + expert_add_info(pinfo, sub_item, &ei_access_address_bit_errors); + break; default: - if (tvb_reported_length_remaining(tvb, offset) > 3) { - proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - offset += tvb_reported_length_remaining(tvb, offset) - 3; - } + break; } + } + offset += 4; + + if (btle_context && btle_context->phy == LE_CODED_PHY) { + proto_tree_add_item(btle_tree, hf_coding_indicator, tvb, offset, 1, ENC_LITTLE_ENDIAN); + offset += 1; + } + + if (btle_context) { + btle_pdu_type = btle_context->pdu_type; + } + + if (btle_pdu_type == BTLE_PDU_TYPE_UNKNOWN) { + /* No context to provide us with physical channel pdu type, make an assumption from the access address */ + btle_pdu_type = guess_btle_pdu_type_from_access(interface_id, + adapter_id, + access_address); + } + if (btle_pdu_type == BTLE_PDU_TYPE_ADVERTISING) { + next_tvb = tvb_new_subset_remaining(tvb, offset); + length = dissect_btle_adv(next_tvb, + pinfo, + btle_tree, + btle_context, + adapter_id, + interface_id, + access_address) - 2; + offset += length + 2; + } else if (btle_pdu_type == BTLE_PDU_TYPE_DATA || btle_pdu_type == BTLE_PDU_TYPE_CONNECTEDISO) { + next_tvb = tvb_new_subset_remaining(tvb, offset); + length = dissect_btle_acl_or_iso(next_tvb, + pinfo, + tree, + btle_tree, + btle_context, + adapter_id, + interface_id, + access_address, + btle_pdu_type) - 2; + offset += length + 2; + } else if (btle_pdu_type == BTLE_PDU_TYPE_BROADCASTISO) { + next_tvb = tvb_new_subset_remaining(tvb, offset); + length = dissect_btle_broadcast_iso(next_tvb, + pinfo, + btle_tree, + adapter_id, + interface_id, + access_address) - 2; + offset += length + 2; } else { - /* Unknown physical channel PDU type */ + /* Unknown physical channel PDU type. Assume CRC size is 3 bytes */ if (tvb_reported_length_remaining(tvb, offset) > 3) { proto_tree_add_expert(btle_tree, pinfo, &ei_unknown_data, tvb, offset, tvb_reported_length_remaining(tvb, offset) - 3); - offset += tvb_reported_length_remaining(tvb, offset) - 3; + length = tvb_reported_length_remaining(tvb, offset) - 3; + offset += length; + } else { + /* Length is unknown. */ + length = 0; } } - /* BT spec Vol 6, Part B, Section 1.2: CRC is big endian and bits in byte are flipped */ - packet_crc = reverse_bits_per_byte(tvb_get_ntoh24(tvb, offset)); - sub_item = proto_tree_add_uint(btle_tree, hf_crc, tvb, offset, 3, packet_crc); - offset += 3; - if (crc_status == CRC_CAN_BE_CALCULATED) { - guint32 crc = btle_crc(tvb, length, crc_init); - crc_status = (packet_crc == crc) ? CRC_CORRECT : CRC_INCORRECT; - } - switch(crc_status) { - case CRC_INDETERMINATE: - expert_add_info(pinfo, sub_item, &ei_crc_cannot_be_determined); - break; - case CRC_INCORRECT: - expert_add_info(pinfo, sub_item, &ei_crc_incorrect); - break; - case CRC_CORRECT: - default: - break; - } + offset += dissect_crc(tvb, + btle_tree, + offset, + pinfo, + length, + connection_info, + btle_context, + access_address); return offset; } @@ -4430,13 +4619,13 @@ proto_register_btle(void) FT_UINT8, BASE_DEC, VALS(le_coding_indicators), 0x3, NULL, HFILL } }, - { &hf_master_bd_addr, - { "Master Address", "btle.master_bd_addr", + { &hf_central_bd_addr, + { "Central Address", "btle.central_bd_addr", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, - { &hf_slave_bd_addr, - { "Slave Address", "btle.slave_bd_addr", + { &hf_peripheral_bd_addr, + { "Peripheral Address", "btle.peripheral_bd_addr", FT_ETHER, BASE_NONE, NULL, 0x0, NULL, HFILL } }, @@ -4516,7 +4705,7 @@ proto_register_btle(void) NULL, HFILL } }, { &hf_scan_response_data, - { "Scan Response Data", "btle.scan_responce_data", + { "Scan Response Data", "btle.scan_response_data", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL } }, @@ -4726,7 +4915,7 @@ proto_register_btle(void) NULL, HFILL } }, { &hf_extended_advertising_sync_info_reserved, - { "Reserved", "btle.extended_advertising_header.sync_info.offset_units", + { "Reserved", "btle.extended_advertising_header.sync_info.reserved", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL } }, @@ -4762,7 +4951,7 @@ proto_register_btle(void) }, { &hf_extended_advertising_tx_power, { "TX Power", "btle.extended_advertising_header.tx_power", - FT_INT8, BASE_DEC | BASE_UNIT_STRING, &units_dbm, 0x0, + FT_INT8, BASE_DEC | BASE_UNIT_STRING, UNS(&units_dbm), 0x0, NULL, HFILL } }, { &hf_extended_advertising_header_acad, @@ -4925,8 +5114,8 @@ proto_register_btle(void) FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } }, - { &hf_control_feature_set_slave_initiated_features_exchange, - { "Slave Initiated Features Exchange", "btle.control.feature_set.slave_initiated_features_exchange", + { &hf_control_feature_set_peripheral_initiated_features_exchange, + { "Peripheral Initiated Features Exchange", "btle.control.feature_set.peripheral_initiated_features_exchange", FT_BOOLEAN, 8, NULL, 0x08, NULL, HFILL } }, @@ -5240,23 +5429,23 @@ proto_register_btle(void) FT_UINT16, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_master_session_key_diversifier, - { "Master Session Key Diversifier", "btle.control.master_session_key_diversifier", + { &hf_control_central_session_key_diversifier, + { "Central Session Key Diversifier", "btle.control.central_session_key_diversifier", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_slave_session_key_diversifier, - { "Slave Session Key Diversifier", "btle.control.slave_session_key_diversifier", + { &hf_control_peripheral_session_key_diversifier, + { "Peripheral Session Key Diversifier", "btle.control.peripheral_session_key_diversifier", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_master_session_initialization_vector, - { "Master Session Initialization Vector", "btle.control.master_session_initialization_vector", + { &hf_control_central_session_initialization_vector, + { "Central Session Initialization Vector", "btle.control.central_session_initialization_vector", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_slave_session_initialization_vector, - { "Slave Session Initialization Vector", "btle.control.slave_session_initialization_vector", + { &hf_control_peripheral_session_initialization_vector, + { "Peripheral Session Initialization Vector", "btle.control.peripheral_session_initialization_vector", FT_UINT64, BASE_DEC_HEX, NULL, 0x0, NULL, HFILL } }, @@ -5267,7 +5456,7 @@ proto_register_btle(void) }, { &hf_control_max_rx_time, { "Max RX time", "btle.control.max_rx_time", - FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_microsecond_microseconds, 0x0, + FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microsecond_microseconds), 0x0, NULL, HFILL } }, { &hf_control_max_tx_octets, @@ -5277,7 +5466,7 @@ proto_register_btle(void) }, { &hf_control_max_tx_time, { "Max TX time", "btle.control.max_tx_time", - FT_UINT16, BASE_DEC|BASE_UNIT_STRING, &units_microsecond_microseconds, 0x0, + FT_UINT16, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microsecond_microseconds), 0x0, NULL, HFILL } }, { &hf_control_phys_sender_le_1m_phy, @@ -5325,52 +5514,52 @@ proto_register_btle(void) FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_m_to_s_phy, - { "Master to Slave PHY", "btle.control.m_to_s_phy", + { &hf_control_c_to_p_phy, + { "Central to Peripheral PHY", "btle.control.m_to_s_phy", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_m_to_s_phy_le_1m_phy, + { &hf_control_c_to_p_phy_le_1m_phy, { "LE 1M PHY", "btle.control.m_to_s_phy.le_1m_phy", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } }, - { &hf_control_m_to_s_phy_le_2m_phy, + { &hf_control_c_to_p_phy_le_2m_phy, { "LE 2M PHY", "btle.control.m_to_s_phy.le_2m_phy", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL } }, - { &hf_control_m_to_s_phy_le_coded_phy, + { &hf_control_c_to_p_phy_le_coded_phy, { "LE Coded PHY", "btle.control.m_to_s_phy.le_coded_phy", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } }, - { &hf_control_m_to_s_phy_reserved_bits, + { &hf_control_c_to_p_phy_reserved_bits, { "Reserved for future use", "btle.control.m_to_s_phy.reserved", FT_UINT8, BASE_DEC, NULL, 0xF8, NULL, HFILL } }, - { &hf_control_s_to_m_phy, - { "Slave to Master PHY", "btle.control.s_to_m_phy", + { &hf_control_p_to_c_phy, + { "Peripheral to Central PHY", "btle.control.s_to_m_phy", FT_UINT8, BASE_HEX, NULL, 0x0, NULL, HFILL } }, - { &hf_control_s_to_m_phy_le_1m_phy, + { &hf_control_p_to_c_phy_le_1m_phy, { "LE 1M PHY", "btle.control.s_to_m_phy.le_1m_phy", FT_BOOLEAN, 8, NULL, 0x01, NULL, HFILL } }, - { &hf_control_s_to_m_phy_le_2m_phy, + { &hf_control_p_to_c_phy_le_2m_phy, { "LE 2M PHY", "btle.control.s_to_m_phy.le_2m_phy", FT_BOOLEAN, 8, NULL, 0x02, NULL, HFILL } }, - { &hf_control_s_to_m_phy_le_coded_phy, + { &hf_control_p_to_c_phy_le_coded_phy, { "LE Coded PHY", "btle.control.s_to_m_phy.le_coded_phy", FT_BOOLEAN, 8, NULL, 0x04, NULL, HFILL } }, - { &hf_control_s_to_m_phy_reserved_bits, + { &hf_control_p_to_c_phy_reserved_bits, { "Reserved for future use", "btle.control.s_to_m_phy.reserved", FT_UINT8, BASE_DEC, NULL, 0xF8, NULL, HFILL } @@ -5436,7 +5625,7 @@ proto_register_btle(void) NULL, HFILL } }, { &hf_control_sync_info_reserved, - { "Reserved", "btle.control.sync_info.offset_units", + { "Reserved", "btle.control.sync_info.reserved", FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL } }, @@ -5515,8 +5704,8 @@ proto_register_btle(void) FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_control_max_sdu_m_to_s, - { "Max_SDU_M_To_S", "btle.control.max_sdu_m_to_s", + { &hf_control_max_sdu_c_to_p, + { "Max_SDU_C_To_P", "btle.control.max_sdu_c_to_p", FT_UINT16, BASE_DEC, NULL, 0x0fff, NULL, HFILL } }, @@ -5530,8 +5719,8 @@ proto_register_btle(void) FT_BOOLEAN, 16, NULL, 0x8000, NULL, HFILL } }, - { &hf_control_max_sdu_s_to_m, - { "Max_SDU_S_To_M", "btle.control.max_sdu_s_to_m", + { &hf_control_max_sdu_p_to_c, + { "Max_SDU_P_To_C", "btle.control.max_sdu_p_to_c", FT_UINT16, BASE_DEC, NULL, 0x0fff, NULL, HFILL } }, @@ -5540,9 +5729,9 @@ proto_register_btle(void) FT_UINT16, BASE_DEC, NULL, 0xf000, "Reserved for Future Use", HFILL } }, - { &hf_control_sdu_interval_m_to_s, - { "SDU_Interval_M_To_S", "btle.control.sdu_interval_m_to_s", - FT_UINT24, BASE_DEC|BASE_UNIT_STRING, &units_microsecond_microseconds, 0x0fffff, + { &hf_control_sdu_interval_c_to_p, + { "SDU_Interval_C_To_P", "btle.control.sdu_interval_c_to_p", + FT_UINT24, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microsecond_microseconds), 0x0fffff, NULL, HFILL } }, { &hf_control_rfu_3, @@ -5550,9 +5739,9 @@ proto_register_btle(void) FT_UINT24, BASE_DEC, NULL, 0xf00000, "Reserved for Future Use", HFILL } }, - { &hf_control_sdu_interval_s_to_m, - { "SDU_Interval_S_To_M", "btle.control.sdu_interval_s_to_m", - FT_UINT24, BASE_DEC|BASE_UNIT_STRING, &units_microsecond_microseconds, 0x0fffff, + { &hf_control_sdu_interval_p_to_c, + { "SDU_Interval_P_To_C", "btle.control.sdu_interval_p_to_c", + FT_UINT24, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microsecond_microseconds), 0x0fffff, NULL, HFILL } }, { &hf_control_rfu_4, @@ -5560,13 +5749,13 @@ proto_register_btle(void) FT_UINT24, BASE_DEC, NULL, 0xf00000, "Reserved for Future Use", HFILL } }, - { &hf_control_max_pdu_m_to_s, - { "Max_PDU_M_To_S", "btle.control.max_pdu_m_to_s", + { &hf_control_max_pdu_c_to_p, + { "Max_PDU_C_To_P", "btle.control.max_pdu_c_to_p", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_control_max_pdu_s_to_m, - { "Max_PDU_S_To_M", "btle.control.max_pdu_s_to_m", + { &hf_control_max_pdu_p_to_c, + { "Max_PDU_P_To_C", "btle.control.max_pdu_p_to_c", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL } }, @@ -5577,26 +5766,26 @@ proto_register_btle(void) }, { &hf_control_sub_interval, { "Sub_Interval", "btle.control.sub_interval", - FT_UINT24, BASE_DEC|BASE_UNIT_STRING, &units_microsecond_microseconds, 0x0, + FT_UINT24, BASE_DEC|BASE_UNIT_STRING, UNS(&units_microsecond_microseconds), 0x0, NULL, HFILL } }, - { &hf_control_bn_m_to_s, - { "BN_M_To_S", "btle.control.bn_m_to_s", + { &hf_control_bn_c_to_p, + { "BN_C_To_P", "btle.control.bn_c_to_p", FT_UINT8, BASE_DEC, NULL, 0x0f, NULL, HFILL } }, - { &hf_control_bn_s_to_m, - { "BN_S_To_M", "btle.control.bn_s_to_m", + { &hf_control_bn_p_to_c, + { "BN_P_To_C", "btle.control.bn_p_to_c", FT_UINT8, BASE_DEC, NULL, 0xf0, NULL, HFILL } }, - { &hf_control_ft_m_to_s, - { "FT_M_To_S", "btle.control.ft_m_to_s", + { &hf_control_ft_c_to_p, + { "FT_C_To_P", "btle.control.ft_c_to_p", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, - { &hf_control_ft_s_to_m, - { "FT_S_To_M", "btle.control.ft_s_to_m", + { &hf_control_ft_p_to_c, + { "FT_P_To_C", "btle.control.ft_p_to_c", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL } }, @@ -5952,7 +6141,7 @@ proto_register_btle(void) { "btle.nack", PI_SEQUENCE, PI_NOTE, "Not acknowledged", EXPFILL }}, }; - static gint *ett[] = { + static int *ett[] = { &ett_btle, &ett_advertising_header, &ett_link_layer_data, @@ -5968,8 +6157,8 @@ proto_register_btle(void) &ett_features, &ett_tx_phys, &ett_rx_phys, - &ett_m_to_s_phy, - &ett_s_to_m_phy, + &ett_c_to_p_phy, + &ett_p_to_c_phy, &ett_phys, &ett_pwr_phy, &ett_cte, @@ -5983,6 +6172,7 @@ proto_register_btle(void) }; connection_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); + periodic_adv_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); broadcastiso_connection_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); connection_parameter_info_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); adi_to_first_frame_tree = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope()); |