Revert "Fixup: tvb_* -> tvb_captured"
[metze/wireshark/wip.git] / epan / dissectors / packet-btatt.c
1 /* packet-btatt.c
2  * Routines for Bluetooth Attribute Protocol dissection
3  *
4  * Copyright 2012, Allan M. Madsen <allan.m@madsen.dk>
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * Wireshark - Network traffic analyzer
11  * By Gerald Combs <gerald@wireshark.org>
12  * Copyright 1998 Gerald Combs
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27  */
28
29 #include "config.h"
30
31 #include <epan/packet.h>
32 #include <epan/prefs.h>
33 #include <epan/expert.h>
34
35 #include "packet-bluetooth-hci.h"
36 #include "packet-btl2cap.h"
37
38 /* Initialize the protocol and registered fields */
39 static int proto_btatt = -1;
40
41 static int hf_btatt_opcode = -1;
42 static int hf_btatt_handle = -1;
43 static int hf_btatt_starting_handle = -1;
44 static int hf_btatt_ending_handle = -1;
45 static int hf_btatt_group_end_handle = -1;
46 static int hf_btatt_value = -1;
47 static int hf_btatt_req_opcode_in_error = -1;
48 static int hf_btatt_handle_in_error = -1;
49 static int hf_btatt_error_code = -1;
50 static int hf_btatt_uuid16 = -1;
51 static int hf_btatt_uuid128 = -1;
52 static int hf_btatt_client_rx_mtu = -1;
53 static int hf_btatt_server_rx_mtu = -1;
54 static int hf_btatt_uuid_format = -1;
55 static int hf_btatt_length = -1;
56 static int hf_btatt_offset = -1;
57 static int hf_btatt_flags = -1;
58 static int hf_btatt_sign_counter = -1;
59 static int hf_btatt_signature = -1;
60 static int hf_btatt_attribute_data = -1;
61 static int hf_btatt_handles_info = -1;
62
63 /* Initialize the subtree pointers */
64 static gint ett_btatt = -1;
65 static gint ett_btatt_list = -1;
66
67 static expert_field ei_btatt_uuid_format_unknown = EI_INIT;
68 static expert_field ei_btatt_handle_too_few = EI_INIT;
69
70 static dissector_handle_t btatt_handle;
71
72 /* Opcodes */
73 static const value_string opcode_vals[] = {
74     {0x01, "Error Response"},
75     {0x02, "Exchange MTU Request"},
76     {0x03, "Exchange MTU Response"},
77     {0x04, "Find Information Request"},
78     {0x05, "Find Information Response"},
79     {0x06, "Find By Type Value Request"},
80     {0x07, "Find By Type Value Response"},
81     {0x08, "Read By Type Request"},
82     {0x09, "Read By Type Response"},
83     {0x0a, "Read Request"},
84     {0x0b, "Read Response"},
85     {0x0c, "Read Blob Request"},
86     {0x0d, "Read Blob Response"},
87     {0x0e, "Read Multiple Request"},
88     {0x0f, "Read Multiple Response"},
89     {0x10, "Read By Group Type Request"},
90     {0x11, "Read By Group Type Response"},
91     {0x12, "Write Request"},
92     {0x13, "Write Response"},
93     {0x16, "Prepare Write Request"},
94     {0x17, "Prepare Write Response"},
95     {0x18, "Execute Write Request"},
96     {0x19, "Execute Write Response"},
97     {0x1B, "Handle Value Notification"},
98     {0x1D, "Handle Value Indication"},
99     {0x1E, "Handle Value Confirmation"},
100     {0x52, "Write Command"},
101     {0xD2, "Signed Write Command"},
102     {0x0, NULL}
103 };
104
105 /* Error codes */
106 static const value_string error_vals[] = {
107     {0x01, "Invalid Handle"},
108     {0x02, "Read Not Permitted"},
109     {0x03, "Write Not Permitted"},
110     {0x04, "Invalid PDU"},
111     {0x05, "Insufficient Authentication"},
112     {0x06, "Request Not Supported"},
113     {0x07, "Invalid Offset"},
114     {0x08, "Insufficient Authorization"},
115     {0x09, "Prepare Queue Full"},
116     {0x0a, "Attribute Not Found"},
117     {0x0b, "Attribute Not Long"},
118     {0x0c, "Insufficient Encryption Key Size"},
119     {0x0d, "Invalid Attribute Value Length"},
120     {0x0e, "Unlikely Error"},
121     {0x0f, "Insufficient Encryption"},
122     {0x10, "Unsupported Group Type"},
123     {0x11, "Insufficient Resources"},
124     {0x80, "Application Error"},
125     {0xfd, "Improper Client Characteristic Configuration Descriptor"},
126     {0xfe, "Procedure Already In Progress"},
127     {0xff, "Out of Range"},
128     {0x0, NULL}
129 };
130
131 static const value_string uuid_format_vals[] = {
132     {0x01, "16-bit UUIDs"},
133     {0x02, "128-bit UUIDs"},
134     {0x0, NULL}
135 };
136
137 static const value_string flags_vals[] = {
138     {0x00, "Cancel All"},
139     {0x01, "Immediately Write All"},
140     {0x0, NULL}
141 };
142
143 void proto_register_btatt(void);
144 void proto_reg_handoff_btatt(void);
145
146 static int
147 dissect_btatt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
148 {
149     int offset = 0;
150     proto_item *ti, *item;
151     proto_tree *st, *ltree;
152     guint8 opcode;
153
154     if (tvb_length_remaining(tvb, 0) < 1)
155         return 0;
156
157     ti = proto_tree_add_item(tree, proto_btatt, tvb, 0, -1, ENC_NA);
158     st = proto_item_add_subtree(ti, ett_btatt);
159
160     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ATT");
161
162     switch (pinfo->p2p_dir) {
163         case P2P_DIR_SENT:
164             col_set_str(pinfo->cinfo, COL_INFO, "Sent ");
165             break;
166         case P2P_DIR_RECV:
167             col_set_str(pinfo->cinfo, COL_INFO, "Rcvd ");
168             break;
169         default:
170             col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown direction %d ",
171                 pinfo->p2p_dir);
172             break;
173     }
174
175     item = proto_tree_add_item(st, hf_btatt_opcode, tvb, 0, 1, ENC_LITTLE_ENDIAN);
176     opcode = tvb_get_guint8(tvb, 0);
177     offset++;
178
179     col_append_str(pinfo->cinfo, COL_INFO, val_to_str_const(opcode, opcode_vals, "<unknown>"));
180
181     switch (opcode) {
182     case 0x01: /* Error Response */
183         proto_tree_add_item(st, hf_btatt_req_opcode_in_error, tvb, offset, 1, ENC_LITTLE_ENDIAN);
184         offset++;
185         proto_tree_add_item(st, hf_btatt_handle_in_error, tvb, offset, 2, ENC_LITTLE_ENDIAN);
186         col_append_fstr(pinfo->cinfo, COL_INFO, " - %s, Handle: 0x%04x",
187                         val_to_str_const(tvb_get_guint8(tvb, offset+2), error_vals, "<unknown>"),
188                         tvb_get_letohs(tvb, offset));
189         offset += 2;
190         proto_tree_add_item(st, hf_btatt_error_code, tvb, offset, 1, ENC_LITTLE_ENDIAN);
191         offset++;
192         break;
193
194     case 0x02: /* Exchange MTU Request */
195         col_append_fstr(pinfo->cinfo, COL_INFO, ", Client Rx MTU: %u", tvb_get_letohs(tvb, offset));
196         proto_tree_add_item(st, hf_btatt_client_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
197         offset += 2;
198         break;
199
200     case 0x03: /* Exchange MTU Response */
201         col_append_fstr(pinfo->cinfo, COL_INFO, ", Server Rx MTU: %u", tvb_get_letohs(tvb, offset));
202         proto_tree_add_item(st, hf_btatt_server_rx_mtu, tvb, offset, 2, ENC_LITTLE_ENDIAN);
203         offset += 2;
204         break;
205
206     case 0x04: /* Find Information Request */
207         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handles: 0x%04x..0x%04x",
208                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
209         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
210         offset += 2;
211         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
212         offset += 2;
213         break;
214
215     case 0x05: /* Find Information Response */
216         {
217             guint8 format = tvb_get_guint8(tvb, offset);
218
219             item = proto_tree_add_item(st, hf_btatt_uuid_format, tvb, offset, 1, ENC_LITTLE_ENDIAN);
220             offset++;
221
222             if( format == 1 ) {
223                 while( tvb_length_remaining(tvb, offset) > 0) {
224                     proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
225                     offset += 2;
226                     proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
227                     offset += 2;
228                 }
229             }
230             else if( format == 2 ) {
231                 while( tvb_length_remaining(tvb, offset) > 0) {
232                     proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
233                     offset += 2;
234                     proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
235                     offset += 16;
236                 }
237             }
238             else {
239                 expert_add_info(pinfo, item, &ei_btatt_uuid_format_unknown);
240             }
241         }
242         break;
243
244     case 0x06: /* Find By Type Value Request */
245         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
246                             val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &bt_sig_uuid_vals_ext, "<unknown>"),
247                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
248
249         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
250         offset += 2;
251         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
252         offset += 2;
253         proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
254         offset += 2;
255         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
256         offset = tvb_reported_length(tvb);
257         break;
258
259     case 0x07: /* Find By Type Value Response */
260         while( tvb_length_remaining(tvb, offset) > 0 ) {
261             item = proto_tree_add_none_format(st, hf_btatt_handles_info, tvb, offset, 4,
262                                             "Handles Info, Handle: 0x%04x, Group End Handle: 0x%04x",
263                                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
264
265             ltree = proto_item_add_subtree(item, ett_btatt_list);
266
267             proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
268             offset += 2;
269             proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
270             offset += 2;
271         }
272         break;
273
274     case 0x08: /* Read By Type Request */
275     case 0x10: /* Read By Group Type Request */
276         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s, Handles: 0x%04x..0x%04x",
277                             val_to_str_ext_const(tvb_get_letohs(tvb, offset+4), &bt_sig_uuid_vals_ext, "<unknown>"),
278                             tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
279
280         proto_tree_add_item(st, hf_btatt_starting_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
281         offset += 2;
282         proto_tree_add_item(st, hf_btatt_ending_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
283         offset += 2;
284
285         if (tvb_length_remaining(tvb, offset) == 2) {
286             proto_tree_add_item(st, hf_btatt_uuid16, tvb, offset, 2, ENC_LITTLE_ENDIAN);
287             offset += 2;
288         }
289         else if (tvb_length_remaining(tvb, offset) == 16) {
290             item = proto_tree_add_item(st, hf_btatt_uuid128, tvb, offset, 16, ENC_NA);
291             proto_item_append_text(item, " (%s)", val_to_str_ext_const(tvb_get_letohs(tvb, offset),
292                                             &bt_sig_uuid_vals_ext, "<unknown>"));
293             offset += 16;
294         }
295         break;
296
297     case 0x09: /* Read By Type Response */
298         {
299             guint8 length = tvb_get_guint8(tvb, offset);
300
301             proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
302             offset++;
303
304             if(length > 0) {
305                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u",
306                                         tvb_length_remaining(tvb, offset)/length);
307
308                 while (tvb_length_remaining(tvb, offset) >= length)
309                 {
310                     item = proto_tree_add_none_format(st, hf_btatt_attribute_data, tvb,
311                                                     offset, length, "Attribute Data, Handle: 0x%04x",
312                                                     tvb_get_letohs(tvb, offset));
313
314                     ltree = proto_item_add_subtree(item, ett_btatt_list);
315
316                     proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
317                     offset += 2;
318                     proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length - 2, ENC_NA);
319                     offset += (length-2);
320                 }
321             }
322         }
323         break;
324
325     case 0x0a: /* Read Request */
326         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
327         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
328         offset += 2;
329         break;
330
331     case 0x0b: /* Read Response */
332     case 0x0d: /* Read Blob Response */
333     case 0x0f: /* Multiple Read Response */
334         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
335         offset = tvb_reported_length(tvb);
336         break;
337
338     case 0x0c: /* Read Blob Request */
339         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
340                         tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
341         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
342         offset += 2;
343         proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
344         offset += 2;
345         break;
346
347     case 0x0e: /* Multiple Read Request */
348         if(tvb_length_remaining(tvb, offset) < 4) {
349             expert_add_info(pinfo, item, &ei_btatt_handle_too_few);
350             break;
351         }
352
353         col_append_str(pinfo->cinfo, COL_INFO, ", Handles: ");
354         while (tvb_length_remaining(tvb, offset) >= 2) {
355             proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
356             col_append_fstr(pinfo->cinfo, COL_INFO, "0x%04x ", tvb_get_letohs(tvb, offset));
357             offset += 2;
358         }
359         break;
360
361     case 0x11: /* Read By Group Type Response */
362         {
363             guint8 length = tvb_get_guint8(tvb, offset);
364
365             proto_tree_add_item(st, hf_btatt_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
366             offset++;
367
368             if(length > 0) {
369                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Attribute List Length: %u", tvb_length_remaining(tvb, offset)/length);
370
371                 while (tvb_length_remaining(tvb, offset) >= length) {
372                     item = proto_tree_add_none_format(st, hf_btatt_attribute_data, tvb, offset, length,
373                                                     "Attribute Data, Handle: 0x%04x, Group End Handle: 0x%04x",
374                                                     tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
375
376                     ltree = proto_item_add_subtree(item, ett_btatt_list);
377
378                     proto_tree_add_item(ltree, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
379                     offset += 2;
380                     proto_tree_add_item(ltree, hf_btatt_group_end_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
381                     offset += 2;
382                     proto_tree_add_item(ltree, hf_btatt_value, tvb, offset, length - 4, ENC_NA);
383                     offset += (length-4);
384                 }
385             }
386         }
387         break;
388
389     case 0x12: /* Write Request */
390     case 0x52: /* Write Command */
391     case 0x1b: /* Handle Value Notification */
392     case 0x1d: /* Handle Value Indication */
393         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
394         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
395         offset += 2;
396         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
397         offset = tvb_reported_length(tvb);
398         break;
399
400     case 0x16: /* Prepare Write Request */
401     case 0x17: /* Prepare Write Response */
402         col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x, Offset: %u",
403                         tvb_get_letohs(tvb, offset), tvb_get_letohs(tvb, offset+2));
404         proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
405         offset += 2;
406         proto_tree_add_item(st, hf_btatt_offset, tvb, offset, 2, ENC_LITTLE_ENDIAN);
407         offset += 2;
408         proto_tree_add_item(st, hf_btatt_value, tvb, offset, -1, ENC_NA);
409         offset = tvb_reported_length(tvb);
410         break;
411
412     case 0x18: /* Execute Write Request */
413         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
414                         val_to_str_const(tvb_get_guint8(tvb, offset), flags_vals, "<unknown>"));
415         proto_tree_add_item(st, hf_btatt_flags, tvb, offset, 1, ENC_LITTLE_ENDIAN);
416         offset++;
417         break;
418
419     case 0xd2: /* Signed Write Command */
420         {
421             guint8 length;
422
423             col_append_fstr(pinfo->cinfo, COL_INFO, ", Handle: 0x%04x", tvb_get_letohs(tvb, offset));
424             proto_tree_add_item(st, hf_btatt_handle, tvb, offset, 2, ENC_LITTLE_ENDIAN);
425             offset += 2;
426             length = tvb_length_remaining(tvb, offset);
427             if (length > 12) {
428                 proto_tree_add_item(st, hf_btatt_value, tvb, offset, length-12, ENC_NA);
429                 offset+=length-12;
430             }
431
432             proto_tree_add_item(st, hf_btatt_sign_counter, tvb, offset, 4, ENC_LITTLE_ENDIAN);
433             offset+=4;
434             proto_tree_add_item(st, hf_btatt_signature, tvb, offset, 8, ENC_NA);
435             offset+=8;
436         break;
437         }
438     default:
439         break;
440     }
441     return offset;
442 }
443
444 void
445 proto_register_btatt(void)
446 {
447     module_t *module;
448
449     static hf_register_info hf[] = {
450         {&hf_btatt_opcode,
451             {"Opcode", "btatt.opcode",
452             FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
453             NULL, HFILL}
454         },
455         {&hf_btatt_handles_info,
456             {"Handles Info", "btatt.handles_info",
457             FT_NONE, BASE_NONE, NULL, 0x0,
458             NULL, HFILL}
459         },
460         {&hf_btatt_attribute_data,
461             {"Attribute Data", "btatt.attribute_data",
462             FT_NONE, BASE_NONE, NULL, 0x0,
463             NULL, HFILL}
464         },
465         {&hf_btatt_handle,
466             {"Handle", "btatt.handle",
467             FT_UINT16, BASE_HEX, NULL, 0x0,
468             NULL, HFILL}
469         },
470         {&hf_btatt_starting_handle,
471             {"Starting Handle", "btatt.starting_handle",
472             FT_UINT16, BASE_HEX, NULL, 0x0,
473             NULL, HFILL}
474         },
475         {&hf_btatt_ending_handle,
476             {"Ending Handle", "btatt.ending_handle",
477             FT_UINT16, BASE_HEX, NULL, 0x0,
478             NULL, HFILL}
479         },
480         {&hf_btatt_group_end_handle,
481             {"Group End Handle", "btatt.group_end_handle",
482             FT_UINT16, BASE_HEX, NULL, 0x0,
483             NULL, HFILL}
484         },
485         {&hf_btatt_value,
486             {"Value", "btatt.value",
487             FT_BYTES, BASE_NONE, NULL, 0x0,
488             NULL, HFILL}
489         },
490         {&hf_btatt_req_opcode_in_error,
491             {"Request Opcode in Error", "btatt.req_opcode_in_error",
492             FT_UINT8, BASE_HEX, VALS(opcode_vals), 0x0,
493             NULL, HFILL}
494         },
495         {&hf_btatt_handle_in_error,
496             {"Handle in Error", "btatt.handle_in_error",
497             FT_UINT16, BASE_HEX, NULL, 0x0,
498             NULL, HFILL}
499         },
500         {&hf_btatt_error_code,
501             {"Error Code", "btatt.error_code",
502             FT_UINT8, BASE_HEX, VALS(error_vals), 0x0,
503             NULL, HFILL}
504         },
505         {&hf_btatt_uuid16,
506             {"UUID", "btatt.uuid16",
507             FT_UINT16, BASE_HEX |BASE_EXT_STRING, &bt_sig_uuid_vals_ext, 0x0,
508             NULL, HFILL}
509         },
510         {&hf_btatt_uuid128,
511             {"UUID", "btatt.uuid128",
512             FT_BYTES, BASE_NONE, NULL, 0x0,
513             NULL, HFILL}
514         },
515         {&hf_btatt_client_rx_mtu,
516             {"Client Rx MTU", "btatt.client_rx_mtu",
517             FT_UINT16, BASE_DEC, NULL, 0x0,
518             NULL, HFILL}
519         },
520         {&hf_btatt_server_rx_mtu,
521             {"Server Rx MTU", "btatt.server_rx_mtu",
522             FT_UINT16, BASE_DEC, NULL, 0x0,
523             NULL, HFILL}
524         },
525         {&hf_btatt_uuid_format,
526             {"UUID Format", "btatt.uuid_format",
527             FT_UINT8, BASE_HEX, VALS(uuid_format_vals), 0x0,
528             NULL, HFILL}
529         },
530         {&hf_btatt_length,
531             {"Length", "btatt.length",
532             FT_UINT8, BASE_DEC, NULL, 0x0,
533             "Length of Handle/Value Pair", HFILL}
534         },
535         {&hf_btatt_offset,
536             {"Offset", "btatt.offset",
537             FT_UINT16, BASE_DEC, NULL, 0x0,
538             NULL, HFILL}
539         },
540         {&hf_btatt_flags,
541             {"Flags", "btatt.flags",
542             FT_UINT8, BASE_HEX, VALS(flags_vals), 0x0,
543             NULL, HFILL}
544         },
545         {&hf_btatt_sign_counter,
546             {"Sign Counter", "btatt.sign_counter",
547             FT_UINT32, BASE_DEC, NULL, 0x0,
548             NULL, HFILL}
549         },
550         {&hf_btatt_signature,
551             {"Signature", "btatt.signature",
552             FT_BYTES, BASE_NONE, NULL, 0x0,
553             NULL, HFILL}
554         }
555     };
556
557     /* Setup protocol subtree array */
558     static gint *ett[] = {
559         &ett_btatt,
560         &ett_btatt_list
561     };
562
563     static ei_register_info ei[] = {
564         { &ei_btatt_uuid_format_unknown, { "btatt.uuid_format.unknown", PI_PROTOCOL, PI_WARN, "Unknown format", EXPFILL }},
565         { &ei_btatt_handle_too_few, { "btatt.handle.too_few", PI_PROTOCOL, PI_WARN, "Too few handles, should be 2 or more", EXPFILL }},
566     };
567
568     expert_module_t* expert_btatt;
569
570     /* Register the protocol name and description */
571     proto_btatt = proto_register_protocol("Bluetooth Attribute Protocol", "BT ATT", "btatt");
572
573     btatt_handle = new_register_dissector("btatt", dissect_btatt, proto_btatt);
574
575     /* Required function calls to register the header fields and subtrees used */
576     proto_register_field_array(proto_btatt, hf, array_length(hf));
577     proto_register_subtree_array(ett, array_length(ett));
578     expert_btatt = expert_register_protocol(proto_btatt);
579     expert_register_field_array(expert_btatt, ei, array_length(ei));
580
581     module = prefs_register_protocol(proto_btatt, NULL);
582     prefs_register_static_text_preference(module, "att.version",
583             "Bluetooth Protocol ATT version from Core 4.0",
584             "Version of protocol supported by this dissector.");
585 }
586
587 void
588 proto_reg_handoff_btatt(void)
589 {
590     dissector_add_uint("btl2cap.psm", BTL2CAP_PSM_ATT, btatt_handle);
591     dissector_add_uint("btl2cap.cid", BTL2CAP_FIXED_CID_ATT, btatt_handle);
592 }
593
594 /*
595  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
596  *
597  * Local variables:
598  * c-basic-offset: 4
599  * tab-width: 8
600  * indent-tabs-mode: nil
601  * End:
602  *
603  * vi: set shiftwidth=4 tabstop=8 expandtab:
604  * :indentSize=4:tabSize=8:noTabs=true:
605  */