2 * Routines for Bluetooth Handsfree Profile (HFP)
4 * Copyright 2002, Wolfgang Hansmann <hansmann@cs.uni-bonn.de>
5 * Copyright 2006, Ronnie Sahlberg
6 * - refactored for Wireshark checkin
7 * Copyright 2013, Michal Labedzki for Tieto Corporation
9 * - dissection of HFP's AT-commands
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * SPDX-License-Identifier: GPL-2.0-or-later
20 #include <epan/packet.h>
21 #include <epan/prefs.h>
22 #include <epan/expert.h>
23 #include <epan/strutil.h>
24 #include <epan/unit_strings.h>
26 #include "packet-btrfcomm.h"
27 #include "packet-btsdp.h"
29 static int proto_bthfp
;
31 static int hf_command
;
32 static int hf_parameters
;
35 static int hf_at_cmd_type
;
36 static int hf_at_command_line_prefix
;
37 static int hf_at_ignored
;
38 static int hf_parameter
;
39 static int hf_unknown_parameter
;
41 static int hf_fragment
;
42 static int hf_fragmented
;
43 static int hf_brsf_hs
;
44 static int hf_brsf_hs_ec_nr_function
;
45 static int hf_brsf_hs_call_waiting_or_tree_way
;
46 static int hf_brsf_hs_cli_presentation
;
47 static int hf_brsf_hs_voice_recognition_activation
;
48 static int hf_brsf_hs_remote_volume_control
;
49 static int hf_brsf_hs_enhanced_call_status
;
50 static int hf_brsf_hs_enhanced_call_control
;
51 static int hf_brsf_hs_codec_negotiation
;
52 static int hf_brsf_hs_hf_indicators
;
53 static int hf_brsf_hs_esco_s4_t2_settings_support
;
54 static int hf_brsf_hs_reserved
;
55 static int hf_brsf_ag
;
56 static int hf_brsf_ag_three_way_calling
;
57 static int hf_brsf_ag_ec_nr_function
;
58 static int hf_brsf_ag_voice_recognition_function
;
59 static int hf_brsf_ag_inband_ring_tone
;
60 static int hf_brsf_ag_attach_number_to_voice_tag
;
61 static int hf_brsf_ag_ability_to_reject_a_call
;
62 static int hf_brsf_ag_enhanced_call_status
;
63 static int hf_brsf_ag_enhanced_call_control
;
64 static int hf_brsf_ag_extended_error_result_codes
;
65 static int hf_brsf_ag_codec_negotiation
;
66 static int hf_brsf_ag_hf_indicators
;
67 static int hf_brsf_ag_esco_s4_t2_settings_support
;
68 static int hf_brsf_ag_reserved
;
72 static int hf_bvra_vrect
;
75 static int hf_chld_mode
;
76 static int hf_chld_mode_1x
;
77 static int hf_chld_mode_2x
;
78 static int hf_chld_supported_modes
;
79 static int hf_cmer_mode
;
80 static int hf_cmer_keyp
;
81 static int hf_cmer_disp
;
82 static int hf_cmer_ind
;
83 static int hf_cmer_bfr
;
85 static int hf_cme_error
;
86 static int hf_cnum_speed
;
87 static int hf_cnum_service
;
88 static int hf_cnum_itc
;
89 static int hf_bcs_codec
;
90 static int hf_bac_codec
;
91 static int hf_binp_request
;
92 static int hf_binp_response
;
93 static int hf_ciev_indicator_index
;
94 static int hf_vts_dtmf
;
95 static int hf_vts_duration
;
96 static int hf_cops_mode
;
97 static int hf_cops_format
;
98 static int hf_cops_operator
;
99 static int hf_cops_act
;
100 static int hf_at_number
;
101 static int hf_at_type
;
102 static int hf_at_subaddress
;
103 static int hf_at_subaddress_type
;
104 static int hf_at_alpha
;
105 static int hf_at_priority
;
106 static int hf_at_cli_validity
;
107 static int hf_clip_mode
;
108 static int hf_clip_status
;
109 static int hf_clcc_id
;
110 static int hf_clcc_dir
;
111 static int hf_clcc_stat
;
112 static int hf_clcc_mode
;
113 static int hf_clcc_mpty
;
114 static int hf_ccwa_show_result_code
;
115 static int hf_ccwa_mode
;
116 static int hf_ccwa_class
;
117 static int hf_biev_assigned_number
;
118 static int hf_biev_value
;
119 static int hf_bind_parameter
;
120 static int hf_bia_indicator
[20];
121 static int hf_indicator
[20];
122 static int hf_aplefm_state
;
123 static int hf_aplsiri_state
;
124 static int hf_iphoneaccev_count
;
125 static int hf_iphoneaccev_key
;
126 static int hf_iphoneaccev_value
;
127 static int hf_xapl_accessory_info
;
128 static int hf_xapl_accessory_info_vendor_id
;
129 static int hf_xapl_accessory_info_product_id
;
130 static int hf_xapl_accessory_info_version
;
131 static int hf_xapl_host_info
;
132 static int hf_xapl_features
;
133 static int hf_xapl_features_reserved_x
;
134 static int hf_xapl_features_noise_reduction_status_reporting
;
135 static int hf_xapl_features_siri_status_reporting
;
136 static int hf_xapl_features_docked_or_powered
;
137 static int hf_xapl_features_battery_reporting
;
138 static int hf_xapl_features_reserved
;
140 static expert_field ei_non_mandatory_command
;
141 static expert_field ei_invalid_usage
;
142 static expert_field ei_unknown_parameter
;
143 static expert_field ei_brfs_hs_reserved_bits
;
144 static expert_field ei_brfs_ag_reserved_bits
;
145 static expert_field ei_vgm_gain
;
146 static expert_field ei_vgs_gain
;
147 static expert_field ei_nrec
;
148 static expert_field ei_bvra
;
149 static expert_field ei_bcs
;
150 static expert_field ei_bac
;
151 static expert_field ei_bsir
;
152 static expert_field ei_btrh
;
153 static expert_field ei_binp
;
154 static expert_field ei_biev_assigned_number
;
155 static expert_field ei_biev_assigned_number_no
;
156 static expert_field ei_bia
;
157 static expert_field ei_cmer_mode
;
158 static expert_field ei_cmer_keyp
;
159 static expert_field ei_cmer_disp
;
160 static expert_field ei_cmer_ind
;
161 static expert_field ei_cmer_btr
;
162 static expert_field ei_chld_mode
;
163 static expert_field ei_ciev_indicator
;
164 static expert_field ei_vts_dtmf
;
165 static expert_field ei_at_type
;
166 static expert_field ei_cnum_service
;
167 static expert_field ei_cnum_itc
;
168 static expert_field ei_aplefm_out_of_range
;
169 static expert_field ei_aplsiri_out_of_range
;
170 static expert_field ei_iphoneaccev_key_out_of_range
;
171 static expert_field ei_xapl_features_reserved
;
172 static expert_field ei_parameter_blank
;
174 static int ett_bthfp
;
175 static int ett_bthfp_command
;
176 static int ett_bthfp_parameters
;
177 static int ett_bthfp_brsf_hf
;
178 static int ett_bthfp_brsf_ag
;
179 static int ett_bthfp_xapl_features
;
180 static int ett_bthfp_xapl_accessory_info
;
182 static dissector_handle_t bthfp_handle
;
184 static wmem_tree_t
*fragments
;
186 #define ROLE_UNKNOWN 0
190 #define TYPE_UNKNOWN 0x0000
191 #define TYPE_RESPONSE_ACK 0x0d0a
192 #define TYPE_RESPONSE 0x003a
193 #define TYPE_ACTION 0x003d
194 #define TYPE_ACTION_SIMPLY 0x000d
195 #define TYPE_READ 0x003f
196 #define TYPE_TEST 0x3d3f
198 static int hfp_role
= ROLE_UNKNOWN
;
200 enum reassemble_state_t
{
202 REASSEMBLE_PARTIALLY
,
206 typedef struct _fragment_t
{
207 uint32_t interface_id
;
216 struct _fragment_t
*previous_fragment
;
218 unsigned reassemble_start_offset
;
219 unsigned reassemble_end_offset
;
220 enum reassemble_state_t reassemble_state
;
223 typedef struct _at_cmd_t
{
225 const char *long_name
;
227 bool (*check_command
)(int role
, uint16_t type
);
228 bool (*dissect_parameter
)(tvbuff_t
*tvb
, packet_info
*pinfo
,
229 proto_tree
*tree
, int offset
, int role
, uint16_t type
,
230 uint8_t *parameter_stream
, unsigned parameter_number
,
231 int parameter_length
, void **data
);
234 static const value_string role_vals
[] = {
235 { ROLE_UNKNOWN
, "Unknown" },
236 { ROLE_AG
, "AG - Audio Gate" },
237 { ROLE_HS
, "HS - Headset" },
241 static const value_string at_cmd_type_vals
[] = {
242 { 0x0d, "Action Command" },
243 { 0x3a, "Response" },
244 { 0x3d, "Action Command" },
245 { 0x3f, "Read Command" },
246 { 0x0d0a, "Response" },
247 { 0x3d3f, "Test Command" },
251 static const enum_val_t pref_hfp_role
[] = {
252 { "off", "Off", ROLE_UNKNOWN
},
253 { "ag", "Sent is AG, Rcvd is HS", ROLE_AG
},
254 { "hs", "Sent is HS, Rcvd is AG", ROLE_HS
},
258 static const value_string nrec_vals
[] = {
259 { 0x00, "Disable EC/NR in the AG" },
263 static const value_string bvra_vrect_vals
[] = {
264 { 0x00, "Disable Voice recognition in the AG" },
265 { 0x01, "Enable Voice recognition in the AG" },
269 static const value_string bsir_vals
[] = {
270 { 0x00, "The AG provides no in-band ring tone" },
271 { 0x01, "The AG provides an in-band ring tone" },
275 static const value_string btrh_vals
[] = {
276 { 0x00, "Incoming call is put on hold in the AG" },
277 { 0x01, "Held incoming call is accepted in the AG" },
278 { 0x02, "Held incoming call is rejected in the AG" },
282 static const value_string codecs_vals
[] = {
288 static const value_string binp_request_vals
[] = {
289 { 0x01, "Phone number corresponding to the last voice tag recorded in the HF" },
293 static const value_string indicator_vals
[] = {
294 { 0x00, "Deactivate" },
295 { 0x01, "Activate" },
299 static const value_string cme_error_vals
[] = {
300 { 0, "Phone/AG failure" },
301 { 1, "No Connection to Phone" },
302 { 2, "Phone-adaptor Link Reserved" },
303 { 3, "Operation not Allowed" },
304 { 4, "Operation not Supported" },
305 { 5, "PH-SIM PIN required" },
306 { 6, "PH-FSIM PIN Required" },
307 { 7, "PH-FSIM PUK Required" },
308 { 10, "SIM not Inserted" },
309 { 11, "SIM PIN Required" },
310 { 12, "SIM PUK Required" },
311 { 13, "SIM Failure" },
314 { 16, "Incorrect Password" },
315 { 17, "SIM PIN2 Required" },
316 { 18, "SIM PUK2 Required" },
317 { 20, "Memory Full" },
318 { 21, "Invalid Index" },
320 { 23, "Memory Failure" },
321 { 24, "Text String too Long" },
322 { 25, "Invalid Characters in Text String" },
323 { 26, "Dial String too Long" },
324 { 27, "Invalid Characters in Dial String" },
325 { 30, "No Network Service" },
326 { 31, "Network Timeout" },
327 { 32, "Network not Allowed - Emergency Calls Only" },
328 { 40, "Network Personalization PIN Required" },
329 { 41, "Network Personalization PUK Required" },
330 { 42, "Network Subset Personalization PIN Required" },
331 { 43, "Network Subset Personalization PUK Required" },
332 { 44, "Service Provider Personalization PIN Required" },
333 { 45, "Service Provider Personalization PUK Required" },
334 { 46, "Corporate Personalization PIN Required" },
335 { 47, "Corporate Personalization PUK Required" },
336 { 48, "Hidden Key Required" },
337 { 49, "EAP Method not Supported" },
338 { 50, "Incorrect Parameters" },
343 static const value_string cmee_vals
[] = {
350 static const value_string chld_vals
[] = {
351 { 0, "Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call" },
352 { 1, "Releases all active calls (if any exist) and accepts the other (held or waiting) call" },
353 { 2, "Places all active calls (if any exist) on hold and accepts the other (held or waiting) call" },
354 { 3, "Adds a held call to the conversation" },
355 { 4, "Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)" },
359 static const value_string cops_mode_vals
[] = {
362 { 2, "Deregister from Network" },
363 { 3, "Set Only Format" },
364 { 4, "Manual/Automatic" },
368 static const value_string cops_format_vals
[] = {
369 { 0, "Long Format Alphanumeric" },
370 { 1, "Short Format Alphanumeric" },
375 static const value_string cops_act_vals
[] = {
377 { 1, "GSM Compact" },
382 static const range_string at_type_vals
[] = {
383 { 128, 143, "The phone number format may be a national or international format, and may contain prefix and/or escape digits. No changes on the number presentation are required." },
384 { 144, 159, "The phone number format is an international number, including the country code prefix. If the plus sign (\"+\") is not included as part of the number and shall be added by the AG as needed." },
385 { 160, 175, "National number. No prefix nor escape digits included." },
389 static const value_string cli_validity_vals
[] = {
391 { 1, "CLI has been withheld by the originator" },
392 { 2, "CLI is not available due to interworking problems or limitations of originating network" },
396 static const value_string cnum_service_vals
[] = {
397 { 0, "Asynchronous Modem" },
398 { 1, "Synchronous Modem" },
400 { 3, "Packet Access" },
406 static const value_string cnum_itc_vals
[] = {
412 static const value_string clip_mode_vals
[] = {
418 static const value_string clip_status_vals
[] = {
419 { 0, "CLIP not Provisioned" },
420 { 1, "CLIP Provisioned" },
425 static const value_string clcc_dir_vals
[] = {
426 { 0, "Mobile Originated" },
427 { 1, "Mobile Terminated" },
431 static const value_string clcc_stat_vals
[] = {
441 static const value_string clcc_mode_vals
[] = {
445 { 3, "Voice Followed by Data, Voice Mode" },
446 { 4, "Alternating Voice/Data, Voice Mode" },
447 { 5, "Alternating Voice/Fax, Voice Mode" },
448 { 6, "Voice Followed by Data, Data Mode" },
449 { 7, "Alternating Voice/Data, Data Mode" },
450 { 8, "Alternating Voice/Fax, Fax Mode" },
455 static const value_string clcc_mpty_vals
[] = {
456 { 0, "Call is not one of multiparty (conference) call parties" },
457 { 1, "Call is one of multiparty (conference) call parties" },
461 static const value_string ccwa_show_result_code_vals
[] = {
467 static const value_string ccwa_mode_vals
[] = {
470 { 2, "Query Status" },
474 static const value_string ccwa_class_vals
[] = {
478 { 8, "Short Message Service" },
479 { 16, "Data Circuit Sync" },
480 { 32, "Data Circuit Async" },
481 { 64, "Dedicated Packet Access" },
482 { 128, "Dedicated PAD Access" },
486 static const value_string biev_assigned_number_vals
[] = {
487 { 1, "Enhanced Safety" },
488 { 2, "Battery Level" },
492 static const value_string aplefm_state_vals
[] = {
498 static const value_string aplsiri_state_vals
[] = {
504 static const value_string iphoneaccev_key_vals
[] = {
505 { 1, "Battery Level" },
511 static const unit_name_string units_slash15
= { "/15", NULL
};
513 extern value_string_ext csd_data_rate_vals_ext
;
515 void proto_register_bthfp(void);
516 void proto_reg_handoff_bthfp(void);
518 static uint32_t get_uint_parameter(uint8_t *parameter_stream
, int parameter_length
)
523 val
= (char *) wmem_alloc(wmem_packet_scope(), parameter_length
+ 1);
524 memcpy(val
, parameter_stream
, parameter_length
);
525 val
[parameter_length
] = '\0';
526 value
= (uint32_t) g_ascii_strtoull(val
, NULL
, 10);
531 static uint32_t get_uint_hex_parameter(uint8_t *parameter_stream
, int parameter_length
)
536 val
= (char *) wmem_alloc(wmem_packet_scope(), parameter_length
+ 1);
537 memcpy(val
, parameter_stream
, parameter_length
);
538 val
[parameter_length
] = '\0';
539 value
= (uint32_t) g_ascii_strtoull(val
, NULL
, 16);
544 static bool check_aplefm(int role
, uint16_t type
) {
545 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
546 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
551 static bool check_aplsiri(int role
, uint16_t type
) {
552 if (role
== ROLE_HS
&& type
== TYPE_READ
) return true;
553 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
558 static bool check_iphoneaccev(int role
, uint16_t type
) {
559 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
564 static bool check_xapl(int role
, uint16_t type
) {
565 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
566 if (role
== ROLE_AG
&& (type
== TYPE_RESPONSE
|| type
== TYPE_ACTION
)) return true;
571 static bool check_biev(int role
, uint16_t type
) {
572 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
577 static bool check_bind(int role
, uint16_t type
) {
578 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
|| type
== TYPE_TEST
)) return true;
579 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
584 static bool check_bac(int role
, uint16_t type
) {
585 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
590 static bool check_bcs(int role
, uint16_t type
) {
591 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
592 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
597 static bool check_bcc(int role
, uint16_t type
) {
598 if (role
== ROLE_HS
&& type
== TYPE_ACTION_SIMPLY
) return true;
603 static bool check_bia(int role
, uint16_t type
) {
604 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
609 static bool check_binp(int role
, uint16_t type
) {
610 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
611 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
616 static bool check_bldn(int role
, uint16_t type
) {
617 if (role
== ROLE_HS
&& type
== TYPE_ACTION_SIMPLY
) return true;
622 static bool check_bvra(int role
, uint16_t type
) {
623 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
624 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
629 static bool check_brsf(int role
, uint16_t type
) {
630 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
631 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
636 static bool check_nrec(int role
, uint16_t type
) {
637 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
642 static bool check_vgs(int role
, uint16_t type
) {
643 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
644 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
649 static bool check_vgm(int role
, uint16_t type
) {
650 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
651 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
656 static bool check_bsir(int role
, uint16_t type
) {
657 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
662 static bool check_btrh(int role
, uint16_t type
) {
663 if (role
== ROLE_HS
&& (type
== TYPE_READ
|| type
== TYPE_ACTION
)) return true;
664 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
669 static bool check_only_ag_role(int role
, uint16_t type
) {
670 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE_ACK
) return true;
675 static bool check_only_hs_role(int role
, uint16_t type
) {
676 if (role
== ROLE_HS
&& type
== TYPE_ACTION_SIMPLY
) return true;
681 static bool check_ccwa(int role
, uint16_t type
) {
682 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
|| type
== TYPE_TEST
)) return true;
683 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
688 static bool check_chld(int role
, uint16_t type
) {
689 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_TEST
)) return true;
690 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
695 static bool check_chup(int role
, uint16_t type
) {
696 if (role
== ROLE_HS
&& (type
== TYPE_ACTION_SIMPLY
|| type
== TYPE_TEST
)) return true;
701 static bool check_clcc(int role
, uint16_t type
) {
702 if (role
== ROLE_HS
&& (type
== TYPE_ACTION_SIMPLY
|| type
== TYPE_TEST
)) return true;
703 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
708 static bool check_cind(int role
, uint16_t type
) {
709 if (role
== ROLE_HS
&& (type
== TYPE_READ
|| type
== TYPE_TEST
)) return true;
710 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
715 static bool check_cmer(int role
, uint16_t type
) {
716 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
|| type
== TYPE_TEST
)) return true;
717 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
722 static bool check_cops(int role
, uint16_t type
) {
723 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
)) return true;
724 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
729 static bool check_cmee(int role
, uint16_t type
) {
730 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) return true;
735 static bool check_cme(int role
, uint16_t type
) {
736 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
741 static bool check_clip(int role
, uint16_t type
) {
742 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
|| type
== TYPE_TEST
)) return true;
743 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
748 static bool check_ciev(int role
, uint16_t type
) {
749 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
754 static bool check_vts(int role
, uint16_t type
) {
755 if (role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_TEST
)) return true;
756 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
761 static bool check_cnum(int role
, uint16_t type
) {
762 if (role
== ROLE_HS
&& type
== TYPE_ACTION_SIMPLY
) return true;
763 if (role
== ROLE_AG
&& type
== TYPE_RESPONSE
) return true;
769 dissect_brsf_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
770 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
771 unsigned parameter_number
, int parameter_length
, void **data _U_
)
776 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
777 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
781 if (parameter_number
> 0) return false;
783 value
= get_uint_parameter(parameter_stream
, parameter_length
);
785 if (role
== ROLE_HS
) {
786 static int * const hs
[] = {
787 &hf_brsf_hs_ec_nr_function
,
788 &hf_brsf_hs_call_waiting_or_tree_way
,
789 &hf_brsf_hs_cli_presentation
,
790 &hf_brsf_hs_voice_recognition_activation
,
791 &hf_brsf_hs_remote_volume_control
,
792 &hf_brsf_hs_enhanced_call_status
,
793 &hf_brsf_hs_enhanced_call_control
,
794 &hf_brsf_hs_codec_negotiation
,
795 &hf_brsf_hs_hf_indicators
,
796 &hf_brsf_hs_esco_s4_t2_settings_support
,
797 &hf_brsf_hs_reserved
,
801 pitem
= proto_tree_add_bitmask_value_with_flags(tree
, tvb
, offset
, hf_brsf_hs
, ett_bthfp_brsf_hf
, hs
, value
, BMT_NO_APPEND
);
803 expert_add_info(pinfo
, pitem
, &ei_brfs_hs_reserved_bits
);
806 static int * const ag
[] = {
807 &hf_brsf_ag_three_way_calling
,
808 &hf_brsf_ag_ec_nr_function
,
809 &hf_brsf_ag_voice_recognition_function
,
810 &hf_brsf_ag_inband_ring_tone
,
811 &hf_brsf_ag_attach_number_to_voice_tag
,
812 &hf_brsf_ag_ability_to_reject_a_call
,
813 &hf_brsf_ag_enhanced_call_status
,
814 &hf_brsf_ag_enhanced_call_control
,
815 &hf_brsf_ag_extended_error_result_codes
,
816 &hf_brsf_ag_codec_negotiation
,
817 &hf_brsf_ag_hf_indicators
,
818 &hf_brsf_ag_esco_s4_t2_settings_support
,
819 &hf_brsf_ag_reserved
,
823 pitem
= proto_tree_add_bitmask_value_with_flags(tree
, tvb
, offset
, hf_brsf_ag
, ett_bthfp_brsf_ag
, ag
, value
, BMT_NO_APPEND
);
826 expert_add_info(pinfo
, pitem
, &ei_brfs_ag_reserved_bits
);
834 dissect_vgs_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
835 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
836 unsigned parameter_number
, int parameter_length
, void **data _U_
)
841 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
842 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
846 if (parameter_number
> 0) return false;
848 value
= get_uint_parameter(parameter_stream
, parameter_length
);
850 pitem
= proto_tree_add_uint(tree
, hf_vgs
, tvb
, offset
, parameter_length
, value
);
853 expert_add_info(pinfo
, pitem
, &ei_vgs_gain
);
860 dissect_vgm_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
861 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
862 unsigned parameter_number
, int parameter_length
, void **data _U_
)
867 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
868 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
872 if (parameter_number
> 0) return false;
874 value
= get_uint_parameter(parameter_stream
, parameter_length
);
876 pitem
= proto_tree_add_uint(tree
, hf_vgm
, tvb
, offset
, parameter_length
, value
);
879 expert_add_info(pinfo
, pitem
, &ei_vgm_gain
);
886 dissect_nrec_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
887 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
888 unsigned parameter_number
, int parameter_length
, void **data _U_
)
893 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
894 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
898 if (parameter_number
> 0) return false;
900 value
= get_uint_parameter(parameter_stream
, parameter_length
);
902 pitem
= proto_tree_add_uint(tree
, hf_nrec
, tvb
, offset
, parameter_length
, value
);
905 expert_add_info(pinfo
, pitem
, &ei_nrec
);
912 dissect_bvra_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
913 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
914 unsigned parameter_number
, int parameter_length
, void **data _U_
)
919 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
920 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
924 if (parameter_number
> 0) return false;
926 value
= get_uint_parameter(parameter_stream
, parameter_length
);
928 pitem
= proto_tree_add_uint(tree
, hf_bvra_vrect
, tvb
, offset
, parameter_length
, value
);
931 expert_add_info(pinfo
, pitem
, &ei_bvra
);
938 dissect_bcs_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
939 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
940 unsigned parameter_number
, int parameter_length
, void **data _U_
)
945 if (!check_bcs(role
, type
)) {
949 if (parameter_number
> 0) return false;
951 value
= get_uint_parameter(parameter_stream
, parameter_length
);
953 pitem
= proto_tree_add_uint(tree
, hf_bcs_codec
, tvb
, offset
, parameter_length
, value
);
955 if (value
< 1 || value
> 2) {
956 expert_add_info(pinfo
, pitem
, &ei_bcs
);
963 dissect_bac_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
964 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
965 unsigned parameter_number _U_
, int parameter_length
, void **data _U_
)
970 if (!check_bac(role
, type
)) {
974 value
= get_uint_parameter(parameter_stream
, parameter_length
);
976 pitem
= proto_tree_add_uint(tree
, hf_bac_codec
, tvb
, offset
, parameter_length
, value
);
978 if (value
< 1 || value
> 2) {
979 expert_add_info(pinfo
, pitem
, &ei_bac
);
986 dissect_bind_parameter(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
,
987 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
988 unsigned parameter_number
, int parameter_length
, void **data _U_
)
992 if (!check_bind(role
, type
)) return false;
994 /* TODO Need to implement request-response tracking to recognise answer to AT+BIND? vs unsolicited */
995 if (parameter_number
< 20) {
996 value
= get_uint_parameter(parameter_stream
, parameter_length
);
998 proto_tree_add_uint(tree
, hf_bind_parameter
, tvb
, offset
,
999 parameter_length
, value
);
1008 dissect_aplefm_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1009 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1010 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1015 if (!check_aplefm(role
, type
)) return false;
1017 if (parameter_number
== 0) {
1018 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1020 pitem
= proto_tree_add_uint(tree
, hf_aplefm_state
, tvb
, offset
,
1021 parameter_length
, value
);
1024 expert_add_info(pinfo
, pitem
, &ei_aplefm_out_of_range
);
1026 } else return false;
1032 dissect_aplsiri_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1033 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1034 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1039 if (!check_aplsiri(role
, type
)) return false;
1041 if (parameter_number
== 0) {
1042 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1044 pitem
= proto_tree_add_uint(tree
, hf_aplsiri_state
, tvb
, offset
,
1045 parameter_length
, value
);
1047 if (value
< 1 || value
> 2) {
1048 expert_add_info(pinfo
, pitem
, &ei_aplsiri_out_of_range
);
1050 } else return false;
1056 dissect_iphoneaccev_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1057 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1058 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1063 if (!check_iphoneaccev(role
, type
)) return false;
1065 if (parameter_number
== 0) {
1066 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1068 proto_tree_add_uint(tree
, hf_iphoneaccev_count
, tvb
, offset
,
1069 parameter_length
, value
);
1070 } else if (parameter_number
% 2 == 1) {
1071 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1073 pitem
= proto_tree_add_uint(tree
, hf_iphoneaccev_key
, tvb
, offset
,
1074 parameter_length
, value
);
1076 if (value
< 1 || value
> 2) {
1077 expert_add_info(pinfo
, pitem
, &ei_iphoneaccev_key_out_of_range
);
1080 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1082 proto_tree_add_uint(tree
, hf_iphoneaccev_value
, tvb
, offset
,
1083 parameter_length
, value
);
1090 dissect_xapl_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1091 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1092 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1098 if (!check_xapl(role
, type
)) return false;
1100 if (parameter_number
== 0) {
1101 if (role
== ROLE_HS
) {
1102 pitem
= proto_tree_add_item(tree
, hf_xapl_accessory_info
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1103 ptree
= proto_item_add_subtree(pitem
, ett_bthfp_xapl_accessory_info
);
1105 value
= get_uint_hex_parameter(parameter_stream
+ (4 + 1) * 0, 4);
1106 proto_tree_add_uint(ptree
, hf_xapl_accessory_info_vendor_id
, tvb
, offset
, 4, value
);
1108 value
= get_uint_hex_parameter(parameter_stream
+ (4 + 1) * 1, 4);
1109 proto_tree_add_uint(ptree
, hf_xapl_accessory_info_product_id
, tvb
, offset
+ (4 + 1) * 1, 4, value
);
1111 value
= get_uint_hex_parameter(parameter_stream
+ (4 + 1) * 2, 4);
1112 proto_tree_add_uint(ptree
, hf_xapl_accessory_info_version
, tvb
, offset
+ (4 + 1) * 2, 4, value
);
1114 proto_tree_add_item(tree
, hf_xapl_host_info
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1116 } else if (parameter_number
== 1) {
1117 static int * const hfx
[] = {
1118 &hf_xapl_features_reserved_x
,
1119 &hf_xapl_features_noise_reduction_status_reporting
,
1120 &hf_xapl_features_siri_status_reporting
,
1121 &hf_xapl_features_docked_or_powered
,
1122 &hf_xapl_features_battery_reporting
,
1123 &hf_xapl_features_reserved
,
1127 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1129 pitem
= proto_tree_add_bitmask_value_with_flags(tree
, tvb
, offset
, hf_xapl_features
, ett_bthfp_xapl_features
, hfx
, value
, BMT_NO_APPEND
);
1132 expert_add_info(pinfo
, pitem
, &ei_xapl_features_reserved
);
1134 } else return false;
1140 dissect_biev_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1141 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1142 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1147 if (!check_biev(role
, type
)) return false;
1148 if (parameter_number
== 0) {
1149 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1151 pitem
= proto_tree_add_uint(tree
, hf_biev_assigned_number
, tvb
, offset
,
1152 parameter_length
, value
);
1154 if (value
> 65535) {
1155 expert_add_info(pinfo
, pitem
, &ei_biev_assigned_number
);
1156 } else if (value
> 2) {
1157 expert_add_info(pinfo
, pitem
, &ei_biev_assigned_number_no
);
1159 } else if (parameter_number
== 1) {
1160 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1161 /* TODO: Decode assigned numbers - assigned_number=1 */
1162 /*pitem =*/ proto_tree_add_uint(tree
, hf_biev_value
, tvb
, offset
,
1163 parameter_length
, value
);
1164 } else return false;
1170 dissect_no_parameter(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree _U_
,
1171 int offset _U_
, int role _U_
, uint16_t type _U_
, uint8_t *parameter_stream _U_
,
1172 unsigned parameter_number _U_
, int parameter_length _U_
, void **data _U_
)
1178 dissect_bsir_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1179 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1180 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1185 if (!(role
== ROLE_AG
&& type
== TYPE_RESPONSE
)) {
1189 if (parameter_number
> 0) return false;
1191 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1193 pitem
= proto_tree_add_uint(tree
, hf_bsir
, tvb
, offset
, parameter_length
, value
);
1196 expert_add_info(pinfo
, pitem
, &ei_bsir
);
1203 dissect_btrh_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1204 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1205 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1210 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
1211 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
1215 if (parameter_number
> 0) return false;
1217 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1219 pitem
= proto_tree_add_uint(tree
, hf_btrh
, tvb
, offset
, parameter_length
, value
);
1222 expert_add_info(pinfo
, pitem
, &ei_btrh
);
1230 dissect_binp_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1231 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1232 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1237 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
) ||
1238 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
1242 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) {
1243 if (parameter_number
== 0) {
1244 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1246 pitem
= proto_tree_add_uint(tree
, hf_binp_request
, tvb
, offset
,
1247 parameter_length
, value
);
1250 expert_add_info(pinfo
, pitem
, &ei_binp
);
1252 } else return false;
1254 proto_tree_add_item(tree
, hf_binp_response
, tvb
, offset
,
1255 parameter_length
, ENC_NA
| ENC_ASCII
);
1261 dissect_bia_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1262 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1263 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1268 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
))) return false;
1269 if (parameter_number
> 19) return false;
1271 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1273 pitem
= proto_tree_add_uint(tree
, hf_bia_indicator
[parameter_number
], tvb
,
1274 offset
, parameter_length
, value
);
1276 expert_add_info(pinfo
, pitem
, &ei_bia
);
1283 dissect_cind_parameter(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
,
1284 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream _U_
,
1285 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1287 if (!check_cind(role
, type
)) return false;
1288 if (parameter_number
> 19) return false;
1290 proto_tree_add_item(tree
, hf_indicator
[parameter_number
], tvb
, offset
,
1291 parameter_length
, ENC_NA
| ENC_ASCII
);
1297 dissect_chld_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1298 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1299 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1303 if (!check_chld(role
, type
)) return false;
1305 if (role
== ROLE_HS
&& type
== TYPE_ACTION
&& parameter_number
== 0) {
1306 value
= get_uint_parameter(parameter_stream
, 1);
1308 if (parameter_length
>= 2) {
1309 if (tvb_get_uint8(tvb
, offset
+ 1) == 'x') {
1311 proto_tree_add_item(tree
, hf_chld_mode_1x
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1312 else if (value
== 2)
1313 proto_tree_add_item(tree
, hf_chld_mode_2x
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1316 if (tvb_get_uint8(tvb
, offset
+ 1) != 'x' || value
> 4) {
1317 proto_tree_add_expert(tree
, pinfo
, &ei_chld_mode
, tvb
, offset
, parameter_length
);
1321 proto_tree_add_uint(tree
, hf_chld_mode
, tvb
, offset
, parameter_length
, value
);
1326 proto_tree_add_item(tree
, hf_chld_supported_modes
, tvb
, offset
,
1327 parameter_length
, ENC_NA
| ENC_ASCII
);
1333 dissect_ccwa_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1334 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1335 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1340 if (!check_ccwa(role
, type
)) return false;
1342 if (role
== ROLE_HS
&& parameter_number
> 2) return false;
1343 if (role
== ROLE_AG
&& parameter_number
> 7) return false;
1345 if (role
== ROLE_HS
) switch (parameter_number
) {
1347 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1348 proto_tree_add_uint(tree
, hf_ccwa_show_result_code
, tvb
, offset
, parameter_length
, value
);
1351 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1352 proto_tree_add_uint(tree
, hf_ccwa_mode
, tvb
, offset
, parameter_length
, value
);
1355 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1356 proto_tree_add_uint(tree
, hf_ccwa_class
, tvb
, offset
, parameter_length
, value
);
1360 /* If AT+CCWA = 1 */
1361 if (role
== ROLE_AG
) switch (parameter_number
) {
1363 proto_tree_add_item(tree
, hf_at_number
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1366 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1367 pitem
= proto_tree_add_uint(tree
, hf_at_type
, tvb
, offset
, parameter_length
, value
);
1368 if (value
< 128 || value
> 175)
1369 expert_add_info(pinfo
, pitem
, &ei_at_type
);
1372 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1373 proto_tree_add_uint(tree
, hf_ccwa_class
, tvb
, offset
, parameter_length
, value
);
1376 proto_tree_add_item(tree
, hf_at_alpha
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1379 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1380 proto_tree_add_uint(tree
, hf_at_cli_validity
, tvb
, offset
, parameter_length
, value
);
1383 proto_tree_add_item(tree
, hf_at_subaddress
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1386 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1387 proto_tree_add_uint(tree
, hf_at_subaddress_type
, tvb
, offset
, parameter_length
, value
);
1390 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1391 proto_tree_add_uint(tree
, hf_at_priority
, tvb
, offset
, parameter_length
, value
);
1399 dissect_cmer_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1400 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1401 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1406 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION
))) {
1410 if (parameter_number
> 4) return false;
1412 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1414 switch (parameter_number
) {
1416 pitem
= proto_tree_add_uint(tree
, hf_cmer_mode
, tvb
, offset
, parameter_length
, value
);
1418 expert_add_info(pinfo
, pitem
, &ei_cmer_mode
);
1421 pitem
= proto_tree_add_uint(tree
, hf_cmer_keyp
, tvb
, offset
, parameter_length
, value
);
1423 expert_add_info(pinfo
, pitem
, &ei_cmer_keyp
);
1426 pitem
= proto_tree_add_uint(tree
, hf_cmer_disp
, tvb
, offset
, parameter_length
, value
);
1428 expert_add_info(pinfo
, pitem
, &ei_cmer_disp
);
1431 pitem
= proto_tree_add_uint(tree
, hf_cmer_ind
, tvb
, offset
, parameter_length
, value
);
1433 expert_add_info(pinfo
, pitem
, &ei_cmer_ind
);
1436 pitem
= proto_tree_add_uint(tree
, hf_cmer_bfr
, tvb
, offset
, parameter_length
, value
);
1438 expert_add_info(pinfo
, pitem
, &ei_cmer_btr
);
1446 dissect_clip_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1447 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1448 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1453 if (!check_clip(role
, type
))
1456 if (role
== ROLE_HS
&& type
== TYPE_ACTION
&& parameter_number
> 1)
1458 else if (role
== ROLE_AG
&& parameter_number
> 5)
1461 if (role
== ROLE_HS
&& type
== TYPE_ACTION
) switch (parameter_number
) {
1463 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1464 proto_tree_add_uint(tree
, hf_clip_mode
, tvb
, offset
, parameter_length
, value
);
1467 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1468 proto_tree_add_uint(tree
, hf_clip_status
, tvb
, offset
, parameter_length
, value
);
1471 switch (parameter_number
) {
1473 proto_tree_add_item(tree
, hf_at_number
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1476 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1477 pitem
= proto_tree_add_uint(tree
, hf_at_type
, tvb
, offset
, parameter_length
, value
);
1478 if (value
< 128 || value
> 175)
1479 expert_add_info(pinfo
, pitem
, &ei_at_type
);
1482 proto_tree_add_item(tree
, hf_at_subaddress
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1485 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1486 proto_tree_add_uint(tree
, hf_at_subaddress_type
, tvb
, offset
, parameter_length
, value
);
1489 proto_tree_add_item(tree
, hf_at_alpha
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1492 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1493 proto_tree_add_uint(tree
, hf_at_cli_validity
, tvb
, offset
, parameter_length
, value
);
1502 dissect_cmee_parameter(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
,
1503 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1504 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1508 if (!(role
== ROLE_HS
&& type
== TYPE_ACTION
)) {
1512 if (parameter_number
> 0) return false;
1514 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1515 proto_tree_add_uint(tree
, hf_cmee
, tvb
, offset
, parameter_length
, value
);
1521 dissect_cops_parameter(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
,
1522 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1523 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1527 if (!((role
== ROLE_HS
&& (type
== TYPE_ACTION
|| type
== TYPE_READ
)) ||
1528 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
1532 if (parameter_number
> 3) return false;
1534 switch (parameter_number
) {
1536 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1537 proto_tree_add_uint(tree
, hf_cops_mode
, tvb
, offset
, parameter_length
, value
);
1540 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1541 proto_tree_add_uint(tree
, hf_cops_format
, tvb
, offset
, parameter_length
, value
);
1544 proto_tree_add_item(tree
, hf_cops_operator
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1547 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1548 proto_tree_add_uint(tree
, hf_cops_act
, tvb
, offset
, parameter_length
, value
);
1556 dissect_clcc_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1557 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1558 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1563 if (!((role
== ROLE_HS
&& type
== TYPE_ACTION_SIMPLY
) ||
1564 (role
== ROLE_AG
&& type
== TYPE_RESPONSE
))) {
1568 if (parameter_number
> 8) return false;
1570 switch (parameter_number
) {
1572 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1573 proto_tree_add_uint(tree
, hf_clcc_id
, tvb
, offset
, parameter_length
, value
);
1576 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1577 proto_tree_add_uint(tree
, hf_clcc_dir
, tvb
, offset
, parameter_length
, value
);
1580 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1581 proto_tree_add_uint(tree
, hf_clcc_stat
, tvb
, offset
, parameter_length
, value
);
1584 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1585 proto_tree_add_uint(tree
, hf_clcc_mode
, tvb
, offset
, parameter_length
, value
);
1588 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1589 proto_tree_add_uint(tree
, hf_clcc_mpty
, tvb
, offset
, parameter_length
, value
);
1592 proto_tree_add_item(tree
, hf_at_number
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1595 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1596 pitem
= proto_tree_add_uint(tree
, hf_at_type
, tvb
, offset
, parameter_length
, value
);
1597 if (value
< 128 || value
> 175)
1598 expert_add_info(pinfo
, pitem
, &ei_at_type
);
1601 proto_tree_add_item(tree
, hf_at_alpha
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1604 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1605 proto_tree_add_uint(tree
, hf_at_priority
, tvb
, offset
, parameter_length
, value
);
1614 dissect_cme_error_parameter(tvbuff_t
*tvb
, packet_info
*pinfo _U_
, proto_tree
*tree
,
1615 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1616 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1620 if (!(role
== ROLE_AG
&& type
== TYPE_RESPONSE
)) {
1624 if (parameter_number
> 0) return false;
1626 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1627 proto_tree_add_uint(tree
, hf_cme_error
, tvb
, offset
, parameter_length
, value
);
1633 dissect_cnum_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1634 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1635 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1640 if (!(role
== ROLE_AG
&& type
== TYPE_RESPONSE
)) return true;
1641 if (parameter_number
> 5) return false;
1643 switch (parameter_number
) {
1645 pitem
= proto_tree_add_item(tree
, hf_at_alpha
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1646 if (parameter_length
> 0)
1647 expert_add_info(pinfo
, pitem
, &ei_parameter_blank
);
1650 proto_tree_add_item(tree
, hf_at_number
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1653 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1654 pitem
= proto_tree_add_uint(tree
, hf_at_type
, tvb
, offset
, parameter_length
, value
);
1655 if (value
< 128 || value
> 175)
1656 expert_add_info(pinfo
, pitem
, &ei_at_type
);
1659 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1660 pitem
= proto_tree_add_uint(tree
, hf_cnum_speed
, tvb
, offset
, parameter_length
, value
);
1661 if (parameter_length
> 0)
1662 expert_add_info(pinfo
, pitem
, &ei_parameter_blank
);
1665 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1666 pitem
= proto_tree_add_uint(tree
, hf_cnum_service
, tvb
, offset
, parameter_length
, value
);
1668 expert_add_info(pinfo
, pitem
, &ei_cnum_service
);
1671 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1672 pitem
= proto_tree_add_uint(tree
, hf_cnum_itc
, tvb
, offset
, parameter_length
, value
);
1674 expert_add_info(pinfo
, pitem
, &ei_cnum_itc
);
1682 dissect_vts_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1683 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1684 unsigned parameter_number
, int parameter_length
, void **data _U_
)
1689 if (!(role
== ROLE_HS
&& type
== TYPE_ACTION
)) return true;
1690 if (parameter_number
> 1) return false;
1692 switch (parameter_number
) {
1694 pitem
= proto_tree_add_item(tree
, hf_vts_dtmf
, tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1695 if (parameter_length
!= 1)
1696 expert_add_info(pinfo
, pitem
, &ei_vts_dtmf
);
1699 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1700 proto_tree_add_uint(tree
, hf_vts_duration
, tvb
, offset
, parameter_length
, value
);
1708 dissect_ciev_parameter(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1709 int offset
, int role
, uint16_t type
, uint8_t *parameter_stream
,
1710 unsigned parameter_number
, int parameter_length
, void **data
)
1713 unsigned indicator_index
;
1715 if (!(role
== ROLE_AG
&& type
== TYPE_RESPONSE
)) return true;
1716 if (parameter_number
> 1) return false;
1718 switch (parameter_number
) {
1720 value
= get_uint_parameter(parameter_stream
, parameter_length
);
1721 proto_tree_add_uint(tree
, hf_ciev_indicator_index
, tvb
, offset
, parameter_length
, value
);
1722 *data
= wmem_alloc(pinfo
->pool
, sizeof(unsigned));
1723 *((unsigned *) *data
) = value
;
1726 indicator_index
= *((unsigned *) *data
) - 1;
1727 if (indicator_index
> 19) {
1728 proto_tree_add_expert(tree
, pinfo
, &ei_ciev_indicator
, tvb
, offset
, parameter_length
);
1730 proto_tree_add_item(tree
, hf_indicator
[indicator_index
], tvb
, offset
, parameter_length
, ENC_NA
| ENC_ASCII
);
1738 /* TODO: Some commands need to save request command type (request with TYPE_READ vs TYPE_TEST, etc.)
1739 to properly dissect response parameters.
1740 Some commands can use TYPE_TEST respose to properly dissect parameters,
1741 for example: AT+CIND=?, AT+CIND? */
1742 static const at_cmd_t at_cmds
[] = {
1743 /* Vendor specific: Apple */
1744 { "+XAPL", "Apple Bluetooth Accessory Identification", check_xapl
, dissect_xapl_parameter
},
1745 { "+IPHONEACCEV", "Apple Bluetooth Headset Battery Level Indication", check_iphoneaccev
, dissect_iphoneaccev_parameter
},
1746 { "+APLSIRI", "Apple Siri Availability Information", check_aplsiri
, dissect_aplsiri_parameter
},
1747 { "+APLEFM", "Apple Siri Eyes Free Mode", check_aplefm
, dissect_aplefm_parameter
},
1748 /* Bluetooth HFP specific AT Commands */
1749 { "+BIEV", "Bluetooth Indicator Enter Value", check_biev
, dissect_biev_parameter
}, /* HFP 1.7 */
1750 { "+BIND", "Bluetooth Indicator", check_bind
, dissect_bind_parameter
}, /* HFP 1.7 */
1751 { "+BAC", "Bluetooth Available Codecs", check_bac
, dissect_bac_parameter
},
1752 { "+BCS", "Bluetooth Codec Selection", check_bcs
, dissect_bcs_parameter
},
1753 { "+BCC", "Bluetooth Codec Connection", check_bcc
, dissect_no_parameter
},
1754 { "+BTRH", "Bluetooth Response and Hold Feature", check_btrh
, dissect_btrh_parameter
},
1755 { "+BSIR", "Bluetooth Setting of In-band Ring Tone", check_bsir
, dissect_bsir_parameter
},
1756 { "+VGS", "Gain of Speaker", check_vgs
, dissect_vgs_parameter
},
1757 { "+VGM", "Gain of Microphone", check_vgm
, dissect_vgm_parameter
},
1758 { "+NREC", "Noise Reduction and Echo Cancelling", check_nrec
, dissect_nrec_parameter
},
1759 { "+BRSF", "Bluetooth Retrieve Supported Features", check_brsf
, dissect_brsf_parameter
},
1760 { "+BVRA", "Bluetooth Voice Recognition Activation", check_bvra
, dissect_bvra_parameter
},
1761 { "+BLDN", "Bluetooth Last Dialled Number", check_bldn
, dissect_no_parameter
},
1762 { "+BINP", "Bluetooth Input", check_binp
, dissect_binp_parameter
},
1763 { "+BIA", "Bluetooth Indicators Activation", check_bia
, dissect_bia_parameter
},
1764 /* Inherited from normal AT Commands */
1765 { "+CCWA", "Call Waiting Notification", check_ccwa
, dissect_ccwa_parameter
},
1766 { "+CHLD", "Call Hold and Multiparty Handling", check_chld
, dissect_chld_parameter
},
1767 { "+CHUP", "Call Hang-up", check_chup
, dissect_no_parameter
},
1768 { "+CIND", "Phone Indicators", check_cind
, dissect_cind_parameter
},
1769 { "+CLCC", "Current Calls", check_clcc
, dissect_clcc_parameter
},
1770 { "+COPS", "Reading Network Operator", check_cops
, dissect_cops_parameter
},
1771 { "+CMEE", "Mobile Equipment Error", check_cmee
, dissect_cmee_parameter
},
1772 { "+CME ERROR", "Extended Audio Gateway Error Result Code", check_cme
, dissect_cme_error_parameter
},
1773 { "+CLIP", "Calling Line Identification Notification", check_clip
, dissect_clip_parameter
},
1774 { "+CMER", "Event Reporting Activation/Deactivation", check_cmer
, dissect_cmer_parameter
},
1775 { "+CIEV", "Indicator Events Reporting", check_ciev
, dissect_ciev_parameter
},
1776 { "+VTS", "DTMF and tone generation", check_vts
, dissect_vts_parameter
},
1777 { "+CNUM", "Subscriber Number Information", check_cnum
, dissect_cnum_parameter
},
1778 { "ERROR", "ERROR", check_only_ag_role
, dissect_no_parameter
},
1779 { "RING", "Incoming Call Indication", check_only_ag_role
, dissect_no_parameter
},
1780 { "OK", "OK", check_only_ag_role
, dissect_no_parameter
},
1781 { "D", "Dial", check_only_hs_role
, NULL
},
1782 { "A", "Call Answer", check_only_hs_role
, dissect_no_parameter
},
1783 { NULL
, NULL
, NULL
, NULL
}
1788 dissect_at_command(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1789 int offset
, uint32_t role
, int command_number
)
1792 proto_tree
*command_item
= NULL
;
1793 proto_item
*command_tree
= NULL
;
1794 proto_tree
*parameters_item
= NULL
;
1795 proto_item
*parameters_tree
= NULL
;
1796 uint8_t *col_str
= NULL
;
1798 uint8_t *at_command
= NULL
;
1800 unsigned i_char_fix
= 0;
1802 const at_cmd_t
*i_at_cmd
;
1803 int parameter_length
;
1804 unsigned parameter_number
= 0;
1805 int first_parameter_offset
= offset
;
1806 int last_parameter_offset
= offset
;
1807 uint16_t type
= TYPE_UNKNOWN
;
1813 length
= tvb_reported_length_remaining(tvb
, offset
);
1815 return tvb_reported_length(tvb
);
1817 if (!command_number
) {
1818 proto_tree_add_item(tree
, hf_data
, tvb
, offset
, length
, ENC_NA
| ENC_ASCII
);
1819 col_str
= (uint8_t *) wmem_alloc(pinfo
->pool
, length
+ 1);
1820 tvb_memcpy(tvb
, col_str
, offset
, length
);
1821 col_str
[length
] = '\0';
1824 at_stream
= (uint8_t *) wmem_alloc(pinfo
->pool
, length
+ 1);
1825 tvb_memcpy(tvb
, at_stream
, offset
, length
);
1826 at_stream
[length
] = '\0';
1828 while (at_stream
[i_char
]) {
1829 at_stream
[i_char
] = g_ascii_toupper(at_stream
[i_char
]);
1830 if (!command_number
) {
1831 col_str
[i_char
] = g_ascii_toupper(col_str
[i_char
]);
1832 if (!g_ascii_isgraph(col_str
[i_char
])) col_str
[i_char
] = ' ';
1837 if (!command_number
) col_append_str(pinfo
->cinfo
, COL_INFO
, col_str
);
1839 if (role
== ROLE_HS
) {
1840 if (command_number
) {
1841 at_command
= at_stream
;
1844 at_command
= g_strstr_len(at_stream
, length
, "AT");
1846 command_item
= proto_tree_add_none_format(tree
, hf_command
, tvb
,
1847 offset
, 0, "Command %u", command_number
);
1848 command_tree
= proto_item_add_subtree(command_item
, ett_bthfp_command
);
1850 i_char
= (unsigned) (at_command
- at_stream
);
1852 proto_tree_add_item(command_tree
, hf_at_ignored
, tvb
, offset
,
1853 i_char
, ENC_NA
| ENC_ASCII
);
1857 proto_tree_add_item(command_tree
, hf_at_command_line_prefix
,
1858 tvb
, offset
, 2, ENC_NA
| ENC_ASCII
);
1861 at_command
= at_stream
;
1862 at_command
+= i_char
;
1864 i_char_fix
+= i_char
;
1868 } else if (at_stream
[0] == '\r' && at_stream
[1] == '\n') {
1869 command_item
= proto_tree_add_none_format(tree
, hf_command
, tvb
,
1870 offset
, 0, "Command %u", command_number
);
1871 command_tree
= proto_item_add_subtree(command_item
, ett_bthfp_command
);
1873 at_command
= at_stream
;
1875 while (i_char
<= length
&&
1876 (at_command
[i_char
] == '\r' || at_command
[i_char
] == '\n' ||
1877 at_command
[i_char
] == ' ' || at_command
[i_char
] == '\t')) {
1878 /* ignore white characters */
1883 at_command
+= i_char
;
1885 i_char_fix
+= i_char
;
1891 while (i_char
< length
&&
1892 (at_command
[i_char
] != '\r' && at_command
[i_char
] != '=' &&
1893 at_command
[i_char
] != ';' && at_command
[i_char
] != '?' &&
1894 at_command
[i_char
] != ':')) {
1899 if (at_command
[0] == '\r') {
1900 pitem
= proto_tree_add_item(command_tree
, hf_at_cmd
, tvb
, offset
- 2,
1901 2, ENC_NA
| ENC_ASCII
);
1905 while (i_at_cmd
->name
) {
1906 if (g_str_has_prefix(&at_command
[0], i_at_cmd
->name
)) {
1907 pitem
= proto_tree_add_item(command_tree
, hf_at_cmd
, tvb
, offset
,
1908 (int) strlen(i_at_cmd
->name
), ENC_NA
| ENC_ASCII
);
1909 proto_item_append_text(pitem
, " (%s)", i_at_cmd
->long_name
);
1916 pitem
= proto_tree_add_item(command_tree
, hf_at_cmd
, tvb
, offset
,
1917 i_char
, ENC_NA
| ENC_ASCII
);
1922 if (i_at_cmd
&& i_at_cmd
->name
== NULL
) {
1925 name
= format_text(pinfo
->pool
, at_command
, i_char
+ 1);
1926 proto_item_append_text(command_item
, ": %s (Unknown)", name
);
1927 proto_item_append_text(pitem
, " (Unknown - Non-Standard HFP Command)");
1928 expert_add_info(pinfo
, pitem
, &ei_non_mandatory_command
);
1929 } else if (i_at_cmd
== NULL
) {
1930 proto_item_append_text(command_item
, ": AT");
1932 proto_item_append_text(command_item
, ": %s", i_at_cmd
->name
);
1937 if (i_at_cmd
&& g_strcmp0(i_at_cmd
->name
, "D")) {
1938 if (length
>= 2 && at_command
[i_char
] == '=' && at_command
[i_char
+ 1] == '?') {
1939 type
= at_command
[i_char
] << 8 | at_command
[i_char
+ 1];
1940 proto_tree_add_uint(command_tree
, hf_at_cmd_type
, tvb
, offset
, 2, type
);
1943 } else if (role
== ROLE_AG
&& length
>= 2 && at_command
[i_char
] == '\r' && at_command
[i_char
+ 1] == '\n') {
1944 type
= at_command
[i_char
] << 8 | at_command
[i_char
+ 1];
1945 proto_tree_add_uint(command_tree
, hf_at_cmd_type
, tvb
, offset
, 2, type
);
1948 } else if (length
>= 1 && (at_command
[i_char
] == '=' ||
1949 at_command
[i_char
] == '\r' ||
1950 at_command
[i_char
] == ':' ||
1951 at_command
[i_char
] == '?')) {
1952 type
= at_command
[i_char
];
1953 proto_tree_add_uint(command_tree
, hf_at_cmd_type
, tvb
, offset
, 1, type
);
1959 if (i_at_cmd
&& i_at_cmd
->check_command
&& !i_at_cmd
->check_command(role
, type
)) {
1960 expert_add_info(pinfo
, command_item
, &ei_invalid_usage
);
1963 parameters_item
= proto_tree_add_none_format(command_tree
, hf_parameters
, tvb
,
1964 offset
, 0, "Parameters");
1965 parameters_tree
= proto_item_add_subtree(parameters_item
, ett_bthfp_parameters
);
1966 first_parameter_offset
= offset
;
1970 while (i_char
< length
) {
1972 while (at_command
[i_char
] == ' ' || at_command
[i_char
] == '\t') {
1977 parameter_length
= 0;
1982 if (at_command
[i_char
+ parameter_length
] != '\r') {
1983 while (i_char
+ parameter_length
< length
&&
1984 at_command
[i_char
+ parameter_length
] != '\r') {
1986 if (at_command
[i_char
+ parameter_length
] == ';') {
1991 if (at_command
[i_char
+ parameter_length
] == '"') {
1992 quotation
= quotation
? false : true;
1995 if (quotation
== true) {
1996 parameter_length
+= 1;
2000 if (at_command
[i_char
+ parameter_length
] == '(') {
2003 if (at_command
[i_char
+ parameter_length
] == ')') {
2007 if (brackets
== 0 && at_command
[i_char
+ parameter_length
] == ',') {
2011 parameter_length
+= 1;
2014 if (type
== TYPE_ACTION
|| type
== TYPE_RESPONSE
) {
2015 if (i_at_cmd
&& (i_at_cmd
->dissect_parameter
!= NULL
&&
2016 !i_at_cmd
->dissect_parameter(tvb
, pinfo
, parameters_tree
, offset
, role
,
2017 type
, &at_command
[i_char
], parameter_number
, parameter_length
, &data
) )) {
2018 pitem
= proto_tree_add_item(parameters_tree
,
2019 hf_unknown_parameter
, tvb
, offset
,
2020 parameter_length
, ENC_NA
| ENC_ASCII
);
2021 expert_add_info(pinfo
, pitem
, &ei_unknown_parameter
);
2022 } else if (i_at_cmd
&& i_at_cmd
->dissect_parameter
== NULL
) {
2023 proto_tree_add_item(parameters_tree
, hf_parameter
, tvb
, offset
,
2024 parameter_length
, ENC_NA
| ENC_ASCII
);
2029 if (type
!= TYPE_ACTION_SIMPLY
&& type
!= TYPE_RESPONSE_ACK
&& type
!= TYPE_TEST
&& type
!= TYPE_READ
)
2030 parameter_number
+= 1;
2031 i_char
+= parameter_length
;
2032 offset
+= parameter_length
;
2033 last_parameter_offset
= offset
;
2035 if (role
== ROLE_AG
&&
2036 i_char
+ 1 <= length
&&
2037 at_command
[i_char
] == '\r' &&
2038 at_command
[i_char
+ 1] == '\n') {
2042 } else if (at_command
[i_char
] == ',' ||
2043 at_command
[i_char
] == '\r' ||
2044 at_command
[i_char
] == ';') {
2052 i_char
+= i_char_fix
;
2053 proto_item_set_len(command_item
, i_char
);
2055 length
= tvb_reported_length_remaining(tvb
, offset
);
2061 if (parameter_number
> 0 && last_parameter_offset
- first_parameter_offset
> 0)
2062 proto_item_set_len(parameters_item
, last_parameter_offset
- first_parameter_offset
);
2064 proto_item_append_text(parameters_item
, ": No");
2070 dissect_bthfp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data
)
2072 proto_item
*main_item
;
2073 proto_tree
*main_tree
;
2076 uint32_t role
= ROLE_UNKNOWN
;
2077 wmem_tree_key_t key
[10];
2078 uint32_t interface_id
;
2079 uint32_t adapter_id
;
2082 uint32_t frame_number
;
2084 uint32_t bd_addr_oui
;
2085 uint32_t bd_addr_id
;
2086 fragment_t
*fragment
;
2087 fragment_t
*previous_fragment
;
2088 fragment_t
*i_fragment
;
2093 tvbuff_t
*reassembled_tvb
= NULL
;
2094 unsigned reassemble_start_offset
= 0;
2095 unsigned reassemble_end_offset
= 0;
2098 previous_proto
= (GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo
->layers
)))));
2099 if (data
&& previous_proto
== proto_btrfcomm
) {
2100 btrfcomm_data_t
*rfcomm_data
;
2102 rfcomm_data
= (btrfcomm_data_t
*) data
;
2104 interface_id
= rfcomm_data
->interface_id
;
2105 adapter_id
= rfcomm_data
->adapter_id
;
2106 chandle
= rfcomm_data
->chandle
;
2107 dlci
= rfcomm_data
->dlci
;
2108 direction
= (rfcomm_data
->is_local_psm
) ? P2P_DIR_SENT
: P2P_DIR_RECV
;
2110 if (direction
== P2P_DIR_RECV
) {
2111 bd_addr_oui
= rfcomm_data
->remote_bd_addr_oui
;
2112 bd_addr_id
= rfcomm_data
->remote_bd_addr_id
;
2118 interface_id
= HCI_INTERFACE_DEFAULT
;
2119 adapter_id
= HCI_ADAPTER_DEFAULT
;
2122 direction
= P2P_DIR_UNKNOWN
;
2128 main_item
= proto_tree_add_item(tree
, proto_bthfp
, tvb
, 0, tvb_captured_length(tvb
), ENC_NA
);
2129 main_tree
= proto_item_add_subtree(main_item
, ett_bthfp
);
2131 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "HFP");
2133 switch (pinfo
->p2p_dir
) {
2135 col_set_str(pinfo
->cinfo
, COL_INFO
, "Sent ");
2138 col_set_str(pinfo
->cinfo
, COL_INFO
, "Rcvd ");
2141 col_set_str(pinfo
->cinfo
, COL_INFO
, "UnknownDirection ");
2145 if ((hfp_role
== ROLE_AG
&& pinfo
->p2p_dir
== P2P_DIR_SENT
) ||
2146 (hfp_role
== ROLE_HS
&& pinfo
->p2p_dir
== P2P_DIR_RECV
)) {
2148 } else if (hfp_role
!= ROLE_UNKNOWN
) {
2152 if (role
== ROLE_UNKNOWN
) {
2154 uint32_t service_type
;
2155 uint32_t service_channel
;
2156 service_info_t
*service_info
;
2158 sdp_psm
= SDP_PSM_DEFAULT
;
2160 service_type
= BTSDP_RFCOMM_PROTOCOL_UUID
;
2161 service_channel
= dlci
>> 1;
2162 frame_number
= pinfo
->num
;
2165 key
[0].key
= &interface_id
;
2167 key
[1].key
= &adapter_id
;
2169 key
[2].key
= &sdp_psm
;
2171 key
[3].key
= &direction
;
2173 key
[4].key
= &bd_addr_oui
;
2175 key
[5].key
= &bd_addr_id
;
2177 key
[6].key
= &service_type
;
2179 key
[7].key
= &service_channel
;
2181 key
[8].key
= &frame_number
;
2185 service_info
= btsdp_get_service_info(key
);
2186 if (service_info
&& service_info
->interface_id
== interface_id
&&
2187 service_info
->adapter_id
== adapter_id
&&
2188 service_info
->sdp_psm
== SDP_PSM_DEFAULT
&&
2189 ((service_info
->direction
== P2P_DIR_RECV
&&
2190 service_info
->bd_addr_oui
== bd_addr_oui
&&
2191 service_info
->bd_addr_id
== bd_addr_id
) ||
2192 (service_info
->direction
!= P2P_DIR_RECV
&&
2193 service_info
->bd_addr_oui
== 0 &&
2194 service_info
->bd_addr_id
== 0)) &&
2195 service_info
->type
== BTSDP_RFCOMM_PROTOCOL_UUID
&&
2196 service_info
->channel
== (dlci
>> 1)) {
2197 if ((service_info
->uuid
.bt_uuid
== BTSDP_HFP_GW_SERVICE_UUID
&& service_info
->direction
== P2P_DIR_RECV
&& pinfo
->p2p_dir
== P2P_DIR_SENT
) ||
2198 (service_info
->uuid
.bt_uuid
== BTSDP_HFP_GW_SERVICE_UUID
&& service_info
->direction
== P2P_DIR_SENT
&& pinfo
->p2p_dir
== P2P_DIR_RECV
) ||
2199 (service_info
->uuid
.bt_uuid
== BTSDP_HFP_SERVICE_UUID
&& service_info
->direction
== P2P_DIR_RECV
&& pinfo
->p2p_dir
== P2P_DIR_RECV
) ||
2200 (service_info
->uuid
.bt_uuid
== BTSDP_HFP_SERVICE_UUID
&& service_info
->direction
== P2P_DIR_SENT
&& pinfo
->p2p_dir
== P2P_DIR_SENT
)) {
2208 pitem
= proto_tree_add_uint(main_tree
, hf_role
, tvb
, 0, 0, role
);
2209 proto_item_set_generated(pitem
);
2211 if (role
== ROLE_UNKNOWN
) {
2212 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Data: %s",
2213 tvb_format_text(pinfo
->pool
, tvb
, 0, tvb_reported_length(tvb
)));
2214 proto_tree_add_item(main_tree
, hf_data
, tvb
, 0, tvb_captured_length(tvb
), ENC_NA
| ENC_ASCII
);
2215 return tvb_reported_length(tvb
);
2218 /* save fragments */
2219 if (!pinfo
->fd
->visited
) {
2220 frame_number
= pinfo
->num
- 1;
2223 key
[0].key
= &interface_id
;
2225 key
[1].key
= &adapter_id
;
2227 key
[2].key
= &chandle
;
2233 key
[5].key
= &frame_number
;
2237 previous_fragment
= (fragment_t
*) wmem_tree_lookup32_array_le(fragments
, key
);
2238 if (!(previous_fragment
&& previous_fragment
->interface_id
== interface_id
&&
2239 previous_fragment
->adapter_id
== adapter_id
&&
2240 previous_fragment
->chandle
== chandle
&&
2241 previous_fragment
->dlci
== dlci
&&
2242 previous_fragment
->role
== role
&&
2243 previous_fragment
->reassemble_state
!= REASSEMBLE_DONE
)) {
2244 previous_fragment
= NULL
;
2247 frame_number
= pinfo
->num
;
2250 key
[0].key
= &interface_id
;
2252 key
[1].key
= &adapter_id
;
2254 key
[2].key
= &chandle
;
2260 key
[5].key
= &frame_number
;
2264 fragment
= wmem_new(wmem_file_scope(), fragment_t
);
2265 fragment
->interface_id
= interface_id
;
2266 fragment
->adapter_id
= adapter_id
;
2267 fragment
->chandle
= chandle
;
2268 fragment
->dlci
= dlci
;
2269 fragment
->role
= role
;
2270 fragment
->idx
= previous_fragment
? previous_fragment
->idx
+ previous_fragment
->length
: 0;
2271 fragment
->reassemble_state
= REASSEMBLE_FRAGMENT
;
2272 fragment
->length
= tvb_reported_length(tvb
);
2273 fragment
->data
= (uint8_t *) wmem_alloc(wmem_file_scope(), fragment
->length
);
2274 fragment
->previous_fragment
= previous_fragment
;
2275 tvb_memcpy(tvb
, fragment
->data
, offset
, fragment
->length
);
2277 wmem_tree_insert32_array(fragments
, key
, fragment
);
2279 /* Detect reassemble end character: \r for HS or \n for AG */
2280 length
= tvb_reported_length(tvb
);
2281 at_stream
= tvb_get_string_enc(pinfo
->pool
, tvb
, 0, length
, ENC_ASCII
);
2283 reassemble_start_offset
= 0;
2285 for (i_length
= 0; i_length
< length
; i_length
+= 1) {
2286 if (!((role
== ROLE_HS
&& at_stream
[i_length
] == '\r') ||
2287 (role
== ROLE_AG
&& at_stream
[i_length
] == '\n'))) {
2291 if (role
== ROLE_HS
&& at_stream
[i_length
] == '\r') {
2292 reassemble_start_offset
= i_length
+ 1;
2293 if (reassemble_end_offset
== 0) reassemble_end_offset
= i_length
+ 1;
2296 if (role
== ROLE_AG
&& at_stream
[i_length
] == '\n') {
2297 reassemble_start_offset
= i_length
+ 1;
2300 frame_number
= pinfo
->num
;
2303 key
[0].key
= &interface_id
;
2305 key
[1].key
= &adapter_id
;
2307 key
[2].key
= &chandle
;
2313 key
[5].key
= &frame_number
;
2317 fragment
= (fragment_t
*) wmem_tree_lookup32_array_le(fragments
, key
);
2318 if (fragment
&& fragment
->interface_id
== interface_id
&&
2319 fragment
->adapter_id
== adapter_id
&&
2320 fragment
->chandle
== chandle
&&
2321 fragment
->dlci
== dlci
&&
2322 fragment
->role
== role
) {
2323 i_fragment
= fragment
;
2324 while (i_fragment
&& i_fragment
->idx
> 0) {
2325 i_fragment
= i_fragment
->previous_fragment
;
2328 if (i_length
+ 1 == length
&&
2330 at_stream
[i_length
] == '\r') {
2331 fragment
->reassemble_state
= REASSEMBLE_DONE
;
2332 } else if (i_length
+ 1 == length
&&
2335 at_stream
[i_length
] == '\n' &&
2336 at_stream
[i_length
- 1] == '\r' &&
2337 at_stream
[0] == '\r' &&
2338 at_stream
[1] == '\n') {
2339 fragment
->reassemble_state
= REASSEMBLE_DONE
;
2340 } else if (i_length
+ 1 == length
&&
2343 at_stream
[i_length
] == '\n' &&
2344 at_stream
[i_length
- 1] == '\r' &&
2346 i_fragment
->reassemble_state
== REASSEMBLE_FRAGMENT
&&
2347 i_fragment
->length
>= 2 &&
2348 i_fragment
->data
[0] == '\r' &&
2349 i_fragment
->data
[1] == '\n') {
2350 fragment
->reassemble_state
= REASSEMBLE_DONE
;
2351 } else if (role
== ROLE_HS
) {
2352 /* XXX: Temporary disable reassembling of partial message, it seems to be broken */
2353 /* fragment->reassemble_state = REASSEMBLE_PARTIALLY;*/
2355 fragment
->reassemble_start_offset
= reassemble_start_offset
;
2356 fragment
->reassemble_end_offset
= reassemble_end_offset
;
2361 /* recover reassembled payload */
2362 frame_number
= pinfo
->num
;
2365 key
[0].key
= &interface_id
;
2367 key
[1].key
= &adapter_id
;
2369 key
[2].key
= &chandle
;
2375 key
[5].key
= &frame_number
;
2379 fragment
= (fragment_t
*) wmem_tree_lookup32_array_le(fragments
, key
);
2380 if (fragment
&& fragment
->interface_id
== interface_id
&&
2381 fragment
->adapter_id
== adapter_id
&&
2382 fragment
->chandle
== chandle
&&
2383 fragment
->dlci
== dlci
&&
2384 fragment
->role
== role
&&
2385 fragment
->reassemble_state
!= REASSEMBLE_FRAGMENT
) {
2387 unsigned i_data_offset
;
2389 i_data_offset
= fragment
->idx
+ fragment
->length
;
2390 at_data
= (uint8_t *) wmem_alloc(pinfo
->pool
, fragment
->idx
+ fragment
->length
);
2392 i_fragment
= fragment
;
2394 if (i_fragment
&& i_fragment
->reassemble_state
== REASSEMBLE_PARTIALLY
) {
2395 i_data_offset
-= i_fragment
->reassemble_end_offset
;
2396 memcpy(at_data
+ i_data_offset
, i_fragment
->data
, i_fragment
->reassemble_end_offset
);
2397 i_fragment
= i_fragment
->previous_fragment
;
2401 while (i_fragment
&& i_fragment
->idx
> 0) {
2402 i_data_offset
-= i_fragment
->length
;
2403 memcpy(at_data
+ i_data_offset
, i_fragment
->data
, i_fragment
->length
);
2404 i_fragment
= i_fragment
->previous_fragment
;
2407 if (i_fragment
&& i_fragment
->reassemble_state
== REASSEMBLE_PARTIALLY
) {
2408 i_data_offset
-= (i_fragment
->length
- i_fragment
->reassemble_start_offset
);
2409 memcpy(at_data
+ i_data_offset
, i_fragment
->data
+ i_fragment
->reassemble_start_offset
,
2410 i_fragment
->length
- i_fragment
->reassemble_start_offset
);
2411 } else if (i_fragment
) {
2412 i_data_offset
-= i_fragment
->length
;
2413 memcpy(at_data
+ i_data_offset
, i_fragment
->data
, i_fragment
->length
);
2417 if (fragment
->idx
> 0 && fragment
->length
> 0) {
2418 proto_tree_add_item(main_tree
, hf_fragment
, tvb
, offset
,
2419 tvb_captured_length_remaining(tvb
, offset
), ENC_ASCII
| ENC_NA
);
2420 reassembled_tvb
= tvb_new_child_real_data(tvb
, at_data
,
2421 fragment
->idx
+ fragment
->length
, fragment
->idx
+ fragment
->length
);
2422 add_new_data_source(pinfo
, reassembled_tvb
, "Reassembled HFP");
2426 if (reassembled_tvb
) {
2427 unsigned reassembled_offset
= 0;
2429 while (tvb_reported_length(reassembled_tvb
) > reassembled_offset
) {
2430 reassembled_offset
= dissect_at_command(reassembled_tvb
,
2431 pinfo
, main_tree
, reassembled_offset
, role
, command_number
);
2432 command_number
+= 1;
2434 offset
= tvb_captured_length(tvb
);
2436 while (tvb_reported_length(tvb
) > (unsigned) offset
) {
2437 offset
= dissect_at_command(tvb
, pinfo
, main_tree
, offset
, role
, command_number
);
2438 command_number
+= 1;
2442 pitem
= proto_tree_add_item(main_tree
, hf_fragmented
, tvb
, 0, 0, ENC_NA
);
2443 proto_item_set_generated(pitem
);
2445 proto_tree_add_item_ret_display_string(main_tree
, hf_fragment
, tvb
, offset
, -1, ENC_ASCII
, pinfo
->pool
, &display_str
);
2446 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "Fragment: %s", display_str
);
2447 offset
= tvb_captured_length(tvb
);
2454 proto_register_bthfp(void)
2457 expert_module_t
*expert_bthfp
;
2459 static hf_register_info hf
[] = {
2461 { "Command", "bthfp.command",
2462 FT_NONE
, BASE_NONE
, NULL
, 0,
2466 { "Parameters", "bthfp.parameters",
2467 FT_NONE
, BASE_NONE
, NULL
, 0,
2471 { "AT Stream", "bthfp.data",
2472 FT_STRING
, BASE_NONE
, NULL
, 0,
2476 { "Fragment", "bthfp.fragment",
2477 FT_STRING
, BASE_NONE
, NULL
, 0,
2481 { "Fragmented", "bthfp.fragmented",
2482 FT_NONE
, BASE_NONE
, NULL
, 0,
2486 { "Ignored", "bthfp.ignored",
2487 FT_BYTES
, BASE_NONE
, NULL
, 0,
2491 { "Command", "bthfp.at_cmd",
2492 FT_STRING
, BASE_NONE
, NULL
, 0,
2496 { "Type", "bthfp.at_cmd.type",
2497 FT_UINT16
, BASE_HEX
, VALS(at_cmd_type_vals
), 0,
2500 { &hf_at_command_line_prefix
,
2501 { "Command Line Prefix", "bthfp.command_line_prefix",
2502 FT_STRING
, BASE_NONE
, NULL
, 0,
2506 { "Parameter", "bthfp.parameter",
2507 FT_STRING
, BASE_NONE
, NULL
, 0,
2510 { &hf_unknown_parameter
,
2511 { "Unknown Parameter", "bthfp.unknown_parameter",
2512 FT_STRING
, BASE_NONE
, NULL
, 0,
2516 { "Role", "bthfp.role",
2517 FT_UINT8
, BASE_DEC
, VALS(role_vals
), 0,
2521 { "HS supported features bitmask", "bthfp.brsf.hs.features",
2522 FT_UINT32
, BASE_DEC
, NULL
, 0,
2525 { &hf_brsf_hs_ec_nr_function
,
2526 { "EC and/or NR function", "bthfp.brsf.hs.ec_nr_function",
2527 FT_BOOLEAN
, 32, NULL
, 0x00000001,
2530 { &hf_brsf_hs_call_waiting_or_tree_way
,
2531 { "Call waiting or 3-way calling", "bthfp.brsf.hs.call_waiting_or_tree_way",
2532 FT_BOOLEAN
, 32, NULL
, 0x00000002,
2535 { &hf_brsf_hs_cli_presentation
,
2536 { "CLI Presentation", "bthfp.brsf.hs.cli_presentation",
2537 FT_BOOLEAN
, 32, NULL
, 0x00000004,
2540 { &hf_brsf_hs_voice_recognition_activation
,
2541 { "Voice Recognition Activation", "bthfp.brsf.hs.voice_recognition_activation",
2542 FT_BOOLEAN
, 32, NULL
, 0x00000008,
2545 { &hf_brsf_hs_remote_volume_control
,
2546 { "Remote Volume Control", "bthfp.brsf.hs.remote_volume_control",
2547 FT_BOOLEAN
, 32, NULL
, 0x00000010,
2550 { &hf_brsf_hs_enhanced_call_status
,
2551 { "Enhanced Call Status", "bthfp.brsf.hs.enhanced_call_status",
2552 FT_BOOLEAN
, 32, NULL
, 0x00000020,
2555 { &hf_brsf_hs_enhanced_call_control
,
2556 { "Enhanced Call Control", "bthfp.brsf.hs.enhanced_call_control",
2557 FT_BOOLEAN
, 32, NULL
, 0x00000040,
2560 { &hf_brsf_hs_codec_negotiation
,
2561 { "Codec Negotiation", "bthfp.brsf.hs.codec_negotiation",
2562 FT_BOOLEAN
, 32, NULL
, 0x00000080,
2565 { &hf_brsf_hs_hf_indicators
,
2566 { "HF Indicators", "bthfp.brsf.hs.hf_indicators",
2567 FT_BOOLEAN
, 32, NULL
, 0x00000100,
2570 { &hf_brsf_hs_esco_s4_t2_settings_support
,
2571 { "eSCO S4 (and T2) Settings Support","bthfp.brsf.hs.esco_s4_t2_settings_support",
2572 FT_BOOLEAN
, 32, NULL
, 0x00000200,
2575 { &hf_brsf_hs_reserved
,
2576 { "Reserved", "bthfp.brsf.hs.reserved",
2577 FT_UINT32
, BASE_HEX
, NULL
, 0xFFFFFC00,
2581 { "AG supported features bitmask", "bthfp.brsf.ag.features",
2582 FT_UINT32
, BASE_DEC
, NULL
, 0,
2585 { &hf_brsf_ag_three_way_calling
,
2586 { "Three Way Calling", "bthfp.brsf.ag.three_way_calling",
2587 FT_BOOLEAN
, 32, NULL
, 0x00000001,
2590 { &hf_brsf_ag_ec_nr_function
,
2591 { "EC and/or NR function", "bthfp.brsf.ag.ec_nr_function",
2592 FT_BOOLEAN
, 32, NULL
, 0x00000002,
2595 { &hf_brsf_ag_voice_recognition_function
,
2596 { "Voice Recognition Function", "bthfp.brsf.ag.voice_recognition_function",
2597 FT_BOOLEAN
, 32, NULL
, 0x00000004,
2600 { &hf_brsf_ag_inband_ring_tone
,
2601 { "In-band Ring Tone", "bthfp.brsf.ag.inband_ring_tone",
2602 FT_BOOLEAN
, 32, NULL
, 0x00000008,
2605 { &hf_brsf_ag_attach_number_to_voice_tag
,
2606 { "Attach Number to Voice Tag", "bthfp.brsf.ag.attach_number_to_voice_tag",
2607 FT_BOOLEAN
, 32, NULL
, 0x00000010,
2610 { &hf_brsf_ag_ability_to_reject_a_call
,
2611 { "Ability to Reject a Call", "bthfp.brsf.ag.ability_to_reject_a_call",
2612 FT_BOOLEAN
, 32, NULL
, 0x00000020,
2615 { &hf_brsf_ag_enhanced_call_status
,
2616 { "Enhanced Call Status", "bthfp.brsf.ag.enhanced_call_status",
2617 FT_BOOLEAN
, 32, NULL
, 0x00000040,
2620 { &hf_brsf_ag_enhanced_call_control
,
2621 { "Enhanced Call Control", "bthfp.brsf.ag.enhanced_call_control",
2622 FT_BOOLEAN
, 32, NULL
, 0x00000080,
2625 { &hf_brsf_ag_extended_error_result_codes
,
2626 { "Extended Error Result Codes", "bthfp.brsf.ag.extended_error_result_codes",
2627 FT_BOOLEAN
, 32, NULL
, 0x00000100,
2630 { &hf_brsf_ag_codec_negotiation
,
2631 { "Codec Negotiation", "bthfp.brsf.ag.codec_negotiation",
2632 FT_BOOLEAN
, 32, NULL
, 0x00000200,
2635 { &hf_brsf_ag_hf_indicators
,
2636 { "HF Indicators", "bthfp.brsf.ag.hf_indicators",
2637 FT_BOOLEAN
, 32, NULL
, 0x00000400,
2640 { &hf_brsf_ag_esco_s4_t2_settings_support
,
2641 { "eSCO S4 (and T2) Settings Support","bthfp.brsf.ag.esco_s4_t2_settings_support",
2642 FT_BOOLEAN
, 32, NULL
, 0x00000800,
2645 { &hf_brsf_ag_reserved
,
2646 { "Reserved", "bthfp.brsf.ag.reserved",
2647 FT_UINT32
, BASE_HEX
, NULL
, 0xFFFFF000,
2651 { "Gain", "bthfp.vgs",
2652 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_slash15
), 0,
2656 { "Gain", "bthfp.vgm",
2657 FT_UINT8
, BASE_DEC
|BASE_UNIT_STRING
, UNS(&units_slash15
), 0,
2661 { "Noise Reduction", "bthfp.nrec",
2662 FT_UINT8
, BASE_DEC
, VALS(nrec_vals
), 0,
2666 { "Voice Recognition", "bthfp.bvra.vrect",
2667 FT_UINT8
, BASE_DEC
, VALS(bvra_vrect_vals
), 0,
2671 { "Feature", "bthfp.bsir",
2672 FT_UINT8
, BASE_DEC
, VALS(bsir_vals
), 0,
2676 { "Feature", "bthfp.btrh",
2677 FT_UINT8
, BASE_DEC
, VALS(btrh_vals
), 0,
2681 { "Mode", "bthfp.cmer.mode",
2682 FT_UINT8
, BASE_DEC
, NULL
, 0,
2686 { "Keypad", "bthfp.cmer.keyp",
2687 FT_UINT8
, BASE_DEC
, NULL
, 0,
2691 { "Display", "bthfp.cmer.disp",
2692 FT_UINT8
, BASE_DEC
, NULL
, 0,
2696 { "Indicator", "bthfp.cmer.ind",
2697 FT_UINT8
, BASE_DEC
, NULL
, 0,
2701 { "Buffer", "bthfp.cmer.bfr",
2702 FT_UINT8
, BASE_DEC
, NULL
, 0,
2706 { "Codec", "bthfp.bac.codec",
2707 FT_UINT8
, BASE_DEC
, VALS(codecs_vals
), 0,
2711 { "Codec", "bthfp.bcs.codec",
2712 FT_UINT8
, BASE_DEC
, VALS(codecs_vals
), 0,
2716 { "Request", "bthfp.binp.request",
2717 FT_UINT8
, BASE_DEC
, VALS(binp_request_vals
), 0,
2720 { &hf_binp_response
,
2721 { "Response", "bthfp.binp.response",
2722 FT_STRING
, BASE_NONE
, NULL
, 0,
2726 { "CME Error", "bthfp.cme_error",
2727 FT_UINT8
, BASE_DEC
, VALS(cme_error_vals
), 0,
2731 { "Mode", "bthfp.cmee",
2732 FT_UINT8
, BASE_DEC
, VALS(cmee_vals
), 0,
2736 { "Mode", "bthfp.chld.mode_value",
2737 FT_UINT8
, BASE_DEC
, VALS(chld_vals
), 0,
2741 { "Mode: Releases specified active call only", "bthfp.chld.mode",
2742 FT_STRING
, BASE_NONE
, NULL
, 0,
2746 { "Mode: Request private consultation mode with specified call - place all calls on hold EXCEPT the call indicated by x", "bthfp.chld.mode",
2747 FT_STRING
, BASE_NONE
, NULL
, 0,
2750 { &hf_chld_supported_modes
,
2751 { "Supported Modes", "bthfp.chld.supported_modes",
2752 FT_STRING
, BASE_NONE
, NULL
, 0,
2755 { &hf_ciev_indicator_index
,
2756 { "Indicator Index", "bthfp.ciev.indicator_index",
2757 FT_UINT8
, BASE_DEC
, NULL
, 0,
2761 { "DTMF", "bthfp.vts.dtmf",
2762 FT_STRING
, BASE_NONE
, NULL
, 0,
2766 { "Duration", "bthfp.vts.duration",
2767 FT_UINT32
, BASE_DEC
, NULL
, 0,
2771 { "Mode", "bthfp.cops.mode",
2772 FT_UINT8
, BASE_DEC
, VALS(cops_mode_vals
), 0,
2776 { "Format", "bthfp.cops.format",
2777 FT_UINT8
, BASE_DEC
, VALS(cops_format_vals
), 0,
2780 { &hf_cops_operator
,
2781 { "Operator", "bthfp.cops.operator",
2782 FT_STRING
, BASE_NONE
, NULL
, 0,
2786 { "AcT", "bthfp.cops.act",
2787 FT_UINT8
, BASE_DEC
, VALS(cops_act_vals
), 0,
2791 { "Mode", "bthfp.clip.mode",
2792 FT_UINT8
, BASE_DEC
, VALS(clip_mode_vals
), 0,
2796 { "Status", "bthfp.clip.status",
2797 FT_UINT8
, BASE_DEC
, VALS(clip_status_vals
), 0,
2801 { "Number", "bthfp.at.number",
2802 FT_STRING
, BASE_NONE
, NULL
, 0,
2806 { "Type", "bthfp.at.type",
2807 FT_UINT8
, BASE_DEC
| BASE_RANGE_STRING
, RVALS(at_type_vals
), 0,
2810 { &hf_at_subaddress
,
2811 { "Subaddress", "bthfp.at.subaddress",
2812 FT_STRING
, BASE_NONE
, NULL
, 0,
2815 { &hf_at_subaddress_type
,
2816 { "Subaddress Type", "bthfp.at.subaddress_type",
2817 FT_UINT8
, BASE_DEC
| BASE_RANGE_STRING
, RVALS(at_type_vals
), 0,
2821 { "Speed", "bthfp.cnum.speed",
2822 FT_UINT8
, BASE_DEC
| BASE_EXT_STRING
, &csd_data_rate_vals_ext
, 0,
2826 { "Service", "bthfp.cnum.service",
2827 FT_UINT8
, BASE_DEC
, VALS(cnum_service_vals
), 0,
2831 { "Information Transfer Capability", "bthfp.cnum.itc",
2832 FT_UINT8
, BASE_DEC
, VALS(cnum_itc_vals
), 0,
2836 { "Alpha", "bthfp.at.alpha",
2837 FT_STRING
, BASE_NONE
, NULL
, 0,
2840 { &hf_at_cli_validity
,
2841 { "CLI Validity", "bthfp.at.cli_validity",
2842 FT_UINT8
, BASE_DEC
, VALS(cli_validity_vals
), 0,
2846 { "Priority", "bthfp.at.priority",
2847 FT_UINT8
, BASE_DEC
, NULL
, 0,
2851 { "ID", "bthfp.clcc.id",
2852 FT_UINT32
, BASE_DEC
, NULL
, 0,
2856 { "Direction", "bthfp.clcc.dir",
2857 FT_UINT32
, BASE_DEC
, VALS(clcc_dir_vals
), 0,
2861 { "State", "bthfp.clcc.stat",
2862 FT_UINT32
, BASE_DEC
, VALS(clcc_stat_vals
), 0,
2866 { "Mode", "bthfp.clcc.mode",
2867 FT_UINT32
, BASE_DEC
, VALS(clcc_mode_vals
), 0,
2871 { "Mpty", "bthfp.clcc.mpty",
2872 FT_UINT32
, BASE_DEC
, VALS(clcc_mpty_vals
), 0,
2875 { &hf_ccwa_show_result_code
,
2876 { "Show Result Code Presentation Status", "bthfp.ccwa.presentation_status",
2877 FT_UINT32
, BASE_DEC
, VALS(ccwa_show_result_code_vals
), 0,
2881 { "Mode", "bthfp.ccwa.mode",
2882 FT_UINT32
, BASE_DEC
, VALS(ccwa_mode_vals
), 0,
2886 { "Class", "bthfp.ccwa.class",
2887 FT_UINT32
, BASE_DEC
, VALS(ccwa_class_vals
), 0,
2890 { &hf_biev_assigned_number
,
2891 { "Assigned Number", "bthfp.biev.assigned_number",
2892 FT_UINT16
, BASE_DEC
, VALS(biev_assigned_number_vals
), 0,
2895 { &hf_bind_parameter
,
2896 { "Parameter", "bthfp.bind.parameter",
2897 FT_UINT16
, BASE_DEC
, NULL
, 0,
2901 { "Value", "bthfp.biev.value",
2902 FT_UINT32
, BASE_DEC
, NULL
, 0,
2905 { &hf_bia_indicator
[0],
2906 { "Indicator 1", "bthfp.bia.indicator.1",
2907 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2910 { &hf_bia_indicator
[1],
2911 { "Indicator 2", "bthfp.bia.indicator.2",
2912 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2915 { &hf_bia_indicator
[2],
2916 { "Indicator 3", "bthfp.bia.indicator.3",
2917 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2920 { &hf_bia_indicator
[3],
2921 { "Indicator 4", "bthfp.bia.indicator.4",
2922 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2925 { &hf_bia_indicator
[4],
2926 { "Indicator 5", "bthfp.bia.indicator.5",
2927 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2930 { &hf_bia_indicator
[5],
2931 { "Indicator 6", "bthfp.bia.indicator.6",
2932 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2935 { &hf_bia_indicator
[6],
2936 { "Indicator 7", "bthfp.bia.indicator.7",
2937 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2940 { &hf_bia_indicator
[7],
2941 { "Indicator 8", "bthfp.bia.indicator.8",
2942 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2945 { &hf_bia_indicator
[8],
2946 { "Indicator 9", "bthfp.bia.indicator.9",
2947 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2950 { &hf_bia_indicator
[9],
2951 { "Indicator 10", "bthfp.bia.indicator.10",
2952 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2955 { &hf_bia_indicator
[10],
2956 { "Indicator 11", "bthfp.bia.indicator.11",
2957 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2960 { &hf_bia_indicator
[11],
2961 { "Indicator 12", "bthfp.bia.indicator.12",
2962 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2965 { &hf_bia_indicator
[12],
2966 { "Indicator 13", "bthfp.bia.indicator.13",
2967 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2970 { &hf_bia_indicator
[13],
2971 { "Indicator 14", "bthfp.bia.indicator.14",
2972 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2975 { &hf_bia_indicator
[14],
2976 { "Indicator 15", "bthfp.bia.indicator.15",
2977 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2980 { &hf_bia_indicator
[15],
2981 { "Indicator 16", "bthfp.bia.indicator.16",
2982 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2985 { &hf_bia_indicator
[16],
2986 { "Indicator 17", "bthfp.bia.indicator.17",
2987 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2990 { &hf_bia_indicator
[17],
2991 { "Indicator 18", "bthfp.bia.indicator.18",
2992 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
2995 { &hf_bia_indicator
[18],
2996 { "Indicator 19", "bthfp.bia.indicator.19",
2997 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
3000 { &hf_bia_indicator
[19],
3001 { "Indicator 20", "bthfp.bia.indicator.20",
3002 FT_UINT8
, BASE_DEC
, VALS(indicator_vals
), 0,
3006 { "Indicator 1", "bthfp.indicator.1",
3007 FT_STRING
, BASE_NONE
, NULL
, 0,
3011 { "Indicator 2", "bthfp.indicator.2",
3012 FT_STRING
, BASE_NONE
, NULL
, 0,
3016 { "Indicator 3", "bthfp.indicator.3",
3017 FT_STRING
, BASE_NONE
, NULL
, 0,
3021 { "Indicator 4", "bthfp.indicator.4",
3022 FT_STRING
, BASE_NONE
, NULL
, 0,
3026 { "Indicator 5", "bthfp.indicator.5",
3027 FT_STRING
, BASE_NONE
, NULL
, 0,
3031 { "Indicator 6", "bthfp.indicator.6",
3032 FT_STRING
, BASE_NONE
, NULL
, 0,
3036 { "Indicator 7", "bthfp.indicator.7",
3037 FT_STRING
, BASE_NONE
, NULL
, 0,
3041 { "Indicator 8", "bthfp.indicator.8",
3042 FT_STRING
, BASE_NONE
, NULL
, 0,
3046 { "Indicator 9", "bthfp.indicator.9",
3047 FT_STRING
, BASE_NONE
, NULL
, 0,
3051 { "Indicator 10", "bthfp.indicator.10",
3052 FT_STRING
, BASE_NONE
, NULL
, 0,
3055 { &hf_indicator
[10],
3056 { "Indicator 11", "bthfp.indicator.11",
3057 FT_STRING
, BASE_NONE
, NULL
, 0,
3060 { &hf_indicator
[11],
3061 { "Indicator 12", "bthfp.indicator.12",
3062 FT_STRING
, BASE_NONE
, NULL
, 0,
3065 { &hf_indicator
[12],
3066 { "Indicator 13", "bthfp.indicator.13",
3067 FT_STRING
, BASE_NONE
, NULL
, 0,
3070 { &hf_indicator
[13],
3071 { "Indicator 14", "bthfp.indicator.14",
3072 FT_STRING
, BASE_NONE
, NULL
, 0,
3075 { &hf_indicator
[14],
3076 { "Indicator 15", "bthfp.indicator.15",
3077 FT_STRING
, BASE_NONE
, NULL
, 0,
3080 { &hf_indicator
[15],
3081 { "Indicator 16", "bthfp.indicator.16",
3082 FT_STRING
, BASE_NONE
, NULL
, 0,
3085 { &hf_indicator
[16],
3086 { "Indicator 17", "bthfp.indicator.17",
3087 FT_STRING
, BASE_NONE
, NULL
, 0,
3090 { &hf_indicator
[17],
3091 { "Indicator 18", "bthfp.indicator.18",
3092 FT_STRING
, BASE_NONE
, NULL
, 0,
3095 { &hf_indicator
[18],
3096 { "Indicator 19", "bthfp.indicator.19",
3097 FT_STRING
, BASE_NONE
, NULL
, 0,
3100 { &hf_indicator
[19],
3101 { "Indicator 20", "bthfp.indicator.20",
3102 FT_STRING
, BASE_NONE
, NULL
, 0,
3106 { "State", "bthfp.aplefm.state",
3107 FT_UINT16
, BASE_DEC
, VALS(aplefm_state_vals
), 0,
3110 { &hf_aplsiri_state
,
3111 { "Siri State", "bthfp.aplsiri.state",
3112 FT_UINT16
, BASE_DEC
, VALS(aplsiri_state_vals
), 0,
3115 { &hf_iphoneaccev_count
,
3116 { "Count", "bthfp.iphoneaccev.count",
3117 FT_UINT16
, BASE_DEC
, NULL
, 0,
3120 { &hf_iphoneaccev_key
,
3121 { "Key", "bthfp.iphoneaccev.key",
3122 FT_UINT16
, BASE_DEC
, VALS(iphoneaccev_key_vals
), 0,
3125 { &hf_iphoneaccev_value
,
3126 { "Value", "bthfp.iphoneaccev.value",
3127 FT_UINT16
, BASE_DEC
, NULL
, 0,
3130 { &hf_xapl_accessory_info
,
3131 { "Accessory Info", "bthfp.xapl.accessory_info",
3132 FT_STRING
, BASE_NONE
, NULL
, 0,
3135 { &hf_xapl_accessory_info_vendor_id
,
3136 { "Vendor ID", "bthfp.xapl.accessory_info.vendor_id",
3137 FT_UINT32
, BASE_HEX
, NULL
, 0,
3140 { &hf_xapl_accessory_info_product_id
,
3141 { "Product ID", "bthfp.xapl.accessory_info.product_id",
3142 FT_UINT16
, BASE_HEX
, NULL
, 0,
3145 { &hf_xapl_accessory_info_version
,
3146 { "Version", "bthfp.xapl.accessory_info.version",
3147 FT_UINT16
, BASE_HEX
, NULL
, 0,
3150 { &hf_xapl_host_info
,
3151 { "Host Info", "bthfp.xapl.host_info",
3152 FT_STRING
, BASE_NONE
, NULL
, 0,
3155 { &hf_xapl_features
,
3156 { "Features", "bthfp.xapl.features",
3157 FT_UINT32
, BASE_DEC
, NULL
, 0,
3160 { &hf_xapl_features_reserved
,
3161 { "Reserved", "bthfp.xapl.features.reserved.0",
3162 FT_BOOLEAN
, 32, NULL
, 0x00000001,
3165 { &hf_xapl_features_battery_reporting
,
3166 { "Battery Reporting", "bthfp.xapl.features.battery_reporting",
3167 FT_BOOLEAN
, 32, NULL
, 0x00000002,
3170 { &hf_xapl_features_docked_or_powered
,
3171 { "Accessory is Docked or Powered", "bthfp.xapl.features.docked_or_powered",
3172 FT_BOOLEAN
, 32, NULL
, 0x00000004,
3175 { &hf_xapl_features_siri_status_reporting
,
3176 { "Siri Status Reporting", "bthfp.xapl.features.siri_status_reporting",
3177 FT_BOOLEAN
, 32, NULL
, 0x00000008,
3180 { &hf_xapl_features_noise_reduction_status_reporting
,
3181 { "Noise Reduction Status Reporting", "bthfp.xapl.features.noise_reduction_status_reporting",
3182 FT_BOOLEAN
, 32, NULL
, 0x00000010,
3185 { &hf_xapl_features_reserved_x
,
3186 { "Reserved", "bthfp.xapl.features.reserved.x",
3187 FT_BOOLEAN
, 32, NULL
, 0xFFFFFFE0,
3192 static ei_register_info ei
[] = {
3193 { &ei_non_mandatory_command
, { "bthfp.expert.non_mandatory_command", PI_PROTOCOL
, PI_NOTE
, "Non-mandatory command in HFP", EXPFILL
}},
3194 { &ei_invalid_usage
, { "bthfp.expert.invalid_usage", PI_PROTOCOL
, PI_WARN
, "Non mandatory type or command in this role", EXPFILL
}},
3195 { &ei_unknown_parameter
, { "bthfp.expert.unknown_parameter", PI_PROTOCOL
, PI_WARN
, "Unknown parameter", EXPFILL
}},
3196 { &ei_brfs_hs_reserved_bits
, { "bthfp.expert.brsf.hs.reserved_bits", PI_PROTOCOL
, PI_WARN
, "The reserved bits [10-31] shall be initialized to Zero", EXPFILL
}},
3197 { &ei_brfs_ag_reserved_bits
, { "bthfp.expert.brsf.ag.reserved_bits", PI_PROTOCOL
, PI_WARN
, "The reserved bits [12-31] shall be initialized to Zero", EXPFILL
}},
3198 { &ei_vgm_gain
, { "bthfp.expert.vgm", PI_PROTOCOL
, PI_WARN
, "Gain of microphone exceeds range 0-15", EXPFILL
}},
3199 { &ei_vgs_gain
, { "bthfp.expert.vgs", PI_PROTOCOL
, PI_WARN
, "Gain of speaker exceeds range 0-15", EXPFILL
}},
3200 { &ei_nrec
, { "bthfp.expert.nrec", PI_PROTOCOL
, PI_WARN
, "Only 0 is valid", EXPFILL
}},
3201 { &ei_bvra
, { "bthfp.expert.bvra", PI_PROTOCOL
, PI_WARN
, "Only 0-1 is valid", EXPFILL
}},
3202 { &ei_bcs
, { "bthfp.expert.bcs", PI_PROTOCOL
, PI_NOTE
, "BCS codec may only be 1-2", EXPFILL
}},
3203 { &ei_bac
, { "bthfp.expert.bac", PI_PROTOCOL
, PI_NOTE
, "BAC codec may only be 1-2", EXPFILL
}},
3204 { &ei_bsir
, { "bthfp.expert.bsir", PI_PROTOCOL
, PI_WARN
, "Only 0-1 is valid", EXPFILL
}},
3205 { &ei_btrh
, { "bthfp.expert.btrh", PI_PROTOCOL
, PI_WARN
, "Only 0-2 is valid", EXPFILL
}},
3206 { &ei_binp
, { "bthfp.expert.binp", PI_PROTOCOL
, PI_WARN
, "Only 1 is valid", EXPFILL
}},
3207 { &ei_bia
, { "bthfp.expert.bia", PI_PROTOCOL
, PI_WARN
, "Only 0-1 is valid", EXPFILL
}},
3208 { &ei_biev_assigned_number
, { "bthfp.expert.biev.assigned_number", PI_PROTOCOL
, PI_WARN
, "Only 0-65535 is valid", EXPFILL
}},
3209 { &ei_biev_assigned_number_no
, { "bthfp.expert.biev.assigned_number.not_assigned", PI_PROTOCOL
, PI_WARN
, "Value is unknown for Assign Numbers", EXPFILL
}},
3210 { &ei_cmer_mode
, { "bthfp.expert.cmer.mode", PI_PROTOCOL
, PI_NOTE
, "Only 3 is valid for HFP", EXPFILL
}},
3211 { &ei_cmer_disp
, { "bthfp.expert.cmer.disp", PI_PROTOCOL
, PI_WARN
, "Value is ignored for HFP", EXPFILL
}},
3212 { &ei_cmer_keyp
, { "bthfp.expert.cmer.keyp", PI_PROTOCOL
, PI_WARN
, "Value is ignored for HFP", EXPFILL
}},
3213 { &ei_cmer_ind
, { "bthfp.expert.cmer.ind", PI_PROTOCOL
, PI_NOTE
, "Only 0-1 is valid for HFP", EXPFILL
}},
3214 { &ei_cmer_btr
, { "bthfp.expert.cmer.btr", PI_PROTOCOL
, PI_WARN
, "Value is ignored for HFP", EXPFILL
}},
3215 { &ei_chld_mode
, { "bthfp.expert.chld.mode", PI_PROTOCOL
, PI_WARN
, "Invalid value for HFP", EXPFILL
}},
3216 { &ei_ciev_indicator
, { "bthfp.expert.ciev.indicator", PI_PROTOCOL
, PI_WARN
, "Unknown indicator", EXPFILL
}},
3217 { &ei_vts_dtmf
, { "bthfp.expert.vts.dtmf", PI_PROTOCOL
, PI_WARN
, "DTMF should be single character", EXPFILL
}},
3218 { &ei_at_type
, { "bthfp.expert.at.type", PI_PROTOCOL
, PI_WARN
, "Unknown type value", EXPFILL
}},
3219 { &ei_parameter_blank
, { "bthfp.expert.parameter_blank", PI_PROTOCOL
, PI_WARN
, "Should be blank for HFP", EXPFILL
}},
3220 { &ei_cnum_service
, { "bthfp.expert.cnum.service", PI_PROTOCOL
, PI_WARN
, "Only 0-5 is valid", EXPFILL
}},
3221 { &ei_cnum_itc
, { "bthfp.expert.cnum.itc", PI_PROTOCOL
, PI_WARN
, "Only 0-1 is valid", EXPFILL
}},
3222 { &ei_aplefm_out_of_range
, { "bthfp.expert.aplefm.out_of_range", PI_PROTOCOL
, PI_WARN
, "Only 0-1 is valid", EXPFILL
}},
3223 { &ei_aplsiri_out_of_range
, { "bthfp.expert.aplsiri.out_of_range", PI_PROTOCOL
, PI_WARN
, "Only 1-2 is valid", EXPFILL
}},
3224 { &ei_iphoneaccev_key_out_of_range
, { "bthfp.expert.iphoneaccev.out_of_range", PI_PROTOCOL
, PI_WARN
, "Only 1-2 is valid", EXPFILL
}},
3225 { &ei_xapl_features_reserved
, { "bthfp.expert.xapl.reserved", PI_PROTOCOL
, PI_WARN
, "The reserved bits [6-31] shall be initialized to Zero", EXPFILL
}}
3228 static int *ett
[] = {
3233 &ett_bthfp_parameters
,
3234 &ett_bthfp_xapl_features
,
3235 &ett_bthfp_xapl_accessory_info
3238 fragments
= wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3240 proto_bthfp
= proto_register_protocol("Bluetooth HFP Profile", "BT HFP", "bthfp");
3241 bthfp_handle
= register_dissector("bthfp", dissect_bthfp
, proto_bthfp
);
3243 proto_register_field_array(proto_bthfp
, hf
, array_length(hf
));
3244 proto_register_subtree_array(ett
, array_length(ett
));
3246 module
= prefs_register_protocol_subtree("Bluetooth", proto_bthfp
, NULL
);
3247 prefs_register_static_text_preference(module
, "hfp.version",
3248 "Bluetooth Profile HFP version: 1.7",
3249 "Version of profile supported by this dissector.");
3251 prefs_register_enum_preference(module
, "hfp.hfp_role",
3252 "Force treat packets as AG or HS role",
3253 "Force treat packets as AG or HS role",
3254 &hfp_role
, pref_hfp_role
, true);
3256 expert_bthfp
= expert_register_protocol(proto_bthfp
);
3257 expert_register_field_array(expert_bthfp
, ei
, array_length(ei
));
3261 proto_reg_handoff_bthfp(void)
3263 dissector_add_string("bluetooth.uuid", "111e", bthfp_handle
);
3264 dissector_add_string("bluetooth.uuid", "111f", bthfp_handle
);
3266 dissector_add_for_decode_as("btrfcomm.dlci", bthfp_handle
);
3270 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3275 * indent-tabs-mode: nil
3278 * vi: set shiftwidth=4 tabstop=8 expandtab:
3279 * :indentSize=4:tabSize=8:noTabs=true: