1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2011 Andr Dieb Martins <andre.dieb (at) gmail.com> 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24 #ifdef HAVE_CONFIG_H 25 #include <config.h> 26 #endif 27 28 #include <stdio.h> 29 #include <errno.h> 30 #include <unistd.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #include <sys/types.h> 35 #include <netinet/in.h> 36 37 #include "parser.h" 38 39 #define GATT_PRIM_SVC_UUID 0x2800 40 #define GATT_SND_SVC_UUID 0x2801 41 #define GATT_INCLUDE_UUID 0x2802 42 #define GATT_CHARAC_UUID 0x2803 43 44 #define GATT_CHARAC_DEVICE_NAME 0x2A00 45 #define GATT_CHARAC_APPEARANCE 0x2A01 46 #define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02 47 #define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03 48 #define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04 49 #define GATT_CHARAC_SERVICE_CHANGED 0x2A05 50 51 #define GATT_CHARAC_EXT_PROPER_UUID 0x2900 52 #define GATT_CHARAC_USER_DESC_UUID 0x2901 53 #define GATT_CLIENT_CHARAC_CFG_UUID 0x2902 54 #define GATT_SERVER_CHARAC_CFG_UUID 0x2903 55 #define GATT_CHARAC_FMT_UUID 0x2904 56 #define GATT_CHARAC_AGREG_FMT_UUID 0x2905 57 58 59 60 /* Attribute Protocol Opcodes */ 61 #define ATT_OP_ERROR 0x01 62 #define ATT_OP_MTU_REQ 0x02 63 #define ATT_OP_MTU_RESP 0x03 64 #define ATT_OP_FIND_INFO_REQ 0x04 65 #define ATT_OP_FIND_INFO_RESP 0x05 66 #define ATT_OP_FIND_BY_TYPE_REQ 0x06 67 #define ATT_OP_FIND_BY_TYPE_RESP 0x07 68 #define ATT_OP_READ_BY_TYPE_REQ 0x08 69 #define ATT_OP_READ_BY_TYPE_RESP 0x09 70 #define ATT_OP_READ_REQ 0x0A 71 #define ATT_OP_READ_RESP 0x0B 72 #define ATT_OP_READ_BLOB_REQ 0x0C 73 #define ATT_OP_READ_BLOB_RESP 0x0D 74 #define ATT_OP_READ_MULTI_REQ 0x0E 75 #define ATT_OP_READ_MULTI_RESP 0x0F 76 #define ATT_OP_READ_BY_GROUP_REQ 0x10 77 #define ATT_OP_READ_BY_GROUP_RESP 0x11 78 #define ATT_OP_WRITE_REQ 0x12 79 #define ATT_OP_WRITE_RESP 0x13 80 #define ATT_OP_WRITE_CMD 0x52 81 #define ATT_OP_PREP_WRITE_REQ 0x16 82 #define ATT_OP_PREP_WRITE_RESP 0x17 83 #define ATT_OP_EXEC_WRITE_REQ 0x18 84 #define ATT_OP_EXEC_WRITE_RESP 0x19 85 #define ATT_OP_HANDLE_NOTIFY 0x1B 86 #define ATT_OP_HANDLE_IND 0x1D 87 #define ATT_OP_HANDLE_CNF 0x1E 88 #define ATT_OP_SIGNED_WRITE_CMD 0xD2 89 90 /* Error codes for Error response PDU */ 91 #define ATT_ECODE_INVALID_HANDLE 0x01 92 #define ATT_ECODE_READ_NOT_PERM 0x02 93 #define ATT_ECODE_WRITE_NOT_PERM 0x03 94 #define ATT_ECODE_INVALID_PDU 0x04 95 #define ATT_ECODE_INSUFF_AUTHEN 0x05 96 #define ATT_ECODE_REQ_NOT_SUPP 0x06 97 #define ATT_ECODE_INVALID_OFFSET 0x07 98 #define ATT_ECODE_INSUFF_AUTHO 0x08 99 #define ATT_ECODE_PREP_QUEUE_FULL 0x09 100 #define ATT_ECODE_ATTR_NOT_FOUND 0x0A 101 #define ATT_ECODE_ATTR_NOT_LONG 0x0B 102 #define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C 103 #define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D 104 #define ATT_ECODE_UNLIKELY 0x0E 105 #define ATT_ECODE_INSUFF_ENC 0x0F 106 #define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 107 #define ATT_ECODE_INSUFF_RESOURCES 0x11 108 #define ATT_ECODE_IO 0xFF 109 110 111 /* Attribute Protocol Opcodes */ 112 static const char *attop2str(uint8_t op) 113 { 114 switch (op) { 115 case ATT_OP_ERROR: 116 return "Error"; 117 case ATT_OP_MTU_REQ: 118 return "MTU req"; 119 case ATT_OP_MTU_RESP: 120 return "MTU resp"; 121 case ATT_OP_FIND_INFO_REQ: 122 return "Find Information req"; 123 case ATT_OP_FIND_INFO_RESP: 124 return "Find Information resp"; 125 case ATT_OP_FIND_BY_TYPE_REQ: 126 return "Find By Type req"; 127 case ATT_OP_FIND_BY_TYPE_RESP: 128 return "Find By Type resp"; 129 case ATT_OP_READ_BY_TYPE_REQ: 130 return "Read By Type req"; 131 case ATT_OP_READ_BY_TYPE_RESP: 132 return "Read By Type resp"; 133 case ATT_OP_READ_REQ: 134 return "Read req"; 135 case ATT_OP_READ_RESP: 136 return "Read resp"; 137 case ATT_OP_READ_BLOB_REQ: 138 return "Read Blob req"; 139 case ATT_OP_READ_BLOB_RESP: 140 return "Read Blob resp"; 141 case ATT_OP_READ_MULTI_REQ: 142 return "Read Multi req"; 143 case ATT_OP_READ_MULTI_RESP: 144 return "Read Multi resp"; 145 case ATT_OP_READ_BY_GROUP_REQ: 146 return "Read By Group req"; 147 case ATT_OP_READ_BY_GROUP_RESP: 148 return "Read By Group resp"; 149 case ATT_OP_WRITE_REQ: 150 return "Write req"; 151 case ATT_OP_WRITE_RESP: 152 return "Write resp"; 153 case ATT_OP_WRITE_CMD: 154 return "Write cmd"; 155 case ATT_OP_PREP_WRITE_REQ: 156 return "Prepare Write req"; 157 case ATT_OP_PREP_WRITE_RESP: 158 return "Prepare Write resp"; 159 case ATT_OP_EXEC_WRITE_REQ: 160 return "Exec Write req"; 161 case ATT_OP_EXEC_WRITE_RESP: 162 return "Exec Write resp"; 163 case ATT_OP_HANDLE_NOTIFY: 164 return "Handle notify"; 165 case ATT_OP_HANDLE_IND: 166 return "Handle indicate"; 167 case ATT_OP_HANDLE_CNF: 168 return "Handle CNF"; 169 case ATT_OP_SIGNED_WRITE_CMD: 170 return "Signed Write Cmd"; 171 default: 172 return "Unknown"; 173 } 174 } 175 176 static const char * atterror2str(uint8_t err) 177 { 178 switch (err) { 179 case ATT_ECODE_INVALID_HANDLE: 180 return "Invalid handle"; 181 case ATT_ECODE_READ_NOT_PERM: 182 return "Read not permitted"; 183 case ATT_ECODE_WRITE_NOT_PERM: 184 return "Write not permitted"; 185 case ATT_ECODE_INVALID_PDU: 186 return "Invalid PDU"; 187 case ATT_ECODE_INSUFF_AUTHEN: 188 return "Insufficient authentication"; 189 case ATT_ECODE_REQ_NOT_SUPP: 190 return "Request not supported"; 191 case ATT_ECODE_INVALID_OFFSET: 192 return "Invalid offset"; 193 case ATT_ECODE_INSUFF_AUTHO: 194 return "Insufficient authorization"; 195 case ATT_ECODE_PREP_QUEUE_FULL: 196 return "Prepare queue full"; 197 case ATT_ECODE_ATTR_NOT_FOUND: 198 return "Attribute not found"; 199 case ATT_ECODE_ATTR_NOT_LONG: 200 return "Attribute not long"; 201 case ATT_ECODE_INSUFF_ENCR_KEY_SIZE: 202 return "Insufficient encryption key size"; 203 case ATT_ECODE_INVAL_ATTR_VALUE_LEN: 204 return "Invalid attribute value length"; 205 case ATT_ECODE_UNLIKELY: 206 return "Unlikely error"; 207 case ATT_ECODE_INSUFF_ENC: 208 return "Insufficient encryption"; 209 case ATT_ECODE_UNSUPP_GRP_TYPE: 210 return "Unsupported group type"; 211 case ATT_ECODE_INSUFF_RESOURCES: 212 return "Insufficient resources"; 213 case ATT_ECODE_IO: 214 return "Application Error"; 215 default: 216 return "Reserved"; 217 } 218 } 219 220 static const char *uuid2str(uint16_t uuid) 221 { 222 switch (uuid) { 223 case GATT_PRIM_SVC_UUID: 224 return "GATT Primary Service"; 225 case GATT_SND_SVC_UUID: 226 return "GATT Secondary Service"; 227 case GATT_INCLUDE_UUID: 228 return "GATT Include"; 229 case GATT_CHARAC_UUID: 230 return "GATT Characteristic"; 231 case GATT_CHARAC_DEVICE_NAME: 232 return "GATT(type) Device Name"; 233 case GATT_CHARAC_APPEARANCE: 234 return "GATT(type) Appearance"; 235 case GATT_CHARAC_PERIPHERAL_PRIV_FLAG: 236 return "GATT(type) Peripheral Privacy Flag"; 237 case GATT_CHARAC_RECONNECTION_ADDRESS: 238 return "GATT(type) Characteristic Reconnection Address"; 239 case GATT_CHARAC_PERIPHERAL_PREF_CONN: 240 return "GATT(type) Characteristic Preferred Connection Parameters"; 241 case GATT_CHARAC_SERVICE_CHANGED: 242 return "GATT(type) Characteristic Service Changed"; 243 case GATT_CHARAC_EXT_PROPER_UUID: 244 return "GATT(desc) Characteristic Extended Properties"; 245 case GATT_CHARAC_USER_DESC_UUID: 246 return "GATT(desc) User Description"; 247 case GATT_CLIENT_CHARAC_CFG_UUID: 248 return "GATT(desc) Client Characteristic Configuration"; 249 case GATT_SERVER_CHARAC_CFG_UUID: 250 return "GATT(desc) Server Characteristic Configuration"; 251 case GATT_CHARAC_FMT_UUID: 252 return "GATT(desc) Format"; 253 case GATT_CHARAC_AGREG_FMT_UUID: 254 return "GATT(desc) Aggregate Format"; 255 default: 256 return "Unknown"; 257 } 258 } 259 260 static void att_error_dump(int level, struct frame *frm) 261 { 262 uint8_t op = get_u8(frm); 263 uint16_t handle = btohs(htons(get_u16(frm))); 264 uint8_t err = get_u8(frm); 265 266 p_indent(level, frm); 267 printf("Error: %s (%d)\n", atterror2str(err), err); 268 269 p_indent(level, frm); 270 printf("%s (0x%.2x) on handle 0x%2.2x\n", attop2str(op), op, handle); 271 } 272 273 static void att_mtu_req_dump(int level, struct frame *frm) 274 { 275 uint16_t client_rx_mtu = btohs(htons(get_u16(frm))); 276 277 p_indent(level, frm); 278 printf("client rx mtu %d\n", client_rx_mtu); 279 } 280 281 static void att_mtu_resp_dump(int level, struct frame *frm) 282 { 283 uint16_t server_rx_mtu = btohs(htons(get_u16(frm))); 284 285 p_indent(level, frm); 286 printf("server rx mtu %d\n", server_rx_mtu); 287 } 288 289 static void att_find_info_req_dump(int level, struct frame *frm) 290 { 291 uint16_t start = btohs(htons(get_u16(frm))); 292 uint16_t end = btohs(htons(get_u16(frm))); 293 294 p_indent(level, frm); 295 printf("start 0x%2.2x, end 0x%2.2x\n", start, end); 296 } 297 298 static void att_find_info_resp_dump(int level, struct frame *frm) 299 { 300 uint8_t fmt = get_u8(frm); 301 302 p_indent(level, frm); 303 304 if (fmt == 0x01) { 305 printf("format: uuid-16\n"); 306 307 while (frm->len > 0) { 308 uint16_t handle = btohs(htons(get_u16(frm))); 309 uint16_t uuid = btohs(htons(get_u16(frm))); 310 p_indent(level + 1, frm); 311 printf("handle 0x%2.2x, uuid 0x%2.2x (%s)\n", handle, uuid, 312 uuid2str(uuid)); 313 } 314 } else { 315 printf("format: uuid-128\n"); 316 317 while (frm->len > 0) { 318 uint16_t handle = btohs(htons(get_u16(frm))); 319 int i; 320 321 p_indent(level + 1, frm); 322 printf("handle 0x%2.2x, uuid ", handle); 323 for (i = 0; i < 16; i++) { 324 printf("%02x", get_u8(frm)); 325 if (i == 3 || i == 5 || i == 7 || i == 9) 326 printf("-"); 327 } 328 printf("\n"); 329 } 330 } 331 } 332 333 static void att_find_by_type_req_dump(int level, struct frame *frm) 334 { 335 uint16_t start = btohs(htons(get_u16(frm))); 336 uint16_t end = btohs(htons(get_u16(frm))); 337 uint16_t uuid = btohs(htons(get_u16(frm))); 338 339 p_indent(level, frm); 340 printf("start 0x%4.4x, end 0x%4.4x, uuid 0x%4.4x\n", start, end, uuid); 341 342 p_indent(level, frm); 343 printf("value"); 344 while (frm->len > 0) 345 printf(" 0x%2.2x", get_u8(frm)); 346 printf("\n"); 347 } 348 349 static void att_find_by_type_resp_dump(int level, struct frame *frm) 350 { 351 while (frm->len > 0) { 352 uint16_t uuid = btohs(htons(get_u16(frm))); 353 uint16_t end = btohs(htons(get_u16(frm))); 354 355 p_indent(level, frm); 356 printf("Found attr 0x%4.4x, group end handle 0x%4.4x\n", 357 uuid, end); 358 } 359 } 360 361 static void att_read_by_type_req_dump(int level, struct frame *frm) 362 { 363 uint16_t start = btohs(htons(get_u16(frm))); 364 uint16_t end = btohs(htons(get_u16(frm))); 365 int i; 366 367 p_indent(level, frm); 368 printf("start 0x%4.4x, end 0x%4.4x\n", start, end); 369 370 p_indent(level, frm); 371 if (frm->len == 2) { 372 printf("type-uuid 0x%4.4x\n", btohs(htons(get_u16(frm)))); 373 } else if (frm->len == 16) { 374 printf("type-uuid "); 375 for (i = 0; i < 16; i++) { 376 printf("%02x", get_u8(frm)); 377 if (i == 3 || i == 5 || i == 7 || i == 9) 378 printf("-"); 379 } 380 printf("\n"); 381 } else { 382 printf("malformed uuid (expected 2 or 16 octets)\n"); 383 p_indent(level, frm); 384 raw_dump(level, frm); 385 } 386 } 387 388 static void att_read_by_type_resp_dump(int level, struct frame *frm) 389 { 390 uint8_t length = get_u8(frm); 391 392 p_indent(level, frm); 393 printf("length: %d\n", length); 394 395 while (frm->len > 0) { 396 uint16_t handle = btohs(htons(get_u16(frm))); 397 int val_len = length - 2; 398 int i; 399 400 p_indent(level + 1, frm); 401 printf("handle 0x%2.2x, value ", handle); 402 for (i = 0; i < val_len; i++) { 403 printf("0x%.2x ", get_u8(frm)); 404 } 405 printf("\n"); 406 } 407 } 408 409 static void att_read_req_dump(int level, struct frame *frm) 410 { 411 uint16_t handle = btohs(htons(get_u16(frm))); 412 413 p_indent(level, frm); 414 printf("handle 0x%2.2x\n", handle); 415 } 416 417 static void att_read_blob_req_dump(int level, struct frame *frm) 418 { 419 uint16_t handle = btohs(htons(get_u16(frm))); 420 uint16_t offset = btohs(htons(get_u16(frm))); 421 422 p_indent(level, frm); 423 printf("handle 0x%4.4x offset 0x%4.4x\n", handle, offset); 424 } 425 426 static void att_read_blob_resp_dump(int level, struct frame *frm) 427 { 428 p_indent(level, frm); 429 printf("value"); 430 431 while (frm->len > 0) 432 printf(" 0x%2.2x", get_u8(frm)); 433 printf("\n"); 434 } 435 436 static void att_read_multi_req_dump(int level, struct frame *frm) 437 { 438 p_indent(level, frm); 439 printf("Handles\n"); 440 441 while (frm->len > 0) { 442 p_indent(level, frm); 443 printf("handle 0x%4.4x\n", btohs(htons(get_u16(frm)))); 444 } 445 } 446 447 static void att_read_multi_resp_dump(int level, struct frame *frm) 448 { 449 p_indent(level, frm); 450 printf("values"); 451 452 while (frm->len > 0) 453 printf(" 0x%2.2x", get_u8(frm)); 454 printf("\n"); 455 } 456 457 static void att_read_by_group_resp_dump(int level, struct frame *frm) 458 { 459 uint8_t length = get_u8(frm); 460 461 while (frm->len > 0) { 462 uint16_t attr_handle = btohs(htons(get_u16(frm))); 463 uint16_t end_grp_handle = btohs(htons(get_u16(frm))); 464 uint8_t remaining = length - 4; 465 466 p_indent(level, frm); 467 printf("attr handle 0x%4.4x, end group handle 0x%4.4x\n", 468 attr_handle, end_grp_handle); 469 470 p_indent(level, frm); 471 printf("value"); 472 while (remaining > 0) { 473 printf(" 0x%2.2x", get_u8(frm)); 474 } 475 printf("\n"); 476 } 477 } 478 479 static void att_write_req_dump(int level, struct frame *frm) 480 { 481 uint16_t handle = btohs(htons(get_u16(frm))); 482 483 p_indent(level, frm); 484 printf("handle 0x%4.4x value ", handle); 485 486 while (frm->len > 0) 487 printf(" 0x%2.2x", get_u8(frm)); 488 printf("\n"); 489 } 490 491 static void att_signed_write_dump(int level, struct frame *frm) 492 { 493 uint16_t handle = btohs(htons(get_u16(frm))); 494 int value_len = frm->len - 12; /* handle:2 already accounted, sig: 12 */ 495 496 p_indent(level, frm); 497 printf("handle 0x%4.4x value ", handle); 498 499 while (value_len--) 500 printf(" 0x%2.2x", get_u8(frm)); 501 printf("\n"); 502 503 p_indent(level, frm); 504 printf("auth signature "); 505 while (frm->len > 0) 506 printf(" 0x%2.2x", get_u8(frm)); 507 printf("\n"); 508 } 509 510 static void att_prep_write_dump(int level, struct frame *frm) 511 { 512 uint16_t handle = btohs(htons(get_u16(frm))); 513 uint16_t val_offset = btohs(htons(get_u16(frm))); 514 515 p_indent(level, frm); 516 printf("attr handle 0x%4.4x, value offset 0x%4.4x\n", handle, 517 val_offset); 518 519 p_indent(level, frm); 520 printf("part attr value "); 521 while (frm->len > 0) 522 printf(" 0x%2.2x", get_u8(frm)); 523 printf("\n"); 524 } 525 526 static void att_exec_write_req_dump(int level, struct frame *frm) 527 { 528 uint8_t flags = get_u8(frm); 529 530 p_indent(level, frm); 531 if (flags == 0x00) 532 printf("cancel all prepared writes "); 533 else 534 printf("immediatelly write all pending prepared values "); 535 536 printf("(0x%2.2x)\n", flags); 537 } 538 539 static void att_handle_notify_dump(int level, struct frame *frm) 540 { 541 uint16_t handle = btohs(htons(get_u16(frm))); 542 543 p_indent(level, frm); 544 printf("handle 0x%4.4x\n", handle); 545 546 p_indent(level, frm); 547 printf("value "); 548 while (frm->len > 0) 549 printf("0x%.2x ", get_u8(frm)); 550 printf("\n"); 551 } 552 553 void att_dump(int level, struct frame *frm) 554 { 555 uint8_t op; 556 557 op = get_u8(frm); 558 559 p_indent(level, frm); 560 printf("ATT: %s (0x%.2x)\n", attop2str(op), op); 561 562 switch (op) { 563 case ATT_OP_ERROR: 564 att_error_dump(level + 1, frm); 565 break; 566 case ATT_OP_MTU_REQ: 567 att_mtu_req_dump(level + 1, frm); 568 break; 569 case ATT_OP_MTU_RESP: 570 att_mtu_resp_dump(level + 1, frm); 571 break; 572 case ATT_OP_FIND_INFO_REQ: 573 att_find_info_req_dump(level + 1, frm); 574 break; 575 case ATT_OP_FIND_INFO_RESP: 576 att_find_info_resp_dump(level + 1, frm); 577 break; 578 case ATT_OP_FIND_BY_TYPE_REQ: 579 att_find_by_type_req_dump(level + 1, frm); 580 break; 581 case ATT_OP_FIND_BY_TYPE_RESP: 582 att_find_by_type_resp_dump(level + 1, frm); 583 break; 584 case ATT_OP_READ_BY_TYPE_REQ: 585 case ATT_OP_READ_BY_GROUP_REQ: /* exact same parsing */ 586 att_read_by_type_req_dump(level + 1, frm); 587 break; 588 case ATT_OP_READ_BY_TYPE_RESP: 589 att_read_by_type_resp_dump(level + 1, frm); 590 break; 591 case ATT_OP_READ_REQ: 592 att_read_req_dump(level + 1, frm); 593 break; 594 case ATT_OP_READ_RESP: 595 raw_dump(level + 1, frm); 596 break; 597 case ATT_OP_READ_BLOB_REQ: 598 att_read_blob_req_dump(level + 1, frm); 599 break; 600 case ATT_OP_READ_BLOB_RESP: 601 att_read_blob_resp_dump(level + 1, frm); 602 break; 603 case ATT_OP_READ_MULTI_REQ: 604 att_read_multi_req_dump(level + 1, frm); 605 break; 606 case ATT_OP_READ_MULTI_RESP: 607 att_read_multi_resp_dump(level + 1, frm); 608 break; 609 case ATT_OP_READ_BY_GROUP_RESP: 610 att_read_by_group_resp_dump(level + 1, frm); 611 break; 612 case ATT_OP_WRITE_REQ: 613 case ATT_OP_WRITE_CMD: 614 att_write_req_dump(level + 1, frm); 615 break; 616 case ATT_OP_SIGNED_WRITE_CMD: 617 att_signed_write_dump(level + 1, frm); 618 break; 619 case ATT_OP_PREP_WRITE_REQ: 620 case ATT_OP_PREP_WRITE_RESP: 621 att_prep_write_dump(level + 1, frm); 622 break; 623 case ATT_OP_EXEC_WRITE_REQ: 624 att_exec_write_req_dump(level + 1, frm); 625 break; 626 case ATT_OP_HANDLE_NOTIFY: 627 att_handle_notify_dump(level + 1, frm); 628 break; 629 default: 630 raw_dump(level, frm); 631 break; 632 } 633 } 634