From Michal Labedzki via https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=8416 :
[metze/wireshark/wip.git] / epan / dissectors / packet-btmcap.c
1 /* packet-btmcap.c
2  * Routines for Bluetooth MCAP dissection
3  * https://www.bluetooth.org/Technical/Specifications/adopted.htm
4  *
5  * Copyright 2013, Michal Labedzki for Tieto Corporation
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27
28 #include "config.h"
29
30 #include <epan/packet.h>
31 #include <epan/prefs.h>
32 #include <epan/expert.h>
33
34 #include "packet-btl2cap.h"
35 #include "packet-btsdp.h"
36
37 static int proto_btmcap = -1;
38
39 static int hf_btmcap_op_code                                               = -1;
40 static int hf_btmcap_response_code                                         = -1;
41 static int hf_btmcap_mdl_id                                                = -1;
42 static int hf_btmcap_mdep_id                                               = -1;
43 static int hf_btmcap_response_parameters                                   = -1;
44 static int hf_btmcap_configuration                                         = -1;
45 static int hf_btmcap_timestamp_required_accuracy                           = -1;
46 static int hf_btmcap_timestamp_update_information                          = -1;
47 static int hf_btmcap_bluetooth_clock_sync_time                             = -1;
48 static int hf_btmcap_timestamp_sync_time                                   = -1;
49 static int hf_btmcap_timestamp_sample_accuracy                             = -1;
50 static int hf_btmcap_bluetooth_clock_access_resolution                     = -1;
51 static int hf_btmcap_sync_lead_time                                        = -1;
52 static int hf_btmcap_timestamp_native_resolution                           = -1;
53 static int hf_btmcap_timestamp_native_accuracy                             = -1;
54
55 static int hf_btmcap_data                                                  = -1;
56
57 static gint ett_btmcap = -1;
58
59 static const value_string op_code_vals[] = {
60     { 0x00,   "ERROR_RSP" },
61     { 0x01,   "MD_CREATE_MDL_REQ" },
62     { 0x02,   "MD_CREATE_MDL_RSP" },
63     { 0x03,   "MD_RECONNECT_MDL_REQ" },
64     { 0x04,   "MD_RECONNECT_MDL_RSP" },
65     { 0x05,   "MD_ABORT_MDL_REQ" },
66     { 0x06,   "MD_ABORT_MDL_RSP" },
67     { 0x07,   "MD_DELETE_MDL_REQ" },
68     { 0x08,   "MD_DELETE_MDL_RSP" },
69     { 0x11,   "MD_SYNC_CAP_REQ" },
70     { 0x12,   "MD_SYNC_CAP_RSP" },
71     { 0x13,   "MD_SYNC_SET_REQ" },
72     { 0x14,   "MD_SYNC_SET_RSP" },
73     { 0x15,   "MD_SYNC_INFO_IND" },
74     { 0x16,   "Reserved as pseudoresponse" },
75     { 0, NULL }
76 };
77
78 static const value_string response_code_vals[] = {
79     { 0x00,   "Success" },
80     { 0x01,   "Invalid Op Code" },
81     { 0x02,   "Invalid Parameter Value" },
82     { 0x03,   "Invalid MDEP" },
83     { 0x04,   "MDEP Busy" },
84     { 0x05,   "Invalid MDL" },
85     { 0x06,   "MDL Busy" },
86     { 0x07,   "Invalid Operation" },
87     { 0x08,   "Resource Unavailable" },
88     { 0x09,   "Unspecified Error" },
89     { 0x0A,   "Request Not Supported" },
90     { 0x0B,   "Configuration Rejected" },
91     { 0, NULL }
92 };
93
94 void proto_register_btmcap(void);
95 void proto_reg_handoff_btmcap(void);
96
97 static void
98 dissect_btmcap(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
99 {
100     proto_item *main_item;
101     proto_tree *main_tree;
102     proto_item *pitem;
103     gint        offset = 0;
104     guint32     op_code;
105     guint32     response_code;
106     guint32     mdl_id;
107     guint32     mdep_id;
108     guint32     bluetooth_clock_sync_time;
109     guint64     timestamp_sync_time;
110
111     col_set_str(pinfo->cinfo, COL_PROTOCOL, "MCAP");
112     col_clear(pinfo->cinfo, COL_INFO);
113
114     switch (pinfo->p2p_dir) {
115
116     case P2P_DIR_SENT:
117         col_add_str(pinfo->cinfo, COL_INFO, "Sent ");
118         break;
119
120     case P2P_DIR_RECV:
121         col_add_str(pinfo->cinfo, COL_INFO, "Rcvd ");
122         break;
123
124     case P2P_DIR_UNKNOWN:
125         col_clear(pinfo->cinfo, COL_INFO);
126         break;
127
128     default:
129         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
130             pinfo->p2p_dir);
131         break;
132     }
133
134     main_item = proto_tree_add_item(tree, proto_btmcap, tvb, offset, -1, ENC_NA);
135     main_tree = proto_item_add_subtree(main_item, ett_btmcap);
136
137     pitem = proto_tree_add_item(main_tree, hf_btmcap_op_code, tvb, offset, 1, ENC_BIG_ENDIAN);
138     op_code = tvb_get_guint8(tvb, offset);
139     offset += 1;
140
141     col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(op_code, op_code_vals, "Unknown Op Code"));
142     if (op_code >= 0x11 && op_code <= 0x20) {
143         proto_item_append_text(pitem, " (Clock Sync)");
144         col_append_fstr(pinfo->cinfo, COL_INFO, " (Clock Sync)");
145     } else {
146         proto_item_append_text(pitem, " (Standard)");
147         col_append_fstr(pinfo->cinfo, COL_INFO, " (Standard)");
148     }
149
150     if (op_code & 0x01) {
151         /* isRequest */
152         switch(op_code) {
153             case 0x01: /* MD_CREATE_MDL_REQ */
154             case 0x03: /* MD_RECONNECT_MDL_REQ */
155             case 0x05: /* MD_ABORT_MDL_REQ */
156             case 0x07: /* MD_DELETE_MDL_REQ */
157                 pitem = proto_tree_add_item(main_tree, hf_btmcap_mdl_id, tvb, offset, 2, ENC_BIG_ENDIAN);
158                 mdl_id = tvb_get_ntohs(tvb, offset);
159                 offset += 2;
160
161                 col_append_fstr(pinfo->cinfo, COL_INFO, " - MDL ID: %u", mdl_id);
162                 if (mdl_id == 0xFFFF) {
163                     proto_item_append_text(pitem, " (Indicates all MDLs)");
164                     col_append_fstr(pinfo->cinfo, COL_INFO, " (Indicates all MDLs)");
165                 } else if (mdl_id >= 0x0001 && mdl_id <= 0xFEFF) {
166                     proto_item_append_text(pitem, " (Dynamic Range)");
167                     col_append_fstr(pinfo->cinfo, COL_INFO, " (Dynamic Range)");
168                 } else if (mdl_id == 0x0000) {
169                     proto_item_append_text(pitem, " (Reserved)");
170                     col_append_fstr(pinfo->cinfo, COL_INFO, " (Reserved)");
171                 }
172
173                 if (op_code != 0x07 && mdl_id == 0xFFFF) {
174                     expert_add_info_format(pinfo, pitem, PI_PROTOCOL, PI_WARN,
175                             " The value 0xFFFF is not a valid MDL ID for this request and shall not be used.");
176                     }
177
178                 if (op_code == 0x01) {
179                     /* only MD_CREATE_MDL_REQ */
180                     pitem = proto_tree_add_item(main_tree, hf_btmcap_mdep_id, tvb, offset, 1, ENC_BIG_ENDIAN);
181                     mdep_id = tvb_get_guint8(tvb, offset);
182                     offset += 1;
183
184                     if (mdep_id <= 0x7F) {
185                         proto_item_append_text(pitem, " (Available for use)");
186                     } else {
187                         proto_item_append_text(pitem, " (Reserved)");
188                     }
189
190                     pitem = proto_tree_add_item(main_tree, hf_btmcap_configuration, tvb, offset, 1, ENC_BIG_ENDIAN);
191                     offset += 1;
192                 }
193                 break;
194             case 0x11: /* MD_SYNC_CAP_REQ */
195                 pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_required_accuracy, tvb, offset, 2, ENC_BIG_ENDIAN);
196                 proto_item_append_text(pitem, " ppm");
197                 offset += 2;
198                 break;
199             case 0x13: /* MD_SYNC_SET_REQ */
200                 pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_update_information, tvb, offset, 1, ENC_BIG_ENDIAN);
201                 offset += 1;
202
203                 pitem = proto_tree_add_item(main_tree, hf_btmcap_bluetooth_clock_sync_time, tvb, offset, 4, ENC_BIG_ENDIAN);
204                 bluetooth_clock_sync_time = tvb_get_ntohl(tvb, offset);
205                 if (bluetooth_clock_sync_time == 0xFFFFFFFF)
206                     proto_item_append_text(pitem, " (Instant Synchronization)");
207                 else
208                     proto_item_append_text(pitem, " (Baseband Half-Slot Instant)");;
209                 offset += 4;
210
211                 pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_sync_time, tvb, offset, 8, ENC_BIG_ENDIAN);
212                 timestamp_sync_time = tvb_get_ntoh64(tvb, offset);
213                 if (timestamp_sync_time == G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF))
214                     proto_item_append_text(pitem, " (No Time Synchronization)");
215                 else
216                     proto_item_append_text(pitem, " (Time-Stamp Clock Instant)");
217                 offset += 8;
218                 break;
219             case 0x15: /* MD_SYNC_INFO_IND */
220                 pitem = proto_tree_add_item(main_tree, hf_btmcap_bluetooth_clock_sync_time, tvb, offset, 4, ENC_BIG_ENDIAN);
221                 proto_item_append_text(pitem, " (Baseband Half-Slot Instant)");
222                 offset += 4;
223
224                 pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_sync_time, tvb, offset, 8, ENC_BIG_ENDIAN);
225                 proto_item_append_text(pitem, " (Time-Stamp Clock Instant)");
226                 offset += 8;
227
228                 pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_sample_accuracy, tvb, offset, 2, ENC_BIG_ENDIAN);
229                 proto_item_append_text(pitem, " us");
230                 offset += 2;
231                 break;
232         }
233     } else {
234         /* isResponse */
235
236         proto_tree_add_item(main_tree, hf_btmcap_response_code, tvb, offset, 1, ENC_BIG_ENDIAN);
237         response_code = tvb_get_guint8(tvb, offset);
238         offset += 1;
239
240         col_append_fstr(pinfo->cinfo, COL_INFO, " - %s", val_to_str(response_code, response_code_vals, "Unknown ResponseCode"));
241
242         if (op_code >= 0x11 && op_code <= 0x20) {
243             /* Clock Sync */
244             switch(op_code) {
245                 case 0x12: /* MD_SYNC_CAP_RSP */
246                     pitem = proto_tree_add_item(main_tree, hf_btmcap_bluetooth_clock_access_resolution, tvb, offset, 1, ENC_BIG_ENDIAN);
247                     proto_item_append_text(pitem, " (Baseband half-slots)");
248                     offset += 1;
249
250                     pitem = proto_tree_add_item(main_tree, hf_btmcap_sync_lead_time, tvb, offset, 2, ENC_BIG_ENDIAN);
251                     proto_item_append_text(pitem, " ms");
252                     offset += 2;
253
254                     pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_native_resolution, tvb, offset, 2, ENC_BIG_ENDIAN);
255                     proto_item_append_text(pitem, " us");
256                     offset += 2;
257
258                     pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_native_accuracy, tvb, offset, 2, ENC_BIG_ENDIAN);
259                     proto_item_append_text(pitem, " ppm");
260                     offset += 2;
261                     break;
262                 case 0x14: /* MD_SYNC_SET_RSP */
263                     pitem = proto_tree_add_item(main_tree, hf_btmcap_bluetooth_clock_sync_time, tvb, offset, 4, ENC_BIG_ENDIAN);
264                     bluetooth_clock_sync_time = tvb_get_ntohl(tvb, offset);
265                     if (bluetooth_clock_sync_time == 0xFFFFFFFF)
266                         proto_item_append_text(pitem, " (Instant Synchronization)");
267                     else
268                         proto_item_append_text(pitem, " (Baseband Half-Slot Instant)");
269                     offset += 4;
270
271                     pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_sync_time, tvb, offset, 8, ENC_BIG_ENDIAN);
272                     timestamp_sync_time = tvb_get_ntoh64(tvb, offset);
273                     if (timestamp_sync_time == G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF))
274                         proto_item_append_text(pitem, " (No Time Synchronization)");
275                     else
276                         proto_item_append_text(pitem, " (Time-Stamp Clock Instant)");
277                     offset += 8;
278
279                     pitem = proto_tree_add_item(main_tree, hf_btmcap_timestamp_sample_accuracy, tvb, offset, 2, ENC_BIG_ENDIAN);
280                     proto_item_append_text(pitem, " us");
281                     offset += 2;
282                     break;
283             }
284         } else {
285             /* Standard Op Code */
286             pitem = proto_tree_add_item(main_tree, hf_btmcap_mdl_id, tvb, offset, 2, ENC_BIG_ENDIAN);
287             mdl_id = tvb_get_ntohs(tvb, offset);
288             offset += 2;
289
290             col_append_fstr(pinfo->cinfo, COL_INFO, " - %u", mdl_id);
291             if (mdl_id == 0xFFFF) {
292                 proto_item_append_text(pitem, " (Indicates all MDLs)");
293                 col_append_fstr(pinfo->cinfo, COL_INFO, " (Indicates all MDLs)");
294             } else if (mdl_id >= 0x0001 && mdl_id <= 0xFEFF) {
295                 proto_item_append_text(pitem, " (Dynamic Range)");
296                 col_append_fstr(pinfo->cinfo, COL_INFO, " (Dynamic Range)");
297             } else if (mdl_id == 0x0000) {
298                 proto_item_append_text(pitem, " (Reserved)");
299                 col_append_fstr(pinfo->cinfo, COL_INFO, " (Reserved)");
300             }
301
302             if ((op_code == 0x03 || op_code == 0x05 || op_code == 0x07) && tvb_length_remaining(tvb, offset)) {
303                     expert_add_info_format(pinfo, pitem, PI_PROTOCOL, PI_WARN,
304                             "The Response Parameters for MD_RECONNECT_MDL_RSP shall have length zero.");
305             } else if (tvb_length_remaining(tvb, offset)) {
306                 pitem = proto_tree_add_item(main_tree, hf_btmcap_response_parameters, tvb, offset, -1, ENC_NA);
307                 if (response_code != 0x00) {
308                     expert_add_info_format(pinfo, pitem, PI_PROTOCOL, PI_WARN,
309                             "When the Response Code is not Success, the Response Parameters shall have length zero.");
310                 }
311                 offset += tvb_length_remaining(tvb, offset);
312             }
313         }
314     }
315
316     if (tvb_length_remaining(tvb, offset)) {
317         pitem = proto_tree_add_item(main_tree, hf_btmcap_data, tvb, offset, -1, ENC_NA);
318         expert_add_info_format(pinfo, pitem, PI_PROTOCOL, PI_WARN,
319                 "Unexpected data");
320     }
321 }
322
323
324 void
325 proto_register_btmcap(void)
326 {
327     module_t *module;
328
329     static hf_register_info hf[] = {
330         { &hf_btmcap_op_code,
331             { "Op Code",                         "btmcap.op_code",
332             FT_UINT8, BASE_HEX, VALS(op_code_vals), 0x0,
333             NULL, HFILL }
334         },
335         { &hf_btmcap_response_code,
336             { "Response Code",                   "btmcap.response_code",
337             FT_UINT8, BASE_HEX, VALS(response_code_vals), 0x0,
338             NULL, HFILL }
339         },
340         { &hf_btmcap_mdl_id,
341             { "MDL ID",                          "btmcap.mdl_id",
342             FT_UINT16, BASE_HEX, NULL, 0x0,
343             NULL, HFILL }
344         },
345         { &hf_btmcap_mdep_id,
346             { "MDEP ID",                         "btmcap.mdep_id",
347             FT_UINT8, BASE_HEX, NULL, 0x0,
348             NULL, HFILL }
349         },
350         { &hf_btmcap_configuration,
351             { "Configuration",                   "btmcap.configuration",
352             FT_UINT8, BASE_HEX, NULL, 0x0,
353             NULL, HFILL }
354         },
355         { &hf_btmcap_timestamp_required_accuracy,
356             { "Timestamp Required Accuracy",     "btmcap.timestamp_required_accuracy",
357             FT_UINT16, BASE_DEC, NULL, 0x00,
358             NULL, HFILL }
359         },
360         { &hf_btmcap_timestamp_update_information,
361             { "Timestamp Update Information",    "btmcap.timestamp_update_information",
362             FT_UINT8, BASE_DEC, NULL, 0x00,
363             NULL, HFILL }
364         },
365         { &hf_btmcap_bluetooth_clock_sync_time,
366             { "Bluetooth Clock Sync Time",       "btmcap.bluetooth_clock_sync_time",
367             FT_UINT32, BASE_DEC, NULL, 0x00,
368             NULL, HFILL }
369         },
370         { &hf_btmcap_timestamp_sync_time,
371             { "Timestamp Sync Time",             "btmcap.timestamp_sync_time",
372             FT_UINT64, BASE_DEC, NULL, 0x00,
373             NULL, HFILL }
374         },
375         { &hf_btmcap_timestamp_sample_accuracy,
376             { "Timestamp Sample Accuracy",       "btmcap.timestamp_sample_accuracy",
377             FT_UINT16, BASE_DEC, NULL, 0x00,
378             NULL, HFILL }
379         },
380         { &hf_btmcap_bluetooth_clock_access_resolution,
381             { "Bluetooth Clock Access Resolution","btmcap.bluetooth_clock_access_resolution",
382             FT_UINT8, BASE_DEC, NULL, 0x00,
383             NULL, HFILL }
384         },
385         { &hf_btmcap_sync_lead_time,
386             { "Sync Lead Time",                  "btmcap.sync_lead_time",
387             FT_UINT16, BASE_DEC, NULL, 0x00,
388             NULL, HFILL }
389         },
390         { &hf_btmcap_timestamp_native_resolution,
391             { "Timestamp Native Resolution",     "btmcap.timestamp_native_resolution",
392             FT_UINT16, BASE_DEC, NULL, 0x00,
393             NULL, HFILL }
394         },
395         { &hf_btmcap_timestamp_native_accuracy,
396             { "Timestamp Native Accuracy",       "btmcap.timestamp_native_accuracy",
397             FT_UINT16, BASE_DEC, NULL, 0x00,
398             NULL, HFILL }
399         },
400         { &hf_btmcap_response_parameters,
401             { "Response Parameters",             "btmcap.response_parameters",
402             FT_BYTES, BASE_NONE, NULL, 0x00,
403             NULL, HFILL }
404         },
405
406         { &hf_btmcap_data,
407             { "Data",                            "btmcap.data",
408             FT_NONE, BASE_NONE, NULL, 0x00,
409             NULL, HFILL }
410         },
411
412     };
413
414     static gint *ett[] = {
415         &ett_btmcap
416     };
417
418     proto_btmcap = proto_register_protocol("Bluetooth MCAP Protocol", "BT MCAP", "btmcap");
419     register_dissector("btmcap", dissect_btmcap, proto_btmcap);
420
421     proto_register_field_array(proto_btmcap, hf, array_length(hf));
422     proto_register_subtree_array(ett, array_length(ett));
423
424     module = prefs_register_protocol(proto_btmcap, NULL);
425     prefs_register_static_text_preference(module, "mcap.version",
426             "Bluetooth Protocol MCAP version: 1.0",
427             "Version of protocol supported by this dissector.");
428 }
429
430
431 void
432 proto_reg_handoff_btmcap(void)
433 {
434     dissector_handle_t btmcap_handle;
435
436     btmcap_handle = find_dissector("btmcap");
437
438     dissector_add_uint("btl2cap.service", BTSDP_MCAP_CONTROL_CHANNEL_PROTOCOL_UUID, btmcap_handle);
439     dissector_add_uint("btl2cap.service", BTSDP_MCAP_DATA_CHANNEL_PROTOCOL_UUID, btmcap_handle);
440
441     dissector_add_uint("btl2cap.service", BTSDP_HDP_SERVICE_UUID, btmcap_handle);
442     dissector_add_uint("btl2cap.service", BTSDP_HDP_SOURCE_SERVICE_UUID, btmcap_handle);
443     dissector_add_uint("btl2cap.service", BTSDP_HDP_SINK_SERVICE_UUID, btmcap_handle);
444
445     /* dynamic PSM */
446     dissector_add_handle("btl2cap.psm", btmcap_handle);
447     dissector_add_handle("btl2cap.cid", btmcap_handle);
448 }
449
450 /*
451  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
452  *
453  * Local variables:
454  * c-basic-offset: 4
455  * tab-width: 8
456  * indent-tabs-mode: nil
457  * End:
458  *
459  * vi: set shiftwidth=4 tabstop=8 expandtab:
460  * :indentSize=4:tabSize=8:noTabs=true:
461  */