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
dissect_btatt(tvbuff_t * tvb,packet_info * pinfo,proto_tree * tree)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
proto_register_btatt(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
proto_reg_handoff_btatt(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