xref: /libbtbb/wireshark/plugins-legacy/btatt/packet-btatt.c (revision 25d64f63a355f4c01d10cf4f69da1c2246b040d9)
1 /* packet-btatt.c
2  * Routines for Bluetooth Attribute Protocol dissection
3  *
4  * Copyright 2012, Allan M. Madsen <[email protected]>
5  *
6  * $Id$
7  *
8  * Wireshark - Network traffic analyzer
9  * By Gerald Combs <[email protected]>
10  * Copyright 1998 Gerald Combs
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <[email protected]>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29  */
30 
31 #include "config.h"
32 
33 #include <epan/packet.h>
34 #include <epan/prefs.h>
35 #include <epan/expert.h>
36 #include <epan/dissectors/packet-btl2cap.h>
37 
38 #define BTL2CAP_PSM_ATT             0x001f
39 #define BTL2CAP_FIXED_CID_ATT       0x0004
40 
41 /* Initialize the protocol and registered fields */
42 static int proto_btatt = -1;
43 
44 static int hf_btatt_opcode = -1;
45 static int hf_btatt_handle = -1;
46 static int hf_btatt_starting_handle = -1;
47 static int hf_btatt_ending_handle = -1;
48 static int hf_btatt_group_end_handle = -1;
49 static int hf_btatt_value = -1;
50 static int hf_btatt_req_opcode_in_error = -1;
51 static int hf_btatt_handle_in_error = -1;
52 static int hf_btatt_error_code = -1;
53 static int hf_btatt_uuid16 = -1;
54 static int hf_btatt_uuid128 = -1;
55 static int hf_btatt_client_rx_mtu = -1;
56 static int hf_btatt_server_rx_mtu = -1;
57 static int hf_btatt_uuid_format = -1;
58 static int hf_btatt_length = -1;
59 static int hf_btatt_offset = -1;
60 static int hf_btatt_flags = -1;
61 static int hf_btatt_sign_counter = -1;
62 static int hf_btatt_signature = -1;
63 
64 /* Initialize the subtree pointers */
65 static gint ett_btatt = -1;
66 static gint ett_btatt_list = -1;
67 
68 /* Opcodes */
69 static const value_string opcode_vals[] = {
70     {0x01, "Error Response"},
71     {0x02, "Exchange MTU Request"},
72     {0x03, "Exchange MTU Response"},
73     {0x04, "Find Information Request"},
74     {0x05, "Find Information Response"},
75     {0x06, "Find By Type Value Request"},
76     {0x07, "Find By Type Value Response"},
77     {0x08, "Read By Type Request"},
78     {0x09, "Read By Type Response"},
79     {0x0a, "Read Request"},
80     {0x0b, "Read Response"},
81     {0x0c, "Read Blob Request"},
82     {0x0d, "Read Blob Response"},
83     {0x0e, "Read Multiple Request"},
84     {0x0f, "Read Multiple Response"},
85     {0x10, "Read By Group Type Request"},
86     {0x11, "Read By Group Type Response"},
87     {0x12, "Write Request"},
88     {0x13, "Write Response"},
89     {0x16, "Prepare Write Request"},
90     {0x17, "Prepare Write Response"},
91     {0x18, "Execute Write Request"},
92     {0x19, "Execute Write Response"},
93     {0x1B, "Handle Value Notification"},
94     {0x1D, "Handle Value Indication"},
95     {0x1E, "Handle Value Confirmation"},
96     {0x52, "Write Command"},
97     {0xD2, "Signed Write Command"},
98     {0x0, NULL}
99 };
100 
101 /* Error codes */
102 static const value_string error_vals[] = {
103     {0x01, "Invalid Handle"},
104     {0x02, "Read Not Permitted"},
105     {0x03, "Write Not Permitted"},
106     {0x04, "Invalid PDU"},
107     {0x05, "Insufficient Authentication"},
108     {0x06, "Request Not Supported"},
109     {0x07, "Invalid Offset"},
110     {0x08, "Insufficient Authorization"},
111     {0x09, "Prepare Queue Full"},
112     {0x0a, "Attribute Not Found"},
113     {0x0b, "Attribute Not Long"},
114     {0x0c, "Insufficient Encryption Key Size"},
115     {0x0d, "Invalid Attribute Value Length"},
116     {0x0e, "Unlikely Error"},
117     {0x0f, "Insufficient Encryption"},
118     {0x10, "Unsupported Group Type"},
119     {0x11, "Insufficient Resources"},
120     {0x80, "Application Error"},
121     {0xfd, "Improper Client Characteristic Configuration Descriptor"},
122     {0xfe, "Procedure Already In Progress"},
123     {0xff, "Out of Range"},
124     {0x0, NULL}
125 };
126 
127 static const value_string uuid_vals[] = {
128     /* Services - http://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx */
129     {0x1800, "Generic Access"},
130     {0x1801, "Generic Attribute"},
131     {0x1802, "Immediate Alert"},
132     {0x1803, "Link Loss"},
133     {0x1804, "Tx Power"},
134     {0x1805, "Current Time Service"},
135     {0x1806, "Reference Time Update Service"},
136     {0x1807, "Next DST Change Service"},
137     {0x1808, "Glucose"},
138     {0x1809, "Health Thermometer"},
139     {0x180a, "Device Information"},
140     {0x180d, "Heart Rate"},
141     {0x180e, "Phone Alert Status Service"},
142     {0x180f, "Battery Service"},
143     {0x1810, "Blood Pressure"},
144     {0x1811, "Alert Notification Service"},
145     {0x1812, "Human Interface Device"},
146     {0x1813, "Scan Parameters"},
147     {0x1814, "Running Speed and Cadence"},
148     {0x1816, "Cycling Speed and Cadence"},
149     /* Declarations - http://developer.bluetooth.org/gatt/declarations/Pages/DeclarationsHome.aspx */
150     {0x2800, "GATT Primary Service Declaration"},
151     {0x2801, "GATT Secondary Service Declaration"},
152     {0x2802, "GATT Include Declaration"},
153     {0x2803, "GATT Characteristic Declaration"},
154     /* Descriptors - http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorsHomePage.aspx */
155     {0x2900, "Characteristic Extended Properties"},
156     {0x2901, "Characteristic User Description"},
157     {0x2902, "Client Characteristic Configuration"},
158     {0x2903, "Server Characteristic Configuration"},
159     {0x2904, "Characteristic Presentation Format"},
160     {0x2905, "Characteristic Aggregate Format"},
161     {0x2906, "Valid Range"},
162     {0x2907, "External Report Reference"},
163     {0x2908, "Report Reference"},
164     /* Characteristics - http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx */
165     {0x2a00, "Device Name"},
166     {0x2a01, "Appearance"},
167     {0x2a02, "Peripheral Privacy Flag"},
168     {0x2a03, "Reconnection Address"},
169     {0x2a04, "Peripheral Preferred Connection Parameters"},
170     {0x2a05, "Service Changed"},
171     {0x2a06, "Alert Level"},
172     {0x2a07, "Tx Power Level"},
173     {0x2a08, "Date Time"},
174     {0x2a09, "Day of Week"},
175     {0x2a0a, "Day Date Time"},
176     {0x2a0c, "Exact Time 256"},
177     {0x2a0d, "DST Offset"},
178     {0x2a0e, "Time Zone"},
179     {0x2a0f, "Local Time Information"},
180     {0x2a11, "Time with DST"},
181     {0x2a12, "Time Accuracy"},
182     {0x2a13, "Time Source"},
183     {0x2a14, "Reference Time Information"},
184     {0x2a16, "Time Update Control Point"},
185     {0x2a17, "Time Update State"},
186     {0x2a18, "Glucose Measurement"},
187     {0x2a19, "Battery Level"},
188     {0x2a1c, "Temperature Measurement"},
189     {0x2a1d, "Temperature Type"},
190     {0x2a1e, "Intermediate Temperature"},
191     {0x2a21, "Measurement Interval"},
192     {0x2a22, "Boot Keyboard Input Report"},
193     {0x2a23, "System ID"},
194     {0x2a24, "Model Number String"},
195     {0x2a25, "Serial Number String"},
196     {0x2a26, "Firmware Revision String"},
197     {0x2a27, "Hardware Revision String"},
198     {0x2a28, "Software Revision String"},
199     {0x2a29, "Manufacturer Name String"},
200     {0x2a2a, "IEEE 11073-20601 Reg. Cert. Data List"},
201     {0x2a2b, "Current Time"},
202     {0x2a31, "Scan Refresh"},
203     {0x2a32, "Boot Keyboard Output Report"},
204     {0x2a33, "Boot Mouse Input Report"},
205     {0x2a34, "Glucose Measurement Context"},
206     {0x2a35, "Blood Pressure Measurement"},
207     {0x2a36, "Intermediate Cuff Pressure"},
208     {0x2a37, "Heart Rate Measurement"},
209     {0x2a38, "Body Sensor Location"},
210     {0x2a39, "Heart Rate Control Point"},
211     {0x2a3f, "Alert Status"},
212     {0x2a40, "Ringer Control Point"},
213     {0x2a41, "Ringer Setting"},
214     {0x2a42, "Alert Category ID Bit Mask"},
215     {0x2a43, "Alert Category ID"},
216     {0x2a44, "Alert Notification Control Point"},
217     {0x2a45, "Unread Alert Status"},
218     {0x2a46, "New Alert"},
219     {0x2a47, "Supported New Alert Category"},
220     {0x2a48, "Supported Unread Alert Category"},
221     {0x2a49, "Blood Pressure Feature"},
222     {0x2a4a, "HID Information"},
223     {0x2a4b, "Report Map"},
224     {0x2a4c, "HID Control Point"},
225     {0x2a4d, "Report"},
226     {0x2a4e, "Protocol Mode"},
227     {0x2a4f, "Scan Interval Window"},
228     {0x2a50, "PnP ID"},
229     {0x2a51, "Glucose Feature"},
230     {0x2a52, "Record Access Control Point"},
231     {0x2a53, "RSC Measurement"},
232     {0x2a54, "RSC Feature"},
233     {0x2a55, "SC Control Point"},
234     {0x2a5b, "CSC Measurement"},
235     {0x2a5c, "CSC Feature"},
236     {0x2a5d, "Sensor Location"},
237     {0x0, NULL}
238 };
239 static value_string_ext uuid_vals_ext = VALUE_STRING_EXT_INIT(uuid_vals);
240 
241 static const value_string uuid_format_vals[] = {
242     {0x01, "16-bit UUIDs"},
243     {0x02, "128-bit UUIDs"},
244     {0x0, NULL}
245 };
246 
247 static const value_string flags_vals[] = {
248     {0x00, "Cancel All"},
249     {0x01, "Immediately Write All"},
250     {0x0, NULL}
251 };
252 
253 static void
254 dissect_btatt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
255 {
256     int offset = 0;
257     proto_item *ti, *item;
258     proto_tree *st, *ltree;
259     guint8 opcode;
260 
261     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATT");
262 
263     switch (pinfo->p2p_dir) {
264 
265     case P2P_DIR_SENT:
266         col_add_str(pinfo->cinfo, COL_INFO, "Sent ");
267         break;
268 
269     case P2P_DIR_RECV:
270         col_add_str(pinfo->cinfo, COL_INFO, "Rcvd ");
271         break;
272 
273     case P2P_DIR_UNKNOWN:
274         break;
275 
276     default:
277         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
278             pinfo->p2p_dir);
279         break;
280     }
281 
282     if (tvb_length_remaining(tvb, 0) < 1)
283         return;
284 
285     ti = proto_tree_add_item(tree, proto_btatt, tvb, 0, -1, ENC_NA);
286     st = proto_item_add_subtree(ti, ett_btatt);
287 
288     item = proto_tree_add_item(st, hf_btatt_opcode, tvb, 0, 1, ENC_LITTLE_ENDIAN);
289     opcode = tvb_get_guint8(tvb, 0);
290     offset++;
291 
292     col_append_fstr(pinfo->cinfo, COL_INFO, "%s", val_to_str(opcode, opcode_vals, "<unknown>"));
293 
294     switch (opcode) {
295     case 0x01: /* Error Response */
296         proto_tree_add_item(st, hf_btatt_req_opcode_in_error, tvb, offset, 1, ENC_LITTLE_ENDIAN);
297         offset++;
298         proto_tree_add_item(st, hf_btatt_handle_in_error, tvb, offset, 2, ENC_LITTLE_ENDIAN);
299         col_append_fstr(pinfo->cinfo, COL_INFO, " - %s, Handle: 0x%04x",
300                         val_to_str(tvb_get_guint8(tvb, offset+2), error_vals, "<unknown>"),
301                         tvb_get_letohs(tvb, offset));
302         offset += 2;
303         proto_tree_add_item(st, hf_btatt_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
304         offset++;
305         break;
306 
307     case 0x02: /* Exchange MTU Request */
308         col_append_fstr(pinfo->cinfo, COL_INFO, ", Client Rx MTU: %u", tvb_get_letohs(tvb, offset));
309         proto_tree_add_item(st, hf_btatt_client_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
310         offset += 2;
311         break;
312 
313     case 0x03: /* Exchange MTU Response */
314         col_append_fstr(pinfo->cinfo, COL_INFO, ", Server Rx MTU: %u", tvb_get_letohs(tvb, offset));
315         proto_tree_add_item(st, hf_btatt_server_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
316         offset += 2;
317         break;
318 
319     case 0x04: /* Find Information Request */
320         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handles: 0x%04x..0x%04x",
321                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
322         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
323         offset += 2;
324         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
325         offset += 2;
326         break;
327 
328     case 0x05: /* Find Information Response */
329         {
330             guint8 format = tvb_get_guint8(tvb, offset);
331 
332             item = proto_tree_add_item(st, hf_btatt_uuid_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
333             offset++;
334 
335             if( format == 1 ) {
336                 while( tvb_length_remaining(tvb, offset) > 0) {
337                     proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
338                     offset += 2;
339                     proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
340                     offset += 2;
341                 }
342             }
343             else if( format == 2 ) {
344                 while( tvb_length_remaining(tvb, offset) > 0) {
345                     proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
346                     offset += 2;
347                     proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
348                     offset += 16;
349                 }
350             }
351             else {
352                 expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN, "Unknown format");
353             }
354         }
355         break;
356 
357     case 0x06: /* Find By Type Value Request */
358         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
359                             val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &uuid_vals_ext, "<unknown>"),
360                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
361 
362         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
363         offset += 2;
364         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
365         offset += 2;
366         proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
367         offset += 2;
368         if( tvb_length_remaining(tvb, offset)  > 0)
369             proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
370         break;
371 
372     case 0x07: /* Find By Type Value Response */
373         while( tvb_length_remaining(tvb, offset) > 0 ) {
374             item = proto_tree_add_text(st, tvb, offset, 4,
375                                             "Handles Info, Handle: 0x%04x, Group End Handle: 0x%04x",
376                                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
377 
378             ltree = proto_item_add_subtree(item, ett_btatt_list);
379 
380             proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
381             offset += 2;
382             proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
383             offset += 2;
384         }
385         break;
386 
387     case 0x08: /* Read By Type Request */
388     case 0x10: /* Read By Group Type Request */
389         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
390                             val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &uuid_vals_ext, "<unknown>"),
391                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
392 
393         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
394         offset += 2;
395         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
396         offset += 2;
397 
398         if (tvb_length_remaining(tvb, offset) == 2) {
399             proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
400             offset += 2;
401         }
402         else if (tvb_length_remaining(tvb, offset) == 16) {
403             item = proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
404             proto_item_append_text(item, " (%s)", val_to_str_ext_const(tvb_get_letohs(tvb, offset),
405                                             &uuid_vals_ext, "<unknown>"));
406             offset += 16;
407         }
408         break;
409 
410     case 0x09: /* Read By Type Response */
411         {
412             guint8 length = tvb_get_guint8(tvb, offset);
413 
414             proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
415             offset++;
416 
417             if(length > 0) {
418                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u",
419                                         tvb_length_remaining(tvb, offset)/length);
420 
421                 while (tvb_length_remaining(tvb, offset) >= length)
422                 {
423                     item = proto_tree_add_text(st, tvb, offset, length, "Attribute Data, Handle: 0x%04x",
424                                                     tvb_get_letohs(tvb, offset));
425 
426                     ltree = proto_item_add_subtree(item, ett_btatt_list);
427 
428                     proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
429                     offset += 2;
430                     proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length-2, ENC_LITTLE_ENDIAN);
431                     offset += (length-2);
432                 }
433             }
434         }
435         break;
436 
437     case 0x0a: /* Read Request */
438         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
439         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
440         offset += 2;
441         break;
442 
443     case 0x0b: /* Read Response */
444     case 0x0d: /* Read Blob Response */
445     case 0x0f: /* Multiple Read Response */
446         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
447         break;
448 
449     case 0x0c: /* Read Blob Request */
450         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
451                         tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
452         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
453         offset += 2;
454         proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
455         offset += 2;
456         break;
457 
458     case 0x0e: /* Multiple Read Request */
459         if(tvb_length_remaining(tvb, offset) < 4) {
460             expert_add_info_format(pinfo, item, PI_PROTOCOL, PI_WARN,
461                                                     "Too few handles, should be 2 or more");
462             break;
463         }
464 
465         col_append_str(pinfo->cinfo, COL_INFO, ", Handles: ");
466         while (tvb_length_remaining(tvb, offset) >= 2) {
467             proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
468             col_append_fstr(pinfo->cinfo, COL_INFO, "0x%04x ", tvb_get_letohs(tvb, offset));
469             offset += 2;
470         }
471         break;
472 
473     case 0x11: /* Read By Group Type Response */
474         {
475             guint8 length = tvb_get_guint8(tvb, offset);
476 
477             proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
478             offset++;
479 
480             if(length > 0) {
481                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u", tvb_length_remaining(tvb, offset)/length);
482 
483                 while (tvb_length_remaining(tvb, offset) >= length) {
484                     item = proto_tree_add_text(st, tvb, offset, length,
485                                                     "Attribute Data, Handle: 0x%04x, Group End Handle: 0x%04x",
486                                                     tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
487 
488                     ltree = proto_item_add_subtree(item, ett_btatt_list);
489 
490                     proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
491                     offset += 2;
492                     proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
493                     offset += 2;
494                     proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length-4, ENC_LITTLE_ENDIAN);
495                     offset += (length-4);
496                 }
497             }
498         }
499         break;
500 
501     case 0x12: /* Write Request */
502     case 0x52: /* Write Command */
503     case 0x1b: /* Handle Value Notification */
504     case 0x1d: /* Handle Value Indication */
505         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
506         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
507         offset += 2;
508         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
509         break;
510 
511     case 0x16: /* Prepare Write Request */
512     case 0x17: /* Prepare Write Response */
513         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
514                         tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
515         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
516         offset += 2;
517         proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
518         offset += 2;
519         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
520         break;
521 
522     case 0x18: /* Execute Write Request */
523         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
524                         val_to_str(tvb_get_guint8(tvb, offset), flags_vals, "<unknown>"));
525         proto_tree_add_item(st, hf_btatt_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
526         offset++;
527         break;
528 
529     case 0xd2: /* Signed Write Command */
530         {
531             guint8 length;
532 
533             col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
534             proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
535             offset += 2;
536             length = tvb_length_remaining(tvb, offset);
537             if (length > 12) {
538                 proto_tree_add_item(st, hf_btatt_value, tvb, offset, length-12, ENC_NA);
539                 offset+=length-12;
540             }
541 
542             proto_tree_add_item(st, hf_btatt_sign_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
543             offset+=4;
544             proto_tree_add_item(st, hf_btatt_signature, tvb, offset, 8, ENC_NA);
545             offset+=8;
546         break;
547         }
548     default:
549         break;
550     }
551 }
552 
553 void
554 proto_register_btatt(void)
555 {
556     module_t *module;
557 
558     static hf_register_info hf[] = {
559         {&hf_btatt_opcode,
560             {"Opcode", "btatt.opcode",
561             FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
562             NULL, HFILL}
563         },
564         {&hf_btatt_handle,
565             {"Handle", "btatt.handle",
566             FT_UINT16, BASE_HEX, NULL, 0x0,
567             NULL, HFILL}
568         },
569         {&hf_btatt_starting_handle,
570             {"Starting Handle", "btatt.starting_handle",
571             FT_UINT16, BASE_HEX, NULL, 0x0,
572             NULL, HFILL}
573         },
574         {&hf_btatt_ending_handle,
575             {"Ending Handle", "btatt.ending_handle",
576             FT_UINT16, BASE_HEX, NULL, 0x0,
577             NULL, HFILL}
578         },
579         {&hf_btatt_group_end_handle,
580             {"Group End Handle", "btatt.group_end_handle",
581             FT_UINT16, BASE_HEX, NULL, 0x0,
582             NULL, HFILL}
583         },
584         {&hf_btatt_value,
585             {"Value", "btatt.value",
586             FT_BYTES, BASE_NONE, NULL, 0x0,
587             NULL, HFILL}
588         },
589         {&hf_btatt_req_opcode_in_error,
590             {"Request Opcode in Error", "btatt.req_opcode_in_error",
591             FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
592             NULL, HFILL}
593         },
594         {&hf_btatt_handle_in_error,
595             {"Handle in Error", "btatt.handle_in_error",
596             FT_UINT16, BASE_HEX, NULL, 0x0,
597             NULL, HFILL}
598         },
599         {&hf_btatt_error_code,
600             {"Error Code", "btatt.error_code",
601             FT_UINT8, BASE_HEX, VALS(error_vals), 0x0,
602             NULL, HFILL}
603         },
604         {&hf_btatt_uuid16,
605             {"UUID", "btatt.uuid16",
606             FT_UINT16, BASE_HEX |BASE_EXT_STRING, &uuid_vals_ext, 0x0,
607             NULL, HFILL}
608         },
609         {&hf_btatt_uuid128,
610             {"UUID", "btatt.uuid128",
611             FT_BYTES, BASE_NONE, NULL, 0x0,
612             NULL, HFILL}
613         },
614         {&hf_btatt_client_rx_mtu,
615             {"Client Rx MTU", "btatt.client_rx_mtu",
616             FT_UINT16, BASE_DEC, NULL, 0x0,
617             NULL, HFILL}
618         },
619         {&hf_btatt_server_rx_mtu,
620             {"Server Rx MTU", "btatt.server_rx_mtu",
621             FT_UINT16, BASE_DEC, NULL, 0x0,
622             NULL, HFILL}
623         },
624         {&hf_btatt_uuid_format,
625             {"UUID Format", "btatt.uuid_format",
626             FT_UINT8, BASE_HEX, VALS(uuid_format_vals), 0x0,
627             NULL, HFILL}
628         },
629         {&hf_btatt_length,
630             {"Length", "btatt.length",
631             FT_UINT8, BASE_DEC, NULL, 0x0,
632             "Length of Handle/Value Pair", HFILL}
633         },
634         {&hf_btatt_offset,
635             {"Offset", "btatt.offset",
636             FT_UINT16, BASE_DEC, NULL, 0x0,
637             NULL, HFILL}
638         },
639         {&hf_btatt_flags,
640             {"Flags", "btatt.flags",
641             FT_UINT8, BASE_HEX, VALS(flags_vals), 0x0,
642             NULL, HFILL}
643         },
644         {&hf_btatt_sign_counter,
645             {"Sign Counter", "btatt.sign_counter",
646             FT_UINT32, BASE_DEC, NULL, 0x0,
647             NULL, HFILL}
648         },
649         {&hf_btatt_signature,
650             {"Signature", "btatt.signature",
651             FT_BYTES, BASE_NONE, NULL, 0x0,
652             NULL, HFILL}
653         }
654     };
655 
656     /* Setup protocol subtree array */
657     static gint *ett[] = {
658         &ett_btatt,
659         &ett_btatt_list
660     };
661 
662     /* Register the protocol name and description */
663     proto_btatt = proto_register_protocol("Bluetooth Attribute Protocol", "ATT", "btatt");
664 
665     register_dissector("btatt", dissect_btatt, proto_btatt);
666 
667     /* Required function calls to register the header fields and subtrees used */
668     proto_register_field_array(proto_btatt, hf, array_length(hf));
669     proto_register_subtree_array(ett, array_length(ett));
670 
671     module = prefs_register_protocol(proto_btatt, NULL);
672     prefs_register_static_text_preference(module, "att.version",
673             "Bluetooth Protocol ATT version from Core 4.0",
674             "Version of protocol supported by this dissector.");
675 }
676 
677 void
678 proto_reg_handoff_btatt(void)
679 {
680     dissector_handle_t btatt_handle;
681 
682     btatt_handle = find_dissector("btatt");
683     dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_ATT, btatt_handle);
684     dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_ATT, btatt_handle);
685 }
686 
687 /*
688  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
689  *
690  * Local variables:
691  * c-basic-offset: 4
692  * tab-width: 8
693  * indent-tabs-mode: nil
694  * End:
695  *
696  * vi: set shiftwidth=4 tabstop=8 expandtab:
697  * :indentSize=4:tabSize=8:noTabs=true:
698  */
699