1 /* packet-bthfp.c
2  * Routines for Bluetooth Handsfree Profile (HFP)
3  *
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
8  *     - add reassembling
9  *     - dissection of HFP's AT-commands
10  *
11  * Wireshark - Network traffic analyzer
12  * By Gerald Combs <gerald@wireshark.org>
13  * Copyright 1998 Gerald Combs
14  *
15  * SPDX-License-Identifier: GPL-2.0-or-later
16  */
17 
18 #include "config.h"
19 
20 #include <epan/packet.h>
21 #include <epan/prefs.h>
22 #include <epan/expert.h>
23 #include "packet-btrfcomm.h"
24 #include "packet-btsdp.h"
25 
26 static int proto_bthfp = -1;
27 
28 static int hf_command                                                      = -1;
29 static int hf_parameters                                                   = -1;
30 static int hf_role                                                         = -1;
31 static int hf_at_cmd                                                       = -1;
32 static int hf_at_cmd_type                                                  = -1;
33 static int hf_at_command_line_prefix                                       = -1;
34 static int hf_at_ignored                                                   = -1;
35 static int hf_parameter                                                    = -1;
36 static int hf_unknown_parameter                                            = -1;
37 static int hf_data                                                         = -1;
38 static int hf_fragment                                                     = -1;
39 static int hf_fragmented                                                   = -1;
40 static int hf_brsf_hs                                                      = -1;
41 static int hf_brsf_hs_ec_nr_function                                       = -1;
42 static int hf_brsf_hs_call_waiting_or_tree_way                             = -1;
43 static int hf_brsf_hs_cli_presentation                                     = -1;
44 static int hf_brsf_hs_voice_recognition_activation                         = -1;
45 static int hf_brsf_hs_remote_volume_control                                = -1;
46 static int hf_brsf_hs_enhanced_call_status                                 = -1;
47 static int hf_brsf_hs_enhanced_call_control                                = -1;
48 static int hf_brsf_hs_codec_negotiation                                    = -1;
49 static int hf_brsf_hs_hf_indicators                                        = -1;
50 static int hf_brsf_hs_esco_s4_t2_settings_support                          = -1;
51 static int hf_brsf_hs_reserved                                             = -1;
52 static int hf_brsf_ag                                                      = -1;
53 static int hf_brsf_ag_three_way_calling                                    = -1;
54 static int hf_brsf_ag_ec_nr_function                                       = -1;
55 static int hf_brsf_ag_voice_recognition_function                           = -1;
56 static int hf_brsf_ag_inband_ring_tone                                     = -1;
57 static int hf_brsf_ag_attach_number_to_voice_tag                           = -1;
58 static int hf_brsf_ag_ability_to_reject_a_call                             = -1;
59 static int hf_brsf_ag_enhanced_call_status                                 = -1;
60 static int hf_brsf_ag_enhanced_call_control                                = -1;
61 static int hf_brsf_ag_extended_error_result_codes                          = -1;
62 static int hf_brsf_ag_codec_negotiation                                    = -1;
63 static int hf_brsf_ag_hf_indicators                                        = -1;
64 static int hf_brsf_ag_esco_s4_t2_settings_support                          = -1;
65 static int hf_brsf_ag_reserved                                             = -1;
66 static int hf_vgs                                                          = -1;
67 static int hf_vgm                                                          = -1;
68 static int hf_nrec                                                         = -1;
69 static int hf_bvra_vrect                                                   = -1;
70 static int hf_bsir                                                         = -1;
71 static int hf_btrh                                                         = -1;
72 static int hf_chld_mode                                                    = -1;
73 static int hf_chld_mode_1x                                                 = -1;
74 static int hf_chld_mode_2x                                                 = -1;
75 static int hf_chld_supported_modes                                         = -1;
76 static int hf_cmer_mode                                                    = -1;
77 static int hf_cmer_keyp                                                    = -1;
78 static int hf_cmer_disp                                                    = -1;
79 static int hf_cmer_ind                                                     = -1;
80 static int hf_cmer_bfr                                                     = -1;
81 static int hf_cmee                                                         = -1;
82 static int hf_cme_error                                                    = -1;
83 static int hf_cnum_speed                                                   = -1;
84 static int hf_cnum_service                                                 = -1;
85 static int hf_cnum_itc                                                     = -1;
86 static int hf_bcs_codec                                                    = -1;
87 static int hf_bac_codec                                                    = -1;
88 static int hf_binp_request                                                 = -1;
89 static int hf_binp_response                                                = -1;
90 static int hf_ciev_indicator_index                                         = -1;
91 static int hf_vts_dtmf                                                     = -1;
92 static int hf_vts_duration                                                 = -1;
93 static int hf_cops_mode                                                    = -1;
94 static int hf_cops_format                                                  = -1;
95 static int hf_cops_operator                                                = -1;
96 static int hf_cops_act                                                     = -1;
97 static int hf_at_number                                                    = -1;
98 static int hf_at_type                                                      = -1;
99 static int hf_at_subaddress                                                = -1;
100 static int hf_at_subaddress_type                                           = -1;
101 static int hf_at_alpha                                                     = -1;
102 static int hf_at_priority                                                  = -1;
103 static int hf_at_cli_validity                                              = -1;
104 static int hf_clip_mode                                                    = -1;
105 static int hf_clip_status                                                  = -1;
106 static int hf_clcc_id                                                      = -1;
107 static int hf_clcc_dir                                                     = -1;
108 static int hf_clcc_stat                                                    = -1;
109 static int hf_clcc_mode                                                    = -1;
110 static int hf_clcc_mpty                                                    = -1;
111 static int hf_ccwa_show_result_code                                        = -1;
112 static int hf_ccwa_mode                                                    = -1;
113 static int hf_ccwa_class                                                   = -1;
114 static int hf_biev_assigned_number                                         = -1;
115 static int hf_biev_value                                                   = -1;
116 static int hf_bind_parameter                                               = -1;
117 static int hf_bia_indicator[20]  = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
118 static int hf_indicator[20] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
119 static int hf_aplefm_state                                                 = -1;
120 static int hf_aplsiri_state                                                = -1;
121 static int hf_iphoneaccev_count                                            = -1;
122 static int hf_iphoneaccev_key                                              = -1;
123 static int hf_iphoneaccev_value                                            = -1;
124 static int hf_xapl_accessory_info                                          = -1;
125 static int hf_xapl_accessory_info_vendor_id                                = -1;
126 static int hf_xapl_accessory_info_product_id                               = -1;
127 static int hf_xapl_accessory_info_version                                  = -1;
128 static int hf_xapl_host_info                                               = -1;
129 static int hf_xapl_features                                                = -1;
130 static int hf_xapl_features_reserved_x                                     = -1;
131 static int hf_xapl_features_noise_reduction_status_reporting               = -1;
132 static int hf_xapl_features_siri_status_reporting                          = -1;
133 static int hf_xapl_features_docked_or_powered                              = -1;
134 static int hf_xapl_features_battery_reporting                              = -1;
135 static int hf_xapl_features_reserved                                       = -1;
136 
137 static expert_field ei_non_mandatory_command                          = EI_INIT;
138 static expert_field ei_invalid_usage                                  = EI_INIT;
139 static expert_field ei_unknown_parameter                              = EI_INIT;
140 static expert_field ei_brfs_hs_reserved_bits                          = EI_INIT;
141 static expert_field ei_brfs_ag_reserved_bits                          = EI_INIT;
142 static expert_field ei_vgm_gain                                       = EI_INIT;
143 static expert_field ei_vgs_gain                                       = EI_INIT;
144 static expert_field ei_nrec                                           = EI_INIT;
145 static expert_field ei_bvra                                           = EI_INIT;
146 static expert_field ei_bcs                                            = EI_INIT;
147 static expert_field ei_bac                                            = EI_INIT;
148 static expert_field ei_bsir                                           = EI_INIT;
149 static expert_field ei_btrh                                           = EI_INIT;
150 static expert_field ei_binp                                           = EI_INIT;
151 static expert_field ei_biev_assigned_number                           = EI_INIT;
152 static expert_field ei_biev_assigned_number_no                        = EI_INIT;
153 static expert_field ei_bia                                            = EI_INIT;
154 static expert_field ei_cmer_mode                                      = EI_INIT;
155 static expert_field ei_cmer_keyp                                      = EI_INIT;
156 static expert_field ei_cmer_disp                                      = EI_INIT;
157 static expert_field ei_cmer_ind                                       = EI_INIT;
158 static expert_field ei_cmer_btr                                       = EI_INIT;
159 static expert_field ei_chld_mode                                      = EI_INIT;
160 static expert_field ei_ciev_indicator                                 = EI_INIT;
161 static expert_field ei_vts_dtmf                                       = EI_INIT;
162 static expert_field ei_at_type                                        = EI_INIT;
163 static expert_field ei_cnum_service                                   = EI_INIT;
164 static expert_field ei_cnum_itc                                       = EI_INIT;
165 static expert_field ei_aplefm_out_of_range                            = EI_INIT;
166 static expert_field ei_aplsiri_out_of_range                           = EI_INIT;
167 static expert_field ei_iphoneaccev_key_out_of_range                   = EI_INIT;
168 static expert_field ei_xapl_features_reserved                         = EI_INIT;
169 static expert_field ei_parameter_blank                                = EI_INIT;
170 
171 static gint ett_bthfp            = -1;
172 static gint ett_bthfp_command    = -1;
173 static gint ett_bthfp_parameters = -1;
174 static gint ett_bthfp_brsf_hf    = -1;
175 static gint ett_bthfp_brsf_ag    = -1;
176 static gint ett_bthfp_xapl_features = -1;
177 static gint ett_bthfp_xapl_accessory_info = -1;
178 
179 static dissector_handle_t bthfp_handle;
180 
181 static wmem_tree_t *fragments = NULL;
182 
183 #define ROLE_UNKNOWN  0
184 #define ROLE_AG       1
185 #define ROLE_HS       2
186 
187 #define TYPE_UNKNOWN       0x0000
188 #define TYPE_RESPONSE_ACK  0x0d0a
189 #define TYPE_RESPONSE      0x003a
190 #define TYPE_ACTION        0x003d
191 #define TYPE_ACTION_SIMPLY 0x000d
192 #define TYPE_READ          0x003f
193 #define TYPE_TEST          0x3d3f
194 
195 static gint hfp_role = ROLE_UNKNOWN;
196 
197 enum reassemble_state_t {
198     REASSEMBLE_FRAGMENT,
199     REASSEMBLE_PARTIALLY,
200     REASSEMBLE_DONE
201 };
202 
203 typedef struct _fragment_t {
204     guint32                  interface_id;
205     guint32                  adapter_id;
206     guint32                  chandle;
207     guint32                  dlci;
208     guint32                  role;
209 
210     guint                    idx;
211     guint                    length;
212     guint8                  *data;
213     struct _fragment_t      *previous_fragment;
214 
215     guint                    reassemble_start_offset;
216     guint                    reassemble_end_offset;
217     enum reassemble_state_t  reassemble_state;
218 } fragment_t;
219 
220 typedef struct _at_cmd_t {
221     const gchar *name;
222     const gchar *long_name;
223 
224     gboolean (*check_command)(gint role, guint16 type);
225     gboolean (*dissect_parameter)(tvbuff_t *tvb, packet_info *pinfo,
226             proto_tree *tree, gint offset, gint role, guint16 type,
227             guint8 *parameter_stream, guint parameter_number,
228             gint parameter_length, void **data);
229 } at_cmd_t;
230 
231 static const value_string role_vals[] = {
232     { ROLE_UNKNOWN,   "Unknown" },
233     { ROLE_AG,        "AG - Audio Gate" },
234     { ROLE_HS,        "HS - Headset" },
235     { 0, NULL }
236 };
237 
238 static const value_string at_cmd_type_vals[] = {
239     { 0x0d,   "Action Command" },
240     { 0x3a,   "Response" },
241     { 0x3d,   "Action Command" },
242     { 0x3f,   "Read Command" },
243     { 0x0d0a, "Response" },
244     { 0x3d3f, "Test Command" },
245     { 0, NULL }
246 };
247 
248 static const enum_val_t pref_hfp_role[] = {
249     { "off",     "Off",                    ROLE_UNKNOWN },
250     { "ag",      "Sent is AG, Rcvd is HS", ROLE_AG },
251     { "hs",      "Sent is HS, Rcvd is AG", ROLE_HS },
252     { NULL, NULL, 0 }
253 };
254 
255 static const value_string nrec_vals[] = {
256     { 0x00,   "Disable EC/NR in the AG" },
257     { 0, NULL }
258 };
259 
260 static const value_string bvra_vrect_vals[] = {
261     { 0x00,   "Disable Voice recognition in the AG" },
262     { 0x01,   "Enable Voice recognition in the AG" },
263     { 0, NULL }
264 };
265 
266 static const value_string bsir_vals[] = {
267     { 0x00,   "The AG provides no in-band ring tone" },
268     { 0x01,   "The AG provides an in-band ring tone" },
269     { 0, NULL }
270 };
271 
272 static const value_string btrh_vals[] = {
273     { 0x00,   "Incoming call is put on hold in the AG" },
274     { 0x01,   "Held incoming call is accepted in the AG" },
275     { 0x02,   "Held incoming call is rejected in the AG" },
276     { 0, NULL }
277 };
278 
279 static const value_string codecs_vals[] = {
280     { 0x01,   "CVSD" },
281     { 0x02,   "mSBC" },
282     { 0, NULL }
283 };
284 
285 static const value_string binp_request_vals[] = {
286     { 0x01,   "Phone number corresponding to the last voice tag recorded in the HF" },
287     { 0, NULL }
288 };
289 
290 static const value_string indicator_vals[] = {
291     { 0x00,   "Deactivate" },
292     { 0x01,   "Activate" },
293     { 0, NULL }
294 };
295 
296 static const value_string cme_error_vals[] = {
297     {   0,   "Phone/AG failure" },
298     {   1,   "No Connection to Phone" },
299     {   2,   "Phone-adaptor Link Reserved" },
300     {   3,   "Operation not Allowed" },
301     {   4,   "Operation not Supported" },
302     {   5,   "PH-SIM PIN required" },
303     {   6,   "PH-FSIM PIN Required" },
304     {   7,   "PH-FSIM PUK Required" },
305     {  10,   "SIM not Inserted" },
306     {  11,   "SIM PIN Required" },
307     {  12,   "SIM PUK Required" },
308     {  13,   "SIM Failure" },
309     {  14,   "SIM Busy" },
310     {  15,   "SIM Wrong" },
311     {  16,   "Incorrect Password" },
312     {  17,   "SIM PIN2 Required" },
313     {  18,   "SIM PUK2 Required" },
314     {  20,   "Memory Full" },
315     {  21,   "Invalid Index" },
316     {  22,   "Not Found" },
317     {  23,   "Memory Failure" },
318     {  24,   "Text String too Long" },
319     {  25,   "Invalid Characters in Text String" },
320     {  26,   "Dial String too Long" },
321     {  27,   "Invalid Characters in Dial String" },
322     {  30,   "No Network Service" },
323     {  31,   "Network Timeout" },
324     {  32,   "Network not Allowed - Emergency Calls Only" },
325     {  40,   "Network Personalization PIN Required" },
326     {  41,   "Network Personalization PUK Required" },
327     {  42,   "Network Subset Personalization PIN Required" },
328     {  43,   "Network Subset Personalization PUK Required" },
329     {  44,   "Service Provider Personalization PIN Required" },
330     {  45,   "Service Provider Personalization PUK Required" },
331     {  46,   "Corporate Personalization PIN Required" },
332     {  47,   "Corporate Personalization PUK Required" },
333     {  48,   "Hidden Key Required" },
334     {  49,   "EAP Method not Supported" },
335     {  50,   "Incorrect Parameters" },
336     { 100,   "Unknown" },
337     { 0, NULL }
338 };
339 
340 static const value_string cmee_vals[] = {
341     { 0,   "Disabled" },
342     { 1,   "Enabled" },
343     { 2,   "Verbose" },
344     { 0, NULL }
345 };
346 
347 static const value_string chld_vals[] = {
348     { 0,   "Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call" },
349     { 1,   "Releases all active calls (if any exist) and accepts the other (held or waiting) call" },
350     { 2,   "Places all active calls (if any exist) on hold and accepts the other (held or waiting) call" },
351     { 3,   "Adds a held call to the conversation" },
352     { 4,   "Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)" },
353     { 0, NULL }
354 };
355 
356 static const value_string cops_mode_vals[] = {
357     { 0,   "Automatic" },
358     { 1,   "Manual" },
359     { 2,   "Deregister from Network" },
360     { 3,   "Set Only Format" },
361     { 4,   "Manual/Automatic" },
362     { 0, NULL }
363 };
364 
365 static const value_string cops_format_vals[] = {
366     { 0,   "Long Format Alphanumeric" },
367     { 1,   "Short Format Alphanumeric" },
368     { 2,   "Numeric" },
369     { 0, NULL }
370 };
371 
372 static const value_string cops_act_vals[] = {
373     { 0,   "GSM" },
374     { 1,   "GSM Compact" },
375     { 2,   "UTRAN" },
376     { 0, NULL }
377 };
378 
379 static const range_string at_type_vals[] = {
380     { 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." },
381     { 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." },
382     { 160, 175,  "National number. No prefix nor escape digits included." },
383     { 0, 0, NULL }
384 };
385 
386 static const value_string cli_validity_vals[] = {
387     { 0,   "CLI Valid" },
388     { 1,   "CLI has been withheld by the originator" },
389     { 2,   "CLI is not available due to interworking problems or limitations of originating network" },
390     { 0, NULL }
391 };
392 
393 static const value_string cnum_service_vals[] = {
394     { 0,   "Asynchronous Modem" },
395     { 1,   "Synchronous Modem" },
396     { 2,   "PAD Access" },
397     { 3,   "Packet Access" },
398     { 4,   "Voice" },
399     { 5,   "Fax" },
400     { 0, NULL }
401 };
402 
403 static const value_string cnum_itc_vals[] = {
404     { 0,   "3.1 kHz" },
405     { 1,   "UDI" },
406     { 0, NULL }
407 };
408 
409 static const value_string clip_mode_vals[] = {
410     { 0,   "Disabled" },
411     { 1,   "Enabled" },
412     { 0, NULL }
413 };
414 
415 static const value_string clip_status_vals[] = {
416     { 0,   "CLIP not Provisioned" },
417     { 1,   "CLIP Provisioned" },
418     { 2,   "Unknown" },
419     { 0, NULL }
420 };
421 
422 static const value_string clcc_dir_vals[] = {
423     { 0,   "Mobile Originated" },
424     { 1,   "Mobile Terminated" },
425     { 0, NULL }
426 };
427 
428 static const value_string clcc_stat_vals[] = {
429     { 0,   "Active" },
430     { 1,   "Held" },
431     { 2,   "Dialing" },
432     { 3,   "Alerting" },
433     { 4,   "Incoming" },
434     { 5,   "Waiting" },
435     { 0, NULL }
436 };
437 
438 static const value_string clcc_mode_vals[] = {
439     { 0,   "Voice" },
440     { 1,   "Data" },
441     { 2,   "Fax" },
442     { 3,   "Voice Followed by Data, Voice Mode" },
443     { 4,   "Alternating Voice/Data, Voice Mode" },
444     { 5,   "Alternating Voice/Fax, Voice Mode" },
445     { 6,   "Voice Followed by Data, Data Mode" },
446     { 7,   "Alternating Voice/Data, Data Mode" },
447     { 8,   "Alternating Voice/Fax, Fax Mode" },
448     { 9,   "Unknown" },
449     { 0, NULL }
450 };
451 
452 static const value_string clcc_mpty_vals[] = {
453     { 0,   "Call is not one of multiparty (conference) call parties" },
454     { 1,   "Call is one of multiparty (conference) call parties" },
455     { 0, NULL }
456 };
457 
458 static const value_string ccwa_show_result_code_vals[] = {
459     { 0,   "Disabled" },
460     { 1,   "Enabled" },
461     { 0, NULL }
462 };
463 
464 static const value_string ccwa_mode_vals[] = {
465     { 0,   "Disabled" },
466     { 1,   "Enabled" },
467     { 2,   "Query Status" },
468     { 0, NULL }
469 };
470 
471 static const value_string ccwa_class_vals[] = {
472     {   1,   "Voice" },
473     {   2,   "Data" },
474     {   4,   "Fax" },
475     {   8,   "Short Message Service" },
476     {  16,   "Data Circuit Sync" },
477     {  32,   "Data Circuit Async" },
478     {  64,   "Dedicated Packet Access" },
479     { 128,   "Dedicated PAD Access" },
480     { 0, NULL }
481 };
482 
483 static const value_string biev_assigned_number_vals[] = {
484     { 1,   "Enhanced Safety" },
485     { 2,   "Battery Level" },
486     { 0, NULL }
487 };
488 
489 static const value_string aplefm_state_vals[] = {
490     { 0,   "Disable" },
491     { 1,   "Enable" },
492     { 0, NULL }
493 };
494 
495 static const value_string aplsiri_state_vals[] = {
496     { 1,   "Enabled" },
497     { 2,   "Disabled" },
498     { 0, NULL }
499 };
500 
501 static const value_string iphoneaccev_key_vals[] = {
502     { 1,   "Battery Level" },
503     { 2,   "Dock State" },
504     { 0, NULL }
505 };
506 
507 
508 static const unit_name_string units_slash15 = { "/15", NULL };
509 
510 extern value_string_ext csd_data_rate_vals_ext;
511 
512 void proto_register_bthfp(void);
513 void proto_reg_handoff_bthfp(void);
514 
get_uint_parameter(guint8 * parameter_stream,gint parameter_length)515 static guint32 get_uint_parameter(guint8 *parameter_stream, gint parameter_length)
516 {
517     guint32      value;
518     gchar       *val;
519 
520     val = (gchar *) wmem_alloc(wmem_packet_scope(), parameter_length + 1);
521     memcpy(val, parameter_stream, parameter_length);
522     val[parameter_length] = '\0';
523     value = (guint32) g_ascii_strtoull(val, NULL, 10);
524 
525     return value;
526 }
527 
get_uint_hex_parameter(guint8 * parameter_stream,gint parameter_length)528 static guint32 get_uint_hex_parameter(guint8 *parameter_stream, gint parameter_length)
529 {
530     guint32      value;
531     gchar       *val;
532 
533     val = (gchar *) wmem_alloc(wmem_packet_scope(), parameter_length + 1);
534     memcpy(val, parameter_stream, parameter_length);
535     val[parameter_length] = '\0';
536     value = (guint32) g_ascii_strtoull(val, NULL, 16);
537 
538     return value;
539 }
540 
check_aplefm(gint role,guint16 type)541 static gboolean check_aplefm(gint role, guint16 type) {
542     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
543     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
544 
545     return FALSE;
546 }
547 
check_aplsiri(gint role,guint16 type)548 static gboolean check_aplsiri(gint role, guint16 type) {
549     if (role == ROLE_HS && type == TYPE_READ) return TRUE;
550     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
551 
552     return FALSE;
553 }
554 
check_iphoneaccev(gint role,guint16 type)555 static gboolean check_iphoneaccev(gint role, guint16 type) {
556     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
557 
558     return FALSE;
559 }
560 
check_xapl(gint role,guint16 type)561 static gboolean check_xapl(gint role, guint16 type) {
562     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
563     if (role == ROLE_AG && (type == TYPE_RESPONSE || type == TYPE_ACTION)) return TRUE;
564 
565     return FALSE;
566 }
567 
check_biev(gint role,guint16 type)568 static gboolean check_biev(gint role, guint16 type) {
569     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
570 
571     return FALSE;
572 }
573 
check_bind(gint role,guint16 type)574 static gboolean check_bind(gint role, guint16 type) {
575     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return TRUE;
576     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
577 
578     return FALSE;
579 }
580 
check_bac(gint role,guint16 type)581 static gboolean check_bac(gint role, guint16 type) {
582     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
583 
584     return FALSE;
585 }
586 
check_bcs(gint role,guint16 type)587 static gboolean check_bcs(gint role, guint16 type) {
588     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
589     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
590 
591     return FALSE;
592 }
593 
check_bcc(gint role,guint16 type)594 static gboolean check_bcc(gint role, guint16 type) {
595     if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return TRUE;
596 
597     return FALSE;
598 }
599 
check_bia(gint role,guint16 type)600 static gboolean check_bia(gint role, guint16 type) {
601     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
602 
603     return FALSE;
604 }
605 
check_binp(gint role,guint16 type)606 static gboolean check_binp(gint role, guint16 type) {
607     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
608     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
609 
610     return FALSE;
611 }
612 
check_bldn(gint role,guint16 type)613 static gboolean check_bldn(gint role, guint16 type) {
614     if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return TRUE;
615 
616     return FALSE;
617 }
618 
check_bvra(gint role,guint16 type)619 static gboolean check_bvra(gint role, guint16 type) {
620     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
621     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
622 
623     return FALSE;
624 }
625 
check_brsf(gint role,guint16 type)626 static gboolean check_brsf(gint role, guint16 type) {
627     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
628     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
629 
630     return FALSE;
631 }
632 
check_nrec(gint role,guint16 type)633 static gboolean check_nrec(gint role, guint16 type) {
634     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
635 
636     return FALSE;
637 }
638 
check_vgs(gint role,guint16 type)639 static gboolean check_vgs(gint role, guint16 type) {
640     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
641     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
642 
643     return FALSE;
644 }
645 
check_vgm(gint role,guint16 type)646 static gboolean check_vgm(gint role, guint16 type) {
647     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
648     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
649 
650     return FALSE;
651 }
652 
check_bsir(gint role,guint16 type)653 static gboolean check_bsir(gint role, guint16 type) {
654     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
655 
656     return FALSE;
657 }
658 
check_btrh(gint role,guint16 type)659 static gboolean check_btrh(gint role, guint16 type) {
660     if (role == ROLE_HS && (type == TYPE_READ || type == TYPE_ACTION)) return TRUE;
661     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
662 
663     return FALSE;
664 }
665 
check_only_ag_role(gint role,guint16 type)666 static gboolean check_only_ag_role(gint role, guint16 type) {
667     if (role == ROLE_AG && type == TYPE_RESPONSE_ACK) return TRUE;
668 
669     return FALSE;
670 }
671 
check_only_hs_role(gint role,guint16 type)672 static gboolean check_only_hs_role(gint role, guint16 type) {
673     if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return TRUE;
674 
675     return FALSE;
676 }
677 
check_ccwa(gint role,guint16 type)678 static gboolean check_ccwa(gint role, guint16 type) {
679     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return TRUE;
680     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
681 
682     return FALSE;
683 }
684 
check_chld(gint role,guint16 type)685 static gboolean check_chld(gint role, guint16 type) {
686     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_TEST)) return TRUE;
687     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
688 
689     return FALSE;
690 }
691 
check_chup(gint role,guint16 type)692 static gboolean check_chup(gint role, guint16 type) {
693     if (role == ROLE_HS && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return TRUE;
694 
695     return FALSE;
696 }
697 
check_clcc(gint role,guint16 type)698 static gboolean check_clcc(gint role, guint16 type) {
699     if (role == ROLE_HS && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return TRUE;
700     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
701 
702     return FALSE;
703 }
704 
check_cind(gint role,guint16 type)705 static gboolean check_cind(gint role, guint16 type) {
706     if (role == ROLE_HS && (type == TYPE_READ || type == TYPE_TEST)) return TRUE;
707     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
708 
709     return FALSE;
710 }
711 
check_cmer(gint role,guint16 type)712 static gboolean check_cmer(gint role, guint16 type) {
713     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return TRUE;
714     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
715 
716     return FALSE;
717 }
718 
check_cops(gint role,guint16 type)719 static gboolean check_cops(gint role, guint16 type) {
720     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ)) return TRUE;
721     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
722 
723     return FALSE;
724 }
725 
check_cmee(gint role,guint16 type)726 static gboolean check_cmee(gint role, guint16 type) {
727     if (role == ROLE_HS && type == TYPE_ACTION) return TRUE;
728 
729     return FALSE;
730 }
731 
check_cme(gint role,guint16 type)732 static gboolean check_cme(gint role, guint16 type) {
733     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
734 
735     return FALSE;
736 }
737 
check_clip(gint role,guint16 type)738 static gboolean check_clip(gint role, guint16 type) {
739     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return TRUE;
740     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
741 
742     return FALSE;
743 }
744 
check_ciev(gint role,guint16 type)745 static gboolean check_ciev(gint role, guint16 type) {
746     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
747 
748     return FALSE;
749 }
750 
check_vts(gint role,guint16 type)751 static gboolean check_vts(gint role, guint16 type) {
752     if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_TEST)) return TRUE;
753     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
754 
755     return FALSE;
756 }
757 
check_cnum(gint role,guint16 type)758 static gboolean check_cnum(gint role, guint16 type) {
759     if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return TRUE;
760     if (role == ROLE_AG && type == TYPE_RESPONSE) return TRUE;
761 
762     return FALSE;
763 }
764 
765 static gboolean
dissect_brsf_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)766 dissect_brsf_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
767         gint offset, gint role, guint16 type, guint8 *parameter_stream,
768         guint parameter_number, gint parameter_length, void **data _U_)
769 {
770     proto_item  *pitem;
771     guint32      value;
772 
773     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
774             (role == ROLE_AG && type == TYPE_RESPONSE))) {
775         return FALSE;
776     }
777 
778     if (parameter_number > 0) return FALSE;
779 
780     value = get_uint_parameter(parameter_stream, parameter_length);
781 
782     if (role == ROLE_HS) {
783         static int * const hs[] = {
784             &hf_brsf_hs_ec_nr_function,
785             &hf_brsf_hs_call_waiting_or_tree_way,
786             &hf_brsf_hs_cli_presentation,
787             &hf_brsf_hs_voice_recognition_activation,
788             &hf_brsf_hs_remote_volume_control,
789             &hf_brsf_hs_enhanced_call_status,
790             &hf_brsf_hs_enhanced_call_control,
791             &hf_brsf_hs_codec_negotiation,
792             &hf_brsf_hs_hf_indicators,
793             &hf_brsf_hs_esco_s4_t2_settings_support,
794             &hf_brsf_hs_reserved,
795             NULL
796         };
797 
798         pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_brsf_hs, ett_bthfp_brsf_hf, hs, value, BMT_NO_APPEND);
799         if (value >> 10) {
800             expert_add_info(pinfo, pitem, &ei_brfs_hs_reserved_bits);
801         }
802     } else {
803         static int * const ag[] = {
804             &hf_brsf_ag_three_way_calling,
805             &hf_brsf_ag_ec_nr_function,
806             &hf_brsf_ag_voice_recognition_function,
807             &hf_brsf_ag_inband_ring_tone,
808             &hf_brsf_ag_attach_number_to_voice_tag,
809             &hf_brsf_ag_ability_to_reject_a_call,
810             &hf_brsf_ag_enhanced_call_status,
811             &hf_brsf_ag_enhanced_call_control,
812             &hf_brsf_ag_extended_error_result_codes,
813             &hf_brsf_ag_codec_negotiation,
814             &hf_brsf_ag_hf_indicators,
815             &hf_brsf_ag_esco_s4_t2_settings_support,
816             &hf_brsf_ag_reserved,
817             NULL
818         };
819 
820         pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_brsf_ag, ett_bthfp_brsf_ag, ag, value, BMT_NO_APPEND);
821 
822         if (value >> 12) {
823             expert_add_info(pinfo, pitem, &ei_brfs_ag_reserved_bits);
824         }
825     }
826 
827     return TRUE;
828 }
829 
830 static gint
dissect_vgs_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)831 dissect_vgs_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
832         gint offset, gint role, guint16 type, guint8 *parameter_stream,
833         guint parameter_number, gint parameter_length, void **data _U_)
834 {
835     proto_item  *pitem;
836     guint32      value;
837 
838     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
839             (role == ROLE_AG && type == TYPE_RESPONSE))) {
840         return FALSE;
841     }
842 
843     if (parameter_number > 0) return FALSE;
844 
845     value = get_uint_parameter(parameter_stream, parameter_length);
846 
847     pitem = proto_tree_add_uint(tree, hf_vgs, tvb, offset, parameter_length, value);
848 
849     if (value > 15) {
850         expert_add_info(pinfo, pitem, &ei_vgs_gain);
851     }
852 
853     return TRUE;
854 }
855 
856 static gint
dissect_vgm_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)857 dissect_vgm_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
858         gint offset, gint role, guint16 type, guint8 *parameter_stream,
859         guint parameter_number, gint parameter_length, void **data _U_)
860 {
861     proto_item  *pitem;
862     guint32      value;
863 
864     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
865             (role == ROLE_AG && type == TYPE_RESPONSE))) {
866         return FALSE;
867     }
868 
869     if (parameter_number > 0) return FALSE;
870 
871     value = get_uint_parameter(parameter_stream, parameter_length);
872 
873     pitem = proto_tree_add_uint(tree, hf_vgm, tvb, offset, parameter_length, value);
874 
875     if (value > 15) {
876         expert_add_info(pinfo, pitem, &ei_vgm_gain);
877     }
878 
879     return TRUE;
880 }
881 
882 static gint
dissect_nrec_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)883 dissect_nrec_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
884         gint offset, gint role, guint16 type, guint8 *parameter_stream,
885         guint parameter_number, gint parameter_length, void **data _U_)
886 {
887     proto_item  *pitem;
888     guint32      value;
889 
890     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
891             (role == ROLE_AG && type == TYPE_RESPONSE))) {
892         return FALSE;
893     }
894 
895     if (parameter_number > 0) return FALSE;
896 
897     value = get_uint_parameter(parameter_stream, parameter_length);
898 
899     pitem = proto_tree_add_uint(tree, hf_nrec, tvb, offset, parameter_length, value);
900 
901     if (value != 0) {
902         expert_add_info(pinfo, pitem, &ei_nrec);
903     }
904 
905     return TRUE;
906 }
907 
908 static gint
dissect_bvra_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)909 dissect_bvra_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
910         gint offset, gint role, guint16 type, guint8 *parameter_stream,
911         guint parameter_number, gint parameter_length, void **data _U_)
912 {
913     proto_item  *pitem;
914     guint32      value;
915 
916     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
917             (role == ROLE_AG && type == TYPE_RESPONSE))) {
918         return FALSE;
919     }
920 
921     if (parameter_number > 0) return FALSE;
922 
923     value = get_uint_parameter(parameter_stream, parameter_length);
924 
925     pitem = proto_tree_add_uint(tree, hf_bvra_vrect, tvb, offset, parameter_length, value);
926 
927     if (value > 1) {
928         expert_add_info(pinfo, pitem, &ei_bvra);
929     }
930 
931     return TRUE;
932 }
933 
934 static gint
dissect_bcs_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)935 dissect_bcs_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
936         gint offset, gint role, guint16 type, guint8 *parameter_stream,
937         guint parameter_number, gint parameter_length, void **data _U_)
938 {
939     proto_item  *pitem;
940     guint32      value;
941 
942     if (!check_bcs(role, type)) {
943         return FALSE;
944     }
945 
946     if (parameter_number > 0) return FALSE;
947 
948     value = get_uint_parameter(parameter_stream, parameter_length);
949 
950     pitem = proto_tree_add_uint(tree, hf_bcs_codec, tvb, offset, parameter_length, value);
951 
952     if (value <  1 ||  value > 2) {
953         expert_add_info(pinfo, pitem, &ei_bcs);
954     }
955 
956     return TRUE;
957 }
958 
959 static gint
dissect_bac_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number _U_,gint parameter_length,void ** data _U_)960 dissect_bac_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
961         gint offset, gint role, guint16 type, guint8 *parameter_stream,
962         guint parameter_number _U_, gint parameter_length, void **data _U_)
963 {
964     proto_item  *pitem;
965     guint32      value;
966 
967     if (!check_bac(role, type)) {
968         return FALSE;
969     }
970 
971     value = get_uint_parameter(parameter_stream, parameter_length);
972 
973     pitem = proto_tree_add_uint(tree, hf_bac_codec, tvb, offset, parameter_length, value);
974 
975     if (value <  1 ||  value > 2)  {
976         expert_add_info(pinfo, pitem, &ei_bac);
977     }
978 
979     return TRUE;
980 }
981 
982 static gint
dissect_bind_parameter(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)983 dissect_bind_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
984         gint offset, gint role, guint16 type, guint8 *parameter_stream,
985         guint parameter_number, gint parameter_length, void **data _U_)
986 {
987     guint32      value;
988 
989     if (!check_bind(role, type)) return FALSE;
990 
991 /* TODO Need to implement request-response tracking to recognise answer to AT+BIND? vs unsolicited */
992     if (parameter_number < 20) {
993         value = get_uint_parameter(parameter_stream, parameter_length);
994 
995         proto_tree_add_uint(tree, hf_bind_parameter, tvb, offset,
996                 parameter_length, value);
997 
998         return TRUE;
999     }
1000 
1001     return FALSE;
1002 }
1003 
1004 static gint
dissect_aplefm_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1005 dissect_aplefm_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1006         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1007         guint parameter_number, gint parameter_length, void **data _U_)
1008 {
1009     proto_item  *pitem;
1010     guint32      value;
1011 
1012     if (!check_aplefm(role, type)) return FALSE;
1013 
1014     if (parameter_number == 0) {
1015         value = get_uint_parameter(parameter_stream, parameter_length);
1016 
1017         pitem = proto_tree_add_uint(tree, hf_aplefm_state, tvb, offset,
1018                 parameter_length, value);
1019 
1020         if (value > 1) {
1021             expert_add_info(pinfo, pitem, &ei_aplefm_out_of_range);
1022         }
1023     } else return FALSE;
1024 
1025     return TRUE;
1026 }
1027 
1028 static gint
dissect_aplsiri_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1029 dissect_aplsiri_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1030         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1031         guint parameter_number, gint parameter_length, void **data _U_)
1032 {
1033     proto_item  *pitem;
1034     guint32      value;
1035 
1036     if (!check_aplsiri(role, type)) return FALSE;
1037 
1038     if (parameter_number == 0) {
1039         value = get_uint_parameter(parameter_stream, parameter_length);
1040 
1041         pitem = proto_tree_add_uint(tree, hf_aplsiri_state, tvb, offset,
1042                 parameter_length, value);
1043 
1044         if (value < 1 || value > 2) {
1045             expert_add_info(pinfo, pitem, &ei_aplsiri_out_of_range);
1046         }
1047     } else return FALSE;
1048 
1049     return TRUE;
1050 }
1051 
1052 static gint
dissect_iphoneaccev_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1053 dissect_iphoneaccev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1054         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1055         guint parameter_number, gint parameter_length, void **data _U_)
1056 {
1057     proto_item  *pitem;
1058     guint32      value;
1059 
1060     if (!check_iphoneaccev(role, type)) return FALSE;
1061 
1062     if (parameter_number == 0) {
1063         value = get_uint_parameter(parameter_stream, parameter_length);
1064 
1065         proto_tree_add_uint(tree, hf_iphoneaccev_count, tvb, offset,
1066                 parameter_length, value);
1067     } else if (parameter_number % 2 == 1) {
1068         value = get_uint_parameter(parameter_stream, parameter_length);
1069 
1070         pitem = proto_tree_add_uint(tree, hf_iphoneaccev_key, tvb, offset,
1071                 parameter_length, value);
1072 
1073         if (value < 1 || value > 2) {
1074             expert_add_info(pinfo, pitem, &ei_iphoneaccev_key_out_of_range);
1075         }
1076     } else {
1077         value = get_uint_parameter(parameter_stream, parameter_length);
1078 
1079         proto_tree_add_uint(tree, hf_iphoneaccev_value, tvb, offset,
1080                 parameter_length, value);
1081     }
1082 
1083     return TRUE;
1084 }
1085 
1086 static gint
dissect_xapl_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1087 dissect_xapl_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1088         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1089         guint parameter_number, gint parameter_length, void **data _U_)
1090 {
1091     proto_item  *pitem;
1092     proto_tree  *ptree;
1093     guint32      value;
1094 
1095     if (!check_xapl(role, type)) return FALSE;
1096 
1097     if (parameter_number == 0) {
1098         if (role == ROLE_HS) {
1099             pitem = proto_tree_add_item(tree, hf_xapl_accessory_info, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1100             ptree = proto_item_add_subtree(pitem, ett_bthfp_xapl_accessory_info);
1101 
1102             value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 0, 4);
1103             proto_tree_add_uint(ptree, hf_xapl_accessory_info_vendor_id, tvb, offset, 4, value);
1104 
1105             value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 1, 4);
1106             proto_tree_add_uint(ptree, hf_xapl_accessory_info_product_id, tvb, offset + (4 + 1) * 1, 4, value);
1107 
1108             value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 2, 4);
1109             proto_tree_add_uint(ptree, hf_xapl_accessory_info_version, tvb, offset + (4 + 1) * 2, 4, value);
1110         } else {
1111             proto_tree_add_item(tree, hf_xapl_host_info, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1112         }
1113     } else if (parameter_number == 1) {
1114         static int * const hfx[] = {
1115             &hf_xapl_features_reserved_x,
1116             &hf_xapl_features_noise_reduction_status_reporting,
1117             &hf_xapl_features_siri_status_reporting,
1118             &hf_xapl_features_docked_or_powered,
1119             &hf_xapl_features_battery_reporting,
1120             &hf_xapl_features_reserved,
1121             NULL
1122         };
1123 
1124         value = get_uint_parameter(parameter_stream, parameter_length);
1125 
1126         pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_xapl_features, ett_bthfp_xapl_features, hfx, value, BMT_NO_APPEND);
1127 
1128         if (value >> 5) {
1129             expert_add_info(pinfo, pitem, &ei_xapl_features_reserved);
1130         }
1131     } else return FALSE;
1132 
1133     return TRUE;
1134 }
1135 
1136 static gint
dissect_biev_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1137 dissect_biev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1138         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1139         guint parameter_number, gint parameter_length, void **data _U_)
1140 {
1141     proto_item  *pitem;
1142     guint32      value;
1143 
1144     if (!check_biev(role, type)) return FALSE;
1145     if (parameter_number == 0) {
1146         value = get_uint_parameter(parameter_stream, parameter_length);
1147 
1148         pitem = proto_tree_add_uint(tree, hf_biev_assigned_number, tvb, offset,
1149                 parameter_length, value);
1150 
1151         if (value > 65535) {
1152             expert_add_info(pinfo, pitem, &ei_biev_assigned_number);
1153         } else if (value > 2) {
1154             expert_add_info(pinfo, pitem, &ei_biev_assigned_number_no);
1155         }
1156     } else if (parameter_number == 1) {
1157         value = get_uint_parameter(parameter_stream, parameter_length);
1158 /* TODO: Decode assigned numbers - assigned_number=1 */
1159         /*pitem =*/ proto_tree_add_uint(tree, hf_biev_value, tvb, offset,
1160                 parameter_length, value);
1161     } else return FALSE;
1162 
1163     return TRUE;
1164 }
1165 
1166 static gint
dissect_no_parameter(tvbuff_t * tvb _U_,packet_info * pinfo _U_,proto_tree * tree _U_,gint offset _U_,gint role _U_,guint16 type _U_,guint8 * parameter_stream _U_,guint parameter_number _U_,gint parameter_length _U_,void ** data _U_)1167 dissect_no_parameter(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_,
1168         gint offset _U_, gint role _U_, guint16 type _U_, guint8 *parameter_stream _U_,
1169         guint parameter_number _U_, gint parameter_length _U_, void **data _U_)
1170 {
1171     return FALSE;
1172 }
1173 
1174 static gint
dissect_bsir_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1175 dissect_bsir_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1176         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1177         guint parameter_number, gint parameter_length, void **data _U_)
1178 {
1179     proto_item  *pitem;
1180     guint32      value;
1181 
1182     if (!(role == ROLE_AG && type == TYPE_RESPONSE)) {
1183         return FALSE;
1184     }
1185 
1186     if (parameter_number > 0) return FALSE;
1187 
1188     value = get_uint_parameter(parameter_stream, parameter_length);
1189 
1190     pitem = proto_tree_add_uint(tree, hf_bsir, tvb, offset, parameter_length, value);
1191 
1192     if (value > 1) {
1193         expert_add_info(pinfo, pitem, &ei_bsir);
1194     }
1195 
1196     return TRUE;
1197 }
1198 
1199 static gint
dissect_btrh_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1200 dissect_btrh_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1201         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1202         guint parameter_number, gint parameter_length, void **data _U_)
1203 {
1204     proto_item  *pitem;
1205     guint32      value;
1206 
1207     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
1208             (role == ROLE_AG && type == TYPE_RESPONSE))) {
1209         return FALSE;
1210     }
1211 
1212     if (parameter_number > 0) return FALSE;
1213 
1214     value = get_uint_parameter(parameter_stream, parameter_length);
1215 
1216     pitem = proto_tree_add_uint(tree, hf_btrh, tvb, offset, parameter_length, value);
1217 
1218     if (value != 0) {
1219         expert_add_info(pinfo, pitem, &ei_btrh);
1220     }
1221 
1222     return TRUE;
1223 }
1224 
1225 
1226 static gint
dissect_binp_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1227 dissect_binp_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1228         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1229         guint parameter_number, gint parameter_length, void **data _U_)
1230 {
1231     proto_item  *pitem;
1232     guint32      value;
1233 
1234     if (!((role == ROLE_HS && type == TYPE_ACTION) ||
1235             (role == ROLE_AG && type == TYPE_RESPONSE))) {
1236         return FALSE;
1237     }
1238 
1239     if (role == ROLE_HS && type == TYPE_ACTION) {
1240         if (parameter_number == 0) {
1241             value = get_uint_parameter(parameter_stream, parameter_length);
1242 
1243             pitem = proto_tree_add_uint(tree, hf_binp_request, tvb, offset,
1244                     parameter_length, value);
1245 
1246             if (value != 1) {
1247                 expert_add_info(pinfo, pitem, &ei_binp);
1248             }
1249         } else return FALSE;
1250     } else {
1251         proto_tree_add_item(tree, hf_binp_response, tvb, offset,
1252                 parameter_length, ENC_NA | ENC_ASCII);
1253     }
1254     return TRUE;
1255 }
1256 
1257 static gint
dissect_bia_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1258 dissect_bia_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1259         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1260         guint parameter_number, gint parameter_length, void **data _U_)
1261 {
1262     proto_item  *pitem;
1263     guint32      value;
1264 
1265     if (!((role == ROLE_HS && type == TYPE_ACTION))) return FALSE;
1266     if (parameter_number > 19) return FALSE;
1267 
1268     value = get_uint_parameter(parameter_stream, parameter_length);
1269 
1270     pitem = proto_tree_add_uint(tree, hf_bia_indicator[parameter_number], tvb,
1271             offset, parameter_length, value);
1272     if (value > 1) {
1273         expert_add_info(pinfo, pitem, &ei_bia);
1274     }
1275 
1276     return TRUE;
1277 }
1278 
1279 static gint
dissect_cind_parameter(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream _U_,guint parameter_number,gint parameter_length,void ** data _U_)1280 dissect_cind_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1281         gint offset, gint role, guint16 type, guint8 *parameter_stream _U_,
1282         guint parameter_number, gint parameter_length, void **data _U_)
1283 {
1284     if (!check_cind(role, type)) return FALSE;
1285     if (parameter_number > 19) return FALSE;
1286 
1287     proto_tree_add_item(tree, hf_indicator[parameter_number], tvb, offset,
1288             parameter_length, ENC_NA | ENC_ASCII);
1289 
1290     return TRUE;
1291 }
1292 
1293 static gint
dissect_chld_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1294 dissect_chld_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1295         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1296         guint parameter_number, gint parameter_length, void **data _U_)
1297 {
1298     guint32      value;
1299 
1300     if (!check_chld(role, type)) return FALSE;
1301 
1302     if (role == ROLE_HS && type == TYPE_ACTION && parameter_number == 0) {
1303         value = get_uint_parameter(parameter_stream, 1);
1304 
1305         if (parameter_length >= 2) {
1306             if (tvb_get_guint8(tvb, offset + 1) == 'x') {
1307                 if (value == 1)
1308                     proto_tree_add_item(tree, hf_chld_mode_1x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1309                 else if (value == 2)
1310                     proto_tree_add_item(tree, hf_chld_mode_2x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1311             }
1312 
1313             if (tvb_get_guint8(tvb, offset + 1) != 'x' || value > 4) {
1314                 proto_tree_add_expert(tree, pinfo, &ei_chld_mode, tvb, offset, parameter_length);
1315             }
1316         }
1317 
1318         proto_tree_add_uint(tree, hf_chld_mode, tvb, offset, parameter_length, value);
1319         return TRUE;
1320     }
1321 
1322     /* Type == Test  */
1323     proto_tree_add_item(tree, hf_chld_supported_modes, tvb, offset,
1324             parameter_length, ENC_NA | ENC_ASCII);
1325 
1326     return TRUE;
1327 }
1328 
1329 static gint
dissect_ccwa_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1330 dissect_ccwa_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1331         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1332         guint parameter_number, gint parameter_length, void **data _U_)
1333 {
1334     proto_item  *pitem;
1335     guint32      value;
1336 
1337     if (!check_ccwa(role, type)) return FALSE;
1338 
1339     if (role == ROLE_HS && parameter_number > 2) return FALSE;
1340     if (role == ROLE_AG && parameter_number > 7) return FALSE;
1341 
1342     if (role == ROLE_HS) switch (parameter_number) {
1343         case 0:
1344             value = get_uint_parameter(parameter_stream, parameter_length);
1345             proto_tree_add_uint(tree, hf_ccwa_show_result_code, tvb, offset, parameter_length, value);
1346             break;
1347         case 1:
1348             value = get_uint_parameter(parameter_stream, parameter_length);
1349             proto_tree_add_uint(tree, hf_ccwa_mode, tvb, offset, parameter_length, value);
1350             break;
1351         case 2:
1352             value = get_uint_parameter(parameter_stream, parameter_length);
1353             proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
1354             break;
1355     }
1356 
1357     /* If AT+CCWA = 1 */
1358     if (role == ROLE_AG) switch (parameter_number) {
1359         case 0:
1360             proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1361             break;
1362         case 1:
1363             value = get_uint_parameter(parameter_stream, parameter_length);
1364             pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1365             if (value < 128 || value > 175)
1366                 expert_add_info(pinfo, pitem, &ei_at_type);
1367             break;
1368         case 2:
1369             value = get_uint_parameter(parameter_stream, parameter_length);
1370             proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
1371             break;
1372         case 3:
1373             proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1374             break;
1375         case 4:
1376             value = get_uint_parameter(parameter_stream, parameter_length);
1377             proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
1378             break;
1379         case 5:
1380             proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1381             break;
1382         case 6:
1383             value = get_uint_parameter(parameter_stream, parameter_length);
1384             proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
1385             break;
1386         case 7:
1387             value = get_uint_parameter(parameter_stream, parameter_length);
1388             proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
1389             break;
1390     }
1391 
1392     return TRUE;
1393 }
1394 
1395 static gint
dissect_cmer_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1396 dissect_cmer_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1397         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1398         guint parameter_number, gint parameter_length, void **data _U_)
1399 {
1400     proto_item  *pitem;
1401     guint32      value;
1402 
1403     if (!((role == ROLE_HS && type == TYPE_ACTION))) {
1404         return FALSE;
1405     }
1406 
1407     if (parameter_number > 4) return FALSE;
1408 
1409     value = get_uint_parameter(parameter_stream, parameter_length);
1410 
1411     switch (parameter_number) {
1412         case 0:
1413             pitem = proto_tree_add_uint(tree, hf_cmer_mode, tvb, offset, parameter_length, value);
1414             if (value != 3)
1415                 expert_add_info(pinfo, pitem, &ei_cmer_mode);
1416             break;
1417         case 1:
1418             pitem = proto_tree_add_uint(tree, hf_cmer_keyp, tvb, offset, parameter_length, value);
1419             if (value != 0)
1420                 expert_add_info(pinfo, pitem, &ei_cmer_keyp);
1421             break;
1422         case 2:
1423             pitem = proto_tree_add_uint(tree, hf_cmer_disp, tvb, offset, parameter_length, value);
1424             if (value != 0)
1425                 expert_add_info(pinfo, pitem, &ei_cmer_disp);
1426             break;
1427         case 3:
1428             pitem = proto_tree_add_uint(tree, hf_cmer_ind, tvb, offset, parameter_length, value);
1429             if (value > 1)
1430                 expert_add_info(pinfo, pitem, &ei_cmer_ind);
1431             break;
1432         case 4:
1433             pitem = proto_tree_add_uint(tree, hf_cmer_bfr, tvb, offset, parameter_length, value);
1434             if (value != 0)
1435                 expert_add_info(pinfo, pitem, &ei_cmer_btr);
1436             break;
1437     }
1438 
1439     return TRUE;
1440 }
1441 
1442 static gint
dissect_clip_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1443 dissect_clip_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1444         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1445         guint parameter_number, gint parameter_length, void **data _U_)
1446 {
1447     proto_item  *pitem;
1448     guint32      value;
1449 
1450     if (!check_clip(role, type))
1451         return FALSE;
1452 
1453     if (role == ROLE_HS && type == TYPE_ACTION && parameter_number > 1)
1454         return FALSE;
1455     else if (role == ROLE_AG && parameter_number > 5)
1456         return FALSE;
1457 
1458     if (role == ROLE_HS && type == TYPE_ACTION) switch (parameter_number) {
1459         case 0:
1460             value = get_uint_parameter(parameter_stream, parameter_length);
1461             proto_tree_add_uint(tree, hf_clip_mode, tvb, offset, parameter_length, value);
1462             break;
1463         case 1:
1464             value = get_uint_parameter(parameter_stream, parameter_length);
1465             proto_tree_add_uint(tree, hf_clip_status, tvb, offset, parameter_length, value);
1466             break;
1467     } else {
1468         switch (parameter_number) {
1469         case 0:
1470             proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1471             break;
1472         case 1:
1473             value = get_uint_parameter(parameter_stream, parameter_length);
1474             pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1475             if (value < 128 || value > 175)
1476                 expert_add_info(pinfo, pitem, &ei_at_type);
1477             break;
1478         case 2:
1479             proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1480             break;
1481         case 3:
1482             value = get_uint_parameter(parameter_stream, parameter_length);
1483             proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
1484             break;
1485         case 4:
1486             proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1487             break;
1488         case 5:
1489             value = get_uint_parameter(parameter_stream, parameter_length);
1490             proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
1491             break;
1492         }
1493     }
1494 
1495     return TRUE;
1496 }
1497 
1498 static gint
dissect_cmee_parameter(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1499 dissect_cmee_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1500         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1501         guint parameter_number, gint parameter_length, void **data _U_)
1502 {
1503     guint32      value;
1504 
1505     if (!(role == ROLE_HS && type == TYPE_ACTION)) {
1506         return FALSE;
1507     }
1508 
1509     if (parameter_number > 0) return FALSE;
1510 
1511     value = get_uint_parameter(parameter_stream, parameter_length);
1512     proto_tree_add_uint(tree, hf_cmee, tvb, offset, parameter_length, value);
1513 
1514     return TRUE;
1515 }
1516 
1517 static gint
dissect_cops_parameter(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1518 dissect_cops_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1519         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1520         guint parameter_number, gint parameter_length, void **data _U_)
1521 {
1522     guint32      value;
1523 
1524     if (!((role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ)) ||
1525             (role == ROLE_AG && type == TYPE_RESPONSE))) {
1526         return FALSE;
1527     }
1528 
1529     if (parameter_number > 3) return FALSE;
1530 
1531     switch (parameter_number) {
1532     case 0:
1533         value = get_uint_parameter(parameter_stream, parameter_length);
1534         proto_tree_add_uint(tree, hf_cops_mode, tvb, offset, parameter_length, value);
1535         break;
1536     case 1:
1537         value = get_uint_parameter(parameter_stream, parameter_length);
1538         proto_tree_add_uint(tree, hf_cops_format, tvb, offset, parameter_length, value);
1539         break;
1540     case 2:
1541         proto_tree_add_item(tree, hf_cops_operator, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1542         break;
1543     case 3:
1544         value = get_uint_parameter(parameter_stream, parameter_length);
1545         proto_tree_add_uint(tree, hf_cops_act, tvb, offset, parameter_length, value);
1546         break;
1547     }
1548 
1549     return TRUE;
1550 }
1551 
1552 static gint
dissect_clcc_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1553 dissect_clcc_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1554         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1555         guint parameter_number, gint parameter_length, void **data _U_)
1556 {
1557     proto_item  *pitem;
1558     guint32      value;
1559 
1560     if (!((role == ROLE_HS && type == TYPE_ACTION_SIMPLY) ||
1561             (role == ROLE_AG && type == TYPE_RESPONSE))) {
1562         return FALSE;
1563     }
1564 
1565     if (parameter_number > 8) return FALSE;
1566 
1567     switch (parameter_number) {
1568     case 0:
1569         value = get_uint_parameter(parameter_stream, parameter_length);
1570         proto_tree_add_uint(tree, hf_clcc_id, tvb, offset, parameter_length, value);
1571         break;
1572     case 1:
1573         value = get_uint_parameter(parameter_stream, parameter_length);
1574         proto_tree_add_uint(tree, hf_clcc_dir, tvb, offset, parameter_length, value);
1575         break;
1576     case 2:
1577         value = get_uint_parameter(parameter_stream, parameter_length);
1578         proto_tree_add_uint(tree, hf_clcc_stat, tvb, offset, parameter_length, value);
1579         break;
1580     case 3:
1581         value = get_uint_parameter(parameter_stream, parameter_length);
1582         proto_tree_add_uint(tree, hf_clcc_mode, tvb, offset, parameter_length, value);
1583         break;
1584     case 4:
1585         value = get_uint_parameter(parameter_stream, parameter_length);
1586         proto_tree_add_uint(tree, hf_clcc_mpty, tvb, offset, parameter_length, value);
1587         break;
1588     case 5:
1589         proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1590         break;
1591     case 6:
1592         value = get_uint_parameter(parameter_stream, parameter_length);
1593         pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1594         if (value < 128 || value > 175)
1595             expert_add_info(pinfo, pitem, &ei_at_type);
1596         break;
1597     case 7:
1598         proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1599         break;
1600     case 8:
1601         value = get_uint_parameter(parameter_stream, parameter_length);
1602         proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
1603         break;
1604     }
1605 
1606     return TRUE;
1607 }
1608 
1609 
1610 static gint
dissect_cme_error_parameter(tvbuff_t * tvb,packet_info * pinfo _U_,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1611 dissect_cme_error_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1612         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1613         guint parameter_number, gint parameter_length, void **data _U_)
1614 {
1615     guint32      value;
1616 
1617     if (!(role == ROLE_AG && type == TYPE_RESPONSE)) {
1618         return FALSE;
1619     }
1620 
1621     if (parameter_number > 0) return FALSE;
1622 
1623     value = get_uint_parameter(parameter_stream, parameter_length);
1624     proto_tree_add_uint(tree, hf_cme_error, tvb, offset, parameter_length, value);
1625 
1626     return TRUE;
1627 }
1628 
1629 static gint
dissect_cnum_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1630 dissect_cnum_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1631         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1632         guint parameter_number, gint parameter_length, void **data _U_)
1633 {
1634     proto_item  *pitem;
1635     guint32      value;
1636 
1637     if (!(role == ROLE_AG && type == TYPE_RESPONSE)) return TRUE;
1638     if (parameter_number > 5) return FALSE;
1639 
1640     switch (parameter_number) {
1641     case 0:
1642         pitem = proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1643         if (parameter_length > 0)
1644             expert_add_info(pinfo, pitem, &ei_parameter_blank);
1645         break;
1646     case 1:
1647         proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1648         break;
1649     case 2:
1650         value = get_uint_parameter(parameter_stream, parameter_length);
1651         pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1652         if (value < 128 || value > 175)
1653             expert_add_info(pinfo, pitem, &ei_at_type);
1654         break;
1655     case 3:
1656         value = get_uint_parameter(parameter_stream, parameter_length);
1657         pitem = proto_tree_add_uint(tree, hf_cnum_speed, tvb, offset, parameter_length, value);
1658         if (parameter_length > 0)
1659             expert_add_info(pinfo, pitem, &ei_parameter_blank);
1660         break;
1661     case 4:
1662         value = get_uint_parameter(parameter_stream, parameter_length);
1663         pitem = proto_tree_add_uint(tree, hf_cnum_service, tvb, offset, parameter_length, value);
1664         if (value > 5)
1665             expert_add_info(pinfo, pitem, &ei_cnum_service);
1666         break;
1667     case 5:
1668         value = get_uint_parameter(parameter_stream, parameter_length);
1669         pitem = proto_tree_add_uint(tree, hf_cnum_itc, tvb, offset, parameter_length, value);
1670         if (value > 1)
1671             expert_add_info(pinfo, pitem, &ei_cnum_itc);
1672         break;
1673     }
1674 
1675     return TRUE;
1676 }
1677 
1678 static gint
dissect_vts_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data _U_)1679 dissect_vts_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1680         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1681         guint parameter_number, gint parameter_length, void **data _U_)
1682 {
1683     proto_item  *pitem;
1684     guint32      value;
1685 
1686     if (!(role == ROLE_HS && type == TYPE_ACTION)) return TRUE;
1687     if (parameter_number > 1) return FALSE;
1688 
1689     switch (parameter_number) {
1690     case 0:
1691         pitem = proto_tree_add_item(tree, hf_vts_dtmf, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1692         if (parameter_length != 1)
1693             expert_add_info(pinfo, pitem, &ei_vts_dtmf);
1694         break;
1695     case 1:
1696         value = get_uint_parameter(parameter_stream, parameter_length);
1697         proto_tree_add_uint(tree, hf_vts_duration, tvb, offset, parameter_length, value);
1698         break;
1699     }
1700 
1701     return TRUE;
1702 }
1703 
1704 static gint
dissect_ciev_parameter(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,gint role,guint16 type,guint8 * parameter_stream,guint parameter_number,gint parameter_length,void ** data)1705 dissect_ciev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1706         gint offset, gint role, guint16 type, guint8 *parameter_stream,
1707         guint parameter_number, gint parameter_length, void **data)
1708 {
1709     guint32      value;
1710     guint        indicator_index;
1711 
1712     if (!(role == ROLE_AG && type == TYPE_RESPONSE)) return TRUE;
1713     if (parameter_number > 1) return FALSE;
1714 
1715     switch (parameter_number) {
1716     case 0:
1717         value = get_uint_parameter(parameter_stream, parameter_length);
1718         proto_tree_add_uint(tree, hf_ciev_indicator_index, tvb, offset, parameter_length, value);
1719         *data = wmem_alloc(wmem_packet_scope(), sizeof(guint));
1720         *((guint *) *data) = value;
1721         break;
1722     case 1:
1723         indicator_index = *((guint *) *data) - 1;
1724         if (indicator_index > 19) {
1725             proto_tree_add_expert(tree, pinfo, &ei_ciev_indicator, tvb, offset, parameter_length);
1726         } else {
1727             proto_tree_add_item(tree, hf_indicator[indicator_index], tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1728         }
1729         break;
1730     }
1731 
1732     return TRUE;
1733 }
1734 
1735 /* TODO: Some commands need to save request command type (request with TYPE_READ vs TYPE_TEST, etc.)
1736          to properly dissect response parameters.
1737          Some commands can use TYPE_TEST respose to properly dissect parameters,
1738          for example: AT+CIND=?, AT+CIND? */
1739 static const at_cmd_t at_cmds[] = {
1740     /* Vendor specific: Apple */
1741     { "+XAPL",        "Apple Bluetooth Accessory Identification",         check_xapl,        dissect_xapl_parameter },
1742     { "+IPHONEACCEV", "Apple Bluetooth Headset Battery Level Indication", check_iphoneaccev, dissect_iphoneaccev_parameter },
1743     { "+APLSIRI",     "Apple Siri Availability Information",              check_aplsiri,     dissect_aplsiri_parameter },
1744     { "+APLEFM",      "Apple Siri Eyes Free Mode",                        check_aplefm,      dissect_aplefm_parameter },
1745     /* Bluetooth HFP specific AT Commands */
1746     { "+BIEV",      "Bluetooth Indicator Enter Value",          check_biev, dissect_biev_parameter }, /* HFP 1.7 */
1747     { "+BIND",      "Bluetooth Indicator",                      check_bind, dissect_bind_parameter }, /* HFP 1.7 */
1748     { "+BAC",       "Bluetooth Available Codecs",               check_bac,  dissect_bac_parameter  },
1749     { "+BCS",       "Bluetooth Codec Selection",                check_bcs,  dissect_bcs_parameter  },
1750     { "+BCC",       "Bluetooth Codec Connection",               check_bcc,  dissect_no_parameter   },
1751     { "+BTRH",      "Bluetooth Response and Hold Feature",      check_btrh, dissect_btrh_parameter },
1752     { "+BSIR",      "Bluetooth Setting of In-band Ring Tone",   check_bsir, dissect_bsir_parameter },
1753     { "+VGS",       "Gain of Speaker",                          check_vgs,  dissect_vgs_parameter  },
1754     { "+VGM",       "Gain of Microphone",                       check_vgm,  dissect_vgm_parameter  },
1755     { "+NREC",      "Noise Reduction and Echo Cancelling",      check_nrec, dissect_nrec_parameter },
1756     { "+BRSF",      "Bluetooth Retrieve Supported Features",    check_brsf, dissect_brsf_parameter },
1757     { "+BVRA",      "Bluetooth Voice Recognition Activation",   check_bvra, dissect_bvra_parameter },
1758     { "+BLDN",      "Bluetooth Last Dialled Number",            check_bldn, dissect_no_parameter   },
1759     { "+BINP",      "Bluetooth Input",                          check_binp, dissect_binp_parameter },
1760     { "+BIA",       "Bluetooth Indicators Activation",          check_bia,  dissect_bia_parameter  },
1761     /* Inherited from normal AT Commands */
1762     { "+CCWA",      "Call Waiting Notification",                check_ccwa, dissect_ccwa_parameter },
1763     { "+CHLD",      "Call Hold and Multiparty Handling",        check_chld, dissect_chld_parameter },
1764     { "+CHUP",      "Call Hang-up",                             check_chup, dissect_no_parameter   },
1765     { "+CIND",      "Phone Indicators",                         check_cind, dissect_cind_parameter },
1766     { "+CLCC",      "Current Calls",                            check_clcc, dissect_clcc_parameter },
1767     { "+COPS",      "Reading Network Operator",                 check_cops, dissect_cops_parameter },
1768     { "+CMEE",      "Mobile Equipment Error",                   check_cmee, dissect_cmee_parameter },
1769     { "+CME ERROR", "Extended Audio Gateway Error Result Code", check_cme,  dissect_cme_error_parameter },
1770     { "+CLIP",      "Calling Line Identification Notification", check_clip, dissect_clip_parameter },
1771     { "+CMER",      "Event Reporting Activation/Deactivation",  check_cmer, dissect_cmer_parameter },
1772     { "+CIEV",      "Indicator Events Reporting",               check_ciev, dissect_ciev_parameter },
1773     { "+VTS",       "DTMF and tone generation",                 check_vts,  dissect_vts_parameter  },
1774     { "+CNUM",      "Subscriber Number Information",            check_cnum, dissect_cnum_parameter },
1775     { "ERROR",      "ERROR",                                    check_only_ag_role, dissect_no_parameter },
1776     { "RING",       "Incoming Call Indication",                 check_only_ag_role, dissect_no_parameter },
1777     { "OK",         "OK",                                       check_only_ag_role, dissect_no_parameter },
1778     { "D",          "Dial",                                     check_only_hs_role, NULL },
1779     { "A",          "Call Answer",                              check_only_hs_role, dissect_no_parameter },
1780     { NULL, NULL, NULL, NULL }
1781 };
1782 
1783 
1784 static gint
dissect_at_command(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,gint offset,guint32 role,gint command_number)1785 dissect_at_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1786         gint offset, guint32 role, gint command_number)
1787 {
1788     proto_item      *pitem;
1789     proto_tree      *command_item = NULL;
1790     proto_item      *command_tree = NULL;
1791     proto_tree      *parameters_item = NULL;
1792     proto_item      *parameters_tree = NULL;
1793     guint8          *col_str = NULL;
1794     guint8          *at_stream;
1795     guint8          *at_command = NULL;
1796     gint             i_char = 0;
1797     guint            i_char_fix = 0;
1798     gint             length;
1799     const at_cmd_t  *i_at_cmd;
1800     gint             parameter_length;
1801     guint            parameter_number = 0;
1802     gint             first_parameter_offset = offset;
1803     gint             last_parameter_offset  = offset;
1804     guint16          type = TYPE_UNKNOWN;
1805     guint32          brackets;
1806     gboolean         quotation;
1807     gboolean         next;
1808     void            *data;
1809 
1810     length = tvb_reported_length_remaining(tvb, offset);
1811     if (length <= 0)
1812         return tvb_reported_length(tvb);
1813 
1814     if (!command_number) {
1815         proto_tree_add_item(tree, hf_data, tvb, offset, length, ENC_NA | ENC_ASCII);
1816         col_str = (guint8 *) wmem_alloc(wmem_packet_scope(), length + 1);
1817         tvb_memcpy(tvb, col_str, offset, length);
1818         col_str[length] = '\0';
1819     }
1820 
1821     at_stream = (guint8 *) wmem_alloc(wmem_packet_scope(), length + 1);
1822     tvb_memcpy(tvb, at_stream, offset, length);
1823     at_stream[length] = '\0';
1824 
1825     while (at_stream[i_char]) {
1826         at_stream[i_char] = g_ascii_toupper(at_stream[i_char]);
1827         if (!command_number) {
1828             col_str[i_char] = g_ascii_toupper(col_str[i_char]);
1829             if (!g_ascii_isgraph(col_str[i_char])) col_str[i_char] = ' ';
1830         }
1831         i_char += 1;
1832     }
1833 
1834     if (!command_number) col_append_str(pinfo->cinfo, COL_INFO, col_str);
1835 
1836     if (role == ROLE_HS) {
1837         if (command_number) {
1838             at_command = at_stream;
1839             i_char = 0;
1840         } else {
1841             at_command = g_strstr_len(at_stream, length, "AT");
1842             if (at_command) {
1843                 command_item = proto_tree_add_none_format(tree, hf_command, tvb,
1844                         offset, 0, "Command %u", command_number);
1845                 command_tree = proto_item_add_subtree(command_item, ett_bthfp_command);
1846 
1847                 i_char = (guint) (at_command - at_stream);
1848                 if (i_char) {
1849                     proto_tree_add_item(command_tree, hf_at_ignored, tvb, offset,
1850                         i_char, ENC_NA | ENC_ASCII);
1851                     offset += i_char;
1852                 }
1853 
1854                 proto_tree_add_item(command_tree, hf_at_command_line_prefix,
1855                         tvb, offset, 2, ENC_NA | ENC_ASCII);
1856                 offset += 2;
1857                 i_char += 2;
1858                 at_command = at_stream;
1859                 at_command += i_char;
1860                 length -= i_char;
1861                 i_char_fix += i_char;
1862                 i_char = 0;
1863             }
1864         }
1865     } else if (at_stream[0] == '\r' && at_stream[1] == '\n') {
1866         command_item = proto_tree_add_none_format(tree, hf_command, tvb,
1867                 offset, 0, "Command %u", command_number);
1868         command_tree = proto_item_add_subtree(command_item, ett_bthfp_command);
1869 
1870         at_command = at_stream;
1871         i_char = 0;
1872         while (i_char <= length &&
1873                 (at_command[i_char] == '\r' || at_command[i_char] == '\n' ||
1874                 at_command[i_char] == ' ' || at_command[i_char] == '\t')) {
1875             /* ignore white characters */
1876             i_char += 1;
1877         }
1878 
1879         offset += i_char;
1880         at_command += i_char;
1881         length -= i_char;
1882         i_char_fix += i_char;
1883         i_char = 0;
1884     }
1885 
1886     if (at_command) {
1887 
1888         while (i_char < length &&
1889                         (at_command[i_char] != '\r' && at_command[i_char] != '=' &&
1890                         at_command[i_char] != ';' && at_command[i_char] != '?' &&
1891                         at_command[i_char] != ':')) {
1892             i_char += 1;
1893         }
1894 
1895         i_at_cmd = at_cmds;
1896         if (at_command[0] == '\r') {
1897             pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset - 2,
1898                     2, ENC_NA | ENC_ASCII);
1899             i_at_cmd = NULL;
1900         } else {
1901             pitem = NULL;
1902             while (i_at_cmd->name) {
1903                 if (g_str_has_prefix(&at_command[0], i_at_cmd->name)) {
1904                     pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
1905                             (gint) strlen(i_at_cmd->name), ENC_NA | ENC_ASCII);
1906                     proto_item_append_text(pitem, " (%s)", i_at_cmd->long_name);
1907                     break;
1908                 }
1909                 i_at_cmd += 1;
1910             }
1911 
1912             if (!pitem) {
1913                 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
1914                         i_char, ENC_NA | ENC_ASCII);
1915             }
1916         }
1917 
1918 
1919         if (i_at_cmd && i_at_cmd->name == NULL) {
1920             char *name;
1921 
1922             name = (char *) wmem_alloc(wmem_packet_scope(), i_char + 2);
1923             (void) g_strlcpy(name, at_command, i_char + 1);
1924             name[i_char + 1] = '\0';
1925             proto_item_append_text(command_item, ": %s (Unknown)", name);
1926             proto_item_append_text(pitem, " (Unknown - Non-Standard HFP Command)");
1927             expert_add_info(pinfo, pitem, &ei_non_mandatory_command);
1928         } else if (i_at_cmd == NULL) {
1929             proto_item_append_text(command_item, ": AT");
1930         } else {
1931             proto_item_append_text(command_item, ": %s", i_at_cmd->name);
1932         }
1933 
1934         offset += i_char;
1935 
1936         if (i_at_cmd && g_strcmp0(i_at_cmd->name, "D")) {
1937             if (length >= 2 && at_command[i_char] == '=' && at_command[i_char + 1] == '?') {
1938                 type = at_command[i_char] << 8 | at_command[i_char + 1];
1939                 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
1940                 offset += 2;
1941                 i_char += 2;
1942             } else if (role == ROLE_AG && length >= 2 && at_command[i_char] == '\r' && at_command[i_char + 1] == '\n') {
1943                 type = at_command[i_char] << 8 | at_command[i_char + 1];
1944                 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
1945                 offset += 2;
1946                 i_char += 2;
1947             } else if (length >= 1 && (at_command[i_char] == '=' ||
1948                         at_command[i_char] == '\r' ||
1949                         at_command[i_char] == ':' ||
1950                         at_command[i_char] == '?')) {
1951                 type = at_command[i_char];
1952                 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 1, type);
1953                 offset += 1;
1954                 i_char += 1;
1955             }
1956         }
1957 
1958         if (i_at_cmd && i_at_cmd->check_command && !i_at_cmd->check_command(role, type)) {
1959             expert_add_info(pinfo, command_item, &ei_invalid_usage);
1960         }
1961 
1962         parameters_item = proto_tree_add_none_format(command_tree, hf_parameters, tvb,
1963                 offset, 0, "Parameters");
1964         parameters_tree = proto_item_add_subtree(parameters_item, ett_bthfp_parameters);
1965         first_parameter_offset = offset;
1966 
1967         data = NULL;
1968 
1969         while (i_char < length) {
1970 
1971             while (at_command[i_char] == ' ' || at_command[i_char]  == '\t') {
1972                 offset += 1;
1973                 i_char += 1;
1974             }
1975 
1976             parameter_length = 0;
1977             brackets = 0;
1978             quotation = FALSE;
1979             next = FALSE;
1980 
1981             if (at_command[i_char + parameter_length] != '\r') {
1982                 while (i_char + parameter_length < length &&
1983                         at_command[i_char + parameter_length] != '\r') {
1984 
1985                     if (at_command[i_char + parameter_length] == ';') {
1986                         next = TRUE;
1987                         break;
1988                     }
1989 
1990                     if (at_command[i_char + parameter_length] == '"') {
1991                         quotation = quotation ? FALSE : TRUE;
1992                     }
1993 
1994                     if (quotation == TRUE) {
1995                         parameter_length += 1;
1996                         continue;
1997                     }
1998 
1999                     if (at_command[i_char + parameter_length] == '(') {
2000                         brackets += 1;
2001                     }
2002                     if (at_command[i_char + parameter_length] == ')') {
2003                         brackets -= 1;
2004                     }
2005 
2006                     if (brackets == 0 && at_command[i_char + parameter_length] == ',') {
2007                         break;
2008                     }
2009 
2010                     parameter_length += 1;
2011                 }
2012 
2013                 if (type == TYPE_ACTION || type == TYPE_RESPONSE) {
2014                     if (i_at_cmd && (i_at_cmd->dissect_parameter != NULL &&
2015                             !i_at_cmd->dissect_parameter(tvb, pinfo, parameters_tree, offset, role,
2016                             type, &at_command[i_char], parameter_number, parameter_length, &data) )) {
2017                         pitem = proto_tree_add_item(parameters_tree,
2018                                 hf_unknown_parameter, tvb, offset,
2019                                 parameter_length, ENC_NA | ENC_ASCII);
2020                         expert_add_info(pinfo, pitem, &ei_unknown_parameter);
2021                     } else if (i_at_cmd && i_at_cmd->dissect_parameter == NULL) {
2022                         proto_tree_add_item(parameters_tree, hf_parameter, tvb, offset,
2023                                 parameter_length, ENC_NA | ENC_ASCII);
2024                     }
2025                 }
2026             }
2027 
2028             if (type != TYPE_ACTION_SIMPLY && type != TYPE_RESPONSE_ACK && type != TYPE_TEST && type != TYPE_READ)
2029                 parameter_number += 1;
2030             i_char += parameter_length;
2031             offset += parameter_length;
2032             last_parameter_offset = offset;
2033 
2034             if (role == ROLE_AG &&
2035                     i_char + 1 <= length &&
2036                     at_command[i_char] == '\r' &&
2037                     at_command[i_char + 1] == '\n') {
2038                 offset += 2;
2039                 i_char += 2;
2040                 break;
2041             } else if (at_command[i_char] == ',' ||
2042                         at_command[i_char] == '\r' ||
2043                         at_command[i_char] == ';') {
2044                     i_char += 1;
2045                     offset += 1;
2046             }
2047 
2048             if (next) break;
2049         }
2050 
2051         i_char += i_char_fix;
2052         proto_item_set_len(command_item, i_char);
2053     } else {
2054         length = tvb_reported_length_remaining(tvb, offset);
2055         if (length < 0)
2056             length = 0;
2057         offset += length;
2058     }
2059 
2060     if (parameter_number > 0 && last_parameter_offset - first_parameter_offset > 0)
2061         proto_item_set_len(parameters_item, last_parameter_offset - first_parameter_offset);
2062     else
2063         proto_item_append_text(parameters_item, ": No");
2064 
2065     return offset;
2066 }
2067 
2068 static gint
dissect_bthfp(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree,void * data)2069 dissect_bthfp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2070 {
2071     proto_item       *main_item;
2072     proto_tree       *main_tree;
2073     proto_item       *pitem;
2074     gint              offset = 0;
2075     guint32           role = ROLE_UNKNOWN;
2076     wmem_tree_key_t   key[10];
2077     guint32           interface_id;
2078     guint32           adapter_id;
2079     guint32           chandle;
2080     guint32           dlci;
2081     guint32           frame_number;
2082     guint32           direction;
2083     guint32           bd_addr_oui;
2084     guint32           bd_addr_id;
2085     fragment_t       *fragment;
2086     fragment_t       *previous_fragment;
2087     fragment_t       *i_fragment;
2088     guint8           *at_stream;
2089     gint              length;
2090     gint              command_number;
2091     gint              i_length;
2092     tvbuff_t         *reassembled_tvb = NULL;
2093     guint             reassemble_start_offset = 0;
2094     guint             reassemble_end_offset   = 0;
2095     gint              previous_proto;
2096 
2097     previous_proto = (GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))));
2098     if (data && previous_proto == proto_btrfcomm) {
2099         btrfcomm_data_t  *rfcomm_data;
2100 
2101         rfcomm_data = (btrfcomm_data_t *) data;
2102 
2103         interface_id = rfcomm_data->interface_id;
2104         adapter_id   = rfcomm_data->adapter_id;
2105         chandle      = rfcomm_data->chandle;
2106         dlci         = rfcomm_data->dlci;
2107         direction    = (rfcomm_data->is_local_psm) ? P2P_DIR_SENT : P2P_DIR_RECV;
2108 
2109         if (direction == P2P_DIR_RECV) {
2110             bd_addr_oui     = rfcomm_data->remote_bd_addr_oui;
2111             bd_addr_id      = rfcomm_data->remote_bd_addr_id;
2112         } else {
2113             bd_addr_oui     = 0;
2114             bd_addr_id      = 0;
2115         }
2116     } else {
2117         interface_id = HCI_INTERFACE_DEFAULT;
2118         adapter_id   = HCI_ADAPTER_DEFAULT;
2119         chandle      = 0;
2120         dlci         = 0;
2121         direction    = P2P_DIR_UNKNOWN;
2122 
2123         bd_addr_oui     = 0;
2124         bd_addr_id      = 0;
2125     }
2126 
2127     main_item = proto_tree_add_item(tree, proto_bthfp, tvb, 0, tvb_captured_length(tvb), ENC_NA);
2128     main_tree = proto_item_add_subtree(main_item, ett_bthfp);
2129 
2130     col_set_str(pinfo->cinfo, COL_PROTOCOL, "HFP");
2131 
2132     switch (pinfo->p2p_dir) {
2133         case P2P_DIR_SENT:
2134             col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
2135             break;
2136         case P2P_DIR_RECV:
2137             col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
2138             break;
2139         default:
2140             col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
2141             break;
2142     }
2143 
2144     if ((hfp_role == ROLE_AG && pinfo->p2p_dir == P2P_DIR_SENT) ||
2145             (hfp_role == ROLE_HS && pinfo->p2p_dir == P2P_DIR_RECV)) {
2146         role = ROLE_AG;
2147     } else if (hfp_role != ROLE_UNKNOWN) {
2148         role = ROLE_HS;
2149     }
2150 
2151     if (role == ROLE_UNKNOWN) {
2152         guint32          sdp_psm;
2153         guint32          service_type;
2154         guint32          service_channel;
2155         service_info_t  *service_info;
2156 
2157         sdp_psm         = SDP_PSM_DEFAULT;
2158 
2159         service_type    = BTSDP_RFCOMM_PROTOCOL_UUID;
2160         service_channel = dlci >> 1;
2161         frame_number    = pinfo->num;
2162 
2163         key[0].length = 1;
2164         key[0].key = &interface_id;
2165         key[1].length = 1;
2166         key[1].key = &adapter_id;
2167         key[2].length = 1;
2168         key[2].key = &sdp_psm;
2169         key[3].length = 1;
2170         key[3].key = &direction;
2171         key[4].length = 1;
2172         key[4].key = &bd_addr_oui;
2173         key[5].length = 1;
2174         key[5].key = &bd_addr_id;
2175         key[6].length = 1;
2176         key[6].key = &service_type;
2177         key[7].length = 1;
2178         key[7].key = &service_channel;
2179         key[8].length = 1;
2180         key[8].key = &frame_number;
2181         key[9].length = 0;
2182         key[9].key = NULL;
2183 
2184         service_info = btsdp_get_service_info(key);
2185         if (service_info && service_info->interface_id == interface_id &&
2186                 service_info->adapter_id == adapter_id &&
2187                 service_info->sdp_psm == SDP_PSM_DEFAULT &&
2188                 ((service_info->direction == P2P_DIR_RECV &&
2189                 service_info->bd_addr_oui == bd_addr_oui &&
2190                 service_info->bd_addr_id == bd_addr_id) ||
2191                 (service_info->direction != P2P_DIR_RECV &&
2192                 service_info->bd_addr_oui == 0 &&
2193                 service_info->bd_addr_id == 0)) &&
2194                 service_info->type == BTSDP_RFCOMM_PROTOCOL_UUID &&
2195                 service_info->channel == (dlci >> 1)) {
2196             if ((service_info->uuid.bt_uuid == BTSDP_HFP_GW_SERVICE_UUID && service_info->direction == P2P_DIR_RECV && pinfo->p2p_dir == P2P_DIR_SENT) ||
2197                 (service_info->uuid.bt_uuid == BTSDP_HFP_GW_SERVICE_UUID && service_info->direction == P2P_DIR_SENT && pinfo->p2p_dir == P2P_DIR_RECV) ||
2198                 (service_info->uuid.bt_uuid == BTSDP_HFP_SERVICE_UUID && service_info->direction == P2P_DIR_RECV && pinfo->p2p_dir == P2P_DIR_RECV) ||
2199                 (service_info->uuid.bt_uuid == BTSDP_HFP_SERVICE_UUID && service_info->direction == P2P_DIR_SENT && pinfo->p2p_dir == P2P_DIR_SENT)) {
2200                 role = ROLE_HS;
2201             } else {
2202                 role = ROLE_AG;
2203             }
2204         }
2205     }
2206 
2207     pitem = proto_tree_add_uint(main_tree, hf_role, tvb, 0, 0, role);
2208     proto_item_set_generated(pitem);
2209 
2210     if (role == ROLE_UNKNOWN) {
2211         col_append_fstr(pinfo->cinfo, COL_INFO, "Data: %s",
2212                 tvb_format_text(pinfo->pool, tvb, 0, tvb_reported_length(tvb)));
2213         proto_tree_add_item(main_tree, hf_data, tvb, 0, tvb_captured_length(tvb), ENC_NA | ENC_ASCII);
2214         return tvb_reported_length(tvb);
2215     }
2216 
2217     /* save fragments */
2218     if (!pinfo->fd->visited) {
2219         frame_number = pinfo->num - 1;
2220 
2221         key[0].length = 1;
2222         key[0].key = &interface_id;
2223         key[1].length = 1;
2224         key[1].key = &adapter_id;
2225         key[2].length = 1;
2226         key[2].key = &chandle;
2227         key[3].length = 1;
2228         key[3].key = &dlci;
2229         key[4].length = 1;
2230         key[4].key = &role;
2231         key[5].length = 1;
2232         key[5].key = &frame_number;
2233         key[6].length = 0;
2234         key[6].key = NULL;
2235 
2236         previous_fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2237         if (!(previous_fragment && previous_fragment->interface_id == interface_id &&
2238                 previous_fragment->adapter_id == adapter_id &&
2239                 previous_fragment->chandle == chandle &&
2240                 previous_fragment->dlci == dlci &&
2241                 previous_fragment->role == role &&
2242                 previous_fragment->reassemble_state != REASSEMBLE_DONE)) {
2243             previous_fragment = NULL;
2244         }
2245 
2246         frame_number = pinfo->num;
2247 
2248         key[0].length = 1;
2249         key[0].key = &interface_id;
2250         key[1].length = 1;
2251         key[1].key = &adapter_id;
2252         key[2].length = 1;
2253         key[2].key = &chandle;
2254         key[3].length = 1;
2255         key[3].key = &dlci;
2256         key[4].length = 1;
2257         key[4].key = &role;
2258         key[5].length = 1;
2259         key[5].key = &frame_number;
2260         key[6].length = 0;
2261         key[6].key = NULL;
2262 
2263         fragment = wmem_new(wmem_file_scope(), fragment_t);
2264         fragment->interface_id      = interface_id;
2265         fragment->adapter_id        = adapter_id;
2266         fragment->chandle           = chandle;
2267         fragment->dlci              = dlci;
2268         fragment->role              = role;
2269         fragment->idx               = previous_fragment ? previous_fragment->idx + previous_fragment->length : 0;
2270         fragment->reassemble_state  = REASSEMBLE_FRAGMENT;
2271         fragment->length            = tvb_reported_length(tvb);
2272         fragment->data              = (guint8 *) wmem_alloc(wmem_file_scope(), fragment->length);
2273         fragment->previous_fragment = previous_fragment;
2274         tvb_memcpy(tvb, fragment->data, offset, fragment->length);
2275 
2276         wmem_tree_insert32_array(fragments, key, fragment);
2277 
2278         /* Detect reassemble end character: \r for HS or \n for AG */
2279         length = tvb_reported_length(tvb);
2280         at_stream = tvb_get_string_enc(wmem_packet_scope(), tvb, 0, length, ENC_ASCII);
2281 
2282         reassemble_start_offset = 0;
2283 
2284         for (i_length = 0; i_length < length; i_length += 1) {
2285             if (!((role == ROLE_HS && at_stream[i_length] == '\r') ||
2286                     (role == ROLE_AG && at_stream[i_length] == '\n'))) {
2287                 continue;
2288             }
2289 
2290             if (role == ROLE_HS && at_stream[i_length] == '\r') {
2291                 reassemble_start_offset = i_length + 1;
2292                 if (reassemble_end_offset == 0) reassemble_end_offset = i_length + 1;
2293             }
2294 
2295             if (role == ROLE_AG && at_stream[i_length] == '\n') {
2296                 reassemble_start_offset = i_length + 1;
2297             }
2298 
2299             frame_number = pinfo->num;
2300 
2301             key[0].length = 1;
2302             key[0].key = &interface_id;
2303             key[1].length = 1;
2304             key[1].key = &adapter_id;
2305             key[2].length = 1;
2306             key[2].key = &chandle;
2307             key[3].length = 1;
2308             key[3].key = &dlci;
2309             key[4].length = 1;
2310             key[4].key = &role;
2311             key[5].length = 1;
2312             key[5].key = &frame_number;
2313             key[6].length = 0;
2314             key[6].key = NULL;
2315 
2316             fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2317             if (fragment && fragment->interface_id == interface_id &&
2318                     fragment->adapter_id == adapter_id &&
2319                     fragment->chandle == chandle &&
2320                     fragment->dlci == dlci &&
2321                     fragment->role == role) {
2322                 i_fragment = fragment;
2323                 while (i_fragment && i_fragment->idx > 0) {
2324                     i_fragment = i_fragment->previous_fragment;
2325                 }
2326 
2327                 if (i_length + 1 == length &&
2328                         role == ROLE_HS &&
2329                         at_stream[i_length] == '\r') {
2330                     fragment->reassemble_state = REASSEMBLE_DONE;
2331                 } else if (i_length + 1 == length &&
2332                         role == ROLE_AG &&
2333                         i_length >= 4 &&
2334                         at_stream[i_length] == '\n' &&
2335                         at_stream[i_length - 1] == '\r' &&
2336                         at_stream[0] == '\r' &&
2337                         at_stream[1] == '\n') {
2338                     fragment->reassemble_state = REASSEMBLE_DONE;
2339                 } else if (i_length + 1 == length &&
2340                         role == ROLE_AG &&
2341                         i_length >= 2 &&
2342                         at_stream[i_length] == '\n' &&
2343                         at_stream[i_length - 1] == '\r' &&
2344                         i_fragment &&
2345                         i_fragment->reassemble_state == REASSEMBLE_FRAGMENT &&
2346                         i_fragment->length >= 2 &&
2347                         i_fragment->data[0] == '\r' &&
2348                         i_fragment->data[1] == '\n') {
2349                     fragment->reassemble_state = REASSEMBLE_DONE;
2350                 } else if (role == ROLE_HS) {
2351 /* XXX: Temporary disable reassembling of partial message, it seems to be broken */
2352 /*                    fragment->reassemble_state = REASSEMBLE_PARTIALLY;*/
2353                 }
2354                 fragment->reassemble_start_offset = reassemble_start_offset;
2355                 fragment->reassemble_end_offset = reassemble_end_offset;
2356             }
2357         }
2358     }
2359 
2360     /* recover reassembled payload */
2361     frame_number = pinfo->num;
2362 
2363     key[0].length = 1;
2364     key[0].key = &interface_id;
2365     key[1].length = 1;
2366     key[1].key = &adapter_id;
2367     key[2].length = 1;
2368     key[2].key = &chandle;
2369     key[3].length = 1;
2370     key[3].key = &dlci;
2371     key[4].length = 1;
2372     key[4].key = &role;
2373     key[5].length = 1;
2374     key[5].key = &frame_number;
2375     key[6].length = 0;
2376     key[6].key = NULL;
2377 
2378     fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2379     if (fragment && fragment->interface_id == interface_id &&
2380             fragment->adapter_id == adapter_id &&
2381             fragment->chandle == chandle &&
2382             fragment->dlci == dlci &&
2383             fragment->role == role &&
2384             fragment->reassemble_state != REASSEMBLE_FRAGMENT) {
2385         guint8    *at_data;
2386         guint      i_data_offset;
2387 
2388         i_data_offset = fragment->idx + fragment->length;
2389         at_data = (guint8 *) wmem_alloc(pinfo->pool, fragment->idx + fragment->length);
2390 
2391         i_fragment = fragment;
2392 
2393         if (i_fragment && i_fragment->reassemble_state == REASSEMBLE_PARTIALLY) {
2394             i_data_offset -= i_fragment->reassemble_end_offset;
2395             memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->reassemble_end_offset);
2396             i_fragment = i_fragment->previous_fragment;
2397         }
2398 
2399         if (i_fragment) {
2400             while (i_fragment && i_fragment->idx > 0) {
2401                 i_data_offset -= i_fragment->length;
2402                 memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->length);
2403                 i_fragment = i_fragment->previous_fragment;
2404             }
2405 
2406             if (i_fragment && i_fragment->reassemble_state == REASSEMBLE_PARTIALLY) {
2407                 i_data_offset -= (i_fragment->length - i_fragment->reassemble_start_offset);
2408                 memcpy(at_data + i_data_offset, i_fragment->data + i_fragment->reassemble_start_offset,
2409                         i_fragment->length - i_fragment->reassemble_start_offset);
2410             } else if (i_fragment) {
2411                 i_data_offset -= i_fragment->length;
2412                 memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->length);
2413             }
2414         }
2415 
2416         if (fragment->idx > 0 && fragment->length > 0) {
2417             proto_tree_add_item(main_tree, hf_fragment, tvb, offset,
2418                     tvb_captured_length_remaining(tvb, offset), ENC_ASCII | ENC_NA);
2419             reassembled_tvb = tvb_new_child_real_data(tvb, at_data,
2420                     fragment->idx + fragment->length, fragment->idx + fragment->length);
2421             add_new_data_source(pinfo, reassembled_tvb, "Reassembled HFP");
2422         }
2423 
2424         command_number = 0;
2425         if (reassembled_tvb) {
2426             guint reassembled_offset = 0;
2427 
2428             while (tvb_reported_length(reassembled_tvb) > reassembled_offset) {
2429                 reassembled_offset = dissect_at_command(reassembled_tvb,
2430                         pinfo, main_tree, reassembled_offset, role, command_number);
2431                 command_number += 1;
2432             }
2433             offset = tvb_captured_length(tvb);
2434         } else {
2435             while (tvb_reported_length(tvb) > (guint) offset) {
2436                 offset = dissect_at_command(tvb, pinfo, main_tree, offset, role, command_number);
2437                 command_number += 1;
2438             }
2439         }
2440     } else {
2441         col_append_fstr(pinfo->cinfo, COL_INFO, "Fragment: %s",
2442                 tvb_format_text_wsp(wmem_packet_scope(), tvb, offset, tvb_captured_length_remaining(tvb, offset)));
2443         pitem = proto_tree_add_item(main_tree, hf_fragmented, tvb, 0, 0, ENC_NA);
2444         proto_item_set_generated(pitem);
2445         proto_tree_add_item(main_tree, hf_fragment, tvb, offset,
2446                 tvb_captured_length_remaining(tvb, offset), ENC_ASCII | ENC_NA);
2447         offset = tvb_captured_length(tvb);
2448     }
2449 
2450     return offset;
2451 }
2452 
2453 void
proto_register_bthfp(void)2454 proto_register_bthfp(void)
2455 {
2456     module_t         *module;
2457     expert_module_t  *expert_bthfp;
2458 
2459     static hf_register_info hf[] = {
2460         { &hf_command,
2461            { "Command",                          "bthfp.command",
2462            FT_NONE, BASE_NONE, NULL, 0,
2463            NULL, HFILL}
2464         },
2465         { &hf_parameters,
2466            { "Parameters",                       "bthfp.parameters",
2467            FT_NONE, BASE_NONE, NULL, 0,
2468            NULL, HFILL}
2469         },
2470         { &hf_data,
2471            { "AT Stream",                        "bthfp.data",
2472            FT_STRING, BASE_NONE, NULL, 0,
2473            NULL, HFILL}
2474         },
2475         { &hf_fragment,
2476            { "Fragment",                         "bthfp.fragment",
2477            FT_STRING, BASE_NONE, NULL, 0,
2478            NULL, HFILL}
2479         },
2480         { &hf_fragmented,
2481            { "Fragmented",                       "bthfp.fragmented",
2482            FT_NONE, BASE_NONE, NULL, 0,
2483            NULL, HFILL}
2484         },
2485         { &hf_at_ignored,
2486            { "Ignored",                          "bthfp.ignored",
2487            FT_BYTES, BASE_NONE, NULL, 0,
2488            NULL, HFILL}
2489         },
2490         { &hf_at_cmd,
2491            { "Command",                          "bthfp.at_cmd",
2492            FT_STRING, BASE_NONE, NULL, 0,
2493            NULL, HFILL}
2494         },
2495         { &hf_at_cmd_type,
2496            { "Type",                             "bthfp.at_cmd.type",
2497            FT_UINT16, BASE_HEX, VALS(at_cmd_type_vals), 0,
2498            NULL, HFILL}
2499         },
2500         { &hf_at_command_line_prefix,
2501            { "Command Line Prefix",              "bthfp.command_line_prefix",
2502            FT_STRING, BASE_NONE, NULL, 0,
2503            NULL, HFILL}
2504         },
2505         { &hf_parameter,
2506            { "Parameter",                        "bthfp.parameter",
2507            FT_STRING, BASE_NONE, NULL, 0,
2508            NULL, HFILL}
2509         },
2510         { &hf_unknown_parameter,
2511            { "Unknown Parameter",                "bthfp.unknown_parameter",
2512            FT_STRING, BASE_NONE, NULL, 0,
2513            NULL, HFILL}
2514         },
2515         { &hf_role,
2516            { "Role",                             "bthfp.role",
2517            FT_UINT8, BASE_DEC, VALS(role_vals), 0,
2518            NULL, HFILL}
2519         },
2520         { &hf_brsf_hs,
2521            { "HS supported features bitmask",    "bthfp.brsf.hs.features",
2522            FT_UINT32, BASE_DEC, NULL, 0,
2523            NULL, HFILL}
2524         },
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,
2528            NULL, HFILL}
2529         },
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,
2533            NULL, HFILL}
2534         },
2535         { &hf_brsf_hs_cli_presentation,
2536            { "CLI Presentation",                 "bthfp.brsf.hs.cli_presentation",
2537            FT_BOOLEAN, 32, NULL, 0x00000004,
2538            NULL, HFILL}
2539         },
2540         { &hf_brsf_hs_voice_recognition_activation,
2541            { "Voice Recognition Activation",     "bthfp.brsf.hs.voice_recognition_activation",
2542            FT_BOOLEAN, 32, NULL, 0x00000008,
2543            NULL, HFILL}
2544         },
2545         { &hf_brsf_hs_remote_volume_control,
2546            { "Remote Volume Control",            "bthfp.brsf.hs.remote_volume_control",
2547            FT_BOOLEAN, 32, NULL, 0x00000010,
2548            NULL, HFILL}
2549         },
2550         { &hf_brsf_hs_enhanced_call_status,
2551            { "Enhanced Call Status",             "bthfp.brsf.hs.enhanced_call_status",
2552            FT_BOOLEAN, 32, NULL, 0x00000020,
2553            NULL, HFILL}
2554         },
2555         { &hf_brsf_hs_enhanced_call_control,
2556            { "Enhanced Call Control",            "bthfp.brsf.hs.enhanced_call_control",
2557            FT_BOOLEAN, 32, NULL, 0x00000040,
2558            NULL, HFILL}
2559         },
2560         { &hf_brsf_hs_codec_negotiation,
2561            { "Codec Negotiation",                "bthfp.brsf.hs.codec_negotiation",
2562            FT_BOOLEAN, 32, NULL, 0x00000080,
2563            NULL, HFILL}
2564         },
2565         { &hf_brsf_hs_hf_indicators,
2566            { "HF Indicators",                    "bthfp.brsf.hs.hf_indicators",
2567            FT_BOOLEAN, 32, NULL, 0x00000100,
2568            NULL, HFILL}
2569         },
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,
2573            NULL, HFILL}
2574         },
2575         { &hf_brsf_hs_reserved,
2576            { "Reserved",                         "bthfp.brsf.hs.reserved",
2577            FT_UINT32, BASE_HEX, NULL, 0xFFFFFC00,
2578            NULL, HFILL}
2579         },
2580         { &hf_brsf_ag,
2581            { "AG supported features bitmask",    "bthfp.brsf.ag.features",
2582            FT_UINT32, BASE_DEC, NULL, 0,
2583            NULL, HFILL}
2584         },
2585         { &hf_brsf_ag_three_way_calling,
2586            { "Three Way Calling",                "bthfp.brsf.ag.three_way_calling",
2587            FT_BOOLEAN, 32, NULL, 0x00000001,
2588            NULL, HFILL}
2589         },
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,
2593            NULL, HFILL}
2594         },
2595         { &hf_brsf_ag_voice_recognition_function,
2596            { "Voice Recognition Function",       "bthfp.brsf.ag.voice_recognition_function",
2597            FT_BOOLEAN, 32, NULL, 0x00000004,
2598            NULL, HFILL}
2599         },
2600         { &hf_brsf_ag_inband_ring_tone,
2601            { "In-band Ring Tone",                "bthfp.brsf.ag.inband_ring_tone",
2602            FT_BOOLEAN, 32, NULL, 0x00000008,
2603            NULL, HFILL}
2604         },
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,
2608            NULL, HFILL}
2609         },
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,
2613            NULL, HFILL}
2614         },
2615         { &hf_brsf_ag_enhanced_call_status,
2616            { "Enhanced Call Status",             "bthfp.brsf.ag.enhanced_call_status",
2617            FT_BOOLEAN, 32, NULL, 0x00000040,
2618            NULL, HFILL}
2619         },
2620         { &hf_brsf_ag_enhanced_call_control,
2621            { "Enhanced Call Control",            "bthfp.brsf.ag.enhanced_call_control",
2622            FT_BOOLEAN, 32, NULL, 0x00000080,
2623            NULL, HFILL}
2624         },
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,
2628            NULL, HFILL}
2629         },
2630         { &hf_brsf_ag_codec_negotiation,
2631            { "Codec Negotiation",                "bthfp.brsf.ag.codec_negotiation",
2632            FT_BOOLEAN, 32, NULL, 0x00000200,
2633            NULL, HFILL}
2634         },
2635         { &hf_brsf_ag_hf_indicators,
2636            { "HF Indicators",                    "bthfp.brsf.ag.hf_indicators",
2637            FT_BOOLEAN, 32, NULL, 0x00000400,
2638            NULL, HFILL}
2639         },
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,
2643            NULL, HFILL}
2644         },
2645         { &hf_brsf_ag_reserved,
2646            { "Reserved",                         "bthfp.brsf.ag.reserved",
2647            FT_UINT32, BASE_HEX, NULL, 0xFFFFF000,
2648            NULL, HFILL}
2649         },
2650         { &hf_vgs,
2651            { "Gain",                             "bthfp.vgs",
2652            FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_slash15, 0,
2653            NULL, HFILL}
2654         },
2655         { &hf_vgm,
2656            { "Gain",                             "bthfp.vgm",
2657            FT_UINT8, BASE_DEC|BASE_UNIT_STRING, &units_slash15, 0,
2658            NULL, HFILL}
2659         },
2660         { &hf_nrec,
2661            { "Noise Reduction",                  "bthfp.nrec",
2662            FT_UINT8, BASE_DEC, VALS(nrec_vals), 0,
2663            NULL, HFILL}
2664         },
2665         { &hf_bvra_vrect,
2666            { "Voice Recognition",                "bthfp.bvra.vrect",
2667            FT_UINT8, BASE_DEC, VALS(bvra_vrect_vals), 0,
2668            NULL, HFILL}
2669         },
2670         { &hf_bsir,
2671            { "Feature",                          "bthfp.bsir",
2672            FT_UINT8, BASE_DEC, VALS(bsir_vals), 0,
2673            NULL, HFILL}
2674         },
2675         { &hf_btrh,
2676            { "Feature",                          "bthfp.btrh",
2677            FT_UINT8, BASE_DEC, VALS(btrh_vals), 0,
2678            NULL, HFILL}
2679         },
2680         { &hf_cmer_mode,
2681            { "Mode",                             "bthfp.cmer.mode",
2682            FT_UINT8, BASE_DEC, NULL, 0,
2683            NULL, HFILL}
2684         },
2685         { &hf_cmer_keyp,
2686            { "Keypad",                           "bthfp.cmer.keyp",
2687            FT_UINT8, BASE_DEC, NULL, 0,
2688            NULL, HFILL}
2689         },
2690         { &hf_cmer_disp,
2691            { "Display",                          "bthfp.cmer.disp",
2692            FT_UINT8, BASE_DEC, NULL, 0,
2693            NULL, HFILL}
2694         },
2695         { &hf_cmer_ind,
2696            { "Indicator",                        "bthfp.cmer.ind",
2697            FT_UINT8, BASE_DEC, NULL, 0,
2698            NULL, HFILL}
2699         },
2700         { &hf_cmer_bfr,
2701            { "Buffer",                           "bthfp.cmer.bfr",
2702            FT_UINT8, BASE_DEC, NULL, 0,
2703            NULL, HFILL}
2704         },
2705         { &hf_bac_codec,
2706            { "Codec",                            "bthfp.bac.codec",
2707            FT_UINT8, BASE_DEC, VALS(codecs_vals), 0,
2708            NULL, HFILL}
2709         },
2710         { &hf_bcs_codec,
2711            { "Codec",                            "bthfp.bcs.codec",
2712            FT_UINT8, BASE_DEC, VALS(codecs_vals), 0,
2713            NULL, HFILL}
2714         },
2715         { &hf_binp_request,
2716            { "Request",                          "bthfp.binp.request",
2717            FT_UINT8, BASE_DEC, VALS(binp_request_vals), 0,
2718            NULL, HFILL}
2719         },
2720         { &hf_binp_response,
2721            { "Response",                         "bthfp.binp.response",
2722            FT_STRING, BASE_NONE, NULL, 0,
2723            NULL, HFILL}
2724         },
2725         { &hf_cme_error,
2726            { "CME Error",                        "bthfp.cme_error",
2727            FT_UINT8, BASE_DEC, VALS(cme_error_vals), 0,
2728            NULL, HFILL}
2729         },
2730         { &hf_cmee,
2731            { "Mode",                             "bthfp.cmee",
2732            FT_UINT8, BASE_DEC, VALS(cmee_vals), 0,
2733            NULL, HFILL}
2734         },
2735         { &hf_chld_mode,
2736            { "Mode",                             "bthfp.chld.mode_value",
2737            FT_UINT8, BASE_DEC, VALS(chld_vals), 0,
2738            NULL, HFILL}
2739         },
2740         { &hf_chld_mode_1x,
2741            { "Mode: Releases specified active call only",  "bthfp.chld.mode",
2742            FT_STRING, BASE_NONE, NULL, 0,
2743            NULL, HFILL}
2744         },
2745         { &hf_chld_mode_2x,
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,
2748            NULL, HFILL}
2749         },
2750         { &hf_chld_supported_modes,
2751            { "Supported Modes",                  "bthfp.chld.supported_modes",
2752            FT_STRING, BASE_NONE, NULL, 0,
2753            NULL, HFILL}
2754         },
2755         { &hf_ciev_indicator_index,
2756            { "Indicator Index",                  "bthfp.ciev.indicator_index",
2757            FT_UINT8, BASE_DEC, NULL, 0,
2758            NULL, HFILL}
2759         },
2760         { &hf_vts_dtmf,
2761            { "DTMF",                             "bthfp.vts.dtmf",
2762            FT_STRING, BASE_NONE, NULL, 0,
2763            NULL, HFILL}
2764         },
2765         { &hf_vts_duration,
2766            { "Duration",                         "bthfp.vts.duration",
2767            FT_UINT32, BASE_DEC, NULL, 0,
2768            NULL, HFILL}
2769         },
2770         { &hf_cops_mode,
2771            { "Mode",                             "bthfp.cops.mode",
2772            FT_UINT8, BASE_DEC, VALS(cops_mode_vals), 0,
2773            NULL, HFILL}
2774         },
2775         { &hf_cops_format,
2776            { "Format",                           "bthfp.cops.format",
2777            FT_UINT8, BASE_DEC, VALS(cops_format_vals), 0,
2778            NULL, HFILL}
2779         },
2780         { &hf_cops_operator,
2781            { "Operator",                         "bthfp.cops.operator",
2782            FT_STRING, BASE_NONE, NULL, 0,
2783            NULL, HFILL}
2784         },
2785         { &hf_cops_act,
2786            { "AcT",                              "bthfp.cops.act",
2787            FT_UINT8, BASE_DEC, VALS(cops_act_vals), 0,
2788            NULL, HFILL}
2789         },
2790         { &hf_clip_mode,
2791            { "Mode",                             "bthfp.clip.mode",
2792            FT_UINT8, BASE_DEC, VALS(clip_mode_vals), 0,
2793            NULL, HFILL}
2794         },
2795         { &hf_clip_status,
2796            { "Status",                           "bthfp.clip.status",
2797            FT_UINT8, BASE_DEC, VALS(clip_status_vals), 0,
2798            NULL, HFILL}
2799         },
2800         { &hf_at_number,
2801            { "Number",                           "bthfp.at.number",
2802            FT_STRING, BASE_NONE, NULL, 0,
2803            NULL, HFILL}
2804         },
2805         { &hf_at_type,
2806            { "Type",                             "bthfp.at.type",
2807            FT_UINT8, BASE_DEC | BASE_RANGE_STRING, RVALS(at_type_vals), 0,
2808            NULL, HFILL}
2809         },
2810         { &hf_at_subaddress,
2811            { "Subaddress",                       "bthfp.at.subaddress",
2812            FT_STRING, BASE_NONE, NULL, 0,
2813            NULL, HFILL}
2814         },
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,
2818            NULL, HFILL}
2819         },
2820         { &hf_cnum_speed,
2821            { "Speed",                            "bthfp.cnum.speed",
2822            FT_UINT8, BASE_DEC | BASE_EXT_STRING, &csd_data_rate_vals_ext, 0,
2823            NULL, HFILL}
2824         },
2825         { &hf_cnum_service,
2826            { "Service",                          "bthfp.cnum.service",
2827            FT_UINT8, BASE_DEC, VALS(cnum_service_vals), 0,
2828            NULL, HFILL}
2829         },
2830         { &hf_cnum_itc,
2831            { "Information Transfer Capability",  "bthfp.cnum.itc",
2832            FT_UINT8, BASE_DEC, VALS(cnum_itc_vals), 0,
2833            NULL, HFILL}
2834         },
2835         { &hf_at_alpha,
2836            { "Alpha",                            "bthfp.at.alpha",
2837            FT_STRING, BASE_NONE, NULL, 0,
2838            NULL, HFILL}
2839         },
2840         { &hf_at_cli_validity,
2841            { "CLI Validity",                     "bthfp.at.cli_validity",
2842            FT_UINT8, BASE_DEC, VALS(cli_validity_vals), 0,
2843            NULL, HFILL}
2844         },
2845         { &hf_at_priority,
2846            { "Priority",                         "bthfp.at.priority",
2847            FT_UINT8, BASE_DEC, NULL, 0,
2848            NULL, HFILL}
2849         },
2850         { &hf_clcc_id,
2851            { "ID",                               "bthfp.clcc.id",
2852            FT_UINT32, BASE_DEC, NULL, 0,
2853            NULL, HFILL}
2854         },
2855         { &hf_clcc_dir,
2856            { "Direction",                        "bthfp.clcc.dir",
2857            FT_UINT32, BASE_DEC, VALS(clcc_dir_vals), 0,
2858            NULL, HFILL}
2859         },
2860         { &hf_clcc_stat,
2861            { "State",                            "bthfp.clcc.stat",
2862            FT_UINT32, BASE_DEC, VALS(clcc_stat_vals), 0,
2863            NULL, HFILL}
2864         },
2865         { &hf_clcc_mode,
2866            { "Mode",                             "bthfp.clcc.mode",
2867            FT_UINT32, BASE_DEC, VALS(clcc_mode_vals), 0,
2868            NULL, HFILL}
2869         },
2870         { &hf_clcc_mpty,
2871            { "Mpty",                             "bthfp.clcc.mpty",
2872            FT_UINT32, BASE_DEC, VALS(clcc_mpty_vals), 0,
2873            NULL, HFILL}
2874         },
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,
2878            NULL, HFILL}
2879         },
2880         { &hf_ccwa_mode,
2881            { "Mode",                             "bthfp.ccwa.mode",
2882            FT_UINT32, BASE_DEC, VALS(ccwa_mode_vals), 0,
2883            NULL, HFILL}
2884         },
2885         { &hf_ccwa_class,
2886            { "Class",                             "bthfp.ccwa.class",
2887            FT_UINT32, BASE_DEC, VALS(ccwa_class_vals), 0,
2888            NULL, HFILL}
2889         },
2890         { &hf_biev_assigned_number,
2891            { "Assigned Number",                  "bthfp.biev.assigned_number",
2892            FT_UINT16, BASE_DEC, VALS(biev_assigned_number_vals), 0,
2893            NULL, HFILL}
2894         },
2895         { &hf_bind_parameter,
2896            { "Parameter",                        "bthfp.bind.parameter",
2897            FT_UINT16, BASE_DEC, NULL, 0,
2898            NULL, HFILL}
2899         },
2900         { &hf_biev_value,
2901            { "Value",                            "bthfp.biev.value",
2902            FT_UINT32, BASE_DEC, NULL, 0,
2903            NULL, HFILL}
2904         },
2905         { &hf_bia_indicator[0],
2906            { "Indicator 1",                      "bthfp.bia.indicator.1",
2907            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2908            NULL, HFILL}
2909         },
2910         { &hf_bia_indicator[1],
2911            { "Indicator 2",                      "bthfp.bia.indicator.2",
2912            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2913            NULL, HFILL}
2914         },
2915         { &hf_bia_indicator[2],
2916            { "Indicator 3",                      "bthfp.bia.indicator.3",
2917            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2918            NULL, HFILL}
2919         },
2920         { &hf_bia_indicator[3],
2921            { "Indicator 4",                      "bthfp.bia.indicator.4",
2922            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2923            NULL, HFILL}
2924         },
2925         { &hf_bia_indicator[4],
2926            { "Indicator 5",                      "bthfp.bia.indicator.5",
2927            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2928            NULL, HFILL}
2929         },
2930         { &hf_bia_indicator[5],
2931            { "Indicator 6",                      "bthfp.bia.indicator.6",
2932            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2933            NULL, HFILL}
2934         },
2935         { &hf_bia_indicator[6],
2936            { "Indicator 7",                      "bthfp.bia.indicator.7",
2937            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2938            NULL, HFILL}
2939         },
2940         { &hf_bia_indicator[7],
2941            { "Indicator 8",                      "bthfp.bia.indicator.8",
2942            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2943            NULL, HFILL}
2944         },
2945         { &hf_bia_indicator[8],
2946            { "Indicator 9",                      "bthfp.bia.indicator.9",
2947            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2948            NULL, HFILL}
2949         },
2950         { &hf_bia_indicator[9],
2951            { "Indicator 10",                     "bthfp.bia.indicator.10",
2952            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2953            NULL, HFILL}
2954         },
2955         { &hf_bia_indicator[10],
2956            { "Indicator 11",                     "bthfp.bia.indicator.11",
2957            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2958            NULL, HFILL}
2959         },
2960         { &hf_bia_indicator[11],
2961            { "Indicator 12",                     "bthfp.bia.indicator.12",
2962            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2963            NULL, HFILL}
2964         },
2965         { &hf_bia_indicator[12],
2966            { "Indicator 13",                     "bthfp.bia.indicator.13",
2967            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2968            NULL, HFILL}
2969         },
2970         { &hf_bia_indicator[13],
2971            { "Indicator 14",                     "bthfp.bia.indicator.14",
2972            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2973            NULL, HFILL}
2974         },
2975         { &hf_bia_indicator[14],
2976            { "Indicator 15",                     "bthfp.bia.indicator.15",
2977            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2978            NULL, HFILL}
2979         },
2980         { &hf_bia_indicator[15],
2981            { "Indicator 16",                     "bthfp.bia.indicator.16",
2982            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2983            NULL, HFILL}
2984         },
2985         { &hf_bia_indicator[16],
2986            { "Indicator 17",                     "bthfp.bia.indicator.17",
2987            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2988            NULL, HFILL}
2989         },
2990         { &hf_bia_indicator[17],
2991            { "Indicator 18",                     "bthfp.bia.indicator.18",
2992            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2993            NULL, HFILL}
2994         },
2995         { &hf_bia_indicator[18],
2996            { "Indicator 19",                     "bthfp.bia.indicator.19",
2997            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2998            NULL, HFILL}
2999         },
3000         { &hf_bia_indicator[19],
3001            { "Indicator 20",                     "bthfp.bia.indicator.20",
3002            FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
3003            NULL, HFILL}
3004         },
3005         { &hf_indicator[0],
3006            { "Indicator 1",                      "bthfp.indicator.1",
3007            FT_STRING, BASE_NONE, NULL, 0,
3008            NULL, HFILL}
3009         },
3010         { &hf_indicator[1],
3011            { "Indicator 2",                      "bthfp.indicator.2",
3012            FT_STRING, BASE_NONE, NULL, 0,
3013            NULL, HFILL}
3014         },
3015         { &hf_indicator[2],
3016            { "Indicator 3",                      "bthfp.indicator.3",
3017            FT_STRING, BASE_NONE, NULL, 0,
3018            NULL, HFILL}
3019         },
3020         { &hf_indicator[3],
3021            { "Indicator 4",                      "bthfp.indicator.4",
3022            FT_STRING, BASE_NONE, NULL, 0,
3023            NULL, HFILL}
3024         },
3025         { &hf_indicator[4],
3026            { "Indicator 5",                      "bthfp.indicator.5",
3027            FT_STRING, BASE_NONE, NULL, 0,
3028            NULL, HFILL}
3029         },
3030         { &hf_indicator[5],
3031            { "Indicator 6",                      "bthfp.indicator.6",
3032            FT_STRING, BASE_NONE, NULL, 0,
3033            NULL, HFILL}
3034         },
3035         { &hf_indicator[6],
3036            { "Indicator 7",                      "bthfp.indicator.7",
3037            FT_STRING, BASE_NONE, NULL, 0,
3038            NULL, HFILL}
3039         },
3040         { &hf_indicator[7],
3041            { "Indicator 8",                      "bthfp.indicator.8",
3042            FT_STRING, BASE_NONE, NULL, 0,
3043            NULL, HFILL}
3044         },
3045         { &hf_indicator[8],
3046            { "Indicator 9",                      "bthfp.indicator.9",
3047            FT_STRING, BASE_NONE, NULL, 0,
3048            NULL, HFILL}
3049         },
3050         { &hf_indicator[9],
3051            { "Indicator 10",                     "bthfp.indicator.10",
3052            FT_STRING, BASE_NONE, NULL, 0,
3053            NULL, HFILL}
3054         },
3055         { &hf_indicator[10],
3056            { "Indicator 11",                     "bthfp.indicator.11",
3057            FT_STRING, BASE_NONE, NULL, 0,
3058            NULL, HFILL}
3059         },
3060         { &hf_indicator[11],
3061            { "Indicator 12",                     "bthfp.indicator.12",
3062            FT_STRING, BASE_NONE, NULL, 0,
3063            NULL, HFILL}
3064         },
3065         { &hf_indicator[12],
3066            { "Indicator 13",                     "bthfp.indicator.13",
3067            FT_STRING, BASE_NONE, NULL, 0,
3068            NULL, HFILL}
3069         },
3070         { &hf_indicator[13],
3071            { "Indicator 14",                     "bthfp.indicator.14",
3072            FT_STRING, BASE_NONE, NULL, 0,
3073            NULL, HFILL}
3074         },
3075         { &hf_indicator[14],
3076            { "Indicator 15",                     "bthfp.indicator.15",
3077            FT_STRING, BASE_NONE, NULL, 0,
3078            NULL, HFILL}
3079         },
3080         { &hf_indicator[15],
3081            { "Indicator 16",                     "bthfp.indicator.16",
3082            FT_STRING, BASE_NONE, NULL, 0,
3083            NULL, HFILL}
3084         },
3085         { &hf_indicator[16],
3086            { "Indicator 17",                     "bthfp.indicator.17",
3087            FT_STRING, BASE_NONE, NULL, 0,
3088            NULL, HFILL}
3089         },
3090         { &hf_indicator[17],
3091            { "Indicator 18",                     "bthfp.indicator.18",
3092            FT_STRING, BASE_NONE, NULL, 0,
3093            NULL, HFILL}
3094         },
3095         { &hf_indicator[18],
3096            { "Indicator 19",                     "bthfp.indicator.19",
3097            FT_STRING, BASE_NONE, NULL, 0,
3098            NULL, HFILL}
3099         },
3100         { &hf_indicator[19],
3101            { "Indicator 20",                     "bthfp.indicator.20",
3102            FT_STRING, BASE_NONE, NULL, 0,
3103            NULL, HFILL}
3104         },
3105         { &hf_aplefm_state,
3106            { "State",                            "bthfp.aplefm.state",
3107            FT_UINT16, BASE_DEC, VALS(aplefm_state_vals), 0,
3108            NULL, HFILL}
3109         },
3110         { &hf_aplsiri_state,
3111            { "Siri State",                       "bthfp.aplsiri.state",
3112            FT_UINT16, BASE_DEC, VALS(aplsiri_state_vals), 0,
3113            NULL, HFILL}
3114         },
3115         { &hf_iphoneaccev_count,
3116            { "Count",                            "bthfp.iphoneaccev.count",
3117            FT_UINT16, BASE_DEC, NULL, 0,
3118            NULL, HFILL}
3119         },
3120         { &hf_iphoneaccev_key,
3121            { "Key",                              "bthfp.iphoneaccev.key",
3122            FT_UINT16, BASE_DEC, VALS(iphoneaccev_key_vals), 0,
3123            NULL, HFILL}
3124         },
3125         { &hf_iphoneaccev_value,
3126            { "Value",                            "bthfp.iphoneaccev.value",
3127            FT_UINT16, BASE_DEC, NULL, 0,
3128            NULL, HFILL}
3129         },
3130         { &hf_xapl_accessory_info,
3131            { "Accessory Info",                   "bthfp.xapl.accessory_info",
3132            FT_STRING, BASE_NONE, NULL, 0,
3133            NULL, HFILL}
3134         },
3135         { &hf_xapl_accessory_info_vendor_id,
3136            { "Vendor ID",                        "bthfp.xapl.accessory_info.vendor_id",
3137            FT_UINT16, BASE_HEX, NULL, 0,
3138            NULL, HFILL}
3139         },
3140         { &hf_xapl_accessory_info_product_id,
3141            { "Product ID",                       "bthfp.xapl.accessory_info.product_id",
3142            FT_UINT16, BASE_HEX, NULL, 0,
3143            NULL, HFILL}
3144         },
3145         { &hf_xapl_accessory_info_version,
3146            { "Version",                          "bthfp.xapl.accessory_info.version",
3147            FT_UINT16, BASE_HEX, NULL, 0,
3148            NULL, HFILL}
3149         },
3150         { &hf_xapl_host_info,
3151            { "Host Info",                        "bthfp.xapl.host_info",
3152            FT_STRING, BASE_NONE, NULL, 0,
3153            NULL, HFILL}
3154         },
3155         { &hf_xapl_features,
3156            { "Features",                         "bthfp.xapl.features",
3157            FT_UINT32, BASE_DEC, NULL, 0,
3158            NULL, HFILL}
3159         },
3160         { &hf_xapl_features_reserved,
3161            { "Reserved",                         "bthfp.xapl.features.reserved.0",
3162            FT_BOOLEAN, 32, NULL, 0x00000001,
3163            NULL, HFILL}
3164         },
3165         { &hf_xapl_features_battery_reporting,
3166            { "Battery Reporting",                "bthfp.xapl.features.battery_reporting",
3167            FT_BOOLEAN, 32, NULL, 0x00000002,
3168            NULL, HFILL}
3169         },
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,
3173            NULL, HFILL}
3174         },
3175         { &hf_xapl_features_siri_status_reporting,
3176            { "Siri Status Reporting",            "bthfp.xapl.features.siri_status_reporting",
3177            FT_BOOLEAN, 32, NULL, 0x00000008,
3178            NULL, HFILL}
3179         },
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,
3183            NULL, HFILL}
3184         },
3185         { &hf_xapl_features_reserved_x,
3186            { "Reserved",                         "bthfp.xapl.features.reserved.x",
3187            FT_BOOLEAN, 32, NULL, 0xFFFFFFE0,
3188            NULL, HFILL}
3189         }
3190     };
3191 
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, "Reserved value", EXPFILL }},
3203         { &ei_bac,                   { "bthfp.expert.bac", PI_PROTOCOL, PI_NOTE, "Reserved value", 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 }}
3226     };
3227 
3228     static gint *ett[] = {
3229         &ett_bthfp,
3230         &ett_bthfp_brsf_hf,
3231         &ett_bthfp_brsf_ag,
3232         &ett_bthfp_command,
3233         &ett_bthfp_parameters,
3234         &ett_bthfp_xapl_features,
3235         &ett_bthfp_xapl_accessory_info
3236     };
3237 
3238     fragments = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3239 
3240     proto_bthfp = proto_register_protocol("Bluetooth HFP Profile", "BT HFP", "bthfp");
3241     bthfp_handle = register_dissector("bthfp", dissect_bthfp, proto_bthfp);
3242 
3243     proto_register_field_array(proto_bthfp, hf, array_length(hf));
3244     proto_register_subtree_array(ett, array_length(ett));
3245 
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.");
3250 
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);
3255 
3256     expert_bthfp = expert_register_protocol(proto_bthfp);
3257     expert_register_field_array(expert_bthfp, ei, array_length(ei));
3258 }
3259 
3260 void
proto_reg_handoff_bthfp(void)3261 proto_reg_handoff_bthfp(void)
3262 {
3263     dissector_add_string("bluetooth.uuid", "111e", bthfp_handle);
3264     dissector_add_string("bluetooth.uuid", "111f", bthfp_handle);
3265 
3266     dissector_add_for_decode_as("btrfcomm.dlci", bthfp_handle);
3267 }
3268 
3269 /*
3270  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
3271  *
3272  * Local variables:
3273  * c-basic-offset: 4
3274  * tab-width: 8
3275  * indent-tabs-mode: nil
3276  * End:
3277  *
3278  * vi: set shiftwidth=4 tabstop=8 expandtab:
3279  * :indentSize=4:tabSize=8:noTabs=true:
3280  */
3281