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