1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2011 Marcel Holtmann <marcel (at) holtmann.org> 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 <ctype.h> 31 #include <unistd.h> 32 #include <stdlib.h> 33 #include <string.h> 34 35 #include <sys/types.h> 36 #include <netinet/in.h> 37 38 #include <bluetooth/bluetooth.h> 39 40 #include "parser.h" 41 42 #define CAPI_U8(frm) (get_u8(frm)) 43 #define CAPI_U16(frm) (btohs(htons(get_u16(frm)))) 44 #define CAPI_U32(frm) (btohl(htonl(get_u32(frm)))) 45 46 static char *cmd2str(uint8_t cmd) 47 { 48 switch (cmd) { 49 case 0x01: 50 return "ALERT"; 51 case 0x02: 52 return "CONNECT"; 53 case 0x03: 54 return "CONNECT_ACTIVE"; 55 case 0x04: 56 return "DISCONNECT"; 57 case 0x05: 58 return "LISTEN"; 59 case 0x08: 60 return "INFO"; 61 case 0x20: 62 return "INTEROPERABILITY"; 63 case 0x41: 64 return "SELECT_B_PROTOCOL"; 65 case 0x80: 66 return "FACILITY"; 67 case 0x82: 68 return "CONNECT_B3"; 69 case 0x83: 70 return "CONNECT_B3_ACTIVE"; 71 case 0x84: 72 return "DISCONNECT_B3"; 73 case 0x86: 74 return "DATA_B3"; 75 case 0x87: 76 return "RESET_B3"; 77 case 0x88: 78 return "CONNECT_B3_T90_ACTIVE"; 79 case 0xff: 80 return "MANUFACTURER"; 81 default: 82 return "UNKNOWN"; 83 } 84 } 85 86 static char *subcmd2str(uint8_t subcmd) 87 { 88 switch (subcmd) { 89 case 0x80: 90 return "REQ"; 91 case 0x81: 92 return "CONF"; 93 case 0x82: 94 return "IND"; 95 case 0x83: 96 return "RESP"; 97 default: 98 return "UNKN"; 99 } 100 } 101 102 static char *interopsel2str(uint16_t sel) 103 { 104 switch (sel) { 105 case 0x0000: 106 return "USB Device Management"; 107 case 0x0001: 108 return "Bluetooth Device Management"; 109 default: 110 return "Unknown"; 111 } 112 } 113 114 static char *func2str(uint16_t func) 115 { 116 switch (func) { 117 case 0: 118 return "Register"; 119 case 1: 120 return "Release"; 121 case 2: 122 return "Get_Profile"; 123 case 3: 124 return "Get_Manufacturer"; 125 case 4: 126 return "Get_Version"; 127 case 5: 128 return "Get_Serial_Number"; 129 case 6: 130 return "Manufacturer"; 131 case 7: 132 return "Echo_Loopback"; 133 default: 134 return "Unknown"; 135 } 136 } 137 138 static char *facilitysel2str(uint16_t sel) 139 { 140 switch (sel) { 141 case 0x0000: 142 return "Handset"; 143 case 0x0001: 144 return "DTMF"; 145 case 0x0002: 146 return "V.42 bis"; 147 case 0x0003: 148 return "Supplementary Services"; 149 case 0x0004: 150 return "Power management wakeup"; 151 case 0x0005: 152 return "Line Interconnect"; 153 case 0x0006: 154 return "DTMF"; 155 default: 156 return "Unknown"; 157 } 158 } 159 160 static char *info2str(uint16_t info) 161 { 162 switch (info) { 163 case 0x0000: 164 return "No error"; 165 case 0x0001: 166 return "NCPI not supported by current protocol, NCPI ignored"; 167 case 0x0002: 168 return "Flags not supported by current protocol, flags ignored"; 169 case 0x2001: 170 return "Message not supported in current state"; 171 case 0x2002: 172 return "Incorrect Controller/PLCI/NCCI"; 173 case 0x2003: 174 return "No PLCI available"; 175 case 0x2004: 176 return "No NCCI available"; 177 case 0x2005: 178 return "No Listen resources available"; 179 case 0x2007: 180 return "Illegal message parameter coding"; 181 case 0x2008: 182 return "No interconnection resources available"; 183 case 0x3001: 184 return "B1 protocol not supported"; 185 case 0x3002: 186 return "B2 protocol not supported"; 187 case 0x3003: 188 return "B3 protocol not supported"; 189 case 0x3004: 190 return "B1 protocol parameter not supported"; 191 case 0x3005: 192 return "B2 protocol parameter not supported"; 193 case 0x3006: 194 return "B3 protocol parameter not supported"; 195 case 0x3007: 196 return "B protocol combination not supported"; 197 case 0x3008: 198 return "NCPI not supported"; 199 case 0x3009: 200 return "CIP Value unknown"; 201 case 0x300A: 202 return "Flags not supported (reserved bits)"; 203 case 0x300B: 204 return "Facility not supported"; 205 case 0x300C: 206 return "Data length not supported by current protocol"; 207 case 0x300D: 208 return "Reset procedure not supported by current protocol"; 209 case 0x300F: 210 return "Unsupported interoperability"; 211 case 0x3011: 212 return "Facility specific function not supported"; 213 case 0x3301: 214 return "Protocol error, Layer 1"; 215 case 0x3302: 216 return "Protocol error, Layer 2"; 217 case 0x3303: 218 return "Protocol error, Layer 3"; 219 case 0x3304: 220 return "Another application got that call"; 221 case 0x3305: 222 return "Cleared by Call Control Supervision"; 223 case 0x3400: 224 /* The cause value received from the network in a cause 225 * information element (Octet 4) is indicated in the field 00 */ 226 return "Disconnect cause from the network in accordance with Q.850/ETS 300 102-1"; 227 default: 228 return "Unknown"; 229 } 230 } 231 232 static void profile(int level, struct frame *frm) 233 { 234 uint16_t nctr, nchn; 235 uint32_t value; 236 237 nctr = CAPI_U16(frm); 238 nchn = CAPI_U16(frm); 239 240 if (nchn > 0) { 241 p_indent(level, frm); 242 printf("Controller: %d\n", nctr); 243 p_indent(level, frm); 244 printf("Number of B-channels: %d\n", nchn); 245 246 value = CAPI_U32(frm); 247 p_indent(level, frm); 248 printf("Global options: 0x%04x\n", value); 249 value = CAPI_U32(frm); 250 p_indent(level, frm); 251 printf("B1 protocol support: 0x%08x\n", value); 252 value = CAPI_U32(frm); 253 p_indent(level, frm); 254 printf("B2 protocol support: 0x%08x\n", value); 255 value = CAPI_U32(frm); 256 p_indent(level, frm); 257 printf("B3 protocol support: 0x%08x\n", value); 258 259 frm->ptr += 24; 260 frm->len -= 24; 261 262 p_indent(level, frm); 263 printf("Manufacturer-specific information:\n"); 264 hex_dump(level, frm, 20); 265 } else { 266 p_indent(level, frm); 267 printf("Number of controllers: %d\n", nctr); 268 } 269 } 270 271 static void cmd_common(int level, uint8_t subcmd, struct frame *frm) 272 { 273 uint32_t val; 274 uint16_t info, ncci; 275 uint8_t ctr, plci; 276 277 val = CAPI_U32(frm); 278 ctr = val & 0xff; 279 plci = (val & 0xff00) >> 8; 280 ncci = (val & 0xffff0000) >> 16; 281 282 p_indent(level, frm); 283 printf("Controller: %d %s\n", ctr & 0x7f, ctr & 0x80 ? "Ext." : "Int."); 284 285 if (plci > 0) { 286 p_indent(level, frm); 287 printf("PLCI: 0x%02x\n", plci); 288 } 289 290 if (ncci > 0) { 291 p_indent(level, frm); 292 printf("NCCI: 0x%04x\n", ncci); 293 } 294 295 if (subcmd == 0x81) { 296 info = CAPI_U16(frm); 297 p_indent(level, frm); 298 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 299 } 300 } 301 302 static void cmd_alert(int level, uint8_t subcmd, struct frame *frm) 303 { 304 uint8_t len; 305 306 cmd_common(level, subcmd, frm); 307 308 if (subcmd == 0x80) { 309 len = CAPI_U8(frm); 310 if (len > 0) { 311 p_indent(level, frm); 312 printf("Additional info:\n"); 313 hex_dump(level, frm, len); 314 } 315 } 316 } 317 318 static void cmd_connect(int level, uint8_t subcmd, struct frame *frm) 319 { 320 uint16_t cip; 321 uint8_t len; 322 323 cmd_common(level, subcmd, frm); 324 325 if (subcmd == 0x81) 326 return; 327 328 cip = CAPI_U16(frm); 329 p_indent(level, frm); 330 printf("CIP value: 0x%04x\n", cip); 331 332 len = CAPI_U8(frm); 333 frm->ptr += len; 334 frm->len -= len; 335 len = CAPI_U8(frm); 336 frm->ptr += len; 337 frm->len -= len; 338 len = CAPI_U8(frm); 339 frm->ptr += len; 340 frm->len -= len; 341 len = CAPI_U8(frm); 342 frm->ptr += len; 343 frm->len -= len; 344 345 raw_dump(level, frm); 346 } 347 348 static void cmd_disconnect(int level, uint8_t subcmd, struct frame *frm) 349 { 350 uint16_t reason; 351 uint8_t len; 352 353 cmd_common(level, subcmd, frm); 354 355 if (subcmd == 0x80) { 356 len = CAPI_U8(frm); 357 if (len > 0) { 358 p_indent(level, frm); 359 printf("Additional info:\n"); 360 hex_dump(level, frm, len); 361 } 362 } 363 364 if (subcmd == 0x82) { 365 reason = CAPI_U16(frm); 366 p_indent(level, frm); 367 printf("Reason: 0x%04x (%s)\n", reason, info2str(reason)); 368 } 369 } 370 371 static void cmd_connect_active(int level, uint8_t subcmd, struct frame *frm) 372 { 373 uint8_t len; 374 375 cmd_common(level, subcmd, frm); 376 377 if (subcmd == 0x82) { 378 len = CAPI_U8(frm); 379 if (len > 0) { 380 p_indent(level, frm); 381 printf("Connected number:\n"); 382 hex_dump(level, frm, len); 383 } 384 385 len = CAPI_U8(frm); 386 if (len > 0) { 387 p_indent(level, frm); 388 printf("Connected subaddress:\n"); 389 hex_dump(level, frm, len); 390 } 391 392 len = CAPI_U8(frm); 393 if (len > 0) { 394 p_indent(level, frm); 395 printf("LLC:\n"); 396 hex_dump(level, frm, len); 397 } 398 } 399 } 400 401 static void cmd_listen(int level, uint8_t subcmd, struct frame *frm) 402 { 403 uint32_t mask; 404 uint8_t len; 405 406 cmd_common(level, subcmd, frm); 407 408 if (subcmd == 0x80) { 409 mask = CAPI_U32(frm); 410 p_indent(level, frm); 411 printf("Info mask: 0x%08x\n", mask); 412 413 mask = CAPI_U32(frm); 414 p_indent(level, frm); 415 printf("CIP mask: 0x%08x", mask); 416 417 mask = CAPI_U32(frm); 418 if (mask > 0) 419 printf(" 0x%08x\n", mask); 420 else 421 printf("\n"); 422 423 len = CAPI_U8(frm); 424 if (len > 0) { 425 p_indent(level, frm); 426 printf("Calling party number:\n"); 427 hex_dump(level, frm, len); 428 } 429 frm->ptr += len; 430 frm->len -= len; 431 432 len = CAPI_U8(frm); 433 if (len > 0) { 434 p_indent(level, frm); 435 printf("Calling party subaddress:\n"); 436 hex_dump(level, frm, len); 437 } 438 frm->ptr += len; 439 frm->len -= len; 440 } 441 } 442 443 static void cmd_info(int level, uint8_t subcmd, struct frame *frm) 444 { 445 uint8_t len; 446 uint16_t info; 447 448 cmd_common(level, subcmd, frm); 449 450 switch (subcmd) { 451 case 0x80: 452 len = CAPI_U8(frm); 453 if (len > 0) { 454 p_indent(level, frm); 455 printf("Called party number:\n"); 456 hex_dump(level, frm, len); 457 } 458 frm->ptr += len; 459 frm->len -= len; 460 461 len = CAPI_U8(frm); 462 if (len > 0) { 463 p_indent(level, frm); 464 printf("Additional info:\n"); 465 hex_dump(level, frm, len); 466 } 467 break; 468 469 case 0x82: 470 info = CAPI_U16(frm); 471 p_indent(level, frm); 472 printf("Info number: %d\n", info); 473 474 len = CAPI_U8(frm); 475 if (len > 0) { 476 p_indent(level, frm); 477 printf("Info element:\n"); 478 hex_dump(level, frm, len); 479 } 480 break; 481 } 482 } 483 484 static void cmd_interoperability(int level, uint8_t subcmd, struct frame *frm) 485 { 486 uint16_t sel, func, info; 487 uint16_t nconn, datablkcnt, datablklen; 488 uint32_t ctr, value, major, minor; 489 490 info = (subcmd == 0x81) ? CAPI_U16(frm) : 0; 491 sel = CAPI_U16(frm); 492 CAPI_U8(frm); 493 if (subcmd != 0x83) { 494 func = CAPI_U16(frm); 495 CAPI_U8(frm); 496 } else 497 func = 0; 498 499 p_indent(level, frm); 500 printf("Selector: 0x%04x (%s)\n", sel, interopsel2str(sel)); 501 502 switch (sel) { 503 case 0x0001: 504 p_indent(level, frm); 505 printf("Function: %d (%s)\n", func, func2str(func)); 506 507 switch (subcmd) { 508 case 0x80: 509 switch (func) { 510 case 0: 511 nconn = CAPI_U16(frm); 512 p_indent(level + 1, frm); 513 printf("maxLogicalConnections: %d\n", nconn); 514 datablkcnt = CAPI_U16(frm); 515 p_indent(level + 1, frm); 516 printf("maxBDataBlocks: %d\n", datablkcnt); 517 datablklen = CAPI_U16(frm); 518 p_indent(level + 1, frm); 519 printf("maxBDataLen: %d\n", datablklen); 520 break; 521 case 2: 522 case 3: 523 case 4: 524 case 5: 525 ctr = CAPI_U32(frm); 526 p_indent(level + 1, frm); 527 printf("Controller: %d\n", ctr); 528 break; 529 default: 530 raw_dump(level + 1, frm); 531 break; 532 } 533 break; 534 535 case 0x81: 536 switch (func) { 537 case 0: 538 case 1: 539 info = CAPI_U16(frm); 540 p_indent(level + 1, frm); 541 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 542 break; 543 case 2: 544 info = CAPI_U16(frm); 545 p_indent(level + 1, frm); 546 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 547 CAPI_U8(frm); 548 profile(level + 1, frm); 549 break; 550 case 3: 551 info = CAPI_U16(frm); 552 p_indent(level + 1, frm); 553 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 554 ctr = CAPI_U32(frm); 555 p_indent(level + 1, frm); 556 printf("Controller: %d\n", ctr); 557 CAPI_U8(frm); 558 p_indent(level + 1, frm); 559 printf("Identification: \"%s\"\n", (char *) frm->ptr); 560 break; 561 case 4: 562 value = CAPI_U32(frm); 563 p_indent(level + 1, frm); 564 printf("Return value: 0x%04x\n", value); 565 ctr = CAPI_U32(frm); 566 p_indent(level + 1, frm); 567 printf("Controller: %d\n", ctr); 568 p_indent(level + 1, frm); 569 major = CAPI_U32(frm); 570 minor = CAPI_U32(frm); 571 printf("CAPI: %d.%d\n", major, minor); 572 major = CAPI_U32(frm); 573 minor = CAPI_U32(frm); 574 p_indent(level + 1, frm); 575 printf("Manufacture: %u.%01x%01x-%02u (%d.%d)\n", 576 (major & 0xf0) >> 4, (major & 0x0f) << 4, 577 (minor & 0xf0) >> 4, minor & 0x0f, 578 major, minor); 579 break; 580 case 5: 581 value = CAPI_U32(frm); 582 p_indent(level + 1, frm); 583 printf("Return value: 0x%04x\n", value); 584 ctr = CAPI_U32(frm); 585 p_indent(level + 1, frm); 586 printf("Controller: %d\n", ctr); 587 CAPI_U8(frm); 588 p_indent(level + 1, frm); 589 printf("Serial number: %.7s\n", (char *) frm->ptr); 590 break; 591 default: 592 raw_dump(level + 1, frm); 593 break; 594 } 595 break; 596 597 default: 598 raw_dump(level, frm); 599 break; 600 } 601 break; 602 603 default: 604 p_indent(level, frm); 605 printf("Function: %d\n", func); 606 if (subcmd == 0x81) { 607 p_indent(level, frm); 608 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 609 } 610 raw_dump(level + 1, frm); 611 break; 612 } 613 } 614 615 static void cmd_facility(int level, uint8_t subcmd, struct frame *frm) 616 { 617 uint16_t sel; 618 619 cmd_common(level, subcmd, frm); 620 621 sel = CAPI_U16(frm); 622 CAPI_U8(frm); 623 624 p_indent(level, frm); 625 printf("Selector: 0x%04x (%s)\n", sel, facilitysel2str(sel)); 626 627 raw_dump(level, frm); 628 } 629 630 static void cmd_connect_b3(int level, uint8_t subcmd, struct frame *frm) 631 { 632 uint16_t reject; 633 uint8_t len; 634 635 cmd_common(level, subcmd, frm); 636 637 if (subcmd == 0x81) 638 return; 639 640 if (subcmd == 0x83) { 641 reject = CAPI_U16(frm); 642 p_indent(level, frm); 643 printf("Reject: 0x%04x (%s)\n", reject, info2str(reject)); 644 } 645 646 len = CAPI_U8(frm); 647 if (len > 0) { 648 p_indent(level, frm); 649 printf("NCPI:\n"); 650 hex_dump(level, frm, len); 651 } 652 } 653 654 static void cmd_connect_b3_active(int level, uint8_t subcmd, struct frame *frm) 655 { 656 uint8_t len; 657 658 cmd_common(level, subcmd, frm); 659 660 if (subcmd == 0x82) { 661 len = CAPI_U8(frm); 662 if (len > 0) { 663 p_indent(level, frm); 664 printf("NCPI:\n"); 665 hex_dump(level, frm, len); 666 } 667 } 668 } 669 670 static void cmd_disconnect_b3(int level, uint8_t subcmd, struct frame *frm) 671 { 672 uint16_t reason; 673 uint8_t len; 674 675 cmd_common(level, subcmd, frm); 676 677 if (subcmd == 0x82) { 678 reason = CAPI_U16(frm); 679 p_indent(level, frm); 680 printf("Reason: 0x%04x (%s)\n", reason, info2str(reason)); 681 } 682 683 if (subcmd == 0x80 || subcmd == 0x82) { 684 len = CAPI_U8(frm); 685 if (len > 0) { 686 p_indent(level, frm); 687 printf("NCPI:\n"); 688 hex_dump(level, frm, len); 689 } 690 } 691 } 692 693 static void cmd_data_b3(int level, uint8_t subcmd, struct frame *frm) 694 { 695 uint32_t data; 696 uint64_t data64; 697 uint16_t length, handle, flags, info; 698 699 cmd_common(level, 0x00, frm); 700 701 if (subcmd == 0x81 || subcmd == 0x83) { 702 handle = CAPI_U16(frm); 703 p_indent(level, frm); 704 printf("Data handle: 0x%04x\n", handle); 705 706 if (subcmd == 0x81) { 707 info = CAPI_U16(frm); 708 p_indent(level, frm); 709 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 710 } 711 } else { 712 data = CAPI_U32(frm); 713 714 length = CAPI_U16(frm); 715 p_indent(level, frm); 716 printf("Data length: 0x%04x (%d bytes)\n", length, length); 717 718 handle = CAPI_U16(frm); 719 p_indent(level, frm); 720 printf("Data handle: 0x%04x\n", handle); 721 722 flags = CAPI_U16(frm); 723 p_indent(level, frm); 724 printf("Flags: 0x%04x\n", flags); 725 726 if (data == 0) 727 data64 = get_u64(frm); 728 729 raw_dump(level, frm); 730 } 731 } 732 733 static void cmd_reset_b3(int level, uint8_t subcmd, struct frame *frm) 734 { 735 uint8_t len; 736 737 cmd_common(level, subcmd, frm); 738 739 if (subcmd == 0x80 || subcmd == 0x82) { 740 len = CAPI_U8(frm); 741 if (len > 0) { 742 p_indent(level, frm); 743 printf("NCPI:\n"); 744 hex_dump(level, frm, len); 745 } 746 } 747 } 748 749 static void cmd_manufacturer(int level, uint8_t subcmd, struct frame *frm) 750 { 751 uint32_t ctr, class, func; 752 uint16_t len; 753 unsigned char *id; 754 755 ctr = CAPI_U32(frm); 756 p_indent(level, frm); 757 printf("Controller: %d\n", ctr); 758 759 id = (unsigned char *) frm->ptr; 760 p_indent(level, frm); 761 if (isprint(id[0]) && isprint(id[1]) && isprint(id[2]) && isprint(id[3])) 762 printf("Manufacturer: %.4s", id); 763 else 764 printf("Manufacturer: 0x%02x 0x%02x 0x%02x 0x%02x", 765 id[0], id[1], id[2], id[3]); 766 frm->ptr += 4; 767 frm->len -= 4; 768 769 if (!strncmp((char *) id, "AVM!", 4)) { 770 class = CAPI_U32(frm); 771 func = CAPI_U32(frm); 772 len = CAPI_U8(frm); 773 if (len == 0xff) 774 len = CAPI_U16(frm); 775 776 printf(" [class %d func %d len %d]\n", class, func, len); 777 } else 778 printf("\n"); 779 780 raw_dump(level, frm); 781 } 782 783 void capi_dump(int level, struct frame *frm) 784 { 785 uint16_t len, appl, msgnum; 786 uint8_t cmd, subcmd; 787 788 len = CAPI_U16(frm) - 8; 789 appl = CAPI_U16(frm); 790 cmd = CAPI_U8(frm); 791 subcmd = CAPI_U8(frm); 792 msgnum = CAPI_U16(frm); 793 794 p_indent(level, frm); 795 796 printf("CAPI_%s_%s: appl %d msgnum %d len %d\n", 797 cmd2str(cmd), subcmd2str(subcmd), appl, msgnum, len); 798 799 switch (cmd) { 800 case 0x01: 801 cmd_alert(level + 1, subcmd, frm); 802 break; 803 case 0x02: 804 cmd_connect(level + 1, subcmd, frm); 805 break; 806 case 0x03: 807 cmd_connect_active(level + 1, subcmd, frm); 808 break; 809 case 0x04: 810 cmd_disconnect(level + 1, subcmd, frm); 811 break; 812 case 0x05: 813 cmd_listen(level + 1, subcmd, frm); 814 break; 815 case 0x08: 816 cmd_info(level + 1, subcmd, frm); 817 break; 818 case 0x20: 819 cmd_interoperability(level + 1, subcmd, frm); 820 break; 821 case 0x80: 822 cmd_facility(level + 1, subcmd, frm); 823 break; 824 case 0x82: 825 cmd_connect_b3(level + 1, subcmd, frm); 826 break; 827 case 0x83: 828 case 0x88: 829 cmd_connect_b3_active(level + 1, subcmd, frm); 830 break; 831 case 0x84: 832 cmd_disconnect_b3(level + 1, subcmd, frm); 833 break; 834 case 0x86: 835 cmd_data_b3(level + 1, subcmd, frm); 836 break; 837 case 0x87: 838 cmd_reset_b3(level + 1, subcmd, frm); 839 break; 840 case 0xff: 841 cmd_manufacturer(level + 1, subcmd, frm); 842 break; 843 default: 844 raw_dump(level, frm); 845 frm->ptr += len; 846 frm->len -= len; 847 break; 848 } 849 } 850