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