Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-bthfp.c
blob11947208bef185b40b56d3f7b6ae7b33aaf1bdec
1 /* packet-bthfp.c
2 * Routines for Bluetooth Handsfree Profile (HFP)
4 * Copyright 2002, Wolfgang Hansmann <hansmann@cs.uni-bonn.de>
5 * Copyright 2006, Ronnie Sahlberg
6 * - refactored for Wireshark checkin
7 * Copyright 2013, Michal Labedzki for Tieto Corporation
8 * - add reassembling
9 * - dissection of HFP's AT-commands
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * SPDX-License-Identifier: GPL-2.0-or-later
18 #include "config.h"
20 #include <epan/packet.h>
21 #include <epan/prefs.h>
22 #include <epan/expert.h>
23 #include <epan/strutil.h>
24 #include <epan/unit_strings.h>
26 #include "packet-btrfcomm.h"
27 #include "packet-btsdp.h"
29 static int proto_bthfp;
31 static int hf_command;
32 static int hf_parameters;
33 static int hf_role;
34 static int hf_at_cmd;
35 static int hf_at_cmd_type;
36 static int hf_at_command_line_prefix;
37 static int hf_at_ignored;
38 static int hf_parameter;
39 static int hf_unknown_parameter;
40 static int hf_data;
41 static int hf_fragment;
42 static int hf_fragmented;
43 static int hf_brsf_hs;
44 static int hf_brsf_hs_ec_nr_function;
45 static int hf_brsf_hs_call_waiting_or_tree_way;
46 static int hf_brsf_hs_cli_presentation;
47 static int hf_brsf_hs_voice_recognition_activation;
48 static int hf_brsf_hs_remote_volume_control;
49 static int hf_brsf_hs_enhanced_call_status;
50 static int hf_brsf_hs_enhanced_call_control;
51 static int hf_brsf_hs_codec_negotiation;
52 static int hf_brsf_hs_hf_indicators;
53 static int hf_brsf_hs_esco_s4_t2_settings_support;
54 static int hf_brsf_hs_reserved;
55 static int hf_brsf_ag;
56 static int hf_brsf_ag_three_way_calling;
57 static int hf_brsf_ag_ec_nr_function;
58 static int hf_brsf_ag_voice_recognition_function;
59 static int hf_brsf_ag_inband_ring_tone;
60 static int hf_brsf_ag_attach_number_to_voice_tag;
61 static int hf_brsf_ag_ability_to_reject_a_call;
62 static int hf_brsf_ag_enhanced_call_status;
63 static int hf_brsf_ag_enhanced_call_control;
64 static int hf_brsf_ag_extended_error_result_codes;
65 static int hf_brsf_ag_codec_negotiation;
66 static int hf_brsf_ag_hf_indicators;
67 static int hf_brsf_ag_esco_s4_t2_settings_support;
68 static int hf_brsf_ag_reserved;
69 static int hf_vgs;
70 static int hf_vgm;
71 static int hf_nrec;
72 static int hf_bvra_vrect;
73 static int hf_bsir;
74 static int hf_btrh;
75 static int hf_chld_mode;
76 static int hf_chld_mode_1x;
77 static int hf_chld_mode_2x;
78 static int hf_chld_supported_modes;
79 static int hf_cmer_mode;
80 static int hf_cmer_keyp;
81 static int hf_cmer_disp;
82 static int hf_cmer_ind;
83 static int hf_cmer_bfr;
84 static int hf_cmee;
85 static int hf_cme_error;
86 static int hf_cnum_speed;
87 static int hf_cnum_service;
88 static int hf_cnum_itc;
89 static int hf_bcs_codec;
90 static int hf_bac_codec;
91 static int hf_binp_request;
92 static int hf_binp_response;
93 static int hf_ciev_indicator_index;
94 static int hf_vts_dtmf;
95 static int hf_vts_duration;
96 static int hf_cops_mode;
97 static int hf_cops_format;
98 static int hf_cops_operator;
99 static int hf_cops_act;
100 static int hf_at_number;
101 static int hf_at_type;
102 static int hf_at_subaddress;
103 static int hf_at_subaddress_type;
104 static int hf_at_alpha;
105 static int hf_at_priority;
106 static int hf_at_cli_validity;
107 static int hf_clip_mode;
108 static int hf_clip_status;
109 static int hf_clcc_id;
110 static int hf_clcc_dir;
111 static int hf_clcc_stat;
112 static int hf_clcc_mode;
113 static int hf_clcc_mpty;
114 static int hf_ccwa_show_result_code;
115 static int hf_ccwa_mode;
116 static int hf_ccwa_class;
117 static int hf_biev_assigned_number;
118 static int hf_biev_value;
119 static int hf_bind_parameter;
120 static int hf_bia_indicator[20];
121 static int hf_indicator[20];
122 static int hf_aplefm_state;
123 static int hf_aplsiri_state;
124 static int hf_iphoneaccev_count;
125 static int hf_iphoneaccev_key;
126 static int hf_iphoneaccev_value;
127 static int hf_xapl_accessory_info;
128 static int hf_xapl_accessory_info_vendor_id;
129 static int hf_xapl_accessory_info_product_id;
130 static int hf_xapl_accessory_info_version;
131 static int hf_xapl_host_info;
132 static int hf_xapl_features;
133 static int hf_xapl_features_reserved_x;
134 static int hf_xapl_features_noise_reduction_status_reporting;
135 static int hf_xapl_features_siri_status_reporting;
136 static int hf_xapl_features_docked_or_powered;
137 static int hf_xapl_features_battery_reporting;
138 static int hf_xapl_features_reserved;
140 static expert_field ei_non_mandatory_command;
141 static expert_field ei_invalid_usage;
142 static expert_field ei_unknown_parameter;
143 static expert_field ei_brfs_hs_reserved_bits;
144 static expert_field ei_brfs_ag_reserved_bits;
145 static expert_field ei_vgm_gain;
146 static expert_field ei_vgs_gain;
147 static expert_field ei_nrec;
148 static expert_field ei_bvra;
149 static expert_field ei_bcs;
150 static expert_field ei_bac;
151 static expert_field ei_bsir;
152 static expert_field ei_btrh;
153 static expert_field ei_binp;
154 static expert_field ei_biev_assigned_number;
155 static expert_field ei_biev_assigned_number_no;
156 static expert_field ei_bia;
157 static expert_field ei_cmer_mode;
158 static expert_field ei_cmer_keyp;
159 static expert_field ei_cmer_disp;
160 static expert_field ei_cmer_ind;
161 static expert_field ei_cmer_btr;
162 static expert_field ei_chld_mode;
163 static expert_field ei_ciev_indicator;
164 static expert_field ei_vts_dtmf;
165 static expert_field ei_at_type;
166 static expert_field ei_cnum_service;
167 static expert_field ei_cnum_itc;
168 static expert_field ei_aplefm_out_of_range;
169 static expert_field ei_aplsiri_out_of_range;
170 static expert_field ei_iphoneaccev_key_out_of_range;
171 static expert_field ei_xapl_features_reserved;
172 static expert_field ei_parameter_blank;
174 static int ett_bthfp;
175 static int ett_bthfp_command;
176 static int ett_bthfp_parameters;
177 static int ett_bthfp_brsf_hf;
178 static int ett_bthfp_brsf_ag;
179 static int ett_bthfp_xapl_features;
180 static int ett_bthfp_xapl_accessory_info;
182 static dissector_handle_t bthfp_handle;
184 static wmem_tree_t *fragments;
186 #define ROLE_UNKNOWN 0
187 #define ROLE_AG 1
188 #define ROLE_HS 2
190 #define TYPE_UNKNOWN 0x0000
191 #define TYPE_RESPONSE_ACK 0x0d0a
192 #define TYPE_RESPONSE 0x003a
193 #define TYPE_ACTION 0x003d
194 #define TYPE_ACTION_SIMPLY 0x000d
195 #define TYPE_READ 0x003f
196 #define TYPE_TEST 0x3d3f
198 static int hfp_role = ROLE_UNKNOWN;
200 enum reassemble_state_t {
201 REASSEMBLE_FRAGMENT,
202 REASSEMBLE_PARTIALLY,
203 REASSEMBLE_DONE
206 typedef struct _fragment_t {
207 uint32_t interface_id;
208 uint32_t adapter_id;
209 uint32_t chandle;
210 uint32_t dlci;
211 uint32_t role;
213 unsigned idx;
214 unsigned length;
215 uint8_t *data;
216 struct _fragment_t *previous_fragment;
218 unsigned reassemble_start_offset;
219 unsigned reassemble_end_offset;
220 enum reassemble_state_t reassemble_state;
221 } fragment_t;
223 typedef struct _at_cmd_t {
224 const char *name;
225 const char *long_name;
227 bool (*check_command)(int role, uint16_t type);
228 bool (*dissect_parameter)(tvbuff_t *tvb, packet_info *pinfo,
229 proto_tree *tree, int offset, int role, uint16_t type,
230 uint8_t *parameter_stream, unsigned parameter_number,
231 int parameter_length, void **data);
232 } at_cmd_t;
234 static const value_string role_vals[] = {
235 { ROLE_UNKNOWN, "Unknown" },
236 { ROLE_AG, "AG - Audio Gate" },
237 { ROLE_HS, "HS - Headset" },
238 { 0, NULL }
241 static const value_string at_cmd_type_vals[] = {
242 { 0x0d, "Action Command" },
243 { 0x3a, "Response" },
244 { 0x3d, "Action Command" },
245 { 0x3f, "Read Command" },
246 { 0x0d0a, "Response" },
247 { 0x3d3f, "Test Command" },
248 { 0, NULL }
251 static const enum_val_t pref_hfp_role[] = {
252 { "off", "Off", ROLE_UNKNOWN },
253 { "ag", "Sent is AG, Rcvd is HS", ROLE_AG },
254 { "hs", "Sent is HS, Rcvd is AG", ROLE_HS },
255 { NULL, NULL, 0 }
258 static const value_string nrec_vals[] = {
259 { 0x00, "Disable EC/NR in the AG" },
260 { 0, NULL }
263 static const value_string bvra_vrect_vals[] = {
264 { 0x00, "Disable Voice recognition in the AG" },
265 { 0x01, "Enable Voice recognition in the AG" },
266 { 0, NULL }
269 static const value_string bsir_vals[] = {
270 { 0x00, "The AG provides no in-band ring tone" },
271 { 0x01, "The AG provides an in-band ring tone" },
272 { 0, NULL }
275 static const value_string btrh_vals[] = {
276 { 0x00, "Incoming call is put on hold in the AG" },
277 { 0x01, "Held incoming call is accepted in the AG" },
278 { 0x02, "Held incoming call is rejected in the AG" },
279 { 0, NULL }
282 static const value_string codecs_vals[] = {
283 { 0x01, "CVSD" },
284 { 0x02, "mSBC" },
285 { 0, NULL }
288 static const value_string binp_request_vals[] = {
289 { 0x01, "Phone number corresponding to the last voice tag recorded in the HF" },
290 { 0, NULL }
293 static const value_string indicator_vals[] = {
294 { 0x00, "Deactivate" },
295 { 0x01, "Activate" },
296 { 0, NULL }
299 static const value_string cme_error_vals[] = {
300 { 0, "Phone/AG failure" },
301 { 1, "No Connection to Phone" },
302 { 2, "Phone-adaptor Link Reserved" },
303 { 3, "Operation not Allowed" },
304 { 4, "Operation not Supported" },
305 { 5, "PH-SIM PIN required" },
306 { 6, "PH-FSIM PIN Required" },
307 { 7, "PH-FSIM PUK Required" },
308 { 10, "SIM not Inserted" },
309 { 11, "SIM PIN Required" },
310 { 12, "SIM PUK Required" },
311 { 13, "SIM Failure" },
312 { 14, "SIM Busy" },
313 { 15, "SIM Wrong" },
314 { 16, "Incorrect Password" },
315 { 17, "SIM PIN2 Required" },
316 { 18, "SIM PUK2 Required" },
317 { 20, "Memory Full" },
318 { 21, "Invalid Index" },
319 { 22, "Not Found" },
320 { 23, "Memory Failure" },
321 { 24, "Text String too Long" },
322 { 25, "Invalid Characters in Text String" },
323 { 26, "Dial String too Long" },
324 { 27, "Invalid Characters in Dial String" },
325 { 30, "No Network Service" },
326 { 31, "Network Timeout" },
327 { 32, "Network not Allowed - Emergency Calls Only" },
328 { 40, "Network Personalization PIN Required" },
329 { 41, "Network Personalization PUK Required" },
330 { 42, "Network Subset Personalization PIN Required" },
331 { 43, "Network Subset Personalization PUK Required" },
332 { 44, "Service Provider Personalization PIN Required" },
333 { 45, "Service Provider Personalization PUK Required" },
334 { 46, "Corporate Personalization PIN Required" },
335 { 47, "Corporate Personalization PUK Required" },
336 { 48, "Hidden Key Required" },
337 { 49, "EAP Method not Supported" },
338 { 50, "Incorrect Parameters" },
339 { 100, "Unknown" },
340 { 0, NULL }
343 static const value_string cmee_vals[] = {
344 { 0, "Disabled" },
345 { 1, "Enabled" },
346 { 2, "Verbose" },
347 { 0, NULL }
350 static const value_string chld_vals[] = {
351 { 0, "Releases all held calls or sets User Determined User Busy (UDUB) for a waiting call" },
352 { 1, "Releases all active calls (if any exist) and accepts the other (held or waiting) call" },
353 { 2, "Places all active calls (if any exist) on hold and accepts the other (held or waiting) call" },
354 { 3, "Adds a held call to the conversation" },
355 { 4, "Connects the two calls and disconnects the subscriber from both calls (Explicit Call Transfer)" },
356 { 0, NULL }
359 static const value_string cops_mode_vals[] = {
360 { 0, "Automatic" },
361 { 1, "Manual" },
362 { 2, "Deregister from Network" },
363 { 3, "Set Only Format" },
364 { 4, "Manual/Automatic" },
365 { 0, NULL }
368 static const value_string cops_format_vals[] = {
369 { 0, "Long Format Alphanumeric" },
370 { 1, "Short Format Alphanumeric" },
371 { 2, "Numeric" },
372 { 0, NULL }
375 static const value_string cops_act_vals[] = {
376 { 0, "GSM" },
377 { 1, "GSM Compact" },
378 { 2, "UTRAN" },
379 { 0, NULL }
382 static const range_string at_type_vals[] = {
383 { 128, 143, "The phone number format may be a national or international format, and may contain prefix and/or escape digits. No changes on the number presentation are required." },
384 { 144, 159, "The phone number format is an international number, including the country code prefix. If the plus sign (\"+\") is not included as part of the number and shall be added by the AG as needed." },
385 { 160, 175, "National number. No prefix nor escape digits included." },
386 { 0, 0, NULL }
389 static const value_string cli_validity_vals[] = {
390 { 0, "CLI Valid" },
391 { 1, "CLI has been withheld by the originator" },
392 { 2, "CLI is not available due to interworking problems or limitations of originating network" },
393 { 0, NULL }
396 static const value_string cnum_service_vals[] = {
397 { 0, "Asynchronous Modem" },
398 { 1, "Synchronous Modem" },
399 { 2, "PAD Access" },
400 { 3, "Packet Access" },
401 { 4, "Voice" },
402 { 5, "Fax" },
403 { 0, NULL }
406 static const value_string cnum_itc_vals[] = {
407 { 0, "3.1 kHz" },
408 { 1, "UDI" },
409 { 0, NULL }
412 static const value_string clip_mode_vals[] = {
413 { 0, "Disabled" },
414 { 1, "Enabled" },
415 { 0, NULL }
418 static const value_string clip_status_vals[] = {
419 { 0, "CLIP not Provisioned" },
420 { 1, "CLIP Provisioned" },
421 { 2, "Unknown" },
422 { 0, NULL }
425 static const value_string clcc_dir_vals[] = {
426 { 0, "Mobile Originated" },
427 { 1, "Mobile Terminated" },
428 { 0, NULL }
431 static const value_string clcc_stat_vals[] = {
432 { 0, "Active" },
433 { 1, "Held" },
434 { 2, "Dialing" },
435 { 3, "Alerting" },
436 { 4, "Incoming" },
437 { 5, "Waiting" },
438 { 0, NULL }
441 static const value_string clcc_mode_vals[] = {
442 { 0, "Voice" },
443 { 1, "Data" },
444 { 2, "Fax" },
445 { 3, "Voice Followed by Data, Voice Mode" },
446 { 4, "Alternating Voice/Data, Voice Mode" },
447 { 5, "Alternating Voice/Fax, Voice Mode" },
448 { 6, "Voice Followed by Data, Data Mode" },
449 { 7, "Alternating Voice/Data, Data Mode" },
450 { 8, "Alternating Voice/Fax, Fax Mode" },
451 { 9, "Unknown" },
452 { 0, NULL }
455 static const value_string clcc_mpty_vals[] = {
456 { 0, "Call is not one of multiparty (conference) call parties" },
457 { 1, "Call is one of multiparty (conference) call parties" },
458 { 0, NULL }
461 static const value_string ccwa_show_result_code_vals[] = {
462 { 0, "Disabled" },
463 { 1, "Enabled" },
464 { 0, NULL }
467 static const value_string ccwa_mode_vals[] = {
468 { 0, "Disabled" },
469 { 1, "Enabled" },
470 { 2, "Query Status" },
471 { 0, NULL }
474 static const value_string ccwa_class_vals[] = {
475 { 1, "Voice" },
476 { 2, "Data" },
477 { 4, "Fax" },
478 { 8, "Short Message Service" },
479 { 16, "Data Circuit Sync" },
480 { 32, "Data Circuit Async" },
481 { 64, "Dedicated Packet Access" },
482 { 128, "Dedicated PAD Access" },
483 { 0, NULL }
486 static const value_string biev_assigned_number_vals[] = {
487 { 1, "Enhanced Safety" },
488 { 2, "Battery Level" },
489 { 0, NULL }
492 static const value_string aplefm_state_vals[] = {
493 { 0, "Disable" },
494 { 1, "Enable" },
495 { 0, NULL }
498 static const value_string aplsiri_state_vals[] = {
499 { 1, "Enabled" },
500 { 2, "Disabled" },
501 { 0, NULL }
504 static const value_string iphoneaccev_key_vals[] = {
505 { 1, "Battery Level" },
506 { 2, "Dock State" },
507 { 0, NULL }
511 static const unit_name_string units_slash15 = { "/15", NULL };
513 extern value_string_ext csd_data_rate_vals_ext;
515 void proto_register_bthfp(void);
516 void proto_reg_handoff_bthfp(void);
518 static uint32_t get_uint_parameter(uint8_t *parameter_stream, int parameter_length)
520 uint32_t value;
521 char *val;
523 val = (char *) wmem_alloc(wmem_packet_scope(), parameter_length + 1);
524 memcpy(val, parameter_stream, parameter_length);
525 val[parameter_length] = '\0';
526 value = (uint32_t) g_ascii_strtoull(val, NULL, 10);
528 return value;
531 static uint32_t get_uint_hex_parameter(uint8_t *parameter_stream, int parameter_length)
533 uint32_t value;
534 char *val;
536 val = (char *) wmem_alloc(wmem_packet_scope(), parameter_length + 1);
537 memcpy(val, parameter_stream, parameter_length);
538 val[parameter_length] = '\0';
539 value = (uint32_t) g_ascii_strtoull(val, NULL, 16);
541 return value;
544 static bool check_aplefm(int role, uint16_t type) {
545 if (role == ROLE_HS && type == TYPE_ACTION) return true;
546 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
548 return false;
551 static bool check_aplsiri(int role, uint16_t type) {
552 if (role == ROLE_HS && type == TYPE_READ) return true;
553 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
555 return false;
558 static bool check_iphoneaccev(int role, uint16_t type) {
559 if (role == ROLE_HS && type == TYPE_ACTION) return true;
561 return false;
564 static bool check_xapl(int role, uint16_t type) {
565 if (role == ROLE_HS && type == TYPE_ACTION) return true;
566 if (role == ROLE_AG && (type == TYPE_RESPONSE || type == TYPE_ACTION)) return true;
568 return false;
571 static bool check_biev(int role, uint16_t type) {
572 if (role == ROLE_HS && type == TYPE_ACTION) return true;
574 return false;
577 static bool check_bind(int role, uint16_t type) {
578 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
579 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
581 return false;
584 static bool check_bac(int role, uint16_t type) {
585 if (role == ROLE_HS && type == TYPE_ACTION) return true;
587 return false;
590 static bool check_bcs(int role, uint16_t type) {
591 if (role == ROLE_HS && type == TYPE_ACTION) return true;
592 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
594 return false;
597 static bool check_bcc(int role, uint16_t type) {
598 if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return true;
600 return false;
603 static bool check_bia(int role, uint16_t type) {
604 if (role == ROLE_HS && type == TYPE_ACTION) return true;
606 return false;
609 static bool check_binp(int role, uint16_t type) {
610 if (role == ROLE_HS && type == TYPE_ACTION) return true;
611 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
613 return false;
616 static bool check_bldn(int role, uint16_t type) {
617 if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return true;
619 return false;
622 static bool check_bvra(int role, uint16_t type) {
623 if (role == ROLE_HS && type == TYPE_ACTION) return true;
624 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
626 return false;
629 static bool check_brsf(int role, uint16_t type) {
630 if (role == ROLE_HS && type == TYPE_ACTION) return true;
631 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
633 return false;
636 static bool check_nrec(int role, uint16_t type) {
637 if (role == ROLE_HS && type == TYPE_ACTION) return true;
639 return false;
642 static bool check_vgs(int role, uint16_t type) {
643 if (role == ROLE_HS && type == TYPE_ACTION) return true;
644 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
646 return false;
649 static bool check_vgm(int role, uint16_t type) {
650 if (role == ROLE_HS && type == TYPE_ACTION) return true;
651 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
653 return false;
656 static bool check_bsir(int role, uint16_t type) {
657 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
659 return false;
662 static bool check_btrh(int role, uint16_t type) {
663 if (role == ROLE_HS && (type == TYPE_READ || type == TYPE_ACTION)) return true;
664 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
666 return false;
669 static bool check_only_ag_role(int role, uint16_t type) {
670 if (role == ROLE_AG && type == TYPE_RESPONSE_ACK) return true;
672 return false;
675 static bool check_only_hs_role(int role, uint16_t type) {
676 if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return true;
678 return false;
681 static bool check_ccwa(int role, uint16_t type) {
682 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
683 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
685 return false;
688 static bool check_chld(int role, uint16_t type) {
689 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
690 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
692 return false;
695 static bool check_chup(int role, uint16_t type) {
696 if (role == ROLE_HS && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
698 return false;
701 static bool check_clcc(int role, uint16_t type) {
702 if (role == ROLE_HS && (type == TYPE_ACTION_SIMPLY || type == TYPE_TEST)) return true;
703 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
705 return false;
708 static bool check_cind(int role, uint16_t type) {
709 if (role == ROLE_HS && (type == TYPE_READ || type == TYPE_TEST)) return true;
710 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
712 return false;
715 static bool check_cmer(int role, uint16_t type) {
716 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
717 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
719 return false;
722 static bool check_cops(int role, uint16_t type) {
723 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ)) return true;
724 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
726 return false;
729 static bool check_cmee(int role, uint16_t type) {
730 if (role == ROLE_HS && type == TYPE_ACTION) return true;
732 return false;
735 static bool check_cme(int role, uint16_t type) {
736 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
738 return false;
741 static bool check_clip(int role, uint16_t type) {
742 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ || type == TYPE_TEST)) return true;
743 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
745 return false;
748 static bool check_ciev(int role, uint16_t type) {
749 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
751 return false;
754 static bool check_vts(int role, uint16_t type) {
755 if (role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_TEST)) return true;
756 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
758 return false;
761 static bool check_cnum(int role, uint16_t type) {
762 if (role == ROLE_HS && type == TYPE_ACTION_SIMPLY) return true;
763 if (role == ROLE_AG && type == TYPE_RESPONSE) return true;
765 return false;
768 static bool
769 dissect_brsf_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
770 int offset, int role, uint16_t type, uint8_t *parameter_stream,
771 unsigned parameter_number, int parameter_length, void **data _U_)
773 proto_item *pitem;
774 uint32_t value;
776 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
777 (role == ROLE_AG && type == TYPE_RESPONSE))) {
778 return false;
781 if (parameter_number > 0) return false;
783 value = get_uint_parameter(parameter_stream, parameter_length);
785 if (role == ROLE_HS) {
786 static int * const hs[] = {
787 &hf_brsf_hs_ec_nr_function,
788 &hf_brsf_hs_call_waiting_or_tree_way,
789 &hf_brsf_hs_cli_presentation,
790 &hf_brsf_hs_voice_recognition_activation,
791 &hf_brsf_hs_remote_volume_control,
792 &hf_brsf_hs_enhanced_call_status,
793 &hf_brsf_hs_enhanced_call_control,
794 &hf_brsf_hs_codec_negotiation,
795 &hf_brsf_hs_hf_indicators,
796 &hf_brsf_hs_esco_s4_t2_settings_support,
797 &hf_brsf_hs_reserved,
798 NULL
801 pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_brsf_hs, ett_bthfp_brsf_hf, hs, value, BMT_NO_APPEND);
802 if (value >> 10) {
803 expert_add_info(pinfo, pitem, &ei_brfs_hs_reserved_bits);
805 } else {
806 static int * const ag[] = {
807 &hf_brsf_ag_three_way_calling,
808 &hf_brsf_ag_ec_nr_function,
809 &hf_brsf_ag_voice_recognition_function,
810 &hf_brsf_ag_inband_ring_tone,
811 &hf_brsf_ag_attach_number_to_voice_tag,
812 &hf_brsf_ag_ability_to_reject_a_call,
813 &hf_brsf_ag_enhanced_call_status,
814 &hf_brsf_ag_enhanced_call_control,
815 &hf_brsf_ag_extended_error_result_codes,
816 &hf_brsf_ag_codec_negotiation,
817 &hf_brsf_ag_hf_indicators,
818 &hf_brsf_ag_esco_s4_t2_settings_support,
819 &hf_brsf_ag_reserved,
820 NULL
823 pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_brsf_ag, ett_bthfp_brsf_ag, ag, value, BMT_NO_APPEND);
825 if (value >> 12) {
826 expert_add_info(pinfo, pitem, &ei_brfs_ag_reserved_bits);
830 return true;
833 static bool
834 dissect_vgs_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
835 int offset, int role, uint16_t type, uint8_t *parameter_stream,
836 unsigned parameter_number, int parameter_length, void **data _U_)
838 proto_item *pitem;
839 uint32_t value;
841 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
842 (role == ROLE_AG && type == TYPE_RESPONSE))) {
843 return false;
846 if (parameter_number > 0) return false;
848 value = get_uint_parameter(parameter_stream, parameter_length);
850 pitem = proto_tree_add_uint(tree, hf_vgs, tvb, offset, parameter_length, value);
852 if (value > 15) {
853 expert_add_info(pinfo, pitem, &ei_vgs_gain);
856 return true;
859 static bool
860 dissect_vgm_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
861 int offset, int role, uint16_t type, uint8_t *parameter_stream,
862 unsigned parameter_number, int parameter_length, void **data _U_)
864 proto_item *pitem;
865 uint32_t value;
867 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
868 (role == ROLE_AG && type == TYPE_RESPONSE))) {
869 return false;
872 if (parameter_number > 0) return false;
874 value = get_uint_parameter(parameter_stream, parameter_length);
876 pitem = proto_tree_add_uint(tree, hf_vgm, tvb, offset, parameter_length, value);
878 if (value > 15) {
879 expert_add_info(pinfo, pitem, &ei_vgm_gain);
882 return true;
885 static bool
886 dissect_nrec_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
887 int offset, int role, uint16_t type, uint8_t *parameter_stream,
888 unsigned parameter_number, int parameter_length, void **data _U_)
890 proto_item *pitem;
891 uint32_t value;
893 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
894 (role == ROLE_AG && type == TYPE_RESPONSE))) {
895 return false;
898 if (parameter_number > 0) return false;
900 value = get_uint_parameter(parameter_stream, parameter_length);
902 pitem = proto_tree_add_uint(tree, hf_nrec, tvb, offset, parameter_length, value);
904 if (value != 0) {
905 expert_add_info(pinfo, pitem, &ei_nrec);
908 return true;
911 static bool
912 dissect_bvra_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
913 int offset, int role, uint16_t type, uint8_t *parameter_stream,
914 unsigned parameter_number, int parameter_length, void **data _U_)
916 proto_item *pitem;
917 uint32_t value;
919 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
920 (role == ROLE_AG && type == TYPE_RESPONSE))) {
921 return false;
924 if (parameter_number > 0) return false;
926 value = get_uint_parameter(parameter_stream, parameter_length);
928 pitem = proto_tree_add_uint(tree, hf_bvra_vrect, tvb, offset, parameter_length, value);
930 if (value > 1) {
931 expert_add_info(pinfo, pitem, &ei_bvra);
934 return true;
937 static bool
938 dissect_bcs_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
939 int offset, int role, uint16_t type, uint8_t *parameter_stream,
940 unsigned parameter_number, int parameter_length, void **data _U_)
942 proto_item *pitem;
943 uint32_t value;
945 if (!check_bcs(role, type)) {
946 return false;
949 if (parameter_number > 0) return false;
951 value = get_uint_parameter(parameter_stream, parameter_length);
953 pitem = proto_tree_add_uint(tree, hf_bcs_codec, tvb, offset, parameter_length, value);
955 if (value < 1 || value > 2) {
956 expert_add_info(pinfo, pitem, &ei_bcs);
959 return true;
962 static bool
963 dissect_bac_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
964 int offset, int role, uint16_t type, uint8_t *parameter_stream,
965 unsigned parameter_number _U_, int parameter_length, void **data _U_)
967 proto_item *pitem;
968 uint32_t value;
970 if (!check_bac(role, type)) {
971 return false;
974 value = get_uint_parameter(parameter_stream, parameter_length);
976 pitem = proto_tree_add_uint(tree, hf_bac_codec, tvb, offset, parameter_length, value);
978 if (value < 1 || value > 2) {
979 expert_add_info(pinfo, pitem, &ei_bac);
982 return true;
985 static bool
986 dissect_bind_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
987 int offset, int role, uint16_t type, uint8_t *parameter_stream,
988 unsigned parameter_number, int parameter_length, void **data _U_)
990 uint32_t value;
992 if (!check_bind(role, type)) return false;
994 /* TODO Need to implement request-response tracking to recognise answer to AT+BIND? vs unsolicited */
995 if (parameter_number < 20) {
996 value = get_uint_parameter(parameter_stream, parameter_length);
998 proto_tree_add_uint(tree, hf_bind_parameter, tvb, offset,
999 parameter_length, value);
1001 return true;
1004 return false;
1007 static bool
1008 dissect_aplefm_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1009 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1010 unsigned parameter_number, int parameter_length, void **data _U_)
1012 proto_item *pitem;
1013 uint32_t value;
1015 if (!check_aplefm(role, type)) return false;
1017 if (parameter_number == 0) {
1018 value = get_uint_parameter(parameter_stream, parameter_length);
1020 pitem = proto_tree_add_uint(tree, hf_aplefm_state, tvb, offset,
1021 parameter_length, value);
1023 if (value > 1) {
1024 expert_add_info(pinfo, pitem, &ei_aplefm_out_of_range);
1026 } else return false;
1028 return true;
1031 static bool
1032 dissect_aplsiri_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1033 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1034 unsigned parameter_number, int parameter_length, void **data _U_)
1036 proto_item *pitem;
1037 uint32_t value;
1039 if (!check_aplsiri(role, type)) return false;
1041 if (parameter_number == 0) {
1042 value = get_uint_parameter(parameter_stream, parameter_length);
1044 pitem = proto_tree_add_uint(tree, hf_aplsiri_state, tvb, offset,
1045 parameter_length, value);
1047 if (value < 1 || value > 2) {
1048 expert_add_info(pinfo, pitem, &ei_aplsiri_out_of_range);
1050 } else return false;
1052 return true;
1055 static bool
1056 dissect_iphoneaccev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1057 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1058 unsigned parameter_number, int parameter_length, void **data _U_)
1060 proto_item *pitem;
1061 uint32_t value;
1063 if (!check_iphoneaccev(role, type)) return false;
1065 if (parameter_number == 0) {
1066 value = get_uint_parameter(parameter_stream, parameter_length);
1068 proto_tree_add_uint(tree, hf_iphoneaccev_count, tvb, offset,
1069 parameter_length, value);
1070 } else if (parameter_number % 2 == 1) {
1071 value = get_uint_parameter(parameter_stream, parameter_length);
1073 pitem = proto_tree_add_uint(tree, hf_iphoneaccev_key, tvb, offset,
1074 parameter_length, value);
1076 if (value < 1 || value > 2) {
1077 expert_add_info(pinfo, pitem, &ei_iphoneaccev_key_out_of_range);
1079 } else {
1080 value = get_uint_parameter(parameter_stream, parameter_length);
1082 proto_tree_add_uint(tree, hf_iphoneaccev_value, tvb, offset,
1083 parameter_length, value);
1086 return true;
1089 static bool
1090 dissect_xapl_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1091 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1092 unsigned parameter_number, int parameter_length, void **data _U_)
1094 proto_item *pitem;
1095 proto_tree *ptree;
1096 uint32_t value;
1098 if (!check_xapl(role, type)) return false;
1100 if (parameter_number == 0) {
1101 if (role == ROLE_HS) {
1102 pitem = proto_tree_add_item(tree, hf_xapl_accessory_info, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1103 ptree = proto_item_add_subtree(pitem, ett_bthfp_xapl_accessory_info);
1105 value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 0, 4);
1106 proto_tree_add_uint(ptree, hf_xapl_accessory_info_vendor_id, tvb, offset, 4, value);
1108 value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 1, 4);
1109 proto_tree_add_uint(ptree, hf_xapl_accessory_info_product_id, tvb, offset + (4 + 1) * 1, 4, value);
1111 value = get_uint_hex_parameter(parameter_stream + (4 + 1) * 2, 4);
1112 proto_tree_add_uint(ptree, hf_xapl_accessory_info_version, tvb, offset + (4 + 1) * 2, 4, value);
1113 } else {
1114 proto_tree_add_item(tree, hf_xapl_host_info, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1116 } else if (parameter_number == 1) {
1117 static int * const hfx[] = {
1118 &hf_xapl_features_reserved_x,
1119 &hf_xapl_features_noise_reduction_status_reporting,
1120 &hf_xapl_features_siri_status_reporting,
1121 &hf_xapl_features_docked_or_powered,
1122 &hf_xapl_features_battery_reporting,
1123 &hf_xapl_features_reserved,
1124 NULL
1127 value = get_uint_parameter(parameter_stream, parameter_length);
1129 pitem = proto_tree_add_bitmask_value_with_flags(tree, tvb, offset, hf_xapl_features, ett_bthfp_xapl_features, hfx, value, BMT_NO_APPEND);
1131 if (value >> 5) {
1132 expert_add_info(pinfo, pitem, &ei_xapl_features_reserved);
1134 } else return false;
1136 return true;
1139 static bool
1140 dissect_biev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1141 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1142 unsigned parameter_number, int parameter_length, void **data _U_)
1144 proto_item *pitem;
1145 uint32_t value;
1147 if (!check_biev(role, type)) return false;
1148 if (parameter_number == 0) {
1149 value = get_uint_parameter(parameter_stream, parameter_length);
1151 pitem = proto_tree_add_uint(tree, hf_biev_assigned_number, tvb, offset,
1152 parameter_length, value);
1154 if (value > 65535) {
1155 expert_add_info(pinfo, pitem, &ei_biev_assigned_number);
1156 } else if (value > 2) {
1157 expert_add_info(pinfo, pitem, &ei_biev_assigned_number_no);
1159 } else if (parameter_number == 1) {
1160 value = get_uint_parameter(parameter_stream, parameter_length);
1161 /* TODO: Decode assigned numbers - assigned_number=1 */
1162 /*pitem =*/ proto_tree_add_uint(tree, hf_biev_value, tvb, offset,
1163 parameter_length, value);
1164 } else return false;
1166 return true;
1169 static bool
1170 dissect_no_parameter(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_,
1171 int offset _U_, int role _U_, uint16_t type _U_, uint8_t *parameter_stream _U_,
1172 unsigned parameter_number _U_, int parameter_length _U_, void **data _U_)
1174 return false;
1177 static bool
1178 dissect_bsir_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1179 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1180 unsigned parameter_number, int parameter_length, void **data _U_)
1182 proto_item *pitem;
1183 uint32_t value;
1185 if (!(role == ROLE_AG && type == TYPE_RESPONSE)) {
1186 return false;
1189 if (parameter_number > 0) return false;
1191 value = get_uint_parameter(parameter_stream, parameter_length);
1193 pitem = proto_tree_add_uint(tree, hf_bsir, tvb, offset, parameter_length, value);
1195 if (value > 1) {
1196 expert_add_info(pinfo, pitem, &ei_bsir);
1199 return true;
1202 static bool
1203 dissect_btrh_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1204 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1205 unsigned parameter_number, int parameter_length, void **data _U_)
1207 proto_item *pitem;
1208 uint32_t value;
1210 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
1211 (role == ROLE_AG && type == TYPE_RESPONSE))) {
1212 return false;
1215 if (parameter_number > 0) return false;
1217 value = get_uint_parameter(parameter_stream, parameter_length);
1219 pitem = proto_tree_add_uint(tree, hf_btrh, tvb, offset, parameter_length, value);
1221 if (value != 0) {
1222 expert_add_info(pinfo, pitem, &ei_btrh);
1225 return true;
1229 static bool
1230 dissect_binp_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1231 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1232 unsigned parameter_number, int parameter_length, void **data _U_)
1234 proto_item *pitem;
1235 uint32_t value;
1237 if (!((role == ROLE_HS && type == TYPE_ACTION) ||
1238 (role == ROLE_AG && type == TYPE_RESPONSE))) {
1239 return false;
1242 if (role == ROLE_HS && type == TYPE_ACTION) {
1243 if (parameter_number == 0) {
1244 value = get_uint_parameter(parameter_stream, parameter_length);
1246 pitem = proto_tree_add_uint(tree, hf_binp_request, tvb, offset,
1247 parameter_length, value);
1249 if (value != 1) {
1250 expert_add_info(pinfo, pitem, &ei_binp);
1252 } else return false;
1253 } else {
1254 proto_tree_add_item(tree, hf_binp_response, tvb, offset,
1255 parameter_length, ENC_NA | ENC_ASCII);
1257 return true;
1260 static bool
1261 dissect_bia_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1262 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1263 unsigned parameter_number, int parameter_length, void **data _U_)
1265 proto_item *pitem;
1266 uint32_t value;
1268 if (!((role == ROLE_HS && type == TYPE_ACTION))) return false;
1269 if (parameter_number > 19) return false;
1271 value = get_uint_parameter(parameter_stream, parameter_length);
1273 pitem = proto_tree_add_uint(tree, hf_bia_indicator[parameter_number], tvb,
1274 offset, parameter_length, value);
1275 if (value > 1) {
1276 expert_add_info(pinfo, pitem, &ei_bia);
1279 return true;
1282 static bool
1283 dissect_cind_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1284 int offset, int role, uint16_t type, uint8_t *parameter_stream _U_,
1285 unsigned parameter_number, int parameter_length, void **data _U_)
1287 if (!check_cind(role, type)) return false;
1288 if (parameter_number > 19) return false;
1290 proto_tree_add_item(tree, hf_indicator[parameter_number], tvb, offset,
1291 parameter_length, ENC_NA | ENC_ASCII);
1293 return true;
1296 static bool
1297 dissect_chld_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1298 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1299 unsigned parameter_number, int parameter_length, void **data _U_)
1301 uint32_t value;
1303 if (!check_chld(role, type)) return false;
1305 if (role == ROLE_HS && type == TYPE_ACTION && parameter_number == 0) {
1306 value = get_uint_parameter(parameter_stream, 1);
1308 if (parameter_length >= 2) {
1309 if (tvb_get_uint8(tvb, offset + 1) == 'x') {
1310 if (value == 1)
1311 proto_tree_add_item(tree, hf_chld_mode_1x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1312 else if (value == 2)
1313 proto_tree_add_item(tree, hf_chld_mode_2x, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1316 if (tvb_get_uint8(tvb, offset + 1) != 'x' || value > 4) {
1317 proto_tree_add_expert(tree, pinfo, &ei_chld_mode, tvb, offset, parameter_length);
1321 proto_tree_add_uint(tree, hf_chld_mode, tvb, offset, parameter_length, value);
1322 return true;
1325 /* Type == Test */
1326 proto_tree_add_item(tree, hf_chld_supported_modes, tvb, offset,
1327 parameter_length, ENC_NA | ENC_ASCII);
1329 return true;
1332 static bool
1333 dissect_ccwa_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1334 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1335 unsigned parameter_number, int parameter_length, void **data _U_)
1337 proto_item *pitem;
1338 uint32_t value;
1340 if (!check_ccwa(role, type)) return false;
1342 if (role == ROLE_HS && parameter_number > 2) return false;
1343 if (role == ROLE_AG && parameter_number > 7) return false;
1345 if (role == ROLE_HS) switch (parameter_number) {
1346 case 0:
1347 value = get_uint_parameter(parameter_stream, parameter_length);
1348 proto_tree_add_uint(tree, hf_ccwa_show_result_code, tvb, offset, parameter_length, value);
1349 break;
1350 case 1:
1351 value = get_uint_parameter(parameter_stream, parameter_length);
1352 proto_tree_add_uint(tree, hf_ccwa_mode, tvb, offset, parameter_length, value);
1353 break;
1354 case 2:
1355 value = get_uint_parameter(parameter_stream, parameter_length);
1356 proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
1357 break;
1360 /* If AT+CCWA = 1 */
1361 if (role == ROLE_AG) switch (parameter_number) {
1362 case 0:
1363 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1364 break;
1365 case 1:
1366 value = get_uint_parameter(parameter_stream, parameter_length);
1367 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1368 if (value < 128 || value > 175)
1369 expert_add_info(pinfo, pitem, &ei_at_type);
1370 break;
1371 case 2:
1372 value = get_uint_parameter(parameter_stream, parameter_length);
1373 proto_tree_add_uint(tree, hf_ccwa_class, tvb, offset, parameter_length, value);
1374 break;
1375 case 3:
1376 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1377 break;
1378 case 4:
1379 value = get_uint_parameter(parameter_stream, parameter_length);
1380 proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
1381 break;
1382 case 5:
1383 proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1384 break;
1385 case 6:
1386 value = get_uint_parameter(parameter_stream, parameter_length);
1387 proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
1388 break;
1389 case 7:
1390 value = get_uint_parameter(parameter_stream, parameter_length);
1391 proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
1392 break;
1395 return true;
1398 static bool
1399 dissect_cmer_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1400 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1401 unsigned parameter_number, int parameter_length, void **data _U_)
1403 proto_item *pitem;
1404 uint32_t value;
1406 if (!((role == ROLE_HS && type == TYPE_ACTION))) {
1407 return false;
1410 if (parameter_number > 4) return false;
1412 value = get_uint_parameter(parameter_stream, parameter_length);
1414 switch (parameter_number) {
1415 case 0:
1416 pitem = proto_tree_add_uint(tree, hf_cmer_mode, tvb, offset, parameter_length, value);
1417 if (value != 3)
1418 expert_add_info(pinfo, pitem, &ei_cmer_mode);
1419 break;
1420 case 1:
1421 pitem = proto_tree_add_uint(tree, hf_cmer_keyp, tvb, offset, parameter_length, value);
1422 if (value != 0)
1423 expert_add_info(pinfo, pitem, &ei_cmer_keyp);
1424 break;
1425 case 2:
1426 pitem = proto_tree_add_uint(tree, hf_cmer_disp, tvb, offset, parameter_length, value);
1427 if (value != 0)
1428 expert_add_info(pinfo, pitem, &ei_cmer_disp);
1429 break;
1430 case 3:
1431 pitem = proto_tree_add_uint(tree, hf_cmer_ind, tvb, offset, parameter_length, value);
1432 if (value > 1)
1433 expert_add_info(pinfo, pitem, &ei_cmer_ind);
1434 break;
1435 case 4:
1436 pitem = proto_tree_add_uint(tree, hf_cmer_bfr, tvb, offset, parameter_length, value);
1437 if (value != 0)
1438 expert_add_info(pinfo, pitem, &ei_cmer_btr);
1439 break;
1442 return true;
1445 static bool
1446 dissect_clip_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1447 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1448 unsigned parameter_number, int parameter_length, void **data _U_)
1450 proto_item *pitem;
1451 uint32_t value;
1453 if (!check_clip(role, type))
1454 return false;
1456 if (role == ROLE_HS && type == TYPE_ACTION && parameter_number > 1)
1457 return false;
1458 else if (role == ROLE_AG && parameter_number > 5)
1459 return false;
1461 if (role == ROLE_HS && type == TYPE_ACTION) switch (parameter_number) {
1462 case 0:
1463 value = get_uint_parameter(parameter_stream, parameter_length);
1464 proto_tree_add_uint(tree, hf_clip_mode, tvb, offset, parameter_length, value);
1465 break;
1466 case 1:
1467 value = get_uint_parameter(parameter_stream, parameter_length);
1468 proto_tree_add_uint(tree, hf_clip_status, tvb, offset, parameter_length, value);
1469 break;
1470 } else {
1471 switch (parameter_number) {
1472 case 0:
1473 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1474 break;
1475 case 1:
1476 value = get_uint_parameter(parameter_stream, parameter_length);
1477 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1478 if (value < 128 || value > 175)
1479 expert_add_info(pinfo, pitem, &ei_at_type);
1480 break;
1481 case 2:
1482 proto_tree_add_item(tree, hf_at_subaddress, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1483 break;
1484 case 3:
1485 value = get_uint_parameter(parameter_stream, parameter_length);
1486 proto_tree_add_uint(tree, hf_at_subaddress_type, tvb, offset, parameter_length, value);
1487 break;
1488 case 4:
1489 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1490 break;
1491 case 5:
1492 value = get_uint_parameter(parameter_stream, parameter_length);
1493 proto_tree_add_uint(tree, hf_at_cli_validity, tvb, offset, parameter_length, value);
1494 break;
1498 return true;
1501 static bool
1502 dissect_cmee_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1503 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1504 unsigned parameter_number, int parameter_length, void **data _U_)
1506 uint32_t value;
1508 if (!(role == ROLE_HS && type == TYPE_ACTION)) {
1509 return false;
1512 if (parameter_number > 0) return false;
1514 value = get_uint_parameter(parameter_stream, parameter_length);
1515 proto_tree_add_uint(tree, hf_cmee, tvb, offset, parameter_length, value);
1517 return true;
1520 static bool
1521 dissect_cops_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1522 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1523 unsigned parameter_number, int parameter_length, void **data _U_)
1525 uint32_t value;
1527 if (!((role == ROLE_HS && (type == TYPE_ACTION || type == TYPE_READ)) ||
1528 (role == ROLE_AG && type == TYPE_RESPONSE))) {
1529 return false;
1532 if (parameter_number > 3) return false;
1534 switch (parameter_number) {
1535 case 0:
1536 value = get_uint_parameter(parameter_stream, parameter_length);
1537 proto_tree_add_uint(tree, hf_cops_mode, tvb, offset, parameter_length, value);
1538 break;
1539 case 1:
1540 value = get_uint_parameter(parameter_stream, parameter_length);
1541 proto_tree_add_uint(tree, hf_cops_format, tvb, offset, parameter_length, value);
1542 break;
1543 case 2:
1544 proto_tree_add_item(tree, hf_cops_operator, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1545 break;
1546 case 3:
1547 value = get_uint_parameter(parameter_stream, parameter_length);
1548 proto_tree_add_uint(tree, hf_cops_act, tvb, offset, parameter_length, value);
1549 break;
1552 return true;
1555 static bool
1556 dissect_clcc_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1557 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1558 unsigned parameter_number, int parameter_length, void **data _U_)
1560 proto_item *pitem;
1561 uint32_t value;
1563 if (!((role == ROLE_HS && type == TYPE_ACTION_SIMPLY) ||
1564 (role == ROLE_AG && type == TYPE_RESPONSE))) {
1565 return false;
1568 if (parameter_number > 8) return false;
1570 switch (parameter_number) {
1571 case 0:
1572 value = get_uint_parameter(parameter_stream, parameter_length);
1573 proto_tree_add_uint(tree, hf_clcc_id, tvb, offset, parameter_length, value);
1574 break;
1575 case 1:
1576 value = get_uint_parameter(parameter_stream, parameter_length);
1577 proto_tree_add_uint(tree, hf_clcc_dir, tvb, offset, parameter_length, value);
1578 break;
1579 case 2:
1580 value = get_uint_parameter(parameter_stream, parameter_length);
1581 proto_tree_add_uint(tree, hf_clcc_stat, tvb, offset, parameter_length, value);
1582 break;
1583 case 3:
1584 value = get_uint_parameter(parameter_stream, parameter_length);
1585 proto_tree_add_uint(tree, hf_clcc_mode, tvb, offset, parameter_length, value);
1586 break;
1587 case 4:
1588 value = get_uint_parameter(parameter_stream, parameter_length);
1589 proto_tree_add_uint(tree, hf_clcc_mpty, tvb, offset, parameter_length, value);
1590 break;
1591 case 5:
1592 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1593 break;
1594 case 6:
1595 value = get_uint_parameter(parameter_stream, parameter_length);
1596 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1597 if (value < 128 || value > 175)
1598 expert_add_info(pinfo, pitem, &ei_at_type);
1599 break;
1600 case 7:
1601 proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1602 break;
1603 case 8:
1604 value = get_uint_parameter(parameter_stream, parameter_length);
1605 proto_tree_add_uint(tree, hf_at_priority, tvb, offset, parameter_length, value);
1606 break;
1609 return true;
1613 static bool
1614 dissect_cme_error_parameter(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *tree,
1615 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1616 unsigned parameter_number, int parameter_length, void **data _U_)
1618 uint32_t value;
1620 if (!(role == ROLE_AG && type == TYPE_RESPONSE)) {
1621 return false;
1624 if (parameter_number > 0) return false;
1626 value = get_uint_parameter(parameter_stream, parameter_length);
1627 proto_tree_add_uint(tree, hf_cme_error, tvb, offset, parameter_length, value);
1629 return true;
1632 static bool
1633 dissect_cnum_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1634 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1635 unsigned parameter_number, int parameter_length, void **data _U_)
1637 proto_item *pitem;
1638 uint32_t value;
1640 if (!(role == ROLE_AG && type == TYPE_RESPONSE)) return true;
1641 if (parameter_number > 5) return false;
1643 switch (parameter_number) {
1644 case 0:
1645 pitem = proto_tree_add_item(tree, hf_at_alpha, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1646 if (parameter_length > 0)
1647 expert_add_info(pinfo, pitem, &ei_parameter_blank);
1648 break;
1649 case 1:
1650 proto_tree_add_item(tree, hf_at_number, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1651 break;
1652 case 2:
1653 value = get_uint_parameter(parameter_stream, parameter_length);
1654 pitem = proto_tree_add_uint(tree, hf_at_type, tvb, offset, parameter_length, value);
1655 if (value < 128 || value > 175)
1656 expert_add_info(pinfo, pitem, &ei_at_type);
1657 break;
1658 case 3:
1659 value = get_uint_parameter(parameter_stream, parameter_length);
1660 pitem = proto_tree_add_uint(tree, hf_cnum_speed, tvb, offset, parameter_length, value);
1661 if (parameter_length > 0)
1662 expert_add_info(pinfo, pitem, &ei_parameter_blank);
1663 break;
1664 case 4:
1665 value = get_uint_parameter(parameter_stream, parameter_length);
1666 pitem = proto_tree_add_uint(tree, hf_cnum_service, tvb, offset, parameter_length, value);
1667 if (value > 5)
1668 expert_add_info(pinfo, pitem, &ei_cnum_service);
1669 break;
1670 case 5:
1671 value = get_uint_parameter(parameter_stream, parameter_length);
1672 pitem = proto_tree_add_uint(tree, hf_cnum_itc, tvb, offset, parameter_length, value);
1673 if (value > 1)
1674 expert_add_info(pinfo, pitem, &ei_cnum_itc);
1675 break;
1678 return true;
1681 static bool
1682 dissect_vts_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1683 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1684 unsigned parameter_number, int parameter_length, void **data _U_)
1686 proto_item *pitem;
1687 uint32_t value;
1689 if (!(role == ROLE_HS && type == TYPE_ACTION)) return true;
1690 if (parameter_number > 1) return false;
1692 switch (parameter_number) {
1693 case 0:
1694 pitem = proto_tree_add_item(tree, hf_vts_dtmf, tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1695 if (parameter_length != 1)
1696 expert_add_info(pinfo, pitem, &ei_vts_dtmf);
1697 break;
1698 case 1:
1699 value = get_uint_parameter(parameter_stream, parameter_length);
1700 proto_tree_add_uint(tree, hf_vts_duration, tvb, offset, parameter_length, value);
1701 break;
1704 return true;
1707 static bool
1708 dissect_ciev_parameter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1709 int offset, int role, uint16_t type, uint8_t *parameter_stream,
1710 unsigned parameter_number, int parameter_length, void **data)
1712 uint32_t value;
1713 unsigned indicator_index;
1715 if (!(role == ROLE_AG && type == TYPE_RESPONSE)) return true;
1716 if (parameter_number > 1) return false;
1718 switch (parameter_number) {
1719 case 0:
1720 value = get_uint_parameter(parameter_stream, parameter_length);
1721 proto_tree_add_uint(tree, hf_ciev_indicator_index, tvb, offset, parameter_length, value);
1722 *data = wmem_alloc(pinfo->pool, sizeof(unsigned));
1723 *((unsigned *) *data) = value;
1724 break;
1725 case 1:
1726 indicator_index = *((unsigned *) *data) - 1;
1727 if (indicator_index > 19) {
1728 proto_tree_add_expert(tree, pinfo, &ei_ciev_indicator, tvb, offset, parameter_length);
1729 } else {
1730 proto_tree_add_item(tree, hf_indicator[indicator_index], tvb, offset, parameter_length, ENC_NA | ENC_ASCII);
1732 break;
1735 return true;
1738 /* TODO: Some commands need to save request command type (request with TYPE_READ vs TYPE_TEST, etc.)
1739 to properly dissect response parameters.
1740 Some commands can use TYPE_TEST respose to properly dissect parameters,
1741 for example: AT+CIND=?, AT+CIND? */
1742 static const at_cmd_t at_cmds[] = {
1743 /* Vendor specific: Apple */
1744 { "+XAPL", "Apple Bluetooth Accessory Identification", check_xapl, dissect_xapl_parameter },
1745 { "+IPHONEACCEV", "Apple Bluetooth Headset Battery Level Indication", check_iphoneaccev, dissect_iphoneaccev_parameter },
1746 { "+APLSIRI", "Apple Siri Availability Information", check_aplsiri, dissect_aplsiri_parameter },
1747 { "+APLEFM", "Apple Siri Eyes Free Mode", check_aplefm, dissect_aplefm_parameter },
1748 /* Bluetooth HFP specific AT Commands */
1749 { "+BIEV", "Bluetooth Indicator Enter Value", check_biev, dissect_biev_parameter }, /* HFP 1.7 */
1750 { "+BIND", "Bluetooth Indicator", check_bind, dissect_bind_parameter }, /* HFP 1.7 */
1751 { "+BAC", "Bluetooth Available Codecs", check_bac, dissect_bac_parameter },
1752 { "+BCS", "Bluetooth Codec Selection", check_bcs, dissect_bcs_parameter },
1753 { "+BCC", "Bluetooth Codec Connection", check_bcc, dissect_no_parameter },
1754 { "+BTRH", "Bluetooth Response and Hold Feature", check_btrh, dissect_btrh_parameter },
1755 { "+BSIR", "Bluetooth Setting of In-band Ring Tone", check_bsir, dissect_bsir_parameter },
1756 { "+VGS", "Gain of Speaker", check_vgs, dissect_vgs_parameter },
1757 { "+VGM", "Gain of Microphone", check_vgm, dissect_vgm_parameter },
1758 { "+NREC", "Noise Reduction and Echo Cancelling", check_nrec, dissect_nrec_parameter },
1759 { "+BRSF", "Bluetooth Retrieve Supported Features", check_brsf, dissect_brsf_parameter },
1760 { "+BVRA", "Bluetooth Voice Recognition Activation", check_bvra, dissect_bvra_parameter },
1761 { "+BLDN", "Bluetooth Last Dialled Number", check_bldn, dissect_no_parameter },
1762 { "+BINP", "Bluetooth Input", check_binp, dissect_binp_parameter },
1763 { "+BIA", "Bluetooth Indicators Activation", check_bia, dissect_bia_parameter },
1764 /* Inherited from normal AT Commands */
1765 { "+CCWA", "Call Waiting Notification", check_ccwa, dissect_ccwa_parameter },
1766 { "+CHLD", "Call Hold and Multiparty Handling", check_chld, dissect_chld_parameter },
1767 { "+CHUP", "Call Hang-up", check_chup, dissect_no_parameter },
1768 { "+CIND", "Phone Indicators", check_cind, dissect_cind_parameter },
1769 { "+CLCC", "Current Calls", check_clcc, dissect_clcc_parameter },
1770 { "+COPS", "Reading Network Operator", check_cops, dissect_cops_parameter },
1771 { "+CMEE", "Mobile Equipment Error", check_cmee, dissect_cmee_parameter },
1772 { "+CME ERROR", "Extended Audio Gateway Error Result Code", check_cme, dissect_cme_error_parameter },
1773 { "+CLIP", "Calling Line Identification Notification", check_clip, dissect_clip_parameter },
1774 { "+CMER", "Event Reporting Activation/Deactivation", check_cmer, dissect_cmer_parameter },
1775 { "+CIEV", "Indicator Events Reporting", check_ciev, dissect_ciev_parameter },
1776 { "+VTS", "DTMF and tone generation", check_vts, dissect_vts_parameter },
1777 { "+CNUM", "Subscriber Number Information", check_cnum, dissect_cnum_parameter },
1778 { "ERROR", "ERROR", check_only_ag_role, dissect_no_parameter },
1779 { "RING", "Incoming Call Indication", check_only_ag_role, dissect_no_parameter },
1780 { "OK", "OK", check_only_ag_role, dissect_no_parameter },
1781 { "D", "Dial", check_only_hs_role, NULL },
1782 { "A", "Call Answer", check_only_hs_role, dissect_no_parameter },
1783 { NULL, NULL, NULL, NULL }
1787 static int
1788 dissect_at_command(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1789 int offset, uint32_t role, int command_number)
1791 proto_item *pitem;
1792 proto_tree *command_item = NULL;
1793 proto_item *command_tree = NULL;
1794 proto_tree *parameters_item = NULL;
1795 proto_item *parameters_tree = NULL;
1796 uint8_t *col_str = NULL;
1797 uint8_t *at_stream;
1798 uint8_t *at_command = NULL;
1799 int i_char = 0;
1800 unsigned i_char_fix = 0;
1801 int length;
1802 const at_cmd_t *i_at_cmd;
1803 int parameter_length;
1804 unsigned parameter_number = 0;
1805 int first_parameter_offset = offset;
1806 int last_parameter_offset = offset;
1807 uint16_t type = TYPE_UNKNOWN;
1808 uint32_t brackets;
1809 bool quotation;
1810 bool next;
1811 void *data;
1813 length = tvb_reported_length_remaining(tvb, offset);
1814 if (length <= 0)
1815 return tvb_reported_length(tvb);
1817 if (!command_number) {
1818 proto_tree_add_item(tree, hf_data, tvb, offset, length, ENC_NA | ENC_ASCII);
1819 col_str = (uint8_t *) wmem_alloc(pinfo->pool, length + 1);
1820 tvb_memcpy(tvb, col_str, offset, length);
1821 col_str[length] = '\0';
1824 at_stream = (uint8_t *) wmem_alloc(pinfo->pool, length + 1);
1825 tvb_memcpy(tvb, at_stream, offset, length);
1826 at_stream[length] = '\0';
1828 while (at_stream[i_char]) {
1829 at_stream[i_char] = g_ascii_toupper(at_stream[i_char]);
1830 if (!command_number) {
1831 col_str[i_char] = g_ascii_toupper(col_str[i_char]);
1832 if (!g_ascii_isgraph(col_str[i_char])) col_str[i_char] = ' ';
1834 i_char += 1;
1837 if (!command_number) col_append_str(pinfo->cinfo, COL_INFO, col_str);
1839 if (role == ROLE_HS) {
1840 if (command_number) {
1841 at_command = at_stream;
1842 i_char = 0;
1843 } else {
1844 at_command = g_strstr_len(at_stream, length, "AT");
1845 if (at_command) {
1846 command_item = proto_tree_add_none_format(tree, hf_command, tvb,
1847 offset, 0, "Command %u", command_number);
1848 command_tree = proto_item_add_subtree(command_item, ett_bthfp_command);
1850 i_char = (unsigned) (at_command - at_stream);
1851 if (i_char) {
1852 proto_tree_add_item(command_tree, hf_at_ignored, tvb, offset,
1853 i_char, ENC_NA | ENC_ASCII);
1854 offset += i_char;
1857 proto_tree_add_item(command_tree, hf_at_command_line_prefix,
1858 tvb, offset, 2, ENC_NA | ENC_ASCII);
1859 offset += 2;
1860 i_char += 2;
1861 at_command = at_stream;
1862 at_command += i_char;
1863 length -= i_char;
1864 i_char_fix += i_char;
1865 i_char = 0;
1868 } else if (at_stream[0] == '\r' && at_stream[1] == '\n') {
1869 command_item = proto_tree_add_none_format(tree, hf_command, tvb,
1870 offset, 0, "Command %u", command_number);
1871 command_tree = proto_item_add_subtree(command_item, ett_bthfp_command);
1873 at_command = at_stream;
1874 i_char = 0;
1875 while (i_char <= length &&
1876 (at_command[i_char] == '\r' || at_command[i_char] == '\n' ||
1877 at_command[i_char] == ' ' || at_command[i_char] == '\t')) {
1878 /* ignore white characters */
1879 i_char += 1;
1882 offset += i_char;
1883 at_command += i_char;
1884 length -= i_char;
1885 i_char_fix += i_char;
1886 i_char = 0;
1889 if (at_command) {
1891 while (i_char < length &&
1892 (at_command[i_char] != '\r' && at_command[i_char] != '=' &&
1893 at_command[i_char] != ';' && at_command[i_char] != '?' &&
1894 at_command[i_char] != ':')) {
1895 i_char += 1;
1898 i_at_cmd = at_cmds;
1899 if (at_command[0] == '\r') {
1900 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset - 2,
1901 2, ENC_NA | ENC_ASCII);
1902 i_at_cmd = NULL;
1903 } else {
1904 pitem = NULL;
1905 while (i_at_cmd->name) {
1906 if (g_str_has_prefix(&at_command[0], i_at_cmd->name)) {
1907 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
1908 (int) strlen(i_at_cmd->name), ENC_NA | ENC_ASCII);
1909 proto_item_append_text(pitem, " (%s)", i_at_cmd->long_name);
1910 break;
1912 i_at_cmd += 1;
1915 if (!pitem) {
1916 pitem = proto_tree_add_item(command_tree, hf_at_cmd, tvb, offset,
1917 i_char, ENC_NA | ENC_ASCII);
1922 if (i_at_cmd && i_at_cmd->name == NULL) {
1923 char *name;
1925 name = format_text(pinfo->pool, at_command, i_char + 1);
1926 proto_item_append_text(command_item, ": %s (Unknown)", name);
1927 proto_item_append_text(pitem, " (Unknown - Non-Standard HFP Command)");
1928 expert_add_info(pinfo, pitem, &ei_non_mandatory_command);
1929 } else if (i_at_cmd == NULL) {
1930 proto_item_append_text(command_item, ": AT");
1931 } else {
1932 proto_item_append_text(command_item, ": %s", i_at_cmd->name);
1935 offset += i_char;
1937 if (i_at_cmd && g_strcmp0(i_at_cmd->name, "D")) {
1938 if (length >= 2 && at_command[i_char] == '=' && at_command[i_char + 1] == '?') {
1939 type = at_command[i_char] << 8 | at_command[i_char + 1];
1940 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
1941 offset += 2;
1942 i_char += 2;
1943 } else if (role == ROLE_AG && length >= 2 && at_command[i_char] == '\r' && at_command[i_char + 1] == '\n') {
1944 type = at_command[i_char] << 8 | at_command[i_char + 1];
1945 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 2, type);
1946 offset += 2;
1947 i_char += 2;
1948 } else if (length >= 1 && (at_command[i_char] == '=' ||
1949 at_command[i_char] == '\r' ||
1950 at_command[i_char] == ':' ||
1951 at_command[i_char] == '?')) {
1952 type = at_command[i_char];
1953 proto_tree_add_uint(command_tree, hf_at_cmd_type, tvb, offset, 1, type);
1954 offset += 1;
1955 i_char += 1;
1959 if (i_at_cmd && i_at_cmd->check_command && !i_at_cmd->check_command(role, type)) {
1960 expert_add_info(pinfo, command_item, &ei_invalid_usage);
1963 parameters_item = proto_tree_add_none_format(command_tree, hf_parameters, tvb,
1964 offset, 0, "Parameters");
1965 parameters_tree = proto_item_add_subtree(parameters_item, ett_bthfp_parameters);
1966 first_parameter_offset = offset;
1968 data = NULL;
1970 while (i_char < length) {
1972 while (at_command[i_char] == ' ' || at_command[i_char] == '\t') {
1973 offset += 1;
1974 i_char += 1;
1977 parameter_length = 0;
1978 brackets = 0;
1979 quotation = false;
1980 next = false;
1982 if (at_command[i_char + parameter_length] != '\r') {
1983 while (i_char + parameter_length < length &&
1984 at_command[i_char + parameter_length] != '\r') {
1986 if (at_command[i_char + parameter_length] == ';') {
1987 next = true;
1988 break;
1991 if (at_command[i_char + parameter_length] == '"') {
1992 quotation = quotation ? false : true;
1995 if (quotation == true) {
1996 parameter_length += 1;
1997 continue;
2000 if (at_command[i_char + parameter_length] == '(') {
2001 brackets += 1;
2003 if (at_command[i_char + parameter_length] == ')') {
2004 brackets -= 1;
2007 if (brackets == 0 && at_command[i_char + parameter_length] == ',') {
2008 break;
2011 parameter_length += 1;
2014 if (type == TYPE_ACTION || type == TYPE_RESPONSE) {
2015 if (i_at_cmd && (i_at_cmd->dissect_parameter != NULL &&
2016 !i_at_cmd->dissect_parameter(tvb, pinfo, parameters_tree, offset, role,
2017 type, &at_command[i_char], parameter_number, parameter_length, &data) )) {
2018 pitem = proto_tree_add_item(parameters_tree,
2019 hf_unknown_parameter, tvb, offset,
2020 parameter_length, ENC_NA | ENC_ASCII);
2021 expert_add_info(pinfo, pitem, &ei_unknown_parameter);
2022 } else if (i_at_cmd && i_at_cmd->dissect_parameter == NULL) {
2023 proto_tree_add_item(parameters_tree, hf_parameter, tvb, offset,
2024 parameter_length, ENC_NA | ENC_ASCII);
2029 if (type != TYPE_ACTION_SIMPLY && type != TYPE_RESPONSE_ACK && type != TYPE_TEST && type != TYPE_READ)
2030 parameter_number += 1;
2031 i_char += parameter_length;
2032 offset += parameter_length;
2033 last_parameter_offset = offset;
2035 if (role == ROLE_AG &&
2036 i_char + 1 <= length &&
2037 at_command[i_char] == '\r' &&
2038 at_command[i_char + 1] == '\n') {
2039 offset += 2;
2040 i_char += 2;
2041 break;
2042 } else if (at_command[i_char] == ',' ||
2043 at_command[i_char] == '\r' ||
2044 at_command[i_char] == ';') {
2045 i_char += 1;
2046 offset += 1;
2049 if (next) break;
2052 i_char += i_char_fix;
2053 proto_item_set_len(command_item, i_char);
2054 } else {
2055 length = tvb_reported_length_remaining(tvb, offset);
2056 if (length < 0)
2057 length = 0;
2058 offset += length;
2061 if (parameter_number > 0 && last_parameter_offset - first_parameter_offset > 0)
2062 proto_item_set_len(parameters_item, last_parameter_offset - first_parameter_offset);
2063 else
2064 proto_item_append_text(parameters_item, ": No");
2066 return offset;
2069 static int
2070 dissect_bthfp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
2072 proto_item *main_item;
2073 proto_tree *main_tree;
2074 proto_item *pitem;
2075 int offset = 0;
2076 uint32_t role = ROLE_UNKNOWN;
2077 wmem_tree_key_t key[10];
2078 uint32_t interface_id;
2079 uint32_t adapter_id;
2080 uint32_t chandle;
2081 uint32_t dlci;
2082 uint32_t frame_number;
2083 uint32_t direction;
2084 uint32_t bd_addr_oui;
2085 uint32_t bd_addr_id;
2086 fragment_t *fragment;
2087 fragment_t *previous_fragment;
2088 fragment_t *i_fragment;
2089 uint8_t *at_stream;
2090 int length;
2091 int command_number;
2092 int i_length;
2093 tvbuff_t *reassembled_tvb = NULL;
2094 unsigned reassemble_start_offset = 0;
2095 unsigned reassemble_end_offset = 0;
2096 int previous_proto;
2098 previous_proto = (GPOINTER_TO_INT(wmem_list_frame_data(wmem_list_frame_prev(wmem_list_tail(pinfo->layers)))));
2099 if (data && previous_proto == proto_btrfcomm) {
2100 btrfcomm_data_t *rfcomm_data;
2102 rfcomm_data = (btrfcomm_data_t *) data;
2104 interface_id = rfcomm_data->interface_id;
2105 adapter_id = rfcomm_data->adapter_id;
2106 chandle = rfcomm_data->chandle;
2107 dlci = rfcomm_data->dlci;
2108 direction = (rfcomm_data->is_local_psm) ? P2P_DIR_SENT : P2P_DIR_RECV;
2110 if (direction == P2P_DIR_RECV) {
2111 bd_addr_oui = rfcomm_data->remote_bd_addr_oui;
2112 bd_addr_id = rfcomm_data->remote_bd_addr_id;
2113 } else {
2114 bd_addr_oui = 0;
2115 bd_addr_id = 0;
2117 } else {
2118 interface_id = HCI_INTERFACE_DEFAULT;
2119 adapter_id = HCI_ADAPTER_DEFAULT;
2120 chandle = 0;
2121 dlci = 0;
2122 direction = P2P_DIR_UNKNOWN;
2124 bd_addr_oui = 0;
2125 bd_addr_id = 0;
2128 main_item = proto_tree_add_item(tree, proto_bthfp, tvb, 0, tvb_captured_length(tvb), ENC_NA);
2129 main_tree = proto_item_add_subtree(main_item, ett_bthfp);
2131 col_set_str(pinfo->cinfo, COL_PROTOCOL, "HFP");
2133 switch (pinfo->p2p_dir) {
2134 case P2P_DIR_SENT:
2135 col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
2136 break;
2137 case P2P_DIR_RECV:
2138 col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
2139 break;
2140 default:
2141 col_set_str(pinfo->cinfo, COL_INFO, "UnknownDirection ");
2142 break;
2145 if ((hfp_role == ROLE_AG && pinfo->p2p_dir == P2P_DIR_SENT) ||
2146 (hfp_role == ROLE_HS && pinfo->p2p_dir == P2P_DIR_RECV)) {
2147 role = ROLE_AG;
2148 } else if (hfp_role != ROLE_UNKNOWN) {
2149 role = ROLE_HS;
2152 if (role == ROLE_UNKNOWN) {
2153 uint32_t sdp_psm;
2154 uint32_t service_type;
2155 uint32_t service_channel;
2156 service_info_t *service_info;
2158 sdp_psm = SDP_PSM_DEFAULT;
2160 service_type = BTSDP_RFCOMM_PROTOCOL_UUID;
2161 service_channel = dlci >> 1;
2162 frame_number = pinfo->num;
2164 key[0].length = 1;
2165 key[0].key = &interface_id;
2166 key[1].length = 1;
2167 key[1].key = &adapter_id;
2168 key[2].length = 1;
2169 key[2].key = &sdp_psm;
2170 key[3].length = 1;
2171 key[3].key = &direction;
2172 key[4].length = 1;
2173 key[4].key = &bd_addr_oui;
2174 key[5].length = 1;
2175 key[5].key = &bd_addr_id;
2176 key[6].length = 1;
2177 key[6].key = &service_type;
2178 key[7].length = 1;
2179 key[7].key = &service_channel;
2180 key[8].length = 1;
2181 key[8].key = &frame_number;
2182 key[9].length = 0;
2183 key[9].key = NULL;
2185 service_info = btsdp_get_service_info(key);
2186 if (service_info && service_info->interface_id == interface_id &&
2187 service_info->adapter_id == adapter_id &&
2188 service_info->sdp_psm == SDP_PSM_DEFAULT &&
2189 ((service_info->direction == P2P_DIR_RECV &&
2190 service_info->bd_addr_oui == bd_addr_oui &&
2191 service_info->bd_addr_id == bd_addr_id) ||
2192 (service_info->direction != P2P_DIR_RECV &&
2193 service_info->bd_addr_oui == 0 &&
2194 service_info->bd_addr_id == 0)) &&
2195 service_info->type == BTSDP_RFCOMM_PROTOCOL_UUID &&
2196 service_info->channel == (dlci >> 1)) {
2197 if ((service_info->uuid.bt_uuid == BTSDP_HFP_GW_SERVICE_UUID && service_info->direction == P2P_DIR_RECV && pinfo->p2p_dir == P2P_DIR_SENT) ||
2198 (service_info->uuid.bt_uuid == BTSDP_HFP_GW_SERVICE_UUID && service_info->direction == P2P_DIR_SENT && pinfo->p2p_dir == P2P_DIR_RECV) ||
2199 (service_info->uuid.bt_uuid == BTSDP_HFP_SERVICE_UUID && service_info->direction == P2P_DIR_RECV && pinfo->p2p_dir == P2P_DIR_RECV) ||
2200 (service_info->uuid.bt_uuid == BTSDP_HFP_SERVICE_UUID && service_info->direction == P2P_DIR_SENT && pinfo->p2p_dir == P2P_DIR_SENT)) {
2201 role = ROLE_HS;
2202 } else {
2203 role = ROLE_AG;
2208 pitem = proto_tree_add_uint(main_tree, hf_role, tvb, 0, 0, role);
2209 proto_item_set_generated(pitem);
2211 if (role == ROLE_UNKNOWN) {
2212 col_append_fstr(pinfo->cinfo, COL_INFO, "Data: %s",
2213 tvb_format_text(pinfo->pool, tvb, 0, tvb_reported_length(tvb)));
2214 proto_tree_add_item(main_tree, hf_data, tvb, 0, tvb_captured_length(tvb), ENC_NA | ENC_ASCII);
2215 return tvb_reported_length(tvb);
2218 /* save fragments */
2219 if (!pinfo->fd->visited) {
2220 frame_number = pinfo->num - 1;
2222 key[0].length = 1;
2223 key[0].key = &interface_id;
2224 key[1].length = 1;
2225 key[1].key = &adapter_id;
2226 key[2].length = 1;
2227 key[2].key = &chandle;
2228 key[3].length = 1;
2229 key[3].key = &dlci;
2230 key[4].length = 1;
2231 key[4].key = &role;
2232 key[5].length = 1;
2233 key[5].key = &frame_number;
2234 key[6].length = 0;
2235 key[6].key = NULL;
2237 previous_fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2238 if (!(previous_fragment && previous_fragment->interface_id == interface_id &&
2239 previous_fragment->adapter_id == adapter_id &&
2240 previous_fragment->chandle == chandle &&
2241 previous_fragment->dlci == dlci &&
2242 previous_fragment->role == role &&
2243 previous_fragment->reassemble_state != REASSEMBLE_DONE)) {
2244 previous_fragment = NULL;
2247 frame_number = pinfo->num;
2249 key[0].length = 1;
2250 key[0].key = &interface_id;
2251 key[1].length = 1;
2252 key[1].key = &adapter_id;
2253 key[2].length = 1;
2254 key[2].key = &chandle;
2255 key[3].length = 1;
2256 key[3].key = &dlci;
2257 key[4].length = 1;
2258 key[4].key = &role;
2259 key[5].length = 1;
2260 key[5].key = &frame_number;
2261 key[6].length = 0;
2262 key[6].key = NULL;
2264 fragment = wmem_new(wmem_file_scope(), fragment_t);
2265 fragment->interface_id = interface_id;
2266 fragment->adapter_id = adapter_id;
2267 fragment->chandle = chandle;
2268 fragment->dlci = dlci;
2269 fragment->role = role;
2270 fragment->idx = previous_fragment ? previous_fragment->idx + previous_fragment->length : 0;
2271 fragment->reassemble_state = REASSEMBLE_FRAGMENT;
2272 fragment->length = tvb_reported_length(tvb);
2273 fragment->data = (uint8_t *) wmem_alloc(wmem_file_scope(), fragment->length);
2274 fragment->previous_fragment = previous_fragment;
2275 tvb_memcpy(tvb, fragment->data, offset, fragment->length);
2277 wmem_tree_insert32_array(fragments, key, fragment);
2279 /* Detect reassemble end character: \r for HS or \n for AG */
2280 length = tvb_reported_length(tvb);
2281 at_stream = tvb_get_string_enc(pinfo->pool, tvb, 0, length, ENC_ASCII);
2283 reassemble_start_offset = 0;
2285 for (i_length = 0; i_length < length; i_length += 1) {
2286 if (!((role == ROLE_HS && at_stream[i_length] == '\r') ||
2287 (role == ROLE_AG && at_stream[i_length] == '\n'))) {
2288 continue;
2291 if (role == ROLE_HS && at_stream[i_length] == '\r') {
2292 reassemble_start_offset = i_length + 1;
2293 if (reassemble_end_offset == 0) reassemble_end_offset = i_length + 1;
2296 if (role == ROLE_AG && at_stream[i_length] == '\n') {
2297 reassemble_start_offset = i_length + 1;
2300 frame_number = pinfo->num;
2302 key[0].length = 1;
2303 key[0].key = &interface_id;
2304 key[1].length = 1;
2305 key[1].key = &adapter_id;
2306 key[2].length = 1;
2307 key[2].key = &chandle;
2308 key[3].length = 1;
2309 key[3].key = &dlci;
2310 key[4].length = 1;
2311 key[4].key = &role;
2312 key[5].length = 1;
2313 key[5].key = &frame_number;
2314 key[6].length = 0;
2315 key[6].key = NULL;
2317 fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2318 if (fragment && fragment->interface_id == interface_id &&
2319 fragment->adapter_id == adapter_id &&
2320 fragment->chandle == chandle &&
2321 fragment->dlci == dlci &&
2322 fragment->role == role) {
2323 i_fragment = fragment;
2324 while (i_fragment && i_fragment->idx > 0) {
2325 i_fragment = i_fragment->previous_fragment;
2328 if (i_length + 1 == length &&
2329 role == ROLE_HS &&
2330 at_stream[i_length] == '\r') {
2331 fragment->reassemble_state = REASSEMBLE_DONE;
2332 } else if (i_length + 1 == length &&
2333 role == ROLE_AG &&
2334 i_length >= 4 &&
2335 at_stream[i_length] == '\n' &&
2336 at_stream[i_length - 1] == '\r' &&
2337 at_stream[0] == '\r' &&
2338 at_stream[1] == '\n') {
2339 fragment->reassemble_state = REASSEMBLE_DONE;
2340 } else if (i_length + 1 == length &&
2341 role == ROLE_AG &&
2342 i_length >= 2 &&
2343 at_stream[i_length] == '\n' &&
2344 at_stream[i_length - 1] == '\r' &&
2345 i_fragment &&
2346 i_fragment->reassemble_state == REASSEMBLE_FRAGMENT &&
2347 i_fragment->length >= 2 &&
2348 i_fragment->data[0] == '\r' &&
2349 i_fragment->data[1] == '\n') {
2350 fragment->reassemble_state = REASSEMBLE_DONE;
2351 } else if (role == ROLE_HS) {
2352 /* XXX: Temporary disable reassembling of partial message, it seems to be broken */
2353 /* fragment->reassemble_state = REASSEMBLE_PARTIALLY;*/
2355 fragment->reassemble_start_offset = reassemble_start_offset;
2356 fragment->reassemble_end_offset = reassemble_end_offset;
2361 /* recover reassembled payload */
2362 frame_number = pinfo->num;
2364 key[0].length = 1;
2365 key[0].key = &interface_id;
2366 key[1].length = 1;
2367 key[1].key = &adapter_id;
2368 key[2].length = 1;
2369 key[2].key = &chandle;
2370 key[3].length = 1;
2371 key[3].key = &dlci;
2372 key[4].length = 1;
2373 key[4].key = &role;
2374 key[5].length = 1;
2375 key[5].key = &frame_number;
2376 key[6].length = 0;
2377 key[6].key = NULL;
2379 fragment = (fragment_t *) wmem_tree_lookup32_array_le(fragments, key);
2380 if (fragment && fragment->interface_id == interface_id &&
2381 fragment->adapter_id == adapter_id &&
2382 fragment->chandle == chandle &&
2383 fragment->dlci == dlci &&
2384 fragment->role == role &&
2385 fragment->reassemble_state != REASSEMBLE_FRAGMENT) {
2386 uint8_t *at_data;
2387 unsigned i_data_offset;
2389 i_data_offset = fragment->idx + fragment->length;
2390 at_data = (uint8_t *) wmem_alloc(pinfo->pool, fragment->idx + fragment->length);
2392 i_fragment = fragment;
2394 if (i_fragment && i_fragment->reassemble_state == REASSEMBLE_PARTIALLY) {
2395 i_data_offset -= i_fragment->reassemble_end_offset;
2396 memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->reassemble_end_offset);
2397 i_fragment = i_fragment->previous_fragment;
2400 if (i_fragment) {
2401 while (i_fragment && i_fragment->idx > 0) {
2402 i_data_offset -= i_fragment->length;
2403 memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->length);
2404 i_fragment = i_fragment->previous_fragment;
2407 if (i_fragment && i_fragment->reassemble_state == REASSEMBLE_PARTIALLY) {
2408 i_data_offset -= (i_fragment->length - i_fragment->reassemble_start_offset);
2409 memcpy(at_data + i_data_offset, i_fragment->data + i_fragment->reassemble_start_offset,
2410 i_fragment->length - i_fragment->reassemble_start_offset);
2411 } else if (i_fragment) {
2412 i_data_offset -= i_fragment->length;
2413 memcpy(at_data + i_data_offset, i_fragment->data, i_fragment->length);
2417 if (fragment->idx > 0 && fragment->length > 0) {
2418 proto_tree_add_item(main_tree, hf_fragment, tvb, offset,
2419 tvb_captured_length_remaining(tvb, offset), ENC_ASCII | ENC_NA);
2420 reassembled_tvb = tvb_new_child_real_data(tvb, at_data,
2421 fragment->idx + fragment->length, fragment->idx + fragment->length);
2422 add_new_data_source(pinfo, reassembled_tvb, "Reassembled HFP");
2425 command_number = 0;
2426 if (reassembled_tvb) {
2427 unsigned reassembled_offset = 0;
2429 while (tvb_reported_length(reassembled_tvb) > reassembled_offset) {
2430 reassembled_offset = dissect_at_command(reassembled_tvb,
2431 pinfo, main_tree, reassembled_offset, role, command_number);
2432 command_number += 1;
2434 offset = tvb_captured_length(tvb);
2435 } else {
2436 while (tvb_reported_length(tvb) > (unsigned) offset) {
2437 offset = dissect_at_command(tvb, pinfo, main_tree, offset, role, command_number);
2438 command_number += 1;
2441 } else {
2442 pitem = proto_tree_add_item(main_tree, hf_fragmented, tvb, 0, 0, ENC_NA);
2443 proto_item_set_generated(pitem);
2444 char *display_str;
2445 proto_tree_add_item_ret_display_string(main_tree, hf_fragment, tvb, offset, -1, ENC_ASCII, pinfo->pool, &display_str);
2446 col_append_fstr(pinfo->cinfo, COL_INFO, "Fragment: %s", display_str);
2447 offset = tvb_captured_length(tvb);
2450 return offset;
2453 void
2454 proto_register_bthfp(void)
2456 module_t *module;
2457 expert_module_t *expert_bthfp;
2459 static hf_register_info hf[] = {
2460 { &hf_command,
2461 { "Command", "bthfp.command",
2462 FT_NONE, BASE_NONE, NULL, 0,
2463 NULL, HFILL}
2465 { &hf_parameters,
2466 { "Parameters", "bthfp.parameters",
2467 FT_NONE, BASE_NONE, NULL, 0,
2468 NULL, HFILL}
2470 { &hf_data,
2471 { "AT Stream", "bthfp.data",
2472 FT_STRING, BASE_NONE, NULL, 0,
2473 NULL, HFILL}
2475 { &hf_fragment,
2476 { "Fragment", "bthfp.fragment",
2477 FT_STRING, BASE_NONE, NULL, 0,
2478 NULL, HFILL}
2480 { &hf_fragmented,
2481 { "Fragmented", "bthfp.fragmented",
2482 FT_NONE, BASE_NONE, NULL, 0,
2483 NULL, HFILL}
2485 { &hf_at_ignored,
2486 { "Ignored", "bthfp.ignored",
2487 FT_BYTES, BASE_NONE, NULL, 0,
2488 NULL, HFILL}
2490 { &hf_at_cmd,
2491 { "Command", "bthfp.at_cmd",
2492 FT_STRING, BASE_NONE, NULL, 0,
2493 NULL, HFILL}
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}
2500 { &hf_at_command_line_prefix,
2501 { "Command Line Prefix", "bthfp.command_line_prefix",
2502 FT_STRING, BASE_NONE, NULL, 0,
2503 NULL, HFILL}
2505 { &hf_parameter,
2506 { "Parameter", "bthfp.parameter",
2507 FT_STRING, BASE_NONE, NULL, 0,
2508 NULL, HFILL}
2510 { &hf_unknown_parameter,
2511 { "Unknown Parameter", "bthfp.unknown_parameter",
2512 FT_STRING, BASE_NONE, NULL, 0,
2513 NULL, HFILL}
2515 { &hf_role,
2516 { "Role", "bthfp.role",
2517 FT_UINT8, BASE_DEC, VALS(role_vals), 0,
2518 NULL, HFILL}
2520 { &hf_brsf_hs,
2521 { "HS supported features bitmask", "bthfp.brsf.hs.features",
2522 FT_UINT32, BASE_DEC, NULL, 0,
2523 NULL, HFILL}
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}
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}
2535 { &hf_brsf_hs_cli_presentation,
2536 { "CLI Presentation", "bthfp.brsf.hs.cli_presentation",
2537 FT_BOOLEAN, 32, NULL, 0x00000004,
2538 NULL, HFILL}
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}
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}
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}
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}
2560 { &hf_brsf_hs_codec_negotiation,
2561 { "Codec Negotiation", "bthfp.brsf.hs.codec_negotiation",
2562 FT_BOOLEAN, 32, NULL, 0x00000080,
2563 NULL, HFILL}
2565 { &hf_brsf_hs_hf_indicators,
2566 { "HF Indicators", "bthfp.brsf.hs.hf_indicators",
2567 FT_BOOLEAN, 32, NULL, 0x00000100,
2568 NULL, HFILL}
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}
2575 { &hf_brsf_hs_reserved,
2576 { "Reserved", "bthfp.brsf.hs.reserved",
2577 FT_UINT32, BASE_HEX, NULL, 0xFFFFFC00,
2578 NULL, HFILL}
2580 { &hf_brsf_ag,
2581 { "AG supported features bitmask", "bthfp.brsf.ag.features",
2582 FT_UINT32, BASE_DEC, NULL, 0,
2583 NULL, HFILL}
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}
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}
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}
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}
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}
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}
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}
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}
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}
2630 { &hf_brsf_ag_codec_negotiation,
2631 { "Codec Negotiation", "bthfp.brsf.ag.codec_negotiation",
2632 FT_BOOLEAN, 32, NULL, 0x00000200,
2633 NULL, HFILL}
2635 { &hf_brsf_ag_hf_indicators,
2636 { "HF Indicators", "bthfp.brsf.ag.hf_indicators",
2637 FT_BOOLEAN, 32, NULL, 0x00000400,
2638 NULL, HFILL}
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}
2645 { &hf_brsf_ag_reserved,
2646 { "Reserved", "bthfp.brsf.ag.reserved",
2647 FT_UINT32, BASE_HEX, NULL, 0xFFFFF000,
2648 NULL, HFILL}
2650 { &hf_vgs,
2651 { "Gain", "bthfp.vgs",
2652 FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_slash15), 0,
2653 NULL, HFILL}
2655 { &hf_vgm,
2656 { "Gain", "bthfp.vgm",
2657 FT_UINT8, BASE_DEC|BASE_UNIT_STRING, UNS(&units_slash15), 0,
2658 NULL, HFILL}
2660 { &hf_nrec,
2661 { "Noise Reduction", "bthfp.nrec",
2662 FT_UINT8, BASE_DEC, VALS(nrec_vals), 0,
2663 NULL, HFILL}
2665 { &hf_bvra_vrect,
2666 { "Voice Recognition", "bthfp.bvra.vrect",
2667 FT_UINT8, BASE_DEC, VALS(bvra_vrect_vals), 0,
2668 NULL, HFILL}
2670 { &hf_bsir,
2671 { "Feature", "bthfp.bsir",
2672 FT_UINT8, BASE_DEC, VALS(bsir_vals), 0,
2673 NULL, HFILL}
2675 { &hf_btrh,
2676 { "Feature", "bthfp.btrh",
2677 FT_UINT8, BASE_DEC, VALS(btrh_vals), 0,
2678 NULL, HFILL}
2680 { &hf_cmer_mode,
2681 { "Mode", "bthfp.cmer.mode",
2682 FT_UINT8, BASE_DEC, NULL, 0,
2683 NULL, HFILL}
2685 { &hf_cmer_keyp,
2686 { "Keypad", "bthfp.cmer.keyp",
2687 FT_UINT8, BASE_DEC, NULL, 0,
2688 NULL, HFILL}
2690 { &hf_cmer_disp,
2691 { "Display", "bthfp.cmer.disp",
2692 FT_UINT8, BASE_DEC, NULL, 0,
2693 NULL, HFILL}
2695 { &hf_cmer_ind,
2696 { "Indicator", "bthfp.cmer.ind",
2697 FT_UINT8, BASE_DEC, NULL, 0,
2698 NULL, HFILL}
2700 { &hf_cmer_bfr,
2701 { "Buffer", "bthfp.cmer.bfr",
2702 FT_UINT8, BASE_DEC, NULL, 0,
2703 NULL, HFILL}
2705 { &hf_bac_codec,
2706 { "Codec", "bthfp.bac.codec",
2707 FT_UINT8, BASE_DEC, VALS(codecs_vals), 0,
2708 NULL, HFILL}
2710 { &hf_bcs_codec,
2711 { "Codec", "bthfp.bcs.codec",
2712 FT_UINT8, BASE_DEC, VALS(codecs_vals), 0,
2713 NULL, HFILL}
2715 { &hf_binp_request,
2716 { "Request", "bthfp.binp.request",
2717 FT_UINT8, BASE_DEC, VALS(binp_request_vals), 0,
2718 NULL, HFILL}
2720 { &hf_binp_response,
2721 { "Response", "bthfp.binp.response",
2722 FT_STRING, BASE_NONE, NULL, 0,
2723 NULL, HFILL}
2725 { &hf_cme_error,
2726 { "CME Error", "bthfp.cme_error",
2727 FT_UINT8, BASE_DEC, VALS(cme_error_vals), 0,
2728 NULL, HFILL}
2730 { &hf_cmee,
2731 { "Mode", "bthfp.cmee",
2732 FT_UINT8, BASE_DEC, VALS(cmee_vals), 0,
2733 NULL, HFILL}
2735 { &hf_chld_mode,
2736 { "Mode", "bthfp.chld.mode_value",
2737 FT_UINT8, BASE_DEC, VALS(chld_vals), 0,
2738 NULL, HFILL}
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}
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}
2750 { &hf_chld_supported_modes,
2751 { "Supported Modes", "bthfp.chld.supported_modes",
2752 FT_STRING, BASE_NONE, NULL, 0,
2753 NULL, HFILL}
2755 { &hf_ciev_indicator_index,
2756 { "Indicator Index", "bthfp.ciev.indicator_index",
2757 FT_UINT8, BASE_DEC, NULL, 0,
2758 NULL, HFILL}
2760 { &hf_vts_dtmf,
2761 { "DTMF", "bthfp.vts.dtmf",
2762 FT_STRING, BASE_NONE, NULL, 0,
2763 NULL, HFILL}
2765 { &hf_vts_duration,
2766 { "Duration", "bthfp.vts.duration",
2767 FT_UINT32, BASE_DEC, NULL, 0,
2768 NULL, HFILL}
2770 { &hf_cops_mode,
2771 { "Mode", "bthfp.cops.mode",
2772 FT_UINT8, BASE_DEC, VALS(cops_mode_vals), 0,
2773 NULL, HFILL}
2775 { &hf_cops_format,
2776 { "Format", "bthfp.cops.format",
2777 FT_UINT8, BASE_DEC, VALS(cops_format_vals), 0,
2778 NULL, HFILL}
2780 { &hf_cops_operator,
2781 { "Operator", "bthfp.cops.operator",
2782 FT_STRING, BASE_NONE, NULL, 0,
2783 NULL, HFILL}
2785 { &hf_cops_act,
2786 { "AcT", "bthfp.cops.act",
2787 FT_UINT8, BASE_DEC, VALS(cops_act_vals), 0,
2788 NULL, HFILL}
2790 { &hf_clip_mode,
2791 { "Mode", "bthfp.clip.mode",
2792 FT_UINT8, BASE_DEC, VALS(clip_mode_vals), 0,
2793 NULL, HFILL}
2795 { &hf_clip_status,
2796 { "Status", "bthfp.clip.status",
2797 FT_UINT8, BASE_DEC, VALS(clip_status_vals), 0,
2798 NULL, HFILL}
2800 { &hf_at_number,
2801 { "Number", "bthfp.at.number",
2802 FT_STRING, BASE_NONE, NULL, 0,
2803 NULL, HFILL}
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}
2810 { &hf_at_subaddress,
2811 { "Subaddress", "bthfp.at.subaddress",
2812 FT_STRING, BASE_NONE, NULL, 0,
2813 NULL, HFILL}
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}
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}
2825 { &hf_cnum_service,
2826 { "Service", "bthfp.cnum.service",
2827 FT_UINT8, BASE_DEC, VALS(cnum_service_vals), 0,
2828 NULL, HFILL}
2830 { &hf_cnum_itc,
2831 { "Information Transfer Capability", "bthfp.cnum.itc",
2832 FT_UINT8, BASE_DEC, VALS(cnum_itc_vals), 0,
2833 NULL, HFILL}
2835 { &hf_at_alpha,
2836 { "Alpha", "bthfp.at.alpha",
2837 FT_STRING, BASE_NONE, NULL, 0,
2838 NULL, HFILL}
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}
2845 { &hf_at_priority,
2846 { "Priority", "bthfp.at.priority",
2847 FT_UINT8, BASE_DEC, NULL, 0,
2848 NULL, HFILL}
2850 { &hf_clcc_id,
2851 { "ID", "bthfp.clcc.id",
2852 FT_UINT32, BASE_DEC, NULL, 0,
2853 NULL, HFILL}
2855 { &hf_clcc_dir,
2856 { "Direction", "bthfp.clcc.dir",
2857 FT_UINT32, BASE_DEC, VALS(clcc_dir_vals), 0,
2858 NULL, HFILL}
2860 { &hf_clcc_stat,
2861 { "State", "bthfp.clcc.stat",
2862 FT_UINT32, BASE_DEC, VALS(clcc_stat_vals), 0,
2863 NULL, HFILL}
2865 { &hf_clcc_mode,
2866 { "Mode", "bthfp.clcc.mode",
2867 FT_UINT32, BASE_DEC, VALS(clcc_mode_vals), 0,
2868 NULL, HFILL}
2870 { &hf_clcc_mpty,
2871 { "Mpty", "bthfp.clcc.mpty",
2872 FT_UINT32, BASE_DEC, VALS(clcc_mpty_vals), 0,
2873 NULL, HFILL}
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}
2880 { &hf_ccwa_mode,
2881 { "Mode", "bthfp.ccwa.mode",
2882 FT_UINT32, BASE_DEC, VALS(ccwa_mode_vals), 0,
2883 NULL, HFILL}
2885 { &hf_ccwa_class,
2886 { "Class", "bthfp.ccwa.class",
2887 FT_UINT32, BASE_DEC, VALS(ccwa_class_vals), 0,
2888 NULL, HFILL}
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}
2895 { &hf_bind_parameter,
2896 { "Parameter", "bthfp.bind.parameter",
2897 FT_UINT16, BASE_DEC, NULL, 0,
2898 NULL, HFILL}
2900 { &hf_biev_value,
2901 { "Value", "bthfp.biev.value",
2902 FT_UINT32, BASE_DEC, NULL, 0,
2903 NULL, HFILL}
2905 { &hf_bia_indicator[0],
2906 { "Indicator 1", "bthfp.bia.indicator.1",
2907 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2908 NULL, HFILL}
2910 { &hf_bia_indicator[1],
2911 { "Indicator 2", "bthfp.bia.indicator.2",
2912 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2913 NULL, HFILL}
2915 { &hf_bia_indicator[2],
2916 { "Indicator 3", "bthfp.bia.indicator.3",
2917 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2918 NULL, HFILL}
2920 { &hf_bia_indicator[3],
2921 { "Indicator 4", "bthfp.bia.indicator.4",
2922 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2923 NULL, HFILL}
2925 { &hf_bia_indicator[4],
2926 { "Indicator 5", "bthfp.bia.indicator.5",
2927 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2928 NULL, HFILL}
2930 { &hf_bia_indicator[5],
2931 { "Indicator 6", "bthfp.bia.indicator.6",
2932 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2933 NULL, HFILL}
2935 { &hf_bia_indicator[6],
2936 { "Indicator 7", "bthfp.bia.indicator.7",
2937 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2938 NULL, HFILL}
2940 { &hf_bia_indicator[7],
2941 { "Indicator 8", "bthfp.bia.indicator.8",
2942 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2943 NULL, HFILL}
2945 { &hf_bia_indicator[8],
2946 { "Indicator 9", "bthfp.bia.indicator.9",
2947 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2948 NULL, HFILL}
2950 { &hf_bia_indicator[9],
2951 { "Indicator 10", "bthfp.bia.indicator.10",
2952 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2953 NULL, HFILL}
2955 { &hf_bia_indicator[10],
2956 { "Indicator 11", "bthfp.bia.indicator.11",
2957 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2958 NULL, HFILL}
2960 { &hf_bia_indicator[11],
2961 { "Indicator 12", "bthfp.bia.indicator.12",
2962 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2963 NULL, HFILL}
2965 { &hf_bia_indicator[12],
2966 { "Indicator 13", "bthfp.bia.indicator.13",
2967 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2968 NULL, HFILL}
2970 { &hf_bia_indicator[13],
2971 { "Indicator 14", "bthfp.bia.indicator.14",
2972 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2973 NULL, HFILL}
2975 { &hf_bia_indicator[14],
2976 { "Indicator 15", "bthfp.bia.indicator.15",
2977 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2978 NULL, HFILL}
2980 { &hf_bia_indicator[15],
2981 { "Indicator 16", "bthfp.bia.indicator.16",
2982 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2983 NULL, HFILL}
2985 { &hf_bia_indicator[16],
2986 { "Indicator 17", "bthfp.bia.indicator.17",
2987 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2988 NULL, HFILL}
2990 { &hf_bia_indicator[17],
2991 { "Indicator 18", "bthfp.bia.indicator.18",
2992 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2993 NULL, HFILL}
2995 { &hf_bia_indicator[18],
2996 { "Indicator 19", "bthfp.bia.indicator.19",
2997 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
2998 NULL, HFILL}
3000 { &hf_bia_indicator[19],
3001 { "Indicator 20", "bthfp.bia.indicator.20",
3002 FT_UINT8, BASE_DEC, VALS(indicator_vals), 0,
3003 NULL, HFILL}
3005 { &hf_indicator[0],
3006 { "Indicator 1", "bthfp.indicator.1",
3007 FT_STRING, BASE_NONE, NULL, 0,
3008 NULL, HFILL}
3010 { &hf_indicator[1],
3011 { "Indicator 2", "bthfp.indicator.2",
3012 FT_STRING, BASE_NONE, NULL, 0,
3013 NULL, HFILL}
3015 { &hf_indicator[2],
3016 { "Indicator 3", "bthfp.indicator.3",
3017 FT_STRING, BASE_NONE, NULL, 0,
3018 NULL, HFILL}
3020 { &hf_indicator[3],
3021 { "Indicator 4", "bthfp.indicator.4",
3022 FT_STRING, BASE_NONE, NULL, 0,
3023 NULL, HFILL}
3025 { &hf_indicator[4],
3026 { "Indicator 5", "bthfp.indicator.5",
3027 FT_STRING, BASE_NONE, NULL, 0,
3028 NULL, HFILL}
3030 { &hf_indicator[5],
3031 { "Indicator 6", "bthfp.indicator.6",
3032 FT_STRING, BASE_NONE, NULL, 0,
3033 NULL, HFILL}
3035 { &hf_indicator[6],
3036 { "Indicator 7", "bthfp.indicator.7",
3037 FT_STRING, BASE_NONE, NULL, 0,
3038 NULL, HFILL}
3040 { &hf_indicator[7],
3041 { "Indicator 8", "bthfp.indicator.8",
3042 FT_STRING, BASE_NONE, NULL, 0,
3043 NULL, HFILL}
3045 { &hf_indicator[8],
3046 { "Indicator 9", "bthfp.indicator.9",
3047 FT_STRING, BASE_NONE, NULL, 0,
3048 NULL, HFILL}
3050 { &hf_indicator[9],
3051 { "Indicator 10", "bthfp.indicator.10",
3052 FT_STRING, BASE_NONE, NULL, 0,
3053 NULL, HFILL}
3055 { &hf_indicator[10],
3056 { "Indicator 11", "bthfp.indicator.11",
3057 FT_STRING, BASE_NONE, NULL, 0,
3058 NULL, HFILL}
3060 { &hf_indicator[11],
3061 { "Indicator 12", "bthfp.indicator.12",
3062 FT_STRING, BASE_NONE, NULL, 0,
3063 NULL, HFILL}
3065 { &hf_indicator[12],
3066 { "Indicator 13", "bthfp.indicator.13",
3067 FT_STRING, BASE_NONE, NULL, 0,
3068 NULL, HFILL}
3070 { &hf_indicator[13],
3071 { "Indicator 14", "bthfp.indicator.14",
3072 FT_STRING, BASE_NONE, NULL, 0,
3073 NULL, HFILL}
3075 { &hf_indicator[14],
3076 { "Indicator 15", "bthfp.indicator.15",
3077 FT_STRING, BASE_NONE, NULL, 0,
3078 NULL, HFILL}
3080 { &hf_indicator[15],
3081 { "Indicator 16", "bthfp.indicator.16",
3082 FT_STRING, BASE_NONE, NULL, 0,
3083 NULL, HFILL}
3085 { &hf_indicator[16],
3086 { "Indicator 17", "bthfp.indicator.17",
3087 FT_STRING, BASE_NONE, NULL, 0,
3088 NULL, HFILL}
3090 { &hf_indicator[17],
3091 { "Indicator 18", "bthfp.indicator.18",
3092 FT_STRING, BASE_NONE, NULL, 0,
3093 NULL, HFILL}
3095 { &hf_indicator[18],
3096 { "Indicator 19", "bthfp.indicator.19",
3097 FT_STRING, BASE_NONE, NULL, 0,
3098 NULL, HFILL}
3100 { &hf_indicator[19],
3101 { "Indicator 20", "bthfp.indicator.20",
3102 FT_STRING, BASE_NONE, NULL, 0,
3103 NULL, HFILL}
3105 { &hf_aplefm_state,
3106 { "State", "bthfp.aplefm.state",
3107 FT_UINT16, BASE_DEC, VALS(aplefm_state_vals), 0,
3108 NULL, HFILL}
3110 { &hf_aplsiri_state,
3111 { "Siri State", "bthfp.aplsiri.state",
3112 FT_UINT16, BASE_DEC, VALS(aplsiri_state_vals), 0,
3113 NULL, HFILL}
3115 { &hf_iphoneaccev_count,
3116 { "Count", "bthfp.iphoneaccev.count",
3117 FT_UINT16, BASE_DEC, NULL, 0,
3118 NULL, HFILL}
3120 { &hf_iphoneaccev_key,
3121 { "Key", "bthfp.iphoneaccev.key",
3122 FT_UINT16, BASE_DEC, VALS(iphoneaccev_key_vals), 0,
3123 NULL, HFILL}
3125 { &hf_iphoneaccev_value,
3126 { "Value", "bthfp.iphoneaccev.value",
3127 FT_UINT16, BASE_DEC, NULL, 0,
3128 NULL, HFILL}
3130 { &hf_xapl_accessory_info,
3131 { "Accessory Info", "bthfp.xapl.accessory_info",
3132 FT_STRING, BASE_NONE, NULL, 0,
3133 NULL, HFILL}
3135 { &hf_xapl_accessory_info_vendor_id,
3136 { "Vendor ID", "bthfp.xapl.accessory_info.vendor_id",
3137 FT_UINT32, BASE_HEX, NULL, 0,
3138 NULL, HFILL}
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}
3145 { &hf_xapl_accessory_info_version,
3146 { "Version", "bthfp.xapl.accessory_info.version",
3147 FT_UINT16, BASE_HEX, NULL, 0,
3148 NULL, HFILL}
3150 { &hf_xapl_host_info,
3151 { "Host Info", "bthfp.xapl.host_info",
3152 FT_STRING, BASE_NONE, NULL, 0,
3153 NULL, HFILL}
3155 { &hf_xapl_features,
3156 { "Features", "bthfp.xapl.features",
3157 FT_UINT32, BASE_DEC, NULL, 0,
3158 NULL, HFILL}
3160 { &hf_xapl_features_reserved,
3161 { "Reserved", "bthfp.xapl.features.reserved.0",
3162 FT_BOOLEAN, 32, NULL, 0x00000001,
3163 NULL, HFILL}
3165 { &hf_xapl_features_battery_reporting,
3166 { "Battery Reporting", "bthfp.xapl.features.battery_reporting",
3167 FT_BOOLEAN, 32, NULL, 0x00000002,
3168 NULL, HFILL}
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}
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}
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}
3185 { &hf_xapl_features_reserved_x,
3186 { "Reserved", "bthfp.xapl.features.reserved.x",
3187 FT_BOOLEAN, 32, NULL, 0xFFFFFFE0,
3188 NULL, HFILL}
3192 static ei_register_info ei[] = {
3193 { &ei_non_mandatory_command, { "bthfp.expert.non_mandatory_command", PI_PROTOCOL, PI_NOTE, "Non-mandatory command in HFP", EXPFILL }},
3194 { &ei_invalid_usage, { "bthfp.expert.invalid_usage", PI_PROTOCOL, PI_WARN, "Non mandatory type or command in this role", EXPFILL }},
3195 { &ei_unknown_parameter, { "bthfp.expert.unknown_parameter", PI_PROTOCOL, PI_WARN, "Unknown parameter", EXPFILL }},
3196 { &ei_brfs_hs_reserved_bits, { "bthfp.expert.brsf.hs.reserved_bits", PI_PROTOCOL, PI_WARN, "The reserved bits [10-31] shall be initialized to Zero", EXPFILL }},
3197 { &ei_brfs_ag_reserved_bits, { "bthfp.expert.brsf.ag.reserved_bits", PI_PROTOCOL, PI_WARN, "The reserved bits [12-31] shall be initialized to Zero", EXPFILL }},
3198 { &ei_vgm_gain, { "bthfp.expert.vgm", PI_PROTOCOL, PI_WARN, "Gain of microphone exceeds range 0-15", EXPFILL }},
3199 { &ei_vgs_gain, { "bthfp.expert.vgs", PI_PROTOCOL, PI_WARN, "Gain of speaker exceeds range 0-15", EXPFILL }},
3200 { &ei_nrec, { "bthfp.expert.nrec", PI_PROTOCOL, PI_WARN, "Only 0 is valid", EXPFILL }},
3201 { &ei_bvra, { "bthfp.expert.bvra", PI_PROTOCOL, PI_WARN, "Only 0-1 is valid", EXPFILL }},
3202 { &ei_bcs, { "bthfp.expert.bcs", PI_PROTOCOL, PI_NOTE, "BCS codec may only be 1-2", EXPFILL }},
3203 { &ei_bac, { "bthfp.expert.bac", PI_PROTOCOL, PI_NOTE, "BAC codec may only be 1-2", EXPFILL }},
3204 { &ei_bsir, { "bthfp.expert.bsir", PI_PROTOCOL, PI_WARN, "Only 0-1 is valid", EXPFILL }},
3205 { &ei_btrh, { "bthfp.expert.btrh", PI_PROTOCOL, PI_WARN, "Only 0-2 is valid", EXPFILL }},
3206 { &ei_binp, { "bthfp.expert.binp", PI_PROTOCOL, PI_WARN, "Only 1 is valid", EXPFILL }},
3207 { &ei_bia, { "bthfp.expert.bia", PI_PROTOCOL, PI_WARN, "Only 0-1 is valid", EXPFILL }},
3208 { &ei_biev_assigned_number, { "bthfp.expert.biev.assigned_number", PI_PROTOCOL, PI_WARN, "Only 0-65535 is valid", EXPFILL }},
3209 { &ei_biev_assigned_number_no, { "bthfp.expert.biev.assigned_number.not_assigned", PI_PROTOCOL, PI_WARN, "Value is unknown for Assign Numbers", EXPFILL }},
3210 { &ei_cmer_mode, { "bthfp.expert.cmer.mode", PI_PROTOCOL, PI_NOTE, "Only 3 is valid for HFP", EXPFILL }},
3211 { &ei_cmer_disp, { "bthfp.expert.cmer.disp", PI_PROTOCOL, PI_WARN, "Value is ignored for HFP", EXPFILL }},
3212 { &ei_cmer_keyp, { "bthfp.expert.cmer.keyp", PI_PROTOCOL, PI_WARN, "Value is ignored for HFP", EXPFILL }},
3213 { &ei_cmer_ind, { "bthfp.expert.cmer.ind", PI_PROTOCOL, PI_NOTE, "Only 0-1 is valid for HFP", EXPFILL }},
3214 { &ei_cmer_btr, { "bthfp.expert.cmer.btr", PI_PROTOCOL, PI_WARN, "Value is ignored for HFP", EXPFILL }},
3215 { &ei_chld_mode, { "bthfp.expert.chld.mode", PI_PROTOCOL, PI_WARN, "Invalid value for HFP", EXPFILL }},
3216 { &ei_ciev_indicator, { "bthfp.expert.ciev.indicator", PI_PROTOCOL, PI_WARN, "Unknown indicator", EXPFILL }},
3217 { &ei_vts_dtmf, { "bthfp.expert.vts.dtmf", PI_PROTOCOL, PI_WARN, "DTMF should be single character", EXPFILL }},
3218 { &ei_at_type, { "bthfp.expert.at.type", PI_PROTOCOL, PI_WARN, "Unknown type value", EXPFILL }},
3219 { &ei_parameter_blank, { "bthfp.expert.parameter_blank", PI_PROTOCOL, PI_WARN, "Should be blank for HFP", EXPFILL }},
3220 { &ei_cnum_service, { "bthfp.expert.cnum.service", PI_PROTOCOL, PI_WARN, "Only 0-5 is valid", EXPFILL }},
3221 { &ei_cnum_itc, { "bthfp.expert.cnum.itc", PI_PROTOCOL, PI_WARN, "Only 0-1 is valid", EXPFILL }},
3222 { &ei_aplefm_out_of_range, { "bthfp.expert.aplefm.out_of_range", PI_PROTOCOL, PI_WARN, "Only 0-1 is valid", EXPFILL }},
3223 { &ei_aplsiri_out_of_range, { "bthfp.expert.aplsiri.out_of_range", PI_PROTOCOL, PI_WARN, "Only 1-2 is valid", EXPFILL }},
3224 { &ei_iphoneaccev_key_out_of_range, { "bthfp.expert.iphoneaccev.out_of_range", PI_PROTOCOL, PI_WARN, "Only 1-2 is valid", EXPFILL }},
3225 { &ei_xapl_features_reserved, { "bthfp.expert.xapl.reserved", PI_PROTOCOL, PI_WARN, "The reserved bits [6-31] shall be initialized to Zero", EXPFILL }}
3228 static int *ett[] = {
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
3238 fragments = wmem_tree_new_autoreset(wmem_epan_scope(), wmem_file_scope());
3240 proto_bthfp = proto_register_protocol("Bluetooth HFP Profile", "BT HFP", "bthfp");
3241 bthfp_handle = register_dissector("bthfp", dissect_bthfp, proto_bthfp);
3243 proto_register_field_array(proto_bthfp, hf, array_length(hf));
3244 proto_register_subtree_array(ett, array_length(ett));
3246 module = prefs_register_protocol_subtree("Bluetooth", proto_bthfp, NULL);
3247 prefs_register_static_text_preference(module, "hfp.version",
3248 "Bluetooth Profile HFP version: 1.7",
3249 "Version of profile supported by this dissector.");
3251 prefs_register_enum_preference(module, "hfp.hfp_role",
3252 "Force treat packets as AG or HS role",
3253 "Force treat packets as AG or HS role",
3254 &hfp_role, pref_hfp_role, true);
3256 expert_bthfp = expert_register_protocol(proto_bthfp);
3257 expert_register_field_array(expert_bthfp, ei, array_length(ei));
3260 void
3261 proto_reg_handoff_bthfp(void)
3263 dissector_add_string("bluetooth.uuid", "111e", bthfp_handle);
3264 dissector_add_string("bluetooth.uuid", "111f", bthfp_handle);
3266 dissector_add_for_decode_as("btrfcomm.dlci", bthfp_handle);
3270 * Editor modelines - https://www.wireshark.org/tools/modelines.html
3272 * Local variables:
3273 * c-basic-offset: 4
3274 * tab-width: 8
3275 * indent-tabs-mode: nil
3276 * End:
3278 * vi: set shiftwidth=4 tabstop=8 expandtab:
3279 * :indentSize=4:tabSize=8:noTabs=true: