wireshark/epan/dissectors/packet-btatt.c
Michal Labedzki dac7cf9f8c Bluetooth: Add generic UUID table for DecodeBy
Replace L2CAP Service, RFCOMM Service and AVCTP PID dissector table
by shared Bluetooth Service UUID table. It also supports UUID16,
UUID32 and UUID128 by hex-string, like for AVRCP: "110e".

Change-Id: I473bc73d10939e8ed6dd55a6a92387c7a1ec125a
Reviewed-on: https://code.wireshark.org/review/9678
Reviewed-by: Michal Labedzki <michal.labedzki@tieto.com>
2015-07-17 08:06:40 +00:00

4966 lines
187 KiB
C

/* packet-btatt.c
* Routines for Bluetooth Attribute Protocol dissection
*
* Copyright 2012, Allan M. Madsen <allan.m@madsen.dk>
* Copyright 2015, Michal Labedzki for Tieto Corporation
* - dissect GATT level attributes
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <glib.h>
#include <glib/gprintf.h>
#include <epan/packet.h>
#include <epan/prefs.h>
#include <epan/expert.h>
#include <epan/oui.h>
#include <epan/decode_as.h>
#include <epan/tap.h>
#include "packet-bluetooth.h"
#include "packet-btatt.h"
#include "packet-btl2cap.h"
#include "packet-btsdp.h"
#include "packet-usb-hid.h"
/* Initialize the protocol and registered fields */
static int proto_btatt = -1;
static int hf_btatt_opcode = -1;
static int hf_btatt_handle = -1;
static int hf_btatt_starting_handle = -1;
static int hf_btatt_ending_handle = -1;
static int hf_btatt_group_end_handle = -1;
static int hf_btatt_value = -1;
static int hf_btatt_req_opcode_in_error = -1;
static int hf_btatt_handle_in_error = -1;
static int hf_btatt_error_code = -1;
static int hf_btatt_uuid16 = -1;
static int hf_btatt_uuid128 = -1;
static int hf_btatt_client_rx_mtu = -1;
static int hf_btatt_server_rx_mtu = -1;
static int hf_btatt_uuid_format = -1;
static int hf_btatt_length = -1;
static int hf_btatt_offset = -1;
static int hf_btatt_flags = -1;
static int hf_btatt_sign_counter = -1;
static int hf_btatt_signature = -1;
static int hf_btatt_attribute_data = -1;
static int hf_btatt_handles_info = -1;
static int hf_btatt_opcode_authentication_signature = -1;
static int hf_btatt_opcode_command = -1;
static int hf_btatt_opcode_method = -1;
static int hf_btatt_characteristic_properties = -1;
static int hf_btatt_characteristic_value_handle = -1;
static int hf_btatt_characteristic_properties_extended_properties = -1;
static int hf_btatt_characteristic_properties_authenticated_signed_writes = -1;
static int hf_btatt_characteristic_properties_indicate = -1;
static int hf_btatt_characteristic_properties_notify = -1;
static int hf_btatt_characteristic_properties_write = -1;
static int hf_btatt_characteristic_properties_write_without_response = -1;
static int hf_btatt_characteristic_properties_read = -1;
static int hf_btatt_characteristic_properties_broadcast = -1;
static int hf_btatt_information_data = -1;
static int hf_btatt_included_service_handle = -1;
static int hf_btatt_characteristic_configuration_client = -1;
static int hf_btatt_characteristic_configuration_client_reserved = -1;
static int hf_btatt_characteristic_configuration_client_indication = -1;
static int hf_btatt_characteristic_configuration_client_notification = -1;
static int hf_btatt_characteristic_configuration_server = -1;
static int hf_btatt_characteristic_configuration_server_reserved = -1;
static int hf_btatt_characteristic_configuration_server_broadcast = -1;
static int hf_btatt_hogp_protocol_mode = -1;
static int hf_btatt_hogp_bcd_hid = -1;
static int hf_btatt_hogp_b_country_code = -1;
static int hf_btatt_hogp_flags = -1;
static int hf_btatt_hogp_flags_reserved = -1;
static int hf_btatt_hogp_flags_normally_connectable = -1;
static int hf_btatt_hogp_flags_remote_wake = -1;
static int hf_btatt_hogp_hid_control_point_command = -1;
static int hf_btatt_report_reference_report_id = -1;
static int hf_btatt_report_reference_report_type = -1;
static int hf_btatt_characteristic_user_description = -1;
static int hf_btatt_characteristic_extended_properties = -1;
static int hf_btatt_characteristic_extended_properties_reserved = -1;
static int hf_btatt_characteristic_extended_properties_writable_auxiliaries = -1;
static int hf_btatt_characteristic_extended_properties_reliable_write = -1;
static int hf_btatt_characteristic_presentation_format = -1;
static int hf_btatt_characteristic_presentation_exponent = -1;
static int hf_btatt_characteristic_presentation_unit = -1;
static int hf_btatt_characteristic_presentation_namespace = -1;
static int hf_btatt_characteristic_presentation_namespace_description_btsig = -1;
static int hf_btatt_characteristic_presentation_namespace_description = -1;
static int hf_btatt_esp_trigger_logic = -1;
static int hf_btatt_esp_condition = -1;
static int hf_btatt_esp_operand = -1;
static int hf_btatt_esp_flags = -1;
static int hf_btatt_esp_sampling_function = -1;
static int hf_btatt_esp_measurement_period = -1;
static int hf_btatt_esp_update_interval = -1;
static int hf_btatt_esp_application = -1;
static int hf_btatt_esp_measurement_uncertainty = -1;
static int hf_btatt_device_name = -1;
static int hf_btatt_appearance = -1;
static int hf_btatt_appearance_category = -1;
static int hf_btatt_appearance_subcategory = -1;
static int hf_btatt_appearance_subcategory_watch = -1;
static int hf_btatt_appearance_subcategory_thermometer = -1;
static int hf_btatt_appearance_subcategory_heart_rate = -1;
static int hf_btatt_appearance_subcategory_blood_pressure = -1;
static int hf_btatt_appearance_subcategory_hid = -1;
static int hf_btatt_appearance_subcategory_running_walking_sensor = -1;
static int hf_btatt_appearance_subcategory_cycling = -1;
static int hf_btatt_appearance_subcategory_pulse_oximeter = -1;
static int hf_btatt_appearance_subcategory_outdoor_sports_activity = -1;
static int hf_btatt_peripheral_privacy_flag = -1;
static int hf_btatt_minimum_connection_interval = -1;
static int hf_btatt_maximum_connection_interval = -1;
static int hf_btatt_slave_latency = -1;
static int hf_btatt_connection_supervision_timeout_multiplier = -1;
static int hf_btatt_reconnection_address = -1;
static int hf_btatt_alert_level = -1;
static int hf_btatt_tx_power_level = -1;
static int hf_btatt_year = -1;
static int hf_btatt_month = -1;
static int hf_btatt_day = -1;
static int hf_btatt_hours = -1;
static int hf_btatt_minutes = -1;
static int hf_btatt_seconds = -1;
static int hf_btatt_day_of_week = -1;
static int hf_btatt_fractions256 = -1;
static int hf_btatt_dst_offset = -1;
static int hf_btatt_model_number_string = -1;
static int hf_btatt_serial_number_string = -1;
static int hf_btatt_firmware_revision_string = -1;
static int hf_btatt_hardware_revision_string = -1;
static int hf_btatt_software_revision_string = -1;
static int hf_btatt_manufacturer_string = -1;
static int hf_btatt_system_id_manufacturer_identifier = -1;
static int hf_btatt_system_id_organizationally_unique_identifier = -1;
static int hf_btatt_timezone = -1;
static int hf_btatt_time_accuracy = -1;
static int hf_btatt_time_source = -1;
static int hf_btatt_time_days_since_update = -1;
static int hf_btatt_time_hours_since_update = -1;
static int hf_btatt_time_update_control_point = -1;
static int hf_btatt_time_current_state = -1;
static int hf_btatt_time_result = -1;
static int hf_btatt_battery_level = -1;
static int hf_btatt_temperature_type = -1;
static int hf_btatt_measurement_interval = -1;
static int hf_btatt_time_adjust_reason = -1;
static int hf_btatt_time_adjust_reason_reserved = -1;
static int hf_btatt_time_adjust_reason_change_of_dst = -1;
static int hf_btatt_time_adjust_reason_change_of_timezone = -1;
static int hf_btatt_time_adjust_reason_external_reference_time_update = -1;
static int hf_btatt_time_adjust_reason_manual_time_update = -1;
static int hf_btatt_magnetic_declination = -1;
static int hf_btatt_scan_refresh = -1;
static int hf_btatt_body_sensor_location = -1;
static int hf_btatt_heart_rate_control_point = -1;
static int hf_btatt_alert_status = -1;
static int hf_btatt_alert_status_reserved = -1;
static int hf_btatt_alert_status_display_alert_status = -1;
static int hf_btatt_alert_status_vibrate_state = -1;
static int hf_btatt_alert_status_ringer_state = -1;
static int hf_btatt_ringer_control_point = -1;
static int hf_btatt_ringer_setting = -1;
static int hf_btatt_alert_category_id_bitmask_1 = -1;
static int hf_btatt_alert_category_id_bitmask_1_schedule = -1;
static int hf_btatt_alert_category_id_bitmask_1_voice_mail = -1;
static int hf_btatt_alert_category_id_bitmask_1_sms_mms = -1;
static int hf_btatt_alert_category_id_bitmask_1_missed_call = -1;
static int hf_btatt_alert_category_id_bitmask_1_call = -1;
static int hf_btatt_alert_category_id_bitmask_1_news = -1;
static int hf_btatt_alert_category_id_bitmask_1_email = -1;
static int hf_btatt_alert_category_id_bitmask_1_simple_alert = -1;
static int hf_btatt_alert_category_id_bitmask_2 = -1;
static int hf_btatt_alert_category_id_bitmask_2_reserved = -1;
static int hf_btatt_alert_category_id_bitmask_2_instant_message = -1;
static int hf_btatt_alert_category_id_bitmask_2_high_prioritized_alert = -1;
static int hf_btatt_alert_category_id = -1;
static int hf_btatt_alert_command_id = -1;
static int hf_btatt_alert_unread_count = -1;
static int hf_btatt_alert_number_of_new_alert = -1;
static int hf_btatt_alert_text_string_information = -1;
static int hf_btatt_blood_pressure_feature = -1;
static int hf_btatt_blood_pressure_feature_reserved = -1;
static int hf_btatt_blood_pressure_feature_multiple_bond = -1;
static int hf_btatt_blood_pressure_feature_measurement_position_detection = -1;
static int hf_btatt_blood_pressure_feature_puls_rate_range = -1;
static int hf_btatt_blood_pressure_feature_irregular_pulse_detection = -1;
static int hf_btatt_blood_pressure_feature_cuff_fit_detection = -1;
static int hf_btatt_blood_pressure_feature_body_movement_detection = -1;
static int hf_btatt_le_scan_interval = -1;
static int hf_btatt_le_scan_window = -1;
static int hf_btatt_pnp_id_vendor_id_source = -1;
static int hf_btatt_pnp_id_vendor_id = -1;
static int hf_btatt_pnp_id_vendor_id_bluetooth_sig = -1;
static int hf_btatt_pnp_id_vendor_id_usb_forum = -1;
static int hf_btatt_pnp_id_product_id = -1;
static int hf_btatt_pnp_id_product_version = -1;
static int hf_btatt_glucose_feature = -1;
static int hf_btatt_glucose_feature_reserved = -1;
static int hf_btatt_glucose_feature_multiple_bond = -1;
static int hf_btatt_glucose_feature_time_fault = -1;
static int hf_btatt_glucose_feature_general_device_fault = -1;
static int hf_btatt_glucose_feature_sensor_read_interrupt_detection = -1;
static int hf_btatt_glucose_feature_sensor_temperature_high_low_detection = -1;
static int hf_btatt_glucose_feature_sensor_result_high_low_detection = -1;
static int hf_btatt_glucose_feature_sensor_strip_type_error_detection = -1;
static int hf_btatt_glucose_feature_sensor_strip_insertion_error_detection = -1;
static int hf_btatt_glucose_feature_sensor_sample_size = -1;
static int hf_btatt_glucose_feature_sensor_malfunction_detection = -1;
static int hf_btatt_glucose_feature_low_battery_detection_during_measurement = -1;
static int hf_btatt_rsc_feature = -1;
static int hf_btatt_rsc_feature_reserved = -1;
static int hf_btatt_rsc_feature_multiple_sensor_locations = -1;
static int hf_btatt_rsc_feature_calibration_procedure = -1;
static int hf_btatt_rsc_feature_walking_or_running_status = -1;
static int hf_btatt_rsc_feature_total_distance_measurement = -1;
static int hf_btatt_rsc_feature_instantaneous_stride_length_measurement = -1;
static int hf_btatt_csc_feature = -1;
static int hf_btatt_csc_feature_reserved = -1;
static int hf_btatt_csc_feature_multiple_sensor_locations = -1;
static int hf_btatt_csc_feature_crank_revolution_data = -1;
static int hf_btatt_csc_feature_wheel_revolution_data = -1;
static int hf_btatt_sensor_location = -1;
static int hf_btatt_elevation = -1;
static int hf_btatt_pressure = -1;
static int hf_btatt_temperature = -1;
static int hf_btatt_humidity = -1;
static int hf_btatt_true_wind_speed = -1;
static int hf_btatt_true_wind_direction = -1;
static int hf_btatt_apparent_wind_speed = -1;
static int hf_btatt_apparent_wind_direction = -1;
static int hf_btatt_gust_factor = -1;
static int hf_btatt_pollen_concentration = -1;
static int hf_btatt_uv_index = -1;
static int hf_btatt_irradiance = -1;
static int hf_btatt_rainfall = -1;
static int hf_btatt_wind_chill = -1;
static int hf_btatt_heart_index = -1;
static int hf_btatt_dew_point = -1;
static int hf_btatt_descriptor_value_changed_flags = -1;
static int hf_btatt_descriptor_value_changed_flags_reserved = -1;
static int hf_btatt_descriptor_value_changed_flags_change_to_characteristic_user_description_descriptor = -1;
static int hf_btatt_descriptor_value_changed_flags_change_to_es_measurement_descriptor = -1;
static int hf_btatt_descriptor_value_changed_flags_change_to_es_configuration_descriptor = -1;
static int hf_btatt_descriptor_value_changed_flags_change_to_one_or_more_es_trigger_setting_descriptors = -1;
static int hf_btatt_descriptor_value_changed_flags_source_of_change = -1;
static int hf_btatt_aerobic_heart_rate_lower_limit = -1;
static int hf_btatt_aerobic_threshold = -1;
static int hf_btatt_age = -1;
static int hf_btatt_anaerobic_heart_rate_lower_limit = -1;
static int hf_btatt_anaerobic_heart_rate_upper_limit = -1;
static int hf_btatt_anaerobic_threshold = -1;
static int hf_btatt_aerobic_heart_rate_upper_limit = -1;
static int hf_btatt_email_address = -1;
static int hf_btatt_fat_burn_heart_rate_lower_limit = -1;
static int hf_btatt_fat_burn_heart_rate_upper_limit = -1;
static int hf_btatt_first_name = -1;
static int hf_btatt_five_zone_heart_rate_limits_very_light_light_limit = -1;
static int hf_btatt_five_zone_heart_rate_limits_light_moderate_limit = -1;
static int hf_btatt_five_zone_heart_rate_limits_moderate_hard_limit = -1;
static int hf_btatt_five_zone_heart_rate_limits_hard_maximum_limit = -1;
static int hf_btatt_gender = -1;
static int hf_btatt_heart_rate_max = -1;
static int hf_btatt_height = -1;
static int hf_btatt_hip_circumference = -1;
static int hf_btatt_last_name = -1;
static int hf_btatt_maximum_recommended_heart_rate = -1;
static int hf_btatt_resting_heart_rate = -1;
static int hf_btatt_sport_type_for_aerobic_and_anaerobic_thresholds = -1;
static int hf_btatt_three_zone_heart_rate_limits_light_moderate = -1;
static int hf_btatt_three_zone_heart_rate_limits_moderate_hard = -1;
static int hf_btatt_two_zone_heart_rate_limit_fat_burn_fitness = -1;
static int hf_btatt_vo2_max =-1;
static int hf_btatt_waist_circumference =-1;
static int hf_btatt_weight =-1;
static int hf_btatt_database_change_increment =-1;
static int hf_btatt_user_index = -1;
static int hf_btatt_magnetic_flux_density_x = -1;
static int hf_btatt_magnetic_flux_density_y = -1;
static int hf_btatt_magnetic_flux_density_z = -1;
static int hf_btatt_language = -1;
static int hf_btatt_barometric_pressure_trend = -1;
static int hf_btatt_central_address_resolution = -1;
static int hf_request_in_frame = -1;
static int hf_response_in_frame = -1;
static int btatt_tap_handles = -1;
static const int *hfx_btatt_opcode[] = {
&hf_btatt_opcode_authentication_signature,
&hf_btatt_opcode_command,
&hf_btatt_opcode_method,
NULL
};
static const int *hfx_btatt_characteristic_properties[] = {
&hf_btatt_characteristic_properties_extended_properties,
&hf_btatt_characteristic_properties_authenticated_signed_writes,
&hf_btatt_characteristic_properties_indicate,
&hf_btatt_characteristic_properties_notify,
&hf_btatt_characteristic_properties_write,
&hf_btatt_characteristic_properties_write_without_response,
&hf_btatt_characteristic_properties_read,
&hf_btatt_characteristic_properties_broadcast,
NULL
};
static const int *hfx_btatt_characteristic_configuration_client[] = {
&hf_btatt_characteristic_configuration_client_reserved,
&hf_btatt_characteristic_configuration_client_indication,
&hf_btatt_characteristic_configuration_client_notification,
NULL
};
static const int *hfx_btatt_characteristic_configuration_server[] = {
&hf_btatt_characteristic_configuration_server_reserved,
&hf_btatt_characteristic_configuration_server_broadcast,
NULL
};
static const int *hfx_btatt_hogp_flags[] = {
&hf_btatt_hogp_flags_reserved,
&hf_btatt_hogp_flags_normally_connectable,
&hf_btatt_hogp_flags_remote_wake,
NULL
};
static const int *hfx_btatt_characteristic_extended_properties[] = {
&hf_btatt_characteristic_extended_properties_reserved,
&hf_btatt_characteristic_extended_properties_writable_auxiliaries,
&hf_btatt_characteristic_extended_properties_reliable_write,
NULL
};
static const int *hfx_btatt_appearance[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory,
NULL
};
static const int *hfx_btatt_appearance_watch[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_watch,
NULL
};
static const int *hfx_btatt_appearance_thermometer[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_thermometer,
NULL
};
static const int *hfx_btatt_appearance_heart_rate[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_heart_rate,
NULL
};
static const int *hfx_btatt_appearance_blood_pressure[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_blood_pressure,
NULL
};
static const int *hfx_btatt_appearance_hid[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_hid,
NULL
};
static const int *hfx_btatt_appearance_running_walking_sensor[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_running_walking_sensor,
NULL
};
static const int *hfx_btatt_appearance_cycling[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_cycling,
NULL
};
static const int *hfx_btatt_appearance_pulse_oximeter[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_pulse_oximeter,
NULL
};
static const int *hfx_btatt_appearance_outdoor_sports_activity[] = {
&hf_btatt_appearance_category,
&hf_btatt_appearance_subcategory_outdoor_sports_activity,
NULL
};
static const int *hfx_btatt_time_adjust_reason[] = {
&hf_btatt_time_adjust_reason_reserved,
&hf_btatt_time_adjust_reason_change_of_dst,
&hf_btatt_time_adjust_reason_change_of_timezone,
&hf_btatt_time_adjust_reason_external_reference_time_update,
&hf_btatt_time_adjust_reason_manual_time_update,
NULL
};
static const int *hfx_btatt_alert_status[] = {
&hf_btatt_alert_status_reserved,
&hf_btatt_alert_status_display_alert_status,
&hf_btatt_alert_status_vibrate_state,
&hf_btatt_alert_status_ringer_state,
NULL
};
static const int *hfx_btatt_alert_category_id_bitmask_1[] = {
&hf_btatt_alert_category_id_bitmask_1_schedule,
&hf_btatt_alert_category_id_bitmask_1_voice_mail,
&hf_btatt_alert_category_id_bitmask_1_sms_mms,
&hf_btatt_alert_category_id_bitmask_1_missed_call,
&hf_btatt_alert_category_id_bitmask_1_call,
&hf_btatt_alert_category_id_bitmask_1_news,
&hf_btatt_alert_category_id_bitmask_1_email,
&hf_btatt_alert_category_id_bitmask_1_simple_alert,
NULL
};
static const int *hfx_btatt_alert_category_id_bitmask_2[] = {
&hf_btatt_alert_category_id_bitmask_2_reserved,
&hf_btatt_alert_category_id_bitmask_2_instant_message,
&hf_btatt_alert_category_id_bitmask_2_high_prioritized_alert,
NULL
};
static const int *hfx_btatt_blood_pressure_feature[] = {
&hf_btatt_blood_pressure_feature_reserved,
&hf_btatt_blood_pressure_feature_multiple_bond,
&hf_btatt_blood_pressure_feature_measurement_position_detection,
&hf_btatt_blood_pressure_feature_puls_rate_range,
&hf_btatt_blood_pressure_feature_irregular_pulse_detection,
&hf_btatt_blood_pressure_feature_cuff_fit_detection,
&hf_btatt_blood_pressure_feature_body_movement_detection,
NULL
};
static const int *hfx_btatt_glucose_feature[] = {
&hf_btatt_glucose_feature_reserved,
&hf_btatt_glucose_feature_multiple_bond,
&hf_btatt_glucose_feature_time_fault,
&hf_btatt_glucose_feature_general_device_fault,
&hf_btatt_glucose_feature_sensor_read_interrupt_detection,
&hf_btatt_glucose_feature_sensor_temperature_high_low_detection,
&hf_btatt_glucose_feature_sensor_result_high_low_detection,
&hf_btatt_glucose_feature_sensor_strip_type_error_detection,
&hf_btatt_glucose_feature_sensor_strip_insertion_error_detection,
&hf_btatt_glucose_feature_sensor_sample_size,
&hf_btatt_glucose_feature_sensor_malfunction_detection,
&hf_btatt_glucose_feature_low_battery_detection_during_measurement,
NULL
};
static const int *hfx_btatt_rsc_feature[] = {
&hf_btatt_rsc_feature_reserved,
&hf_btatt_rsc_feature_multiple_sensor_locations,
&hf_btatt_rsc_feature_calibration_procedure,
&hf_btatt_rsc_feature_walking_or_running_status,
&hf_btatt_rsc_feature_total_distance_measurement,
&hf_btatt_rsc_feature_instantaneous_stride_length_measurement,
NULL
};
static const int *hfx_btatt_csc_feature[] = {
&hf_btatt_csc_feature_reserved,
&hf_btatt_csc_feature_multiple_sensor_locations,
&hf_btatt_csc_feature_crank_revolution_data,
&hf_btatt_csc_feature_wheel_revolution_data,
NULL
};
static const int *hfx_btatt_descriptor_value_changed_flags[] = {
&hf_btatt_descriptor_value_changed_flags_reserved,
&hf_btatt_descriptor_value_changed_flags_change_to_characteristic_user_description_descriptor,
&hf_btatt_descriptor_value_changed_flags_change_to_es_measurement_descriptor,
&hf_btatt_descriptor_value_changed_flags_change_to_es_configuration_descriptor,
&hf_btatt_descriptor_value_changed_flags_change_to_one_or_more_es_trigger_setting_descriptors,
&hf_btatt_descriptor_value_changed_flags_source_of_change,
NULL
};
/* Initialize the subtree pointers */
static gint ett_btatt = -1;
static gint ett_btatt_list = -1;
static gint ett_btatt_value = -1;
static gint ett_btatt_opcode = -1;
static gint ett_btatt_handle = -1;
static gint ett_btatt_characteristic_properties = -1;
static gint ett_btgatt = -1;
static expert_field ei_btatt_uuid_format_unknown = EI_INIT;
static expert_field ei_btatt_handle_too_few = EI_INIT;
static expert_field ei_btatt_mtu_exceeded = EI_INIT;
static expert_field ei_btatt_mtu_full = EI_INIT;
static wmem_tree_t *mtus = NULL;
static wmem_tree_t *requests = NULL;
static wmem_tree_t *fragments = NULL;
static wmem_tree_t *handle_to_uuid = NULL;
static dissector_handle_t btatt_handle;
static dissector_handle_t usb_hid_boot_keyboard_input_report_handle;
static dissector_handle_t usb_hid_boot_keyboard_output_report_handle;
static dissector_handle_t usb_hid_boot_mouse_input_report_handle;
static dissector_table_t att_handle_dissector_table;
static dissector_table_t att_uuid16_dissector_table;
static dissector_table_t att_uuid128_dissector_table;
extern value_string_ext ext_usb_vendors_vals;
/* Opcodes */
static const value_string opcode_vals[] = {
{0x01, "Error Response"},
{0x02, "Exchange MTU Request"},
{0x03, "Exchange MTU Response"},
{0x04, "Find Information Request"},
{0x05, "Find Information Response"},
{0x06, "Find By Type Value Request"},
{0x07, "Find By Type Value Response"},
{0x08, "Read By Type Request"},
{0x09, "Read By Type Response"},
{0x0a, "Read Request"},
{0x0b, "Read Response"},
{0x0c, "Read Blob Request"},
{0x0d, "Read Blob Response"},
{0x0e, "Read Multiple Request"},
{0x0f, "Read Multiple Response"},
{0x10, "Read By Group Type Request"},
{0x11, "Read By Group Type Response"},
{0x12, "Write Request"},
{0x13, "Write Response"},
{0x16, "Prepare Write Request"},
{0x17, "Prepare Write Response"},
{0x18, "Execute Write Request"},
{0x19, "Execute Write Response"},
{0x1B, "Handle Value Notification"},
{0x1D, "Handle Value Indication"},
{0x1E, "Handle Value Confirmation"},
{0x52, "Write Command"},
{0xD2, "Signed Write Command"},
{0x0, NULL}
};
/* Error codes */
static const value_string error_vals[] = {
{0x01, "Invalid Handle"},
{0x02, "Read Not Permitted"},
{0x03, "Write Not Permitted"},
{0x04, "Invalid PDU"},
{0x05, "Insufficient Authentication"},
{0x06, "Request Not Supported"},
{0x07, "Invalid Offset"},
{0x08, "Insufficient Authorization"},
{0x09, "Prepare Queue Full"},
{0x0a, "Attribute Not Found"},
{0x0b, "Attribute Not Long"},
{0x0c, "Insufficient Encryption Key Size"},
{0x0d, "Invalid Attribute Value Length"},
{0x0e, "Unlikely Error"},
{0x0f, "Insufficient Encryption"},
{0x10, "Unsupported Group Type"},
{0x11, "Insufficient Resources"},
{0x80, "Application Error"},
{0xfd, "Improper Client Characteristic Configuration Descriptor"},
{0xfe, "Procedure Already In Progress"},
{0xff, "Out of Range"},
{0x0, NULL}
};
static const value_string uuid_format_vals[] = {
{0x01, "16-bit UUIDs"},
{0x02, "128-bit UUIDs"},
{0x0, NULL}
};
static const value_string flags_vals[] = {
{0x00, "Cancel All"},
{0x01, "Immediately Write All"},
{0x0, NULL}
};
static const value_string hogp_protocol_mode_vals[] = {
{0x00, "Boot Protocol Mode"},
{0x01, "Report Protocol Mode"},
{0x0, NULL}
};
static const value_string report_reference_report_type_vals[] = {
{0x01, "Input Report"},
{0x02, "Output Report"},
{0x03, "Feature Report"},
{0x0, NULL}
};
static const value_string characteristic_presentation_format_vals[] = {
{0x01, "unsigned 1-bit"},
{0x02, "unsigned 2-bit integer"},
{0x03, "unsigned 4-bit integer"},
{0x04, "unsigned 8-bit integer"},
{0x05, "unsigned 12-bit integer"},
{0x06, "unsigned 16-bit integer"},
{0x07, "unsigned 24-bit integer"},
{0x08, "unsigned 32-bit integer"},
{0x09, "unsigned 48-bit integer"},
{0x0A, "unsigned 64-bit integer"},
{0x0B, "unsigned 128-bit integer"},
{0x0C, "signed 8-bit integer"},
{0x0D, "signed 12-bit integer"},
{0x0E, "signed 16-bit integer"},
{0x0F, "signed 24-bit integer"},
{0x10, "signed 32-bit integer"},
{0x11, "signed 48-bit integer"},
{0x12, "signed 64-bit integer"},
{0x13, "signed 128-bit integer"},
{0x14, "IEEE-754 32-bit floating point"},
{0x15, "IEEE-754 64-bit floating point"},
{0x16, "IEEE-11073 16-bit SFLOAT"},
{0x17, "IEEE-11073 32-bit FLOAT"},
{0x18, "IEEE-20601 format"},
{0x19, "UTF-8 string"},
{0x1A, "UTF-16 string"},
{0x1B, "Opaque structure"},
{0x0, NULL}
};
static const value_string characteristic_presentation_namespace_vals[] = {
{0x01, "Bluetooth SIG"},
{0x0, NULL}
};
static const value_string characteristic_presentation_namespace_description_btsig_vals[] = {
{0x0000, "unknown"},
{0x0001, "first"},
{0x0002, "second"},
{0x0003, "third"},
{0x0004, "fourth"},
{0x0005, "fifth"},
{0x0006, "sixth"},
{0x0007, "seventh"},
{0x0008, "eighth"},
{0x0009, "nineth"},
{0x000a, "tenth"},
{0x000b, "eleventh"},
{0x000c, "twelveth"},
{0x000d, "thirteenth"},
{0x000e, "fourteenth"},
{0x000f, "fifteenth"},
{0x0010, "sixteenth"},
{0x0011, "seventeenth"},
{0x0012, "eighteenth"},
{0x0013, "nineteenth"},
{0x0014, "twentieth"},
{0x0015, "twenty-first"},
{0x0016, "twenty-second"},
{0x0017, "twenty-third"},
{0x0018, "twenty-fourth"},
{0x0019, "twenty-fifth"},
{0x001a, "twenty-sixth"},
{0x001b, "twenty-seventh"},
{0x001c, "twenty-eighth"},
{0x001d, "twenty-nineth"},
{0x001e, "thirtieth"},
{0x001f, "thirty-first"},
{0x0020, "thirty-second"},
{0x0021, "thirty-third"},
{0x0022, "thirty-fourth"},
{0x0023, "thirty-fifth"},
{0x0024, "thirty-sixth"},
{0x0025, "thirty-seventh"},
{0x0026, "thirty-eighth"},
{0x0027, "thirty-nineth"},
{0x0028, "fortieth"},
{0x0029, "fourty-first"},
{0x002a, "fourty-second"},
{0x002b, "fourty-third"},
{0x002c, "fourty-fourth"},
{0x002d, "fourty-fifth"},
{0x002e, "fourty-sixth"},
{0x002f, "fourty-seventh"},
{0x0030, "fourty-eighth"},
{0x0031, "fourty-nineth"},
{0x0032, "fiftieth"},
{0x0033, "fifty-first"},
{0x0034, "fifty-second"},
{0x0035, "fifty-third"},
{0x0036, "fifty-fourth"},
{0x0037, "fifty-fifth"},
{0x0038, "fifty-sixth"},
{0x0039, "fifty-seventh"},
{0x003a, "fifty-eighth"},
{0x003b, "fifty-nineth"},
{0x003c, "sixtieth"},
{0x003d, "sixty-first"},
{0x003e, "sixty-second"},
{0x003f, "sixty-third"},
{0x0040, "sixty-fourth"},
{0x0041, "sixty-fifth"},
{0x0042, "sixty-sixth"},
{0x0043, "sixty-seventh"},
{0x0044, "sixty-eighth"},
{0x0045, "sixty-nineth"},
{0x0046, "seventieth"},
{0x0047, "seventy-first"},
{0x0048, "seventy-second"},
{0x0049, "seventy-third"},
{0x004a, "seventy-fourth"},
{0x004b, "seventy-fifth"},
{0x004c, "seventy-sixth"},
{0x004d, "seventy-seventh"},
{0x004e, "seventy-eighth"},
{0x004f, "seventy-nineth"},
{0x0050, "eightieth"},
{0x0051, "eighty-first"},
{0x0052, "eighty-second"},
{0x0053, "eighty-third"},
{0x0054, "eighty-fourth"},
{0x0055, "eighty-fifth"},
{0x0056, "eighty-sixth"},
{0x0057, "eighty-seventh"},
{0x0058, "eighty-eighth"},
{0x0059, "eighty-nineth"},
{0x005a, "ninetieth"},
{0x005b, "ninety-first"},
{0x005c, "ninety-second"},
{0x005d, "ninety-third"},
{0x005e, "ninety-fourth"},
{0x005f, "ninety-fifth"},
{0x0060, "ninety-sixth"},
{0x0061, "ninety-seventh"},
{0x0062, "ninety-eighth"},
{0x0063, "ninety-nineth"},
{0x0064, "one-hundredth"},
{0x0065, "one-hundred-and-first"},
{0x0066, "one-hundred-and-second"},
{0x0067, "one-hundred-and-third"},
{0x0068, "one-hundred-and-fourth"},
{0x0069, "one-hundred-and-fifth"},
{0x006a, "one-hundred-and-sixth"},
{0x006b, "one-hundred-and-seventh"},
{0x006c, "one-hundred-and-eighth"},
{0x006d, "one-hundred-and-nineth"},
{0x006e, "one-hundred-and-tenth"},
{0x006f, "one-hundred-and-eleventh"},
{0x0070, "one-hundred-and-twelveth"},
{0x0071, "one-hundred-and-thirteenth"},
{0x0072, "one-hundred-and-fourteenth"},
{0x0073, "one-hundred-and-fifteenth"},
{0x0074, "one-hundred-and-sixteenth"},
{0x0075, "one-hundred-and-seventeenth"},
{0x0076, "one-hundred-and-eighteenth"},
{0x0077, "one-hundred-and-nineteenth"},
{0x0078, "one-hundred-twentieth"},
{0x0079, "one-hundred-and-twenty-first"},
{0x007a, "one-hundred-and-twenty-second"},
{0x007b, "one-hundred-and-twenty-third"},
{0x007c, "one-hundred-and-twenty-fourth"},
{0x007d, "one-hundred-and-twenty-fifth"},
{0x007e, "one-hundred-and-twenty-sixth"},
{0x007f, "one-hundred-and-twenty-seventh"},
{0x0080, "one-hundred-and-twenty-eighth"},
{0x0081, "one-hundred-and-twenty-nineth"},
{0x0082, "one-hundred-thirtieth"},
{0x0083, "one-hundred-and-thirty-first"},
{0x0084, "one-hundred-and-thirty-second"},
{0x0085, "one-hundred-and-thirty-third"},
{0x0086, "one-hundred-and-thirty-fourth"},
{0x0087, "one-hundred-and-thirty-fifth"},
{0x0088, "one-hundred-and-thirty-sixth"},
{0x0089, "one-hundred-and-thirty-seventh"},
{0x008a, "one-hundred-and-thirty-eighth"},
{0x008b, "one-hundred-and-thirty-nineth"},
{0x008c, "one-hundred-fortieth"},
{0x008d, "one-hundred-and-fourty-first"},
{0x008e, "one-hundred-and-fourty-second"},
{0x008f, "one-hundred-and-fourty-third"},
{0x0090, "one-hundred-and-fourty-fourth"},
{0x0091, "one-hundred-and-fourty-fifth"},
{0x0092, "one-hundred-and-fourty-sixth"},
{0x0093, "one-hundred-and-fourty-seventh"},
{0x0094, "one-hundred-and-fourty-eighth"},
{0x0095, "one-hundred-and-fourty-nineth"},
{0x0096, "one-hundred-fiftieth"},
{0x0097, "one-hundred-and-fifty-first"},
{0x0098, "one-hundred-and-fifty-second"},
{0x0099, "one-hundred-and-fifty-third"},
{0x009a, "one-hundred-and-fifty-fourth"},
{0x009b, "one-hundred-and-fifty-fifth"},
{0x009c, "one-hundred-and-fifty-sixth"},
{0x009d, "one-hundred-and-fifty-seventh"},
{0x009e, "one-hundred-and-fifty-eighth"},
{0x009f, "one-hundred-and-fifty-nineth"},
{0x00a0, "one-hundred-sixtieth"},
{0x00a1, "one-hundred-and-sixty-first"},
{0x00a2, "one-hundred-and-sixty-second"},
{0x00a3, "one-hundred-and-sixty-third"},
{0x00a4, "one-hundred-and-sixty-fourth"},
{0x00a5, "one-hundred-and-sixty-fifth"},
{0x00a6, "one-hundred-and-sixty-sixth"},
{0x00a7, "one-hundred-and-sixty-seventh"},
{0x00a8, "one-hundred-and-sixty-eighth"},
{0x00a9, "one-hundred-and-sixty-nineth"},
{0x00aa, "one-hundred-seventieth"},
{0x00ab, "one-hundred-and-seventy-first"},
{0x00ac, "one-hundred-and-seventy-second"},
{0x00ad, "one-hundred-and-seventy-third"},
{0x00ae, "one-hundred-and-seventy-fourth"},
{0x00af, "one-hundred-and-seventy-fifth"},
{0x00b0, "one-hundred-and-seventy-sixth"},
{0x00b1, "one-hundred-and-seventy-seventh"},
{0x00b2, "one-hundred-and-seventy-eighth"},
{0x00b3, "one-hundred-and-seventy-nineth"},
{0x00b4, "one-hundred-eightieth"},
{0x00b5, "one-hundred-and-eighty-first"},
{0x00b6, "one-hundred-and-eighty-second"},
{0x00b7, "one-hundred-and-eighty-third"},
{0x00b8, "one-hundred-and-eighty-fourth"},
{0x00b9, "one-hundred-and-eighty-fifth"},
{0x00ba, "one-hundred-and-eighty-sixth"},
{0x00bb, "one-hundred-and-eighty-seventh"},
{0x00bc, "one-hundred-and-eighty-eighth"},
{0x00bd, "one-hundred-and-eighty-nineth"},
{0x00be, "one-hundred-ninetieth"},
{0x00bf, "one-hundred-and-ninety-first"},
{0x00c0, "one-hundred-and-ninety-second"},
{0x00c1, "one-hundred-and-ninety-third"},
{0x00c2, "one-hundred-and-ninety-fourth"},
{0x00c3, "one-hundred-and-ninety-fifth"},
{0x00c4, "one-hundred-and-ninety-sixth"},
{0x00c5, "one-hundred-and-ninety-seventh"},
{0x00c6, "one-hundred-and-ninety-eighth"},
{0x00c7, "one-hundred-and-ninety-nineth"},
{0x00c8, "two-hundredth"},
{0x00c9, "two-hundred-and-first"},
{0x00ca, "two-hundred-and-second"},
{0x00cb, "two-hundred-and-third"},
{0x00cc, "two-hundred-and-fourth"},
{0x00cd, "two-hundred-and-fifth"},
{0x00ce, "two-hundred-and-sixth"},
{0x00cf, "two-hundred-and-seventh"},
{0x00d0, "two-hundred-and-eighth"},
{0x00d1, "two-hundred-and-nineth"},
{0x00d2, "two-hundred-and-tenth"},
{0x00d3, "two-hundred-and-eleventh"},
{0x00d4, "two-hundred-and-twelveth"},
{0x00d5, "two-hundred-and-thirteenth"},
{0x00d6, "two-hundred-and-fourteenth"},
{0x00d7, "two-hundred-and-fifteenth"},
{0x00d8, "two-hundred-and-sixteenth"},
{0x00d9, "two-hundred-and-seventeenth"},
{0x00da, "two-hundred-and-eighteenth"},
{0x00db, "two-hundred-and-nineteenth"},
{0x00dc, "two-hundred-twentieth"},
{0x00dd, "two-hundred-and-twenty-first"},
{0x00de, "two-hundred-and-twenty-second"},
{0x00df, "two-hundred-and-twenty-third"},
{0x00e0, "two-hundred-and-twenty-fourth"},
{0x00e1, "two-hundred-and-twenty-fifth"},
{0x00e2, "two-hundred-and-twenty-sixth"},
{0x00e3, "two-hundred-and-twenty-seventh"},
{0x00e4, "two-hundred-and-twenty-eighth"},
{0x00e5, "two-hundred-and-twenty-nineth"},
{0x00e6, "two-hundred-thirtieth"},
{0x00e7, "two-hundred-and-thirty-first"},
{0x00e8, "two-hundred-and-thirty-second"},
{0x00e9, "two-hundred-and-thirty-third"},
{0x00ea, "two-hundred-and-thirty-fourth"},
{0x00eb, "two-hundred-and-thirty-fifth"},
{0x00ec, "two-hundred-and-thirty-sixth"},
{0x00ed, "two-hundred-and-thirty-seventh"},
{0x00ee, "two-hundred-and-thirty-eighth"},
{0x00ef, "two-hundred-and-thirty-nineth"},
{0x00f0, "two-hundred-fortieth"},
{0x00f1, "two-hundred-and-fourty-first"},
{0x00f2, "two-hundred-and-fourty-second"},
{0x00f3, "two-hundred-and-fourty-third"},
{0x00f4, "two-hundred-and-fourty-fourth"},
{0x00f5, "two-hundred-and-fourty-fifth"},
{0x00f6, "two-hundred-and-fourty-sixth"},
{0x00f7, "two-hundred-and-fourty-seventh"},
{0x00f8, "two-hundred-and-fourty-eighth"},
{0x00f9, "two-hundred-and-fourty-nineth"},
{0x00fa, "two-hundred-fiftieth"},
{0x00fb, "two-hundred-and-fifty-first"},
{0x00fc, "two-hundred-and-fifty-second"},
{0x00fd, "two-hundred-and-fifty-third"},
{0x00fe, "two-hundred-and-fifty-fourth"},
{0x00ff, "two-hundred-and-fifty-fifth"},
{0x0100, "front"},
{0x0101, "back"},
{0x0102, "top"},
{0x0103, "bottom"},
{0x0104, "upper"},
{0x0105, "lower"},
{0x0106, "main"},
{0x0107, "backup"},
{0x0108, "auxiliary"},
{0x0109, "supplementary"},
{0x010A, "flash"},
{0x010B, "inside"},
{0x010C, "outside"},
{0x010D, "left"},
{0x010E, "right"},
{0x010F, "internal"},
{0x0110, "external"},
{0x0, NULL}
};
static const value_string esp_trigger_logic_vals[] = {
{0x00, "Boolean AND"},
{0x01, "Boolean OR"},
{0x0, NULL}
};
static const value_string esp_condition_vals[] = {
{0x00, "Trigger inactive"},
{0x01, "Use a fixed time interval between"},
{0x02, "No less than the specified time between"},
{0x03, "When value changes compared to"},
{0x04, "While less than the specified value"},
{0x05, "While less than or equal to the specified"},
{0x06, "While greater than the specified value"},
{0x07, "While greater than or equal to the"},
{0x08, "While equal to the specified value"},
{0x09, "While not equal to the specified value"},
{0x0, NULL}
};
static const value_string esp_sampling_function_vals[] = {
{0x00, "Unspecified"},
{0x01, "Instantaneous"},
{0x02, "Arithmetic Mean"},
{0x03, "RMS"},
{0x04, "Maximum"},
{0x05, "Minimum"},
{0x06, "Accumulated"},
{0x07, "Count"},
{0x0, NULL}
};
static const value_string esp_application_vals[] = {
{0x00, "Unspecified"},
{0x01, "Air"},
{0x02, "Water"},
{0x03, "Barometric"},
{0x04, "Soil"},
{0x05, "Infrared"},
{0x06, "Map Database"},
{0x07, "Barometric Elevation Source"},
{0x08, "GPS only Elevation Source"},
{0x09, "GPS and Map database Elevation Source"},
{0x0A, "Vertical datum Elevation Source"},
{0x0B, "Onshore"},
{0x0C, "Onboard vessel or vehicle"},
{0x0D, "Front"},
{0x0E, "Back/Rear"},
{0x0F, "Upper"},
{0x10, "Lower"},
{0x11, "Primary"},
{0x12, "Secondary"},
{0x13, "Outdoor"},
{0x14, "Indoor"},
{0x15, "Top"},
{0x16, "Bottom"},
{0x17, "Main"},
{0x18, "Backup"},
{0x19, "Auxiliary"},
{0x1A, "Supplementary"},
{0x1B, "Inside"},
{0x1C, "Outside"},
{0x1D, "Left"},
{0x1E, "Right"},
{0x1F, "Internal"},
{0x20, "External"},
{0x21, "Solar"},
{0x0, NULL}
};
static const value_string appearance_category_vals[] = {
{0x01, "Phone"},
{0x02, "Computer"},
{0x03, "Watch"},
{0x04, "Clock"},
{0x05, "Display"},
{0x06, "Remote Control"},
{0x07, "Eye Glasses"},
{0x08, "Tag"},
{0x09, "Keyring"},
{0x0A, "Media Player"},
{0x0B, "Barcode Scanner"},
{0x0C, "Thermometer"},
{0x0D, "Heart Rate Sensor"},
{0x0E, "Blood Pressure"},
{0x0F, "Human Interface Device"},
{0x10, "Glucose Meter"},
{0x11, "Running Walking Sensor"},
{0x12, "Cycling"},
{0x31, "Pulse Oximeter"},
{0x32, "Weight Scale"},
{0x51, "Outdoor Sports Activity"},
{0x0, NULL}
};
static const value_string appearance_subcategory_watch_vals[] = {
{0x01, "Sports Watch"},
{0x0, NULL}
};
static const value_string appearance_subcategory_thermometer_vals[] = {
{0x01, "Ear"},
{0x0, NULL}
};
static const value_string appearance_subcategory_heart_rate_vals[] = {
{0x01, "Heart Rate Belt"},
{0x0, NULL}
};
static const value_string appearance_subcategory_blood_pressure_vals[] = {
{0x01, "Arm"},
{0x02, "Wrist"},
{0x0, NULL}
};
static const value_string appearance_subcategory_hid_vals[] = {
{0x01, "Keyboard"},
{0x02, "Mouse"},
{0x03, "Joystick"},
{0x04, "Gamepad"},
{0x05, "Digitizer Tablet"},
{0x06, "Card Reader"},
{0x07, "Digital Pen"},
{0x08, "Barcode"},
{0x0, NULL}
};
static const value_string appearance_subcategory_running_walking_sensor_vals[] = {
{0x01, "In-Shoe"},
{0x02, "On-Shoe"},
{0x03, "On-Hip"},
{0x0, NULL}
};
static const value_string appearance_subcategory_cycling_vals[] = {
{0x01, "Cycling Computer"},
{0x02, "Speed Sensor"},
{0x03, "Cadence Sensor"},
{0x04, "Power Sensor"},
{0x05, "Speed and Cadence Sensor"},
{0x0, NULL}
};
static const value_string appearance_subcategory_pulse_oximeter_vals[] = {
{0x01, "Fingertip"},
{0x02, "Wrist Worn"},
{0x0, NULL}
};
static const value_string appearance_subcategory_outdoor_sports_activity_vals[] = {
{0x01, "Location Display Device"},
{0x02, "Location and Navigation Display Device"},
{0x03, "Location Pod"},
{0x04, "Location and Navigation Pod"},
{0x0, NULL}
};
static const value_string alert_level_vals[] = {
{0x00, "No Alert"},
{0x01, "Mild Alert"},
{0x02, "High Alert"},
{0x0, NULL}
};
static const value_string dst_offset_vals[] = {
{0x00, "Standard Time"},
{0x02, "Half an Hour Daylight Time (+0.5h)"},
{0x04, "Daylight Time (+1h)"},
{0x08, "Double Daylight Time (+2h)"},
{0xFF, "DST is not known"},
{0x0, NULL}
};
static const value_string timezone_vals[] = {
{-128, "Time zone offset is not known"},
{-48, "UTC-12:00"},
{-44, "UTC-11:00"},
{-40, "UTC-10:00"},
{-38, "UTC-9:30"},
{-36, "UTC-9:00"},
{-32, "UTC-8:00"},
{-28, "UTC-7:00"},
{-24, "UTC-6:00"},
{-20, "UTC-5:00"},
{-18, "UTC-4:30"},
{-16, "UTC-4:00"},
{-14, "UTC-3:30"},
{-12, "UTC-3:00"},
{-8, "UTC-2:00"},
{-4, "UTC-1:00"},
{0, "UTC+0:00"},
{4, "UTC+1:00"},
{8, "UTC+2:00"},
{12, "UTC+3:00"},
{14, "UTC+3:30"},
{16, "UTC+4:00"},
{18, "UTC+4:30"},
{20, "UTC+5:00"},
{22, "UTC+5:30"},
{23, "UTC+5:45"},
{24, "UTC+6:00"},
{26, "UTC+6:30"},
{28, "UTC+7:00"},
{32, "UTC+8:00"},
{35, "UTC+8:45"},
{36, "UTC+9:00"},
{38, "UTC+9:30"},
{40, "UTC+10:00"},
{42, "UTC+10:30"},
{44, "UTC+11:00"},
{46, "UTC+11:30"},
{48, "UTC+12:00"},
{51, "UTC+12:45"},
{52, "UTC+13:00"},
{56, "UTC+14:00"},
{0x0, NULL}
};
static const value_string time_source_vals[] = {
{0x00, "Unknown"},
{0x01, "Network Time Protocol"},
{0x02, "GPS"},
{0x03, "Radio Time Signal"},
{0x04, "Manual"},
{0x05, "Atomic Clock"},
{0x06, "Cellular Network"},
{0x0, NULL}
};
static const value_string time_update_control_point_vals[] = {
{0x01, "Get Reference Update"},
{0x02, "Cancel Reference Update"},
{0x0, NULL}
};
static const value_string time_current_state_vals[] = {
{0x00, "Idle"},
{0x01, "Update Pending"},
{0x0, NULL}
};
static const value_string time_result_vals[] = {
{0x00, "Successful"},
{0x01, "Canceled"},
{0x02, "No Connection To Reference"},
{0x03, "Reference responded with an error"},
{0x04, "Timeout"},
{0x05, "Update not attempted after reset"},
{0x0, NULL}
};
static const value_string temperature_type_vals[] = {
{0x01, "Armpit"},
{0x02, "Body (general)"},
{0x03, "Ear (usually ear lobe)"},
{0x04, "Finger"},
{0x05, "Gastro-intestinal Tract"},
{0x06, "Mouth"},
{0x07, "Rectum"},
{0x08, "Toe"},
{0x09, "Tympanum (ear drum)"},
{0x0, NULL}
};
static const value_string scan_refresh_vals[] = {
{0x00, "Server Requires Refresh"},
{0x0, NULL}
};
static const value_string body_sensor_location_vals[] = {
{0x00, "Other"},
{0x01, "Chest"},
{0x02, "Wrist"},
{0x03, "Finger"},
{0x04, "Hand"},
{0x05, "Ear Lobe"},
{0x06, "Foot"},
{0x0, NULL}
};
static const value_string heart_rate_control_point_vals[] = {
{0x01, "Reset Energy Expended"},
{0x0, NULL}
};
static const value_string ringer_control_point_vals[] = {
{0x01, "Silent Mode"},
{0x02, "Mute Once"},
{0x03, "Cancel Silent Mode"},
{0x0, NULL}
};
static const value_string ringer_setting_vals[] = {
{0x00, "Ringer Silent"},
{0x01, "Ringer Normal"},
{0x0, NULL}
};
static const value_string alert_category_id_vals[] = {
{0x00, "Simple Alert: General text alert or non-text alert"},
{0x01, "Email: Alert when Email messages arrives"},
{0x02, "News: News feeds such as RSS, Atom"},
{0x03, "Call: Incoming call"},
{0x04, "Missed call: Missed Call"},
{0x05, "SMS/MMS: SMS/MMS message arrives"},
{0x06, "Voice mail: Voice mail"},
{0x07, "Schedule: Alert occurred on calendar, planner"},
{0x08, "High Prioritized Alert: Alert that should be handled as high priority"},
{0x09, "Instant Message: Alert for incoming instant messages"},
{0xFB, "Defined by service specification"},
{0xFC, "Defined by service specification"},
{0xFD, "Defined by service specification"},
{0xFE, "Defined by service specification"},
{0xFF, "Defined by service specification"},
{0x0, NULL}
};
static const value_string alert_command_id_vals[] = {
{0x00, "Enable New Incoming Alert Notification"},
{0x01, "Enable Unread Category Status Notification"},
{0x02, "Disable New Incoming Alert Notification"},
{0x03, "Disable Unread Category Status Notification"},
{0x04, "Notify New Incoming Alert immediately"},
{0x05, "Notify Unread Category Status immediately"},
{0x0, NULL}
};
static const value_string hid_control_point_command_vals[] = {
{0x00, "Suspend"},
{0x01, "Exit Suspend"},
{0x0, NULL}
};
static const value_string pnp_id_vendor_id_source_vals[] = {
{0x01, "Bluetooth SIG"},
{0x02, "USB Implementer's Forum"},
{0x0, NULL}
};
static const value_string sensor_location_vals[] = {
{0x00, "Other"},
{0x01, "Top of shoe"},
{0x02, "In shoe"},
{0x03, "Hip"},
{0x04, "Front Wheel"},
{0x05, "Left Crank"},
{0x06, "Right Crank"},
{0x07, "Left Pedal"},
{0x08, "Right Pedal"},
{0x09, "Front Hub"},
{0x0A, "Rear Dropout"},
{0x0B, "Chainstay"},
{0x0C, "Rear Wheel"},
{0x0D, "Rear Hub"},
{0x0E, "Chest"},
{0x0, NULL}
};
static const value_string gender_vals[] = {
{0x00, "Male"},
{0x01, "Female"},
{0x02, "Unspecified"},
{0x0, NULL}
};
static const value_string sport_type_for_aerobic_and_anaerobic_thresholds_vals[] = {
{0x00, "Unspecified"},
{0x01, "Running (Treadmill)"},
{0x02, "Cycling (Ergometer)"},
{0x03, "Rowing (Ergometer)"},
{0x04, "Cross Training (Elliptical)"},
{0x05, "Climbing"},
{0x06, "Skiing"},
{0x07, "Skating"},
{0x08, "Arm exercising"},
{0x09, "Lower body exercising"},
{0x0A, "Upper body exercising"},
{0x0B, "Whole body exercising"},
{0x0, NULL}
};
static const value_string barometric_pressure_trend_vals[] = {
{0x00, "Unknown"},
{0x01, "Continuously falling"},
{0x02, "Continuously rising"},
{0x03, "Falling, then steady"},
{0x04, "Rising, then steady"},
{0x05, "Falling before a lesser rise"},
{0x06, "Falling before a greater rise"},
{0x07, "Rising before a greater fall"},
{0x08, "Rising before a lesser fall"},
{0x09, "Steady"},
{0x0, NULL}
};
static const value_string central_address_resolution_vals[] = {
{0x00, "Not supported"},
{0x01, "Supported"},
{0x02, ""},
{0x0, NULL}
};
union request_parameters_union {
void *data;
struct _read_write {
guint16 handle;
guint16 offset;
} read_write;
struct _read_multiple {
guint number_of_handles;
guint16 *handle;
} read_multiple;
struct _mtu {
guint16 mtu;
} mtu;
struct _read_by_type {
guint16 starting_handle;
guint16 ending_handle;
bluetooth_uuid_t uuid;
} read_by_type;
struct _find_information {
guint16 starting_handle;
guint16 ending_handle;
} find_information;
};
typedef struct _request_data_t {
guint8 opcode;
guint32 request_in_frame;
guint32 response_in_frame;
union request_parameters_union parameters;
} request_data_t;
typedef struct _handle_data_t {
bluetooth_uuid_t uuid;
} handle_data_t;
typedef struct _mtu_data_t {
guint mtu;
} mtu_data_t;
typedef struct _fragment_data_t {
guint length;
guint offset;
gint data_in_frame;
guint8 *data;
} fragment_data_t;
void proto_register_btatt(void);
void proto_reg_handoff_btatt(void);
#define PROTO_DATA_BTATT_HANDLE 0x00
#define PROTO_DATA_BTATT_UUID16 0x01
#define PROTO_DATA_BTATT_UUID128 0x02
static void btatt_handle_prompt(packet_info *pinfo, gchar* result)
{
gulong *value_data;
value_data = (gulong *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_HANDLE);
if (value_data)
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "ATT Handle 0x%04x as", (guint) *value_data);
else
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Unknown ATT Handle");
}
static gpointer btatt_handle_value(packet_info *pinfo)
{
gulong *value_data;
value_data = (gulong *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_HANDLE);
if (value_data)
return (gpointer) *value_data;
return NULL;
}
static void btatt_uuid16_prompt(packet_info *pinfo, gchar* result)
{
gulong *value_data;
value_data = (gulong *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID16);
if (value_data)
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "ATT UUID16 0x%04x as", (guint) *value_data);
else
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Unknown ATT UUID16");
}
static gpointer btatt_uuid16_value(packet_info *pinfo)
{
gulong *value_data;
value_data = (gulong *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID16);
if (value_data)
return (gpointer) *value_data;
return NULL;
}
static void btatt_uuid128_prompt(packet_info *pinfo, gchar* result)
{
gchar *value_data;
value_data = (gchar *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID128);
if (value_data)
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "ATT UUID128 %s as", (gchar *) value_data);
else
g_snprintf(result, MAX_DECODE_AS_PROMPT_LEN, "Unknown ATT UUID128");
}
static gpointer btatt_uuid128_value(packet_info *pinfo)
{
gchar *value_data;
value_data = (gchar *) p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID128);
if (value_data)
return (gpointer) value_data;
return NULL;
}
static request_data_t *
get_request(tvbuff_t *tvb, gint offset, packet_info *pinfo, guint8 opcode,
bluetooth_data_t *bluetooth_data)
{
request_data_t *request_data;
wmem_tree_key_t key[4];
wmem_tree_t *sub_wmemtree;
gint frame_number;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 0;
key[2].key = NULL;
frame_number = pinfo->fd->num;
sub_wmemtree = (wmem_tree_t *) wmem_tree_lookup32_array(requests, key);
request_data = (sub_wmemtree) ? (request_data_t *) wmem_tree_lookup32_le(sub_wmemtree, frame_number) : NULL;
if (!request_data)
return NULL;
if (request_data->request_in_frame == pinfo->fd->num)
return request_data;
switch (opcode) {
case 0x01: /* Error Response */
if (tvb_captured_length_remaining(tvb, offset) < 1)
return NULL;
opcode = tvb_get_guint8(tvb, 1) + 1;
/* No break */
case 0x03: /* Exchange MTU Response */
case 0x05: /* Find Information Response */
case 0x07: /* Find By Type Value Response */
case 0x09: /* Read By Type Response */
case 0x0b: /* Read Response */
case 0x0d: /* Read Blob Response */
case 0x0f: /* Read Multiple Response */
case 0x11: /* Read By Group Type Response */
case 0x13: /* Write Response */
case 0x17: /* Prepare Write Response */
case 0x19: /* Execute Write Response */
case 0x1E: /* Handle Value Confirmation */
if (request_data->opcode == opcode -1)
return request_data;
break;
case 0x1B: /* Handle Value Notification */
case 0x52: /* Write Command */
case 0xD2: /* Signed Write Command */
/* There is no response for them */
return NULL;
case 0x02: /* Exchange MTU Request */
case 0x04: /* Find Information Request */
case 0x06: /* Find By Type Value Request */
case 0x08: /* Read By Type Request */
case 0x0a: /* Read Request */
case 0x0c: /* Read Blob Request */
case 0x0e: /* Read Multiple Request */
case 0x10: /* Read By Group Type Request */
case 0x12: /* Write Request */
case 0x16: /* Prepare Write Request */
case 0x18: /* Execute Write Request */
case 0x1D: /* Handle Value Indication */
/* This should never happen */
default:
return NULL;
}
return NULL;
}
static void
save_request(packet_info *pinfo, guint8 opcode, union request_parameters_union parameters,
bluetooth_data_t *bluetooth_data)
{
wmem_tree_key_t key[4];
guint32 frame_number;
request_data_t *request_data;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &frame_number;
key[3].length = 0;
key[3].key = NULL;
request_data = wmem_new(wmem_file_scope(), request_data_t);
request_data->opcode = opcode;
request_data->request_in_frame = frame_number;
request_data->response_in_frame = 0;
request_data->parameters = parameters;
wmem_tree_insert32_array(requests, key, request_data);
}
static void
save_handle(packet_info *pinfo, bluetooth_uuid_t uuid, guint32 handle,
bluetooth_data_t *bluetooth_data)
{
if (!handle && uuid.size != 2 && uuid.size != 16)
return;
if (have_tap_listener(btatt_tap_handles)) {
tap_handles_t *tap_handles;
tap_handles = wmem_new(wmem_packet_scope(), tap_handles_t);
tap_handles->handle = handle;
tap_handles->uuid = uuid;
tap_queue_packet(btatt_tap_handles, pinfo, tap_handles);
}
if (!pinfo->fd->flags.visited && bluetooth_data) {
wmem_tree_key_t key[5];
guint32 frame_number;
handle_data_t *handle_data;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &handle;
key[3].length = 1;
key[3].key = &frame_number;
key[4].length = 0;
key[4].key = NULL;
handle_data = wmem_new(wmem_file_scope(), handle_data_t);
handle_data->uuid = uuid;
wmem_tree_insert32_array(handle_to_uuid, key, handle_data);
}
}
static bluetooth_uuid_t
get_uuid_from_handle(packet_info *pinfo, guint32 handle,
bluetooth_data_t *bluetooth_data)
{
wmem_tree_key_t key[4];
guint32 frame_number;
handle_data_t *handle_data;
wmem_tree_t *sub_wmemtree;
bluetooth_uuid_t uuid;
memset(&uuid, 0, sizeof uuid);
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &handle;
key[3].length = 0;
key[3].key = NULL;
sub_wmemtree = (wmem_tree_t *) wmem_tree_lookup32_array(handle_to_uuid, key);
handle_data = (sub_wmemtree) ? (handle_data_t *) wmem_tree_lookup32_le(sub_wmemtree, frame_number) : NULL;
if (handle_data)
uuid = handle_data->uuid;
return uuid;
}
static int
dissect_handle_uint(proto_tree *tree, packet_info *pinfo, gint hf,
tvbuff_t *tvb, gint offset, bluetooth_data_t *bluetooth_data,
bluetooth_uuid_t *uuid, guint16 handle)
{
proto_item *sub_item;
proto_tree *sub_tree;
bluetooth_uuid_t local_uuid;
sub_item = proto_tree_add_uint(tree, hf, tvb, 0, 0, handle);
PROTO_ITEM_SET_GENERATED(sub_item);
local_uuid = get_uuid_from_handle(pinfo, handle, bluetooth_data);
if (local_uuid.size == 2 || local_uuid.size == 16) {
proto_item_append_text(sub_item, " (%s)", print_uuid(&local_uuid));
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_handle);
if (local_uuid.size == 2)
sub_item = proto_tree_add_uint(sub_tree, hf_btatt_uuid16, tvb, 0, 0, local_uuid.bt_uuid);
else
sub_item = proto_tree_add_bytes_with_length(sub_tree, hf_btatt_uuid128, tvb, 0, 0, local_uuid.data, 16);
PROTO_ITEM_SET_GENERATED(sub_item);
if (uuid)
*uuid = local_uuid;
} else {
if (uuid) {
local_uuid.size = 0;
local_uuid.bt_uuid = 0;
*uuid = local_uuid;
}
}
return offset + 2;
}
static int
dissect_handle(proto_tree *tree, packet_info *pinfo, gint hf,
tvbuff_t *tvb, gint offset, bluetooth_data_t *bluetooth_data,
bluetooth_uuid_t *uuid)
{
proto_item *sub_item;
proto_tree *sub_tree;
guint16 handle;
bluetooth_uuid_t local_uuid;
sub_item = proto_tree_add_item(tree, hf, tvb, offset, 2, ENC_LITTLE_ENDIAN);
handle = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
local_uuid = get_uuid_from_handle(pinfo, handle, bluetooth_data);
if (local_uuid.size == 2 || local_uuid.size == 16) {
proto_item_append_text(sub_item, " (%s)", print_uuid(&local_uuid));
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_handle);
if (local_uuid.size == 2)
sub_item = proto_tree_add_uint(sub_tree, hf_btatt_uuid16, tvb, 0, 0, local_uuid.bt_uuid);
else
sub_item = proto_tree_add_bytes_with_length(sub_tree, hf_btatt_uuid128, tvb, 0, 0, local_uuid.data, 16);
PROTO_ITEM_SET_GENERATED(sub_item);
if (uuid)
*uuid = local_uuid;
} else {
if (uuid) {
local_uuid.size = 0;
local_uuid.bt_uuid = 0;
*uuid = local_uuid;
}
}
return offset + 2;
}
static gint
dissect_attribute_value(proto_tree *tree, proto_item *patron_item, packet_info *pinfo, tvbuff_t *old_tvb,
gint old_offset, gint length, guint16 handle, bluetooth_uuid_t uuid, bluetooth_data_t *bluetooth_data)
{
proto_item *sub_item;
proto_tree *sub_tree;
tvbuff_t *tvb;
gint offset = 0;
bluetooth_uuid_t sub_uuid;
guint16 sub_handle;
guint32 value;
const gint **hfs;
tvb = tvb_new_subset(old_tvb, old_offset, length, length);
if (p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_HANDLE) == NULL) {
guint16 *value_data;
value_data = wmem_new(wmem_file_scope(), guint16);
*value_data = handle;
p_add_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_HANDLE, value_data);
}
if (dissector_try_uint_new(att_handle_dissector_table, handle, tvb, pinfo, tree, TRUE, bluetooth_data))
return old_offset + length;
if (uuid.size == 2) {
if (p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID16) == NULL) {
guint16 *value_data;
value_data = wmem_new(wmem_file_scope(), guint16);
*value_data = uuid.bt_uuid;
p_add_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID16, value_data);
}
} else if (uuid.size == 16) {
if (p_get_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID128) == NULL) {
guint8 *value_data;
value_data = wmem_strdup(wmem_file_scope(), print_numeric_uuid(&uuid));
p_add_proto_data(pinfo->pool, pinfo, proto_btatt, PROTO_DATA_BTATT_UUID128, value_data);
}
}
if (!uuid.bt_uuid) {
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
return old_offset + tvb_captured_length(tvb);
}
if (dissector_try_string(att_uuid128_dissector_table, print_uuid(&uuid), tvb, pinfo, tree, bluetooth_data))
return old_offset + length;
if (dissector_try_uint_new(att_uuid16_dissector_table, uuid.bt_uuid, tvb, pinfo, tree, TRUE, bluetooth_data))
return old_offset + length;
switch (uuid.bt_uuid) {
case 0x2800: /* GATT Primary Service Declaration */
case 0x2801: /* GATT Secondary Service Declaration */
if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
sub_uuid = get_uuid(tvb, offset, 2);
proto_item_append_text(patron_item, ", UUID: %s", print_uuid(&sub_uuid));
offset += 2;
save_handle(pinfo, sub_uuid, handle, bluetooth_data);
} else if (tvb_reported_length_remaining(tvb, offset) == 16) {
proto_tree_add_item(tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
sub_uuid = get_uuid(tvb, offset, 16);
proto_item_append_text(patron_item, ", UUID128: %s", print_uuid(&sub_uuid));
offset += 16;
save_handle(pinfo, sub_uuid, handle, bluetooth_data);
} else {
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
break;
case 0x2802: /* GATT Include Declaration */
offset = dissect_handle(tree, pinfo, hf_btatt_included_service_handle, tvb, offset, bluetooth_data, NULL);
sub_handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(tree, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
sub_uuid = get_uuid(tvb, offset, 2);
proto_item_append_text(patron_item, ", Included Handle: 0x%04x, UUID: %s", sub_handle, print_uuid(&sub_uuid));
offset += 2;
save_handle(pinfo, sub_uuid, sub_handle, bluetooth_data);
break;
case 0x2803: /* GATT Characteristic Declaration*/
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_characteristic_properties, ett_btatt_characteristic_properties, hfx_btatt_characteristic_properties, ENC_NA);
offset += 1;
offset = dissect_handle(tree, pinfo, hf_btatt_characteristic_value_handle, tvb, offset, bluetooth_data, NULL);
sub_handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
if (tvb_reported_length_remaining(tvb, offset) == 16) {
proto_tree_add_item(tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
sub_uuid = get_uuid(tvb, offset, 16);
proto_item_append_text(patron_item, ", Characteristic Handle: 0x%04x, UUID128: %s", tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN), print_uuid(&sub_uuid));
offset += 16;
save_handle(pinfo, sub_uuid, sub_handle, bluetooth_data);
} else if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
sub_uuid = get_uuid(tvb, offset, 2);
proto_item_append_text(patron_item, ", Characteristic Handle: 0x%04x, UUID: %s", sub_handle, print_uuid(&sub_uuid));
offset += 2;
save_handle(pinfo, sub_uuid, sub_handle, bluetooth_data);
} else {
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
break;
case 0x2900: /* Characteristic Extended Properties */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_characteristic_extended_properties, ett_btatt_value, hfx_btatt_characteristic_extended_properties, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2901: /* Characteristic User Description */
proto_tree_add_item(tree, hf_btatt_characteristic_user_description, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2902: /* GATT: Client Characteristic Configuration */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_characteristic_configuration_client, ett_btatt_value, hfx_btatt_characteristic_configuration_client, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2903: /* Server Characteristic Configuration */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_characteristic_configuration_server, ett_btatt_value, hfx_btatt_characteristic_configuration_server, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2904: /* Characteristic Presentation Format */
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_format, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_exponent, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_unit, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_namespace, tvb, offset, 1, ENC_NA);
value = tvb_get_guint8(tvb, offset);
offset += 1;
if (value == 0x01) /* Bluetooth SIG */
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_namespace_description_btsig, tvb, offset, 2, ENC_LITTLE_ENDIAN);
else
proto_tree_add_item(tree, hf_btatt_characteristic_presentation_namespace_description, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2905: /* Characteristic Aggregate Format */
sub_item = proto_tree_add_none_format(tree, hf_btatt_handles_info,
tvb, offset, tvb_captured_length(tvb), "Handles (%i items)",
tvb_captured_length(tvb) / 2);
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
while (offset < (gint64) tvb_captured_length(tvb)) {
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
}
break;
case 0x2907: /* External Report Reference */
if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
} else if (tvb_reported_length_remaining(tvb, offset) == 16) {
proto_tree_add_item(tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
offset += 16;
} else {
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
break;
case 0x2908: /* GATT: Report Reference */
proto_tree_add_item(tree, hf_btatt_report_reference_report_id, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_report_reference_report_type, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x290B: /* Environmental Sensing Configuration */
proto_tree_add_item(tree, hf_btatt_esp_trigger_logic, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x290C: /* Environmental Sensing Measurement */
proto_tree_add_item(tree, hf_btatt_esp_flags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_esp_sampling_function, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_esp_measurement_period, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
proto_tree_add_item(tree, hf_btatt_esp_update_interval, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
proto_tree_add_item(tree, hf_btatt_esp_application, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_esp_measurement_uncertainty, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x290D: /* Environmental Sensing Trigger Setting */
proto_tree_add_item(tree, hf_btatt_esp_condition, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_esp_operand, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A4A: /* HOGP: HID Information */
proto_tree_add_item(tree, hf_btatt_hogp_bcd_hid, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_hogp_b_country_code, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_hogp_flags, ett_btatt_value, hfx_btatt_hogp_flags, ENC_NA);
offset += 1;
break;
case 0x2A4B: /* HOGP: Report Map */
offset = dissect_usb_hid_get_report_descriptor(pinfo, tree, tvb, offset, NULL);
break;
case 0x2A4E: /* HOGP: Protocol Mode */
proto_tree_add_item(tree, hf_btatt_hogp_protocol_mode, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A00: /* Device Name */
proto_tree_add_item(tree, hf_btatt_device_name, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A01: /* Appearance */
switch ((tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN) & 0xFFC0) >> 6) {
case 0x003: /* Watch */
hfs = hfx_btatt_appearance_watch;
break;
case 0x00C: /* Thermometer */
hfs = hfx_btatt_appearance_thermometer;
break;
case 0x00D: /* Heart Rate Sensor */
hfs = hfx_btatt_appearance_heart_rate;
break;
case 0x00E: /* Blood Pressure */
hfs = hfx_btatt_appearance_blood_pressure;
break;
case 0x00F: /* HID */
hfs = hfx_btatt_appearance_hid;
break;
case 0x011: /* Running Walking Sensor */
hfs = hfx_btatt_appearance_running_walking_sensor;
break;
case 0x012: /* Cycling */
hfs = hfx_btatt_appearance_cycling;
break;
case 0x031: /* Pulse Oximeter */
hfs = hfx_btatt_appearance_pulse_oximeter;
break;
case 0x051: /* Outdoor Sports Activity */
hfs = hfx_btatt_appearance_outdoor_sports_activity;
break;
default:
hfs = hfx_btatt_appearance;
}
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_appearance, ett_btatt_value, hfs, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A02: /* Peripheral Privacy Flag */
proto_tree_add_item(tree, hf_btatt_peripheral_privacy_flag, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A03: /* Reconnection Address */
offset = dissect_bd_addr(hf_btatt_reconnection_address, pinfo, tree, tvb, offset, FALSE, bluetooth_data->interface_id, bluetooth_data->adapter_id, NULL);
break;
case 0x2A04: /* Peripheral Preferred Connection Parameters */
proto_tree_add_item(tree, hf_btatt_minimum_connection_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_maximum_connection_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_slave_latency, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_connection_supervision_timeout_multiplier, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A05: /* Service Changed */
proto_tree_add_item(tree, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A06: /* Alert Level */
proto_tree_add_item(tree, hf_btatt_alert_level, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A07: /* Tx Power Level */
proto_tree_add_item(tree, hf_btatt_tx_power_level, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A08: /* Date Time */
proto_tree_add_item(tree, hf_btatt_year, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_month, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_day, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_hours, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_minutes, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_seconds, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A09: /* Day of Week */
proto_tree_add_item(tree, hf_btatt_day_of_week, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A0A: /* Day Date Time */
case 0x2A0C: /* Exact Time 256 */
case 0x2A2B: /* Current Time */
proto_tree_add_item(tree, hf_btatt_year, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_month, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_day, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_hours, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_minutes, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_seconds, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_day_of_week, tvb, offset, 1, ENC_NA);
offset += 1;
if (uuid.bt_uuid == 0x2A0C || uuid.bt_uuid == 0x2A2B) {
proto_tree_add_item(tree, hf_btatt_fractions256, tvb, offset, 1, ENC_NA);
offset += 1;
}
if (uuid.bt_uuid == 0x2A2B) {
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_time_adjust_reason, ett_btatt_value, hfx_btatt_time_adjust_reason, ENC_NA);
offset += 1;
}
break;
case 0x2A0D: /* DST Offset */
proto_tree_add_item(tree, hf_btatt_dst_offset, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A0E: /* Time Zone */
proto_tree_add_item(tree, hf_btatt_timezone, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A0F: /* Local Time Information */
proto_tree_add_item(tree, hf_btatt_timezone, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_dst_offset, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A11: /* Time with DST */
proto_tree_add_item(tree, hf_btatt_year, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_month, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_day, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_hours, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_minutes, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_seconds, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_dst_offset, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A12: /* Time Accuracy */
proto_tree_add_item(tree, hf_btatt_time_accuracy, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A13: /* Time Source */
proto_tree_add_item(tree, hf_btatt_time_source, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A14: /* Reference Time Information */
proto_tree_add_item(tree, hf_btatt_time_source, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_time_accuracy, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_time_days_since_update, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_time_hours_since_update, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A16: /* Time Update Control Point */
proto_tree_add_item(tree, hf_btatt_time_update_control_point, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A17: /* Time Update State */
proto_tree_add_item(tree, hf_btatt_time_current_state, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_time_result, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A19: /* Battery Level */
proto_tree_add_item(tree, hf_btatt_battery_level, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A1D: /* Temperature Type */
proto_tree_add_item(tree, hf_btatt_temperature_type, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A21: /* Measurement Interval */
proto_tree_add_item(tree, hf_btatt_measurement_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A22: /* Boot Keyboard Input Report */
call_dissector_with_data(usb_hid_boot_keyboard_input_report_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
offset += length;
break;
case 0x2A23: /* System ID */
proto_tree_add_item(tree, hf_btatt_system_id_manufacturer_identifier, tvb, offset, 5, ENC_LITTLE_ENDIAN);
offset += 5;
proto_tree_add_item(tree, hf_btatt_system_id_organizationally_unique_identifier, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
break;
case 0x2A24: /* Model Number String */
proto_tree_add_item(tree, hf_btatt_model_number_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A25: /* Serial Number String */
proto_tree_add_item(tree, hf_btatt_serial_number_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A26: /* Firmware Revision String */
proto_tree_add_item(tree, hf_btatt_firmware_revision_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A27: /* Hardware Revision String */
proto_tree_add_item(tree, hf_btatt_hardware_revision_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A28: /* Software Revision String */
proto_tree_add_item(tree, hf_btatt_software_revision_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A29: /* Manufacturer Name String */
proto_tree_add_item(tree, hf_btatt_manufacturer_string, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A2C: /* Magnetic Declination */
proto_tree_add_item(tree, hf_btatt_magnetic_declination, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A31: /* Scan Refresh */
proto_tree_add_item(tree, hf_btatt_scan_refresh, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A32: /* Boot Keyboard Output Report */
call_dissector_with_data(usb_hid_boot_keyboard_output_report_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
offset += length;
break;
case 0x2A33: /* Boot Mouse Input Report */
call_dissector_with_data(usb_hid_boot_mouse_input_report_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
offset += length;
break;
case 0x2A38: /* Body Sensor Location */
proto_tree_add_item(tree, hf_btatt_body_sensor_location, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A39: /* Heart Rate Control Point */
proto_tree_add_item(tree, hf_btatt_heart_rate_control_point, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A3F: /* Alert Status */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_alert_status, ett_btatt_value, hfx_btatt_alert_status, ENC_NA);
offset += 1;
break;
case 0x2A40: /* Ringer Control Point */
proto_tree_add_item(tree, hf_btatt_ringer_control_point, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A41: /* Ringer Setting */
proto_tree_add_item(tree, hf_btatt_ringer_setting, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A42: /* Alert Category ID Bit Mask */
case 0x2A47: /* Supported New Alert Category */
case 0x2A48: /* Supported Unread Alert Category */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_alert_category_id_bitmask_1, ett_btatt_value, hfx_btatt_alert_category_id_bitmask_1, ENC_NA);
offset += 1;
if (tvb_reported_length_remaining(tvb, offset) >= 1) {
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_alert_category_id_bitmask_2, ett_btatt_value, hfx_btatt_alert_category_id_bitmask_2, ENC_NA);
offset += 1;
}
break;
case 0x2A43: /* Alert Category ID */
proto_tree_add_item(tree, hf_btatt_alert_category_id, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A44: /* Alert Notification Control Point */
proto_tree_add_item(tree, hf_btatt_alert_command_id, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_alert_category_id, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A45: /* Unread Alert Status */
proto_tree_add_item(tree, hf_btatt_alert_category_id, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_alert_unread_count, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A46: /* New Alert */
proto_tree_add_item(tree, hf_btatt_alert_category_id, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_alert_number_of_new_alert, tvb, offset, 1, ENC_NA);
offset += 1;
if (tvb_reported_length_remaining(tvb, offset) > 0) {
proto_tree_add_item(tree, hf_btatt_alert_text_string_information, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
}
break;
case 0x2A49: /* Blood Pressure Feature */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_blood_pressure_feature, ett_btatt_value, hfx_btatt_blood_pressure_feature, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A4C: /* HID Control Point */
proto_tree_add_item(tree, hf_btatt_hogp_hid_control_point_command, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A4F: /* Scan Interval Window */
proto_tree_add_item(tree, hf_btatt_le_scan_interval, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_le_scan_window, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A50: /* PnP ID */
proto_tree_add_item(tree, hf_btatt_pnp_id_vendor_id_source, tvb, offset, 1, ENC_NA);
value = tvb_get_guint8(tvb, offset);
offset += 1;
if (value == 1)
proto_tree_add_item(tree, hf_btatt_pnp_id_vendor_id_bluetooth_sig, tvb, offset, 2, ENC_LITTLE_ENDIAN);
else if (value == 2)
proto_tree_add_item(tree, hf_btatt_pnp_id_vendor_id_usb_forum, tvb, offset, 2, ENC_LITTLE_ENDIAN);
else
proto_tree_add_item(tree, hf_btatt_pnp_id_vendor_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_pnp_id_product_id, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_pnp_id_product_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A51: /* Glucose Feature */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_glucose_feature, ett_btatt_value, hfx_btatt_glucose_feature, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A54: /* RSC Feature */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_rsc_feature, ett_btatt_value, hfx_btatt_rsc_feature, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A5C: /* CSC Feature */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_csc_feature, ett_btatt_value, hfx_btatt_csc_feature, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A5D: /* Sensor Location */
proto_tree_add_item(tree, hf_btatt_sensor_location, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A6C: /* Elevation */
proto_tree_add_item(tree, hf_btatt_elevation, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
break;
case 0x2A6D: /* Pressure */
proto_tree_add_item(tree, hf_btatt_pressure, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
break;
case 0x2A6E: /* Temperature */
proto_tree_add_item(tree, hf_btatt_temperature, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A6F: /* Humidity */
proto_tree_add_item(tree, hf_btatt_humidity, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A70: /* True Wind Speed */
proto_tree_add_item(tree, hf_btatt_true_wind_speed, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A71: /* True Wind Direction */
proto_tree_add_item(tree, hf_btatt_true_wind_direction, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A72: /* Apparent Wind Speed */
proto_tree_add_item(tree, hf_btatt_apparent_wind_speed, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A73: /* Apparent Wind Direction */
proto_tree_add_item(tree, hf_btatt_apparent_wind_direction, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A74: /* Gust Factor */
proto_tree_add_item(tree, hf_btatt_gust_factor, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A75: /* Pollen Concentration */
proto_tree_add_item(tree, hf_btatt_pollen_concentration, tvb, offset, 3, ENC_LITTLE_ENDIAN);
offset += 3;
break;
case 0x2A76: /* UV Index */
proto_tree_add_item(tree, hf_btatt_uv_index, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A77: /* Irradiance */
proto_tree_add_item(tree, hf_btatt_irradiance, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A78: /* Rainfall */
proto_tree_add_item(tree, hf_btatt_rainfall, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A79: /* Wind Chill */
proto_tree_add_item(tree, hf_btatt_wind_chill, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A7A: /* Heat Index */
proto_tree_add_item(tree, hf_btatt_heart_index, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A7B: /* Dew Point */
proto_tree_add_item(tree, hf_btatt_dew_point, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A7D: /* Descriptor Value Changed */
proto_tree_add_bitmask(tree, tvb, offset, hf_btatt_descriptor_value_changed_flags , ett_btatt_value, hfx_btatt_descriptor_value_changed_flags, ENC_LITTLE_ENDIAN);
offset += 2;
if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
} else if (tvb_reported_length_remaining(tvb, offset) == 16) {
proto_tree_add_item(tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
offset += 16;
} else {
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
break;
case 0x2A7E: /* Aerobic Heart Rate Lower Limit */
proto_tree_add_item(tree, hf_btatt_aerobic_heart_rate_lower_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A7F: /* Aerobic Threshold */
proto_tree_add_item(tree, hf_btatt_aerobic_threshold, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A80: /* Age */
proto_tree_add_item(tree, hf_btatt_age, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A81: /* Anaerobic Heart Rate Lower Limit */
proto_tree_add_item(tree, hf_btatt_anaerobic_heart_rate_lower_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A82: /* Anaerobic Heart Rate Upper Limit */
proto_tree_add_item(tree, hf_btatt_anaerobic_heart_rate_upper_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A83: /* Anaerobic Threshold */
proto_tree_add_item(tree, hf_btatt_anaerobic_threshold, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A84: /* Aerobic Heart Rate Upper Limit */
proto_tree_add_item(tree, hf_btatt_aerobic_heart_rate_upper_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A85: /* Date of Birth */
case 0x2A86: /* Date of Threshold Assessment */
proto_tree_add_item(tree, hf_btatt_year, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_month, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_day, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A87: /* Email Address */
proto_tree_add_item(tree, hf_btatt_email_address, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A88: /* Fat Burn Heart Rate Lower Limit */
proto_tree_add_item(tree, hf_btatt_fat_burn_heart_rate_lower_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A89: /* Fat Burn Heart Rate Upper Limit */
proto_tree_add_item(tree, hf_btatt_fat_burn_heart_rate_upper_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A8A: /* First Name */
proto_tree_add_item(tree, hf_btatt_first_name, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A8B: /* Five Zone Heart Rate Limits */
proto_tree_add_item(tree, hf_btatt_five_zone_heart_rate_limits_very_light_light_limit, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_five_zone_heart_rate_limits_light_moderate_limit, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_five_zone_heart_rate_limits_moderate_hard_limit, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_five_zone_heart_rate_limits_hard_maximum_limit, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A8C: /* Gender */
proto_tree_add_item(tree, hf_btatt_gender, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A8D: /* Heart Rate Max */
proto_tree_add_item(tree, hf_btatt_heart_rate_max, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A8E: /* Height */
proto_tree_add_item(tree, hf_btatt_height, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A8F: /* Hip Circumference */
proto_tree_add_item(tree, hf_btatt_hip_circumference, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A90: /* Last Name */
proto_tree_add_item(tree, hf_btatt_last_name, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2A91: /* Maximum Recommended Heart Rate */
proto_tree_add_item(tree, hf_btatt_maximum_recommended_heart_rate, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A92: /* Resting Heart Rate */
proto_tree_add_item(tree, hf_btatt_resting_heart_rate, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A93: /* Sport Type for Aerobic and Anaerobic Thresholds */
proto_tree_add_item(tree, hf_btatt_sport_type_for_aerobic_and_anaerobic_thresholds, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A94: /* Three Zone Heart Rate Limits */
proto_tree_add_item(tree, hf_btatt_three_zone_heart_rate_limits_light_moderate, tvb, offset, 1, ENC_NA);
offset += 1;
proto_tree_add_item(tree, hf_btatt_three_zone_heart_rate_limits_moderate_hard, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A95: /* Two Zone Heart Rate Limit */
proto_tree_add_item(tree, hf_btatt_two_zone_heart_rate_limit_fat_burn_fitness, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A96: /* VO2 Max */
proto_tree_add_item(tree, hf_btatt_vo2_max, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2A97: /* Waist Circumference */
proto_tree_add_item(tree, hf_btatt_waist_circumference, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A98: /* Weight */
proto_tree_add_item(tree, hf_btatt_weight, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
break;
case 0x2A99: /* Database Change Increment */
proto_tree_add_item(tree, hf_btatt_database_change_increment, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset += 4;
break;
case 0x2A9A: /* User Index */
proto_tree_add_item(tree, hf_btatt_user_index, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2AA0: /* Magnetic Flux Density - 2D */
case 0x2AA1: /* Magnetic Flux Density - 3D */
proto_tree_add_item(tree, hf_btatt_magnetic_flux_density_x, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(tree, hf_btatt_magnetic_flux_density_y, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (uuid.bt_uuid == 0x2AA1) {
proto_tree_add_item(tree, hf_btatt_magnetic_flux_density_z, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
}
break;
case 0x2AA2: /* Language */
proto_tree_add_item(tree, hf_btatt_language, tvb, offset, tvb_captured_length_remaining(tvb, offset), ENC_NA | ENC_UTF_8);
offset += tvb_captured_length_remaining(tvb, offset);
break;
case 0x2AA3: /* Barometric Pressure Trend */
proto_tree_add_item(tree, hf_btatt_barometric_pressure_trend, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2AA6: /* Central Address Resolution */
proto_tree_add_item(tree, hf_btatt_central_address_resolution, tvb, offset, 1, ENC_NA);
offset += 1;
break;
case 0x2906: /* Valid Range */
case 0x2A18: /* Glucose Measurement */
case 0x2A1C: /* Temperature Measurement */
case 0x2A1E: /* Intermediate Temperature */
case 0x2A2A: /* IEEE 11073-20601 Regulatory Certification Data List */
case 0x2A34: /* Glucose Measurement Context */
case 0x2A35: /* Blood Pressure Measurement */
case 0x2A36: /* Intermediate Cuff Pressure */
case 0x2A37: /* Heart Rate Measurement */
case 0x2A4D: /* Report */
case 0x2A52: /* Record Access Control Point */
case 0x2A53: /* RSC Measurement */
case 0x2A55: /* SC Control Point */
case 0x2A5B: /* CSC Measurement */
case 0x2A63: /* Cycling Power Measurement */
case 0x2A64: /* Cycling Power Vector */
case 0x2A65: /* Cycling Power Feature */
case 0x2A66: /* Cycling Power Control Point */
case 0x2A67: /* Location and Speed */
case 0x2A68: /* Navigation */
case 0x2A69: /* Position Quality */
case 0x2A6A: /* LN Feature */
case 0x2A6B: /* LN Control Point */
case 0x2A9B: /* Body Composition Feature */
case 0x2A9C: /* Body Composition Measurement */
case 0x2A9D: /* Weight Measurement */
case 0x2A9E: /* Weight Scale Feature */
case 0x2A9F: /* User Control Point */
case 0x2AA4: /* Bond Management Control Point */
case 0x2AA5: /* Bond Management Feature */
case 0x2AA7: /* CGM Measurement */
case 0x2AA8: /* CGM Feature */
case 0x2AA9: /* CGM Status */
case 0x2AAA: /* CGM Session Start Time */
case 0x2AAB: /* CGM Session Run Time */
case 0x2AAC: /* CGM Specific Ops Control Point */
/* TODO: Implement */
default:
proto_tree_add_item(tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
return old_offset + offset;
}
static int
dissect_btgatt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *main_item;
proto_tree *main_tree;
proto_item *patron_item = NULL;
bluetooth_uuid_t uuid;
main_item = proto_tree_add_item(tree, (gint) GPOINTER_TO_UINT(wmem_list_frame_data(wmem_list_tail(pinfo->layers))), tvb, 0, -1, ENC_NA);
main_tree = proto_item_add_subtree(main_item, ett_btgatt);
uuid.size = 2;
uuid.bt_uuid = (guint16) g_ascii_strtoull(pinfo->current_proto + strlen(pinfo->current_proto) - 7, NULL, 16);
uuid.data[0] = uuid.bt_uuid & 0xFF;
uuid.data[1] = (uuid.bt_uuid >> 8) & 0xFF;
return dissect_attribute_value(main_tree, patron_item, pinfo, tvb,
0, tvb_captured_length(tvb), 0, uuid, (bluetooth_data_t *) data);
}
static gboolean
is_long_attribute_value(bluetooth_uuid_t uuid)
{
switch (uuid.bt_uuid) {
case 0x2901: /* Characteristic User Description */
case 0x2A00: /* Device Name */
case 0x2A24: /* Model Number String */
case 0x2A25: /* Serial Number String */
case 0x2A26: /* Firmware Revision String */
case 0x2A27: /* Hardware Revision String */
case 0x2A28: /* Software Revision String */
case 0x2A29: /* Manufacturer Name String */
case 0x2A4B: /* Report Map */
case 0x2A87: /* Email Address */
case 0x2A90: /* Last Name */
return TRUE;
}
return FALSE;
}
static guint
get_mtu(packet_info *pinfo, bluetooth_data_t *bluetooth_data)
{
wmem_tree_key_t key[3];
guint32 frame_number;
mtu_data_t *mtu_data;
wmem_tree_t *sub_wmemtree;
guint mtu = 23;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 0;
key[2].key = NULL;
sub_wmemtree = (wmem_tree_t *) wmem_tree_lookup32_array(mtus, key);
mtu_data = (sub_wmemtree) ? (mtu_data_t *) wmem_tree_lookup32_le(sub_wmemtree, frame_number) : NULL;
if (mtu_data)
mtu = mtu_data->mtu;
return mtu;
}
static void
save_mtu(packet_info *pinfo, bluetooth_data_t *bluetooth_data, guint mtu)
{
wmem_tree_key_t key[4];
guint32 frame_number;
mtu_data_t *mtu_data;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &frame_number;
key[3].length = 0;
key[3].key = NULL;
mtu_data = wmem_new(wmem_file_scope(), mtu_data_t);
mtu_data->mtu = mtu;
wmem_tree_insert32_array(mtus, key, mtu_data);
}
static void
save_value_fragment(packet_info *pinfo, tvbuff_t *tvb, gint offset,
guint32 handle, guint data_offset, bluetooth_data_t *bluetooth_data)
{
wmem_tree_key_t key[5];
guint32 frame_number;
fragment_data_t *fragment_data;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &handle;
key[3].length = 1;
key[3].key = &frame_number;
key[4].length = 0;
key[4].key = NULL;
fragment_data = wmem_new(wmem_file_scope(), fragment_data_t);
fragment_data->length = tvb_captured_length_remaining(tvb, offset);
fragment_data->offset = data_offset;
fragment_data->data_in_frame = frame_number;
fragment_data->data = (guint8 *) tvb_memdup(wmem_file_scope(), tvb, offset, fragment_data->length);
wmem_tree_insert32_array(fragments, key, fragment_data);
}
static guint8 *
get_value(packet_info *pinfo, guint32 handle, bluetooth_data_t *bluetooth_data, guint *length)
{
wmem_tree_key_t key[4];
guint32 frame_number;
fragment_data_t *fragment_data;
wmem_tree_t *sub_wmemtree;
guint16 last_offset = 0xFFFF;
guint16 size;
gboolean first = TRUE;
guint8 *data = NULL;
frame_number = pinfo->fd->num;
key[0].length = 1;
key[0].key = &bluetooth_data->interface_id;
key[1].length = 1;
key[1].key = &bluetooth_data->adapter_id;
key[2].length = 1;
key[2].key = &handle;
key[3].length = 0;
key[3].key = NULL;
sub_wmemtree = (wmem_tree_t *) wmem_tree_lookup32_array(fragments, key);
while (1) {
fragment_data = (sub_wmemtree) ? (fragment_data_t *) wmem_tree_lookup32_le(sub_wmemtree, frame_number) : NULL;
if (!fragment_data || (fragment_data && fragment_data->offset >= last_offset)) {
if (length)
*length = 0;
return NULL;
}
last_offset = fragment_data->offset;
if (first) {
size = fragment_data->offset + fragment_data->length;
data = (guint8 *) wmem_alloc(pinfo->pool, size);
if (length)
*length = size;
first = FALSE;
}
memcpy(data + fragment_data->offset, fragment_data->data, fragment_data->length);
if (fragment_data->offset == 0)
return data;
frame_number = fragment_data->data_in_frame - 1;
}
if (length)
*length = 0;
return NULL;
}
static int
dissect_btatt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
{
proto_item *main_item;
proto_tree *main_tree;
proto_item *sub_item;
proto_tree *sub_tree;
int offset = 0;
guint8 opcode;
guint8 request_opcode;
bluetooth_data_t *bluetooth_data;
request_data_t *request_data;
guint16 handle;
bluetooth_uuid_t uuid;
guint mtu;
uuid.size = 0;
uuid.bt_uuid = 0;
bluetooth_data = (bluetooth_data_t *) data;
if (tvb_reported_length_remaining(tvb, 0) < 1)
return 0;
main_item = proto_tree_add_item(tree, proto_btatt, tvb, 0, -1, ENC_NA);
main_tree = proto_item_add_subtree(main_item, ett_btatt);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATT");
switch (pinfo->p2p_dir) {
case P2P_DIR_SENT:
col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
break;
case P2P_DIR_RECV:
col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
break;
default:
col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
break;
}
mtu = get_mtu(pinfo, bluetooth_data);
if (tvb_reported_length(tvb) > mtu)
expert_add_info(pinfo, main_item, &ei_btatt_mtu_exceeded);
proto_tree_add_bitmask_with_flags(main_tree, tvb, offset, hf_btatt_opcode, ett_btatt_opcode, hfx_btatt_opcode, ENC_NA, BMT_NO_APPEND);
opcode = tvb_get_guint8(tvb, 0);
offset++;
request_data = get_request(tvb, offset, pinfo, opcode, bluetooth_data);
col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode, opcode_vals, "<unknown>"));
switch (opcode) {
case 0x01: /* Error Response */
proto_tree_add_bitmask_with_flags(main_tree, tvb, offset, hf_btatt_req_opcode_in_error, ett_btatt_opcode, hfx_btatt_opcode, ENC_NA, BMT_NO_APPEND);
request_opcode = tvb_get_guint8(tvb, offset);
offset += 1;
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle_in_error, tvb, offset, bluetooth_data, NULL);
col_append_fstr(pinfo->cinfo, COL_INFO, " - %s, Handle: 0x%04x",
val_to_str_const(tvb_get_guint8(tvb, offset), error_vals, "<unknown>"),
tvb_get_letohs(tvb, offset - 2));
proto_tree_add_item(main_tree, hf_btatt_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (request_data && (request_opcode == 0x08 || request_opcode == 0x10)) {
sub_item = proto_tree_add_uint(main_tree, hf_btatt_uuid16, tvb, 0, 0, request_data->parameters.read_by_type.uuid.bt_uuid);
PROTO_ITEM_SET_GENERATED(sub_item);
}
break;
case 0x02: /* Exchange MTU Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Client Rx MTU: %u", tvb_get_letohs(tvb, offset));
proto_tree_add_item(main_tree, hf_btatt_client_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.mtu.mtu = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x03: /* Exchange MTU Response */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Server Rx MTU: %u", tvb_get_letohs(tvb, offset));
proto_tree_add_item(main_tree, hf_btatt_server_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
if (!pinfo->fd->flags.visited && request_data && bluetooth_data) {
guint new_mtu;
new_mtu = tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN);
if (new_mtu > request_data->parameters.mtu.mtu)
new_mtu = request_data->parameters.mtu.mtu;
save_mtu(pinfo, bluetooth_data, new_mtu);
}
offset += 2;
break;
case 0x04: /* Find Information Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handles: 0x%04x..0x%04x",
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
proto_tree_add_item(main_tree, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(main_tree, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.find_information.starting_handle = tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN);
request_parameters.find_information.ending_handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x05: /* Find Information Response */
{
guint8 format = tvb_get_guint8(tvb, offset);
sub_item = proto_tree_add_item(main_tree, hf_btatt_uuid_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (format == 1) {
while( tvb_reported_length_remaining(tvb, offset) > 0) {
sub_item = proto_tree_add_item(main_tree, hf_btatt_information_data, tvb, offset, 4, ENC_NA),
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sub_tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
uuid = get_uuid(tvb, offset, 2);
offset += 2;
proto_item_append_text(sub_item, ", Handle: 0x%04x, UUID: %s",
tvb_get_letohs(tvb, offset - 4),
print_uuid(&uuid));
save_handle(pinfo, uuid, handle, bluetooth_data);
}
}
else if (format == 2) {
while( tvb_reported_length_remaining(tvb, offset) > 0) {
sub_item = proto_tree_add_item(main_tree, hf_btatt_information_data, tvb, offset, 4, ENC_NA),
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sub_tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
uuid = get_uuid(tvb, offset, 16);
offset += 16;
proto_item_append_text(sub_item, ", Handle: 0x%04x, UUID: %s",
tvb_get_letohs(tvb, offset - 4),
print_uuid(&uuid));
save_handle(pinfo, uuid, handle, bluetooth_data);
}
}
else {
expert_add_info(pinfo, sub_item, &ei_btatt_uuid_format_unknown);
}
}
break;
case 0x06: /* Find By Type Value Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &bluetooth_uuid_vals_ext, "<unknown>"),
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
proto_tree_add_item(main_tree, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(main_tree, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(main_tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
uuid = get_uuid(tvb, offset - 2, 2);
offset += 2;
dissect_attribute_value(main_tree, NULL, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset), 0, uuid, bluetooth_data);
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_by_type.starting_handle = tvb_get_guint16(tvb, offset - 6, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.ending_handle = tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.uuid = uuid;
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
offset = tvb_reported_length(tvb);
break;
case 0x07: /* Find By Type Value Response */
while( tvb_reported_length_remaining(tvb, offset) > 0 ) {
sub_item = proto_tree_add_none_format(main_tree, hf_btatt_handles_info, tvb, offset, 4,
"Handles Info, Handle: 0x%04x, Group End Handle: 0x%04x",
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
proto_tree_add_item(sub_tree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (request_data)
save_handle(pinfo, request_data->parameters.read_by_type.uuid,
tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN),
bluetooth_data);
}
break;
case 0x08: /* Read By Type Request */
case 0x10: /* Read By Group Type Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &bluetooth_uuid_vals_ext, "<unknown>"),
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
proto_tree_add_item(main_tree, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
proto_tree_add_item(main_tree, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (tvb_reported_length_remaining(tvb, offset) == 2) {
proto_tree_add_item(main_tree, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_by_type.starting_handle = tvb_get_guint16(tvb, offset - 6, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.ending_handle = tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.uuid = get_uuid(tvb, offset - 2, 2);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
}
else if (tvb_reported_length_remaining(tvb, offset) == 16) {
sub_item = proto_tree_add_item(main_tree, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
proto_item_append_text(sub_item, " (%s)", val_to_str_ext_const(tvb_get_letohs(tvb, offset),
&bluetooth_uuid_vals_ext, "<unknown>"));
offset += 16;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_by_type.starting_handle = tvb_get_guint16(tvb, offset - 20, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.ending_handle = tvb_get_guint16(tvb, offset - 18, ENC_LITTLE_ENDIAN);
request_parameters.read_by_type.uuid = get_uuid(tvb, offset - 16, 16);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
}
break;
case 0x09: /* Read By Type Response */
{
guint8 length = tvb_get_guint8(tvb, offset);
proto_tree_add_item(main_tree, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if(length > 0) {
col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u",
tvb_reported_length_remaining(tvb, offset)/length);
while (tvb_reported_length_remaining(tvb, offset) >= length)
{
sub_item = proto_tree_add_none_format(main_tree, hf_btatt_attribute_data, tvb,
offset, length, "Attribute Data, Handle: 0x%04x",
tvb_get_letohs(tvb, offset));
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
if (request_data) {
save_handle(pinfo, request_data->parameters.read_by_type.uuid, tvb_get_guint16(tvb, offset, ENC_LITTLE_ENDIAN), bluetooth_data);
}
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
if (request_data) {
offset = dissect_attribute_value(sub_tree, sub_item, pinfo, tvb, offset, length - 2, tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN), request_data->parameters.read_by_type.uuid, bluetooth_data);
} else {
proto_tree_add_item(sub_tree, hf_btatt_value, tvb, offset, length - 2, ENC_NA);
offset += length - 2;
}
}
}
if (request_data) {
sub_item = proto_tree_add_uint(main_tree, hf_btatt_uuid16, tvb, 0, 0, request_data->parameters.read_by_type.uuid.bt_uuid);
PROTO_ITEM_SET_GENERATED(sub_item);
}
}
break;
case 0x0a: /* Read Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_write.handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
request_parameters.read_write.offset = 0;
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x0b: /* Read Response */
if (request_data) {
dissect_handle_uint(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, &uuid, request_data->parameters.read_write.handle);
}
if (is_long_attribute_value(uuid) && tvb_captured_length(tvb) >= mtu) {
sub_item = proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
if (!pinfo->fd->flags.visited && request_data && bluetooth_data)
save_value_fragment(pinfo, tvb, offset, request_data->parameters.read_write.handle, 0, bluetooth_data);
offset = tvb_captured_length(tvb);
expert_add_info(pinfo, sub_item, &ei_btatt_mtu_full);
} else {
if (request_data)
handle = request_data->parameters.read_write.handle;
else
handle = 0;
offset = dissect_attribute_value(main_tree, NULL, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset), handle, uuid, bluetooth_data);
}
break;
case 0x0c: /* Read Blob Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
proto_tree_add_item(main_tree, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_write.handle = tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN);
request_parameters.read_write.offset = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x0d: /* Read Blob Response */
if (request_data) {
dissect_handle_uint(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, &uuid, request_data->parameters.read_write.handle);
if (request_data->parameters.read_write.offset == 0 && !is_long_attribute_value(uuid)) {
offset = dissect_attribute_value(main_tree, NULL, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset), request_data->parameters.read_write.handle, uuid, bluetooth_data);
} else {
if (!pinfo->fd->flags.visited && bluetooth_data)
save_value_fragment(pinfo, tvb, offset, request_data->parameters.read_write.handle, request_data->parameters.read_write.offset, bluetooth_data);
if (tvb_captured_length(tvb) < mtu) {
tvbuff_t *next_tvb;
guint reassembled_length;
guint8 *reassembled_data;
sub_item = proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
reassembled_data = get_value(pinfo, request_data->parameters.read_write.handle, bluetooth_data, &reassembled_length);
if (reassembled_data) {
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_value);
next_tvb = tvb_new_child_real_data(tvb, reassembled_data, reassembled_length, reassembled_length);
add_new_data_source(pinfo, next_tvb, "Reassembled ATT");
dissect_attribute_value(sub_tree, NULL, pinfo, next_tvb, 0, tvb_captured_length(next_tvb), request_data->parameters.read_write.handle, uuid, bluetooth_data);
}
} else {
sub_item = proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
expert_add_info(pinfo, sub_item, &ei_btatt_mtu_full);
}
}
} else {
proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_captured_length(tvb);
}
break;
case 0x0e: /* Multiple Read Request */
if(tvb_reported_length_remaining(tvb, offset) < 4) {
expert_add_info(pinfo, main_item, &ei_btatt_handle_too_few);
break;
}
col_append_str(pinfo->cinfo, COL_INFO, ", Handles: ");
while (tvb_reported_length_remaining(tvb, offset) >= 2) {
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
col_append_fstr(pinfo->cinfo, COL_INFO, "0x%04x ", tvb_get_letohs(tvb, offset - 2));
}
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.read_multiple.number_of_handles = (tvb_captured_length(tvb) - 1) / 2;
request_parameters.read_multiple.handle = (guint16 *) tvb_memdup(wmem_file_scope(),
tvb, 1, request_parameters.read_multiple.number_of_handles * 2);
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x0f: /* Multiple Read Response */
if (request_data) {
guint i_handle;
for (i_handle = 0; i_handle < request_data->parameters.read_multiple.number_of_handles; i_handle += 1) {
dissect_handle_uint(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, &uuid, request_data->parameters.read_multiple.handle[i_handle]);
offset = dissect_attribute_value(main_tree, NULL, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset), request_data->parameters.read_multiple.handle[i_handle], uuid, bluetooth_data);
}
} else {
proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
offset = tvb_reported_length(tvb);
}
break;
case 0x11: /* Read By Group Type Response */
{
guint8 length = tvb_get_guint8(tvb, offset);
proto_tree_add_item(main_tree, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (length > 0) {
col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u", tvb_reported_length_remaining(tvb, offset)/length);
while (tvb_reported_length_remaining(tvb, offset) >= length) {
sub_item = proto_tree_add_none_format(main_tree, hf_btatt_attribute_data, tvb, offset, length,
"Attribute Data, Handle: 0x%04x, Group End Handle: 0x%04x",
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_list);
offset = dissect_handle(sub_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
handle = tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN);
proto_tree_add_item(sub_tree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (request_data) {
offset = dissect_attribute_value(sub_tree, sub_item, pinfo, tvb, offset, length - 4, handle, request_data->parameters.read_by_type.uuid, bluetooth_data);
} else {
proto_tree_add_item(sub_tree, hf_btatt_value, tvb, offset, length - 4, ENC_NA);
offset += length - 4;
}
}
}
if (request_data) {
sub_item = proto_tree_add_uint(main_tree, hf_btatt_uuid16, tvb, 0, 0, request_data->parameters.read_by_type.uuid.bt_uuid);
PROTO_ITEM_SET_GENERATED(sub_item);
}
}
break;
case 0x12: /* Write Request */
case 0x1d: /* Handle Value Indication */
case 0x52: /* Write Command */
case 0x1b: /* Handle Value Notification */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, &uuid);
offset = dissect_attribute_value(main_tree, NULL, pinfo, tvb, offset, tvb_captured_length_remaining(tvb, offset), tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN), uuid, bluetooth_data);
if (!pinfo->fd->flags.visited && bluetooth_data && (opcode == 0x12 || opcode == 0x1d)) {
union request_parameters_union request_parameters;
request_parameters.data = NULL;
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x13: /* Write Response */
/* No parameters */
break;
case 0x16: /* Prepare Write Request */
case 0x17: /* Prepare Write Response */
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, &uuid);
proto_tree_add_item(main_tree, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
offset += 2;
if (!pinfo->fd->flags.visited && bluetooth_data && opcode == 0x16) {
union request_parameters_union request_parameters;
request_parameters.data = NULL;
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
if (!pinfo->fd->flags.visited && request_data && bluetooth_data && opcode == 0x16)
save_value_fragment(pinfo, tvb, offset,
tvb_get_guint16(tvb, offset - 4, ENC_LITTLE_ENDIAN),
tvb_get_guint16(tvb, offset - 2, ENC_LITTLE_ENDIAN),
bluetooth_data);
/* XXX: How to detect there is max data in frame and it is last fragment?
(Execute Write Request/Response is good candidate, but there is no one handle) */
if (request_data && tvb_captured_length(tvb) < mtu) {
tvbuff_t *next_tvb;
guint reassembled_length;
guint8 *reassembled_data;
sub_item = proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
reassembled_data = get_value(pinfo, request_data->parameters.read_write.handle, bluetooth_data, &reassembled_length);
if (reassembled_data) {
sub_tree = proto_item_add_subtree(sub_item, ett_btatt_value);
next_tvb = tvb_new_child_real_data(tvb, reassembled_data, reassembled_length, reassembled_length);
add_new_data_source(pinfo, next_tvb, "Reassembled ATT");
dissect_attribute_value(sub_tree, NULL, pinfo, next_tvb, 0, tvb_captured_length(next_tvb), request_data->parameters.read_write.handle, uuid, bluetooth_data);
}
} else {
proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, -1, ENC_NA);
}
offset = tvb_reported_length(tvb);
break;
case 0x18: /* Execute Write Request */
col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
val_to_str_const(tvb_get_guint8(tvb, offset), flags_vals, "<unknown>"));
proto_tree_add_item(main_tree, hf_btatt_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
offset++;
if (!pinfo->fd->flags.visited && bluetooth_data) {
union request_parameters_union request_parameters;
request_parameters.data = NULL;
save_request(pinfo, opcode, request_parameters, bluetooth_data);
}
break;
case 0x19: /* Execute Write Response */
/* No parameters */
break;
case 0xd2: /* Signed Write Command */
{
guint8 length;
col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
offset = dissect_handle(main_tree, pinfo, hf_btatt_handle, tvb, offset, bluetooth_data, NULL);
length = tvb_reported_length_remaining(tvb, offset);
if (length > 12) {
proto_tree_add_item(main_tree, hf_btatt_value, tvb, offset, length-12, ENC_NA);
offset+=length-12;
}
proto_tree_add_item(main_tree, hf_btatt_sign_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
offset+=4;
proto_tree_add_item(main_tree, hf_btatt_signature, tvb, offset, 8, ENC_NA);
offset+=8;
break;
}
default:
break;
}
if (request_data) {
if (request_data->request_in_frame > 0 && request_data->request_in_frame != pinfo->fd->num) {
sub_item = proto_tree_add_uint(main_tree, hf_request_in_frame, tvb, 0, 0, request_data->request_in_frame);
PROTO_ITEM_SET_GENERATED(sub_item);
}
if (!pinfo->fd->flags.visited && request_data->response_in_frame == 0 &&
pinfo->fd->num > request_data->request_in_frame)
request_data->response_in_frame = pinfo->fd->num;
if (request_data->response_in_frame > 0 && request_data->response_in_frame != pinfo->fd->num) {
sub_item = proto_tree_add_uint(main_tree, hf_response_in_frame, tvb, 0, 0, request_data->response_in_frame);
PROTO_ITEM_SET_GENERATED(sub_item);
}
}
return offset;
}
void
proto_register_btatt(void)
{
module_t *module;
expert_module_t *expert_btatt;
static hf_register_info hf[] = {
{&hf_btatt_opcode,
{"Opcode", "btatt.opcode",
FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_opcode_authentication_signature,
{"Authentication Signature", "btatt.opcode.authentication_signature",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL}
},
{&hf_btatt_opcode_command,
{"Command", "btatt.opcode.command",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL}
},
{&hf_btatt_opcode_method,
{"Method", "btatt.opcode.method",
FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x3F,
NULL, HFILL}
},
{&hf_btatt_handles_info,
{"Handles Info", "btatt.handles_info",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_attribute_data,
{"Attribute Data", "btatt.attribute_data",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_handle,
{"Handle", "btatt.handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_starting_handle,
{"Starting Handle", "btatt.starting_handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_ending_handle,
{"Ending Handle", "btatt.ending_handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_group_end_handle,
{"Group End Handle", "btatt.group_end_handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_value,
{"Value", "btatt.value",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_req_opcode_in_error,
{"Request Opcode in Error", "btatt.req_opcode_in_error",
FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_handle_in_error,
{"Handle in Error", "btatt.handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_error_code,
{"Error Code", "btatt.error_code",
FT_UINT8, BASE_HEX, VALS(error_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_uuid16,
{"UUID", "btatt.uuid16",
FT_UINT16, BASE_HEX |BASE_EXT_STRING, &bluetooth_uuid_vals_ext, 0x0,
NULL, HFILL}
},
{&hf_btatt_uuid128,
{"UUID", "btatt.uuid128",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_client_rx_mtu,
{"Client Rx MTU", "btatt.client_rx_mtu",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_server_rx_mtu,
{"Server Rx MTU", "btatt.server_rx_mtu",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_uuid_format,
{"UUID Format", "btatt.uuid_format",
FT_UINT8, BASE_HEX, VALS(uuid_format_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_length,
{"Length", "btatt.length",
FT_UINT8, BASE_DEC, NULL, 0x0,
"Length of Handle/Value Pair", HFILL}
},
{&hf_btatt_offset,
{"Offset", "btatt.offset",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_flags,
{"Flags", "btatt.flags",
FT_UINT8, BASE_HEX, VALS(flags_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_sign_counter,
{"Sign Counter", "btatt.sign_counter",
FT_UINT32, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_signature,
{"Signature", "btatt.signature",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties,
{"Characteristic Properties", "btatt.characteristic_properties",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_extended_properties,
{"Extended Properties", "btatt.characteristic_properties.extended_properties",
FT_BOOLEAN, 8, NULL, 0x80,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_authenticated_signed_writes,
{"Authenticated Signed Writes", "btatt.characteristic_properties.authenticated_signed_writes",
FT_BOOLEAN, 8, NULL, 0x40,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_indicate,
{"Indicate", "btatt.characteristic_properties.indicate",
FT_BOOLEAN, 8, NULL, 0x20,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_notify,
{"Notify", "btatt.characteristic_properties.notify",
FT_BOOLEAN, 8, NULL, 0x10,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_write,
{"Write", "btatt.characteristic_properties.write",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_write_without_response,
{"Write without Response", "btatt.characteristic_properties.write_without_response",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_read,
{"Read", "btatt.characteristic_properties.read",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_characteristic_properties_broadcast,
{"Broadcast", "btatt.characteristic_properties.broadcast",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_characteristic_value_handle,
{"Characteristic Value Handle", "btatt.handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_included_service_handle,
{"Included Service Handle", "btatt.handle",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_information_data,
{"Information Data", "btatt.information_data",
FT_NONE, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_client,
{"Characteristic Configuration Client", "btatt.characteristic_configuration_client",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_client_reserved,
{"Reseved", "btatt.characteristic_configuration_client.reserved",
FT_UINT16, BASE_HEX, NULL, 0xFFFC,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_client_indication,
{"Indication", "btatt.characteristic_configuration_client.indication",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_client_notification,
{"Notification", "btatt.characteristic_configuration_client.notification",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_server,
{"Characteristic Configuration Server", "btatt.characteristic_configuration_server",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_server_reserved,
{"Reseved", "btatt.characteristic_configuration_server.reserved",
FT_UINT16, BASE_HEX, NULL, 0xFFFE,
NULL, HFILL}
},
{&hf_btatt_characteristic_configuration_server_broadcast,
{"Broadcast", "btatt.characteristic_configuration_server.broadcast",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_hogp_protocol_mode,
{"Protocol Mode", "btatt.hogp.protocol_mode",
FT_UINT8, BASE_HEX, VALS(hogp_protocol_mode_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_report_reference_report_id,
{"Report ID", "btatt.report_reference.report_id",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_report_reference_report_type,
{"Report Type", "btatt.report_reference.report_id",
FT_UINT8, BASE_HEX, VALS(report_reference_report_type_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_hogp_bcd_hid,
{"bcdHID", "btatt.hogp.bcd_hid",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_hogp_b_country_code,
{"bCountryCode", "btatt.hogp.b_country_code",
FT_UINT8, BASE_HEX, VALS(hid_country_code_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_hogp_flags,
{"Flags", "btatt.hogp.flags",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_hogp_flags_reserved,
{"Reserved", "btatt.hogp.flags.reserved",
FT_UINT8, BASE_HEX, NULL, 0xFC,
NULL, HFILL}
},
{&hf_btatt_hogp_flags_normally_connectable,
{"Normally Connectable", "btatt.hogp.flags.normally_connectable",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_hogp_flags_remote_wake,
{"Remote Wake", "btatt.hogp.flags.remote_wake",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_characteristic_user_description,
{"Characteristic User Description", "btatt.characteristic_user_description",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_extended_properties,
{"Characteristic Extended Properties", "btatt.characteristic_extended_properties",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_extended_properties_reserved,
{"Reserved", "btatt.characteristic_extended_properties.reserved",
FT_UINT16, BASE_HEX, NULL, 0xFFFC,
NULL, HFILL}
},
{&hf_btatt_characteristic_extended_properties_writable_auxiliaries,
{"Writable Auxiliaries", "btatt.characteristic_extended_properties.writable_auxiliaries",
FT_UINT16, BASE_HEX, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_characteristic_extended_properties_reliable_write,
{"Reliable Write", "btatt.characteristic_extended_properties.reliable_write",
FT_UINT16, BASE_HEX, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_format,
{"Format", "btatt.characteristic_presentation.format",
FT_UINT8, BASE_HEX, VALS(characteristic_presentation_format_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_exponent,
{"Exponent", "btatt.characteristic_presentation.exponent",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_unit,
{"Unit", "btatt.characteristic_presentation.unit",
FT_UINT16, BASE_HEX | BASE_EXT_STRING, &bluetooth_uuid_vals_ext, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_namespace,
{"Namespace", "btatt.characteristic_presentation.namespace",
FT_UINT8, BASE_HEX, VALS(characteristic_presentation_namespace_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_namespace_description,
{"Namespace Descrition", "btatt.characteristic_presentation.namespace_description",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_characteristic_presentation_namespace_description_btsig,
{"Namespace Descrition", "btatt.characteristic_presentation.namespace_description",
FT_UINT16, BASE_HEX, VALS(characteristic_presentation_namespace_description_btsig_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_trigger_logic,
{"Trigger Logic", "btatt.esp.trigger_logic",
FT_UINT8, BASE_HEX, VALS(esp_trigger_logic_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_condition,
{"Trigger Logic", "btatt.esp.condition",
FT_UINT8, BASE_HEX, VALS(esp_condition_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_operand,
{"Operand", "btatt.esp.operand",
FT_BYTES, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_flags,
{"Flags", "btatt.esp.flags",
FT_UINT16, BASE_HEX, NULL, 0xFFFF,
NULL, HFILL}
},
{&hf_btatt_esp_sampling_function,
{"Sampling Function", "btatt.esp.sampling_function",
FT_UINT8, BASE_HEX, VALS(esp_sampling_function_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_measurement_period,
{"Measurement Period", "btatt.esp.measurement_period",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_update_interval,
{"Update Interval", "btatt.esp.update_interval",
FT_UINT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_application,
{"Application", "btatt.esp.application",
FT_UINT8, BASE_HEX, VALS(esp_application_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_esp_measurement_uncertainty,
{"Measurement Uncertainty", "btatt.esp.measurement_uncertainty",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_device_name,
{"Device Name", "btatt.device_name",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_appearance,
{"Appearance", "btatt.appearance",
FT_UINT16, BASE_DEC_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_appearance_category,
{"Category", "btatt.appearance.category",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_category_vals), 0xFFC0,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory,
{"Subcategory", "btatt.appearance.subcategory",
FT_UINT16, BASE_DEC_HEX, NULL, 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_watch,
{"Subcategory", "btatt.appearance.subcategory.watch",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_watch_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_thermometer,
{"Subcategory", "btatt.appearance.subcategory.thermometer",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_thermometer_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_heart_rate,
{"Subcategory", "btatt.appearance.subcategory.heart_rate",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_heart_rate_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_blood_pressure,
{"Subcategory", "btatt.appearance.subcategory.blood_pressure",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_blood_pressure_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_hid,
{"Subcategory", "btatt.appearance.subcategory.hid",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_hid_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_running_walking_sensor,
{"Subcategory", "btatt.appearance.subcategory.running_walking_sensor",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_running_walking_sensor_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_cycling,
{"Subcategory", "btatt.appearance.subcategory.cycling",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_cycling_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_pulse_oximeter,
{"Subcategory", "btatt.appearance.subcategory.pulse_oximeter",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_pulse_oximeter_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_appearance_subcategory_outdoor_sports_activity,
{"Subcategory", "btatt.appearance.subcategory.outdoor_sports_activity",
FT_UINT16, BASE_DEC_HEX, VALS(appearance_subcategory_outdoor_sports_activity_vals), 0x003F,
NULL, HFILL}
},
{&hf_btatt_peripheral_privacy_flag,
{"Peripheral Privacy", "btatt.peripheral_privacy_flag",
FT_BOOLEAN, 8, NULL, 0x0,
NULL, HFILL}
},
{ &hf_btatt_reconnection_address,
{ "Reconnection Address", "btatt.reconnection_address",
FT_ETHER, BASE_NONE, NULL, 0x0,
NULL, HFILL }
},
{&hf_btatt_minimum_connection_interval,
{"Minimum Connection Interval", "btatt.minimum_connection_interval",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_maximum_connection_interval,
{"Maximum Connection Interval", "btatt.maximum_connection_interval",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_slave_latency,
{"Slave Latency", "btatt.slave_latency",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_connection_supervision_timeout_multiplier,
{"Connection Supervision Timeout Multiplier", "btatt.connection_supervision_timeout_multiplier",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_level,
{"Alert Level", "btatt.alert_level",
FT_UINT8, BASE_HEX, VALS(alert_level_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_tx_power_level,
{"Tx Power Level", "btatt.tx_power_level",
FT_INT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_year,
{"Year", "btatt.year",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_month,
{"Month", "btatt.month",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_day,
{"Day", "btatt.day",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_hours,
{"Hours", "btatt.hours",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_minutes,
{"Minutes", "btatt.minutes",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_seconds,
{"Seconds", "btatt.seconds",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_day_of_week,
{"Day of Week", "btatt.day_of_week",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_fractions256,
{"Fractions256", "btatt.fractions256",
FT_UINT8, BASE_DEC, NULL, 0x0,
"1/256th of a second", HFILL}
},
{&hf_btatt_dst_offset,
{"Daylight Saving Time Offset", "btatt.dst_offset",
FT_UINT8, BASE_HEX, VALS(dst_offset_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_model_number_string,
{"Model Number String", "btatt.model_number_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_serial_number_string,
{"Serial Number String", "btatt.serial_number_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_firmware_revision_string,
{"Firmware Revision String", "btatt.firmware_revision_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_hardware_revision_string,
{"Hardware Revision String", "btatt.hardware_revision_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_software_revision_string,
{"Software Revision String", "btatt.software_revision_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_manufacturer_string,
{"Manufacturer String", "btatt.manufacturer_string",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
/* TODO: FT_UINT40 */
{&hf_btatt_system_id_manufacturer_identifier,
{"Manufacturer Identifier", "btatt.system_id.manufacturer_identifier",
FT_UINT64, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_system_id_organizationally_unique_identifier,
{"Organizationally Unique Identifier", "btatt.system_id.organizationally_unique_identifier",
FT_UINT24, BASE_HEX, VALS(oui_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_timezone,
{"Timezone", "btatt.timezone",
FT_INT8, BASE_DEC, VALS(timezone_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_time_accuracy,
{"Time Accuracy", "btatt.time_accuracy",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_time_source,
{"Time Source", "btatt.time_source",
FT_UINT8, BASE_DEC, VALS(time_source_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_time_days_since_update,
{"Days Since Update", "btatt.days_since_update",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_time_hours_since_update,
{"Hours Since Update", "btatt.hours_since_update",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_time_update_control_point,
{"Update Control Point", "btatt.update_control_point",
FT_UINT8, BASE_HEX, VALS(time_update_control_point_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_time_current_state,
{"Current State", "btatt.time_current_state",
FT_UINT8, BASE_HEX, VALS(time_current_state_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_time_result,
{"Result", "btatt.time_result",
FT_UINT8, BASE_HEX, VALS(time_result_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_battery_level,
{"Battery Level", "btatt.battery_level",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_temperature_type,
{"Temperature Type", "btatt.temperature_type",
FT_UINT8, BASE_HEX, VALS(temperature_type_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_measurement_interval,
{"Measurement Interval", "btatt.measurement_interval",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason,
{"Adjust Reason", "btatt.adjust_reason",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason_reserved,
{"Reserved", "btatt.adjust_reason.reserved",
FT_UINT8, BASE_HEX, NULL, 0xF0,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason_change_of_dst,
{"Change of DST", "btatt.adjust_reason.change_of_dst",
FT_BOOLEAN, 8, NULL, 0x08,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason_change_of_timezone,
{"Change of Timezone", "btatt.adjust_reason.change_of_timezone",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason_external_reference_time_update,
{"External Reference Time Update", "btatt.adjust_reason.external_reference_time_update",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_time_adjust_reason_manual_time_update,
{"Manual Time Update", "btatt.adjust_reason.manual_time_update",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_magnetic_declination,
{"Magnetic Declination", "btatt.magnetic_declination",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_scan_refresh,
{"Scan Refresh", "btatt.scan_refresh",
FT_UINT8, BASE_HEX, VALS(scan_refresh_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_body_sensor_location,
{"Body Sensor Location", "btatt.body_sensor_location",
FT_UINT8, BASE_HEX, VALS(body_sensor_location_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_heart_rate_control_point,
{"Heart Rate Control Point", "btatt.heart_rate_control_point",
FT_UINT8, BASE_HEX, VALS(heart_rate_control_point_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_status,
{"Alert Status", "btatt.alert.status",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_status_reserved,
{"Reserved", "btatt.alert.status.reserved",
FT_UINT8, BASE_HEX, NULL, 0xF8,
NULL, HFILL}
},
{&hf_btatt_alert_status_display_alert_status,
{"Display Alert Status", "btatt.alert.status.display_alert_status",
FT_BOOLEAN, 8, NULL, 0x04,
NULL, HFILL}
},
{&hf_btatt_alert_status_vibrate_state,
{"Vibrate State", "btatt.alert.status.vibrate_state",
FT_BOOLEAN, 8, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_alert_status_ringer_state,
{"Ringer State", "btatt.alert_status.ringer_state",
FT_BOOLEAN, 8, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_ringer_control_point,
{"Ringer Control Point", "btatt.ringer_control_point",
FT_UINT8, BASE_HEX, VALS(ringer_control_point_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_ringer_setting,
{"Ringer Setting", "btatt.ringer_setting",
FT_UINT8, BASE_HEX, VALS(ringer_setting_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1,
{"Alert Category ID Bitmask 1", "btatt.alert.category_id_bitmask_1",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_schedule,
{"Schedule", "btatt.alert.category_id_bitmask_1.schedule",
FT_UINT8, BASE_HEX, NULL, 0x80,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_voice_mail,
{"Voice Mail", "btatt.alert.category_id_bitmask_1.voice_mail",
FT_UINT8, BASE_HEX, NULL, 0x40,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_sms_mms,
{"SMS/MMS", "btatt.alert.category_id_bitmask_1.sms_mms",
FT_UINT8, BASE_HEX, NULL, 0x20,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_missed_call,
{"Missed Call", "btatt.alert.category_id_bitmask_1.missed_call",
FT_UINT8, BASE_HEX, NULL, 0x10,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_call,
{"Call", "btatt.alert.category_id_bitmask_1.call",
FT_UINT8, BASE_HEX, NULL, 0x08,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_news,
{"News", "btatt.alert.category_id_bitmask_1.news",
FT_UINT8, BASE_HEX, NULL, 0x04,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_email,
{"Email", "btatt.alert.category_id_bitmask_1.email",
FT_UINT8, BASE_HEX, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_1_simple_alert,
{"Simple Alert", "btatt.alert.category_id_bitmask_1.simple_alert",
FT_UINT8, BASE_HEX, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_2,
{"Alert Category ID Bitmask 2", "btatt.alert.category_id_bitmask_2",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_2_reserved,
{"Reserved", "btatt.alert.category_id_bitmask_2.reserved",
FT_UINT8, BASE_HEX, NULL, 0xFC,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_2_instant_message,
{"Instant Message", "btatt.alert.category_id_bitmask_2.instant_message",
FT_UINT8, BASE_HEX, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_alert_category_id_bitmask_2_high_prioritized_alert,
{"High Prioritized Alert", "btatt.alert.category_id_bitmask_2.high_prioritized_alert",
FT_UINT8, BASE_HEX, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_alert_category_id,
{"Alert Category ID", "btatt.alert.category_id",
FT_UINT8, BASE_HEX, VALS(alert_category_id_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_command_id,
{"Alert Command ID", "btatt.alert.command_id",
FT_UINT8, BASE_HEX, VALS(alert_command_id_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_unread_count,
{"Unread Count", "btatt.alert.unread_count",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_number_of_new_alert,
{"Number of New Alert", "btatt.alert.number_of_new_alert",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_alert_text_string_information,
{"Text String Information", "btatt.text_string_information",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature,
{"Blood Pressure Feature", "btatt.blood_pressure.feature",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_reserved,
{"Reserved", "btatt.blood_pressure.feature.reserved",
FT_UINT16, BASE_HEX, NULL, 0xFFC0,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_multiple_bond,
{"Multiple Bond", "btatt.blood_pressure.feature.multiple_bond",
FT_BOOLEAN, 16, NULL, 0x20,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_measurement_position_detection,
{"Measurement Position Detection", "btatt.blood_pressure.feature.measurement_position_detection",
FT_BOOLEAN, 16, NULL, 0x10,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_puls_rate_range,
{"Puls Rate Range", "btatt.blood_pressure.feature.puls_rate_range",
FT_BOOLEAN, 16, NULL, 0x08,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_irregular_pulse_detection,
{"Irregular Pulse Detection", "btatt.blood_pressure.feature.irregular_pulse_detection",
FT_BOOLEAN, 16, NULL, 0x04,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_cuff_fit_detection,
{"Cuff Fit Detection", "btatt.blood_pressure.feature.cuff_fit_detection",
FT_BOOLEAN, 16, NULL, 0x02,
NULL, HFILL}
},
{&hf_btatt_blood_pressure_feature_body_movement_detection,
{"Body Movement Detection", "btatt.blood_pressure.feature.body_movement_detection",
FT_BOOLEAN, 16, NULL, 0x01,
NULL, HFILL}
},
{&hf_btatt_hogp_hid_control_point_command,
{"HID Control Point Command", "btatt.hogp.hid_control_point_command",
FT_UINT8, BASE_HEX, VALS(hid_control_point_command_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_le_scan_interval,
{"LE Scan Interval", "btatt.le_scan_interval",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_le_scan_window,
{"LE Scan Window", "btatt.le_scan_window",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{ &hf_btatt_pnp_id_vendor_id_source,
{ "Vendor ID Source", "btatt.pnp_id.vendor_id_source",
FT_UINT16, BASE_HEX, VALS(pnp_id_vendor_id_source_vals), 0,
NULL, HFILL }
},
{ &hf_btatt_pnp_id_vendor_id,
{ "Vendor ID", "btatt.pnp_id.vendor_id",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_btatt_pnp_id_vendor_id_bluetooth_sig,
{ "Vendor ID", "btatt.pnp_id.vendor_id",
FT_UINT16, BASE_HEX | BASE_EXT_STRING, &bluetooth_company_id_vals_ext, 0,
NULL, HFILL }
},
{ &hf_btatt_pnp_id_vendor_id_usb_forum,
{ "Vendor ID", "btatt.pnp_id.vendor_id",
FT_UINT16, BASE_HEX | BASE_EXT_STRING, &ext_usb_vendors_vals, 0,
NULL, HFILL }
},
{ &hf_btatt_pnp_id_product_id,
{ "Product ID", "btatt.pnp_id.product_id",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{ &hf_btatt_pnp_id_product_version,
{ "Version", "btatt.pnp_id.product_version",
FT_UINT16, BASE_HEX, NULL, 0,
NULL, HFILL }
},
{&hf_btatt_glucose_feature,
{"Glucose Feature", "btatt.glucose.feature",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_reserved,
{"Reserved", "btatt.glucose.feature.reserved",
FT_BOOLEAN, 16, NULL, 0xF800,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_multiple_bond,
{"Multiple Bond", "btatt.glucose.feature.multiple_bond",
FT_BOOLEAN, 16, NULL, 0x0400,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_time_fault,
{"Time Fault", "btatt.glucose.feature.time_fault",
FT_BOOLEAN, 16, NULL, 0x0200,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_general_device_fault,
{"General Device Fault", "btatt.glucose.feature.general_device_fault",
FT_BOOLEAN, 16, NULL, 0x0100,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_read_interrupt_detection,
{"Sensor Read Interrupt Detection", "btatt.glucose.feature.sensor_read_interrupt_detection",
FT_BOOLEAN, 16, NULL, 0x0080,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_temperature_high_low_detection,
{"Sensor Temperature High-Low Detection", "btatt.glucose.feature.sensor_temperature_high_low_detection",
FT_BOOLEAN, 16, NULL, 0x0040,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_result_high_low_detection,
{"Sensor Result High-Low Detection", "btatt.glucose.feature.sensor_result_high_low_detection",
FT_BOOLEAN, 16, NULL, 0x0020,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_strip_type_error_detection,
{"Sensor Strip Type Error Detection", "btatt.glucose.feature.sensor_strip_type_error_detection",
FT_BOOLEAN, 16, NULL, 0x0010,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_strip_insertion_error_detection,
{"Sensor Strip Insertion Error Detection", "btatt.glucose.feature.sensor_strip_insertion_error_detection",
FT_BOOLEAN, 16, NULL, 0x0008,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_sample_size,
{"Sensor Sample Size", "btatt.glucose.feature.sensor_sample_size",
FT_BOOLEAN, 16, NULL, 0x0004,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_sensor_malfunction_detection,
{"Sensor Malfunction Detection", "btatt.glucose.feature.sensor_malfunction_detection",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_glucose_feature_low_battery_detection_during_measurement,
{"Low Battery Detection During Measurement", "btatt.glucose.feature.low_battery_detection_during_measurement",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_rsc_feature,
{"RSC Feature", "btatt.rsc.feature",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_reserved,
{"Reserved", "btatt.rsc.feature.reserved",
FT_BOOLEAN, 16, NULL, 0xFF80,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_multiple_sensor_locations,
{"Multiple Sensor Locations", "btatt.rsc.feature.multiple_sensor_locations",
FT_BOOLEAN, 16, NULL, 0x0010,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_calibration_procedure,
{"Calibration Procedure", "btatt.rsc.feature.calibration_procedure",
FT_BOOLEAN, 16, NULL, 0x0008,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_walking_or_running_status,
{"Walking_or Running Status", "btatt.rsc.feature.walking_or_running_status",
FT_BOOLEAN, 16, NULL, 0x0004,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_total_distance_measurement,
{"Total Distance Measurement", "btatt.rsc.feature.total_distance_measurement",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_rsc_feature_instantaneous_stride_length_measurement,
{"Instantaneous Stride Length Measurement", "btatt.rsc.feature.instantaneous_stride_length_measurement",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_csc_feature,
{"CSC Feature", "btatt.csc.feature",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_csc_feature_reserved,
{"Reserved", "btatt.csc.feature.reserved",
FT_BOOLEAN, 16, NULL, 0xFFF8,
NULL, HFILL}
},
{&hf_btatt_csc_feature_multiple_sensor_locations,
{"Multiple Sensor Locations", "btatt.csc.feature.multiple_sensor_locations",
FT_BOOLEAN, 16, NULL, 0x0004,
NULL, HFILL}
},
{&hf_btatt_csc_feature_crank_revolution_data,
{"Crank Revolution Data", "btatt.csc.feature.crank_revolution_data",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_csc_feature_wheel_revolution_data,
{"Wheel Revolution Data", "btatt.csc.feature.wheel_revolution_data",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_sensor_location,
{"Sensor Location", "btatt.sensor_location",
FT_UINT8, BASE_HEX, VALS(sensor_location_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_elevation,
{"Elevation", "btatt.elevation",
FT_INT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_pressure,
{"Pressure", "btatt.pressure",
FT_UINT32, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_temperature,
{"Temperature", "btatt.temperature",
FT_INT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_humidity,
{"Humidity", "btatt.humidity",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_true_wind_speed,
{"True Wind Speed", "btatt.true_wind_speed",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_true_wind_direction,
{"True Wind Direction", "btatt.true_wind_direction",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_apparent_wind_speed,
{"Apparent Wind Speed", "btatt.apparent_wind_speed",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_apparent_wind_direction,
{"Apparent Wind Direction", "btatt.apparent_wind_direction",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_gust_factor,
{"Gust Factor", "btatt.gust_factor",
FT_UINT8, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_pollen_concentration,
{"Pollen Concentration", "btatt.pollen_concentration",
FT_INT24, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_uv_index,
{"UV Index", "btatt.uv_index",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_irradiance,
{"Irradiance", "btatt.irradiance",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_rainfall,
{"Rainfall", "btatt.rainfall",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_wind_chill,
{"Wind Chill", "btatt.wind_chill",
FT_INT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_heart_index,
{"Heart Index", "btatt.heart_index",
FT_INT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_dew_point,
{"Dew Point", "btatt.dew_point",
FT_INT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags,
{"Flags", "btatt.descriptor_value_changed.flags",
FT_UINT16, BASE_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_reserved,
{"Reserved", "btatt.descriptor_value_changed.flags.reserved",
FT_BOOLEAN, 16, NULL, 0xF800,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_change_to_characteristic_user_description_descriptor,
{"Change to Characteristic User Description Descriptor", "btatt.descriptor_value_changed.flags.change_to_characteristic_user_description_descriptor",
FT_BOOLEAN, 16, NULL, 0x0010,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_change_to_es_measurement_descriptor,
{"Change to ES Measurement Descriptor", "btatt.descriptor_value_changed.flags.change_to_es_measurement_descriptor",
FT_BOOLEAN, 16, NULL, 0x0008,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_change_to_es_configuration_descriptor,
{"Change to ES Configuration Descriptor", "btatt.descriptor_value_changed.flags.change_to_es_configuration_descriptor",
FT_BOOLEAN, 16, NULL, 0x0004,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_change_to_one_or_more_es_trigger_setting_descriptors,
{"Change to One or More ES Trigger Setting Descriptors", "btatt.descriptor_value_changed.flags.change_to_one_or_more_es_trigger_setting_descriptors",
FT_BOOLEAN, 16, NULL, 0x0002,
NULL, HFILL}
},
{&hf_btatt_descriptor_value_changed_flags_source_of_change,
{"Source of Change", "btatt.descriptor_value_changed.flags.source_of_change",
FT_BOOLEAN, 16, NULL, 0x0001,
NULL, HFILL}
},
{&hf_btatt_aerobic_heart_rate_lower_limit,
{"Aerobic Heart Rate Lower Limit", "btatt.aerobic_heart_rate_lower_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_aerobic_threshold,
{"Aerobic Threshold", "btatt.aerobic_threshold",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_age,
{"Age", "btatt.age",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_anaerobic_heart_rate_lower_limit,
{"Anaerobic Heart Rate Lower Limit", "btatt.anaerobic_heart_rate_lower_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_anaerobic_heart_rate_upper_limit,
{"Anaerobic Heart Rate Upper Limit", "btatt.anaerobic_heart_rate_upper_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_anaerobic_threshold,
{"Anaerobic Threshold", "btatt.anaerobic_threshold",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_aerobic_heart_rate_upper_limit,
{"Aerobic Heart Rate Upper Limit", "btatt.aerobic_heart_rate_upper_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_email_address,
{"Email Address", "btatt.email_address",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_fat_burn_heart_rate_lower_limit,
{"Fat Burn Heart Rate Lower Limit", "btatt.fat_burn_heart_rate_lower_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_fat_burn_heart_rate_upper_limit,
{"Fat Burn Heart Rate Upper Limit", "btatt.fat_burn_heart_rate_upper_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_first_name,
{"First Name", "btatt.first_name",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_five_zone_heart_rate_limits_very_light_light_limit,
{"Very Light/Light Limit", "btatt.five_zone_heart_rate_limits.very_light_light_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_five_zone_heart_rate_limits_light_moderate_limit,
{"Light/Moderate Limit,", "btatt.five_zone_heart_rate_limits.light_moderate_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_five_zone_heart_rate_limits_moderate_hard_limit,
{"Moderate/Hard Limit", "btatt.five_zone_heart_rate_limits.moderate_hard_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_five_zone_heart_rate_limits_hard_maximum_limit,
{"Hard/Maximum Limit", "btatt.five_zone_heart_rate_limits.hard_maximum_limit",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_gender,
{"Gender", "btatt.gender",
FT_UINT8, BASE_HEX, VALS(gender_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_heart_rate_max,
{"Heart Rate Max", "btatt.heart_rate_max",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_height,
{"Height", "btatt.height",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_hip_circumference,
{"Hip Circumference", "btatt.hip_circumference",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_last_name,
{"Last Name", "btatt.last_name",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_maximum_recommended_heart_rate,
{"Maximum Recommended Heart Rate", "btatt.maximum_recommended_heart_rate",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_resting_heart_rate,
{"Resting Heart Rate", "btatt.resting_heart_rate",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_sport_type_for_aerobic_and_anaerobic_thresholds,
{"Sport Type for Aerobic and Anaerobic Thresholds", "btatt.sport_type_for_aerobic_and_anaerobic_thresholds",
FT_UINT8, BASE_DEC, VALS(sport_type_for_aerobic_and_anaerobic_thresholds_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_three_zone_heart_rate_limits_light_moderate,
{"Three zone Heart Rate Limits - Light (Fat burn) / Moderate (Aerobic) Limit", "btatt.three_zone_heart_rate_limits.light_moderate",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_three_zone_heart_rate_limits_moderate_hard,
{"Three zone Heart Rate Limits - Moderate (Aerobic) / Hard (Anaerobic) Limit", "btatt.three_zone_heart_rate_limits.moderate_hard",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_two_zone_heart_rate_limit_fat_burn_fitness,
{"Two zone Heart Rate Limit - Fat burn / Fitness Limit", "btatt.two_zone_heart_rate_limit.fat_burn_fitness",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_vo2_max,
{"VO2 Max", "btatt.vo2_max",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_waist_circumference,
{"Waist Circumference", "btatt.waist_circumference",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_weight,
{"Weight", "btatt.weight",
FT_UINT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_database_change_increment,
{"Database Change Increment", "btatt.database_change_increment",
FT_UINT32, BASE_DEC_HEX, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_user_index,
{"User Index", "btatt.user_index",
FT_UINT8, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_magnetic_flux_density_x,
{"X", "btatt.hf_btatt_magnetic_flux_density.x",
FT_INT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_magnetic_flux_density_y,
{"Y", "btatt.hf_btatt_magnetic_flux_density.y",
FT_INT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_magnetic_flux_density_z,
{"Z", "btatt.hf_btatt_magnetic_flux_density.z",
FT_INT16, BASE_DEC, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_language,
{"Language", "btatt.language",
FT_STRING, BASE_NONE, NULL, 0x0,
NULL, HFILL}
},
{&hf_btatt_barometric_pressure_trend,
{"Barometric Pressure Trend", "btatt.barometric_pressure_trend",
FT_UINT8, BASE_DEC, VALS(barometric_pressure_trend_vals), 0x0,
NULL, HFILL}
},
{&hf_btatt_central_address_resolution,
{"Central Address Resolution", "btatt.central_address_resolution",
FT_UINT8, BASE_DEC, VALS(central_address_resolution_vals), 0x0,
NULL, HFILL}
},
{&hf_request_in_frame,
{"Request in Frame", "btatt.request_in_frame",
FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0,
NULL, HFILL}
},
{&hf_response_in_frame,
{"Response in Frame", "btatt.response_in_frame",
FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0,
NULL, HFILL}
},
};
/* Setup protocol subtree array */
static gint *ett[] = {
&ett_btatt,
&ett_btatt_list,
&ett_btatt_value,
&ett_btatt_opcode,
&ett_btatt_handle,
&ett_btatt_characteristic_properties,
&ett_btgatt
};
static ei_register_info ei[] = {
{ &ei_btatt_uuid_format_unknown, { "btatt.uuid_format.unknown", PI_PROTOCOL, PI_WARN, "Unknown format", EXPFILL }},
{ &ei_btatt_handle_too_few, { "btatt.handle.too_few", PI_PROTOCOL, PI_WARN, "Too few handles, should be 2 or more", EXPFILL }},
{ &ei_btatt_mtu_exceeded, { "btatt.mtu.exceeded", PI_PROTOCOL, PI_WARN, "Packet size exceed current ATT_MTU", EXPFILL }},
{ &ei_btatt_mtu_full, { "btatt.mtu.full", PI_PROTOCOL, PI_NOTE, "Reached ATT_MTU. Attribute value may be longer.", EXPFILL }},
};
static build_valid_func btatt_handle_da_build_value[1] = {btatt_handle_value};
static decode_as_value_t btatt_handle_da_values = {btatt_handle_prompt, 1, btatt_handle_da_build_value};
static decode_as_t btatt_handle_da = {"btatt", "ATT Handle", "btatt.handle",
1, 0, &btatt_handle_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
static build_valid_func btatt_uuid16_da_build_value[1] = {btatt_uuid16_value};
static decode_as_value_t btatt_uuid16_da_values = {btatt_uuid16_prompt, 1, btatt_uuid16_da_build_value};
static decode_as_t btatt_uuid16_da = {"btatt", "ATT UUID16", "btatt.uuid16",
1, 0, &btatt_uuid16_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
static build_valid_func btatt_uuid128_da_build_value[1] = {btatt_uuid128_value};
static decode_as_value_t btatt_uuid128_da_values = {btatt_uuid128_prompt, 1, btatt_uuid128_da_build_value};
static decode_as_t btatt_uuid128_da = {"btatt", "ATT UUID128", "btatt.uuid128",
1, 0, &btatt_uuid128_da_values, NULL, NULL,
decode_as_default_populate_list, decode_as_default_reset, decode_as_default_change, NULL};
/* Register the protocol name and description */
proto_btatt = proto_register_protocol("Bluetooth Attribute Protocol", "BT ATT", "btatt");
btatt_handle = new_register_dissector("btatt", dissect_btatt, proto_btatt);
att_handle_dissector_table = register_dissector_table("btatt.handle", "BT ATT Handle", FT_UINT16, BASE_HEX);
att_uuid16_dissector_table = register_dissector_table("btatt.uuid16", "BT ATT UUID16", FT_UINT16, BASE_HEX);
att_uuid128_dissector_table = register_dissector_table("btatt.uuid128", "BT ATT UUID128", FT_STRING, BASE_NONE);
/* Required function calls to register the header fields and subtrees used */
proto_register_field_array(proto_btatt, hf, array_length(hf));
proto_register_subtree_array(ett, array_length(ett));
expert_btatt = expert_register_protocol(proto_btatt);
expert_register_field_array(expert_btatt, ei, array_length(ei));
mtus = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
requests = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
fragments = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
handle_to_uuid = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
module = prefs_register_protocol(proto_btatt, NULL);
prefs_register_static_text_preference(module, "att.version",
"Bluetooth Protocol ATT version from Core 4.0",
"Version of protocol supported by this dissector.");
register_decode_as(&btatt_handle_da);
register_decode_as(&btatt_uuid16_da);
register_decode_as(&btatt_uuid128_da);
}
void
proto_reg_handoff_btatt(void)
{
gint i_array;
usb_hid_boot_keyboard_input_report_handle = find_dissector("usbhid.boot_report.keyboard.input");
usb_hid_boot_keyboard_output_report_handle = find_dissector("usbhid.boot_report.keyboard.output");
usb_hid_boot_mouse_input_report_handle = find_dissector("usbhid.boot_report.mouse.input");
dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_ATT, btatt_handle);
dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_ATT, btatt_handle);
btatt_tap_handles = register_tap("btatt.handles");
for (i_array = 0; bluetooth_uuid_vals[i_array].strptr != NULL; i_array += 1) {
gchar *name;
gchar *short_name;
gchar *abbrev;
dissector_handle_t handle_tmp;
gint proto_tmp = -1;
if (bluetooth_uuid_vals[i_array].value < 0x1800) {
continue;
}
if ((bluetooth_uuid_vals[i_array].value & 0xFF00) == 0x2700) {
continue;
}
name = wmem_strdup_printf(wmem_epan_scope(), "Bluetooth GATT Attribute %s (UUID 0x%04x)",
bluetooth_uuid_vals[i_array].strptr, bluetooth_uuid_vals[i_array].value);
short_name = wmem_strdup_printf(wmem_epan_scope(), "BT GATT %s (UUID 0x%04x)",
bluetooth_uuid_vals[i_array].strptr, bluetooth_uuid_vals[i_array].value);
abbrev = wmem_strdup_printf(wmem_epan_scope(), "btgatt.uuid0x%04x",
bluetooth_uuid_vals[i_array].value);
proto_tmp = proto_register_protocol(name, short_name, abbrev);
handle_tmp = new_register_dissector(short_name, dissect_btgatt, proto_tmp);
dissector_add_for_decode_as("btatt.handle", handle_tmp);
}
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 4
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=4 tabstop=8 expandtab:
* :indentSize=4:tabSize=8:noTabs=true:
*/