capi.c revision 8bc4b3c62e057d23def52d2f5abff740728cc9ab
1/* 2 HCIDump - HCI packet analyzer 3 Copyright (C) 2000-2001 Maxim Krasnyansky <maxk@qualcomm.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License version 2 as 7 published by the Free Software Foundation; 8 9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. 12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY CLAIM, 13 OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER 14 RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 15 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 16 USE OR PERFORMANCE OF THIS SOFTWARE. 17 18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, COPYRIGHTS, 19 TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. 20*/ 21 22/* 23 CAPI parser. 24 Copyright (C) 2004 Marcel Holtmann <marcel@holtmann.org> 25*/ 26 27/* 28 * $Id$ 29 */ 30 31#include <stdio.h> 32#include <errno.h> 33#include <ctype.h> 34#include <stdlib.h> 35#include <unistd.h> 36#include <string.h> 37 38#include <sys/types.h> 39#include <netinet/in.h> 40 41#include "parser.h" 42 43 44static char *cmd2str(uint8_t cmd) 45{ 46 switch (cmd) { 47 case 0x01: 48 return "ALERT"; 49 case 0x02: 50 return "CONNECT"; 51 case 0x03: 52 return "CONNECT_ACTIVE"; 53 case 0x04: 54 return "DISCONNECT"; 55 case 0x05: 56 return "LISTEN"; 57 case 0x08: 58 return "INFO"; 59 case 0x20: 60 return "INTEROPERABILITY"; 61 case 0x41: 62 return "SELECT_B_PROTOCOL"; 63 case 0x80: 64 return "FACILITY"; 65 case 0x82: 66 return "CONNECT_B3"; 67 case 0x83: 68 return "CONNECT_B3_ACTIVE"; 69 case 0x84: 70 return "DISCONNECT_B3"; 71 case 0x86: 72 return "DATA_B3"; 73 case 0x87: 74 return "RESET_B3"; 75 case 0xff: 76 return "MANUFACTURER"; 77 default: 78 return "UNKNOWN"; 79 } 80} 81 82static char *subcmd2str(uint8_t subcmd) 83{ 84 switch (subcmd) { 85 case 0x80: 86 return "REQ"; 87 case 0x81: 88 return "CONF"; 89 case 0x82: 90 return "IND"; 91 case 0x83: 92 return "RESP"; 93 default: 94 return "UNKN"; 95 } 96} 97 98static char *interopsel2str(uint16_t sel) 99{ 100 switch (sel) { 101 case 0x0000: 102 return "USB Device Management"; 103 case 0x0001: 104 return "Bluetooth Device Management"; 105 default: 106 return "Unknown"; 107 } 108} 109 110static char *func2str(uint16_t func) 111{ 112 switch (func) { 113 case 0: 114 return "Register"; 115 case 1: 116 return "Release"; 117 case 2: 118 return "Get_Profile"; 119 case 3: 120 return "Get_Manufacturer"; 121 case 4: 122 return "Get_Version"; 123 case 5: 124 return "Get_Serial_Number"; 125 case 6: 126 return "Manufacturer"; 127 case 7: 128 return "Echo_Loopback"; 129 default: 130 return "Unknown"; 131 } 132} 133 134static char *facilitysel2str(uint16_t sel) 135{ 136 switch (sel) { 137 case 0x0000: 138 return "Handset"; 139 case 0x0001: 140 return "DTMF"; 141 case 0x0002: 142 return "V.42 bis"; 143 case 0x0003: 144 return "Supplementary Services"; 145 case 0x0004: 146 return "Power management wakeup"; 147 case 0x0005: 148 return "Line Interconnect"; 149 case 0x0006: 150 return "DTMF"; 151 default: 152 return "Unknown"; 153 } 154} 155 156static char *info2str(uint16_t info) 157{ 158 switch (info) { 159 case 0x0000: 160 return "No error"; 161 case 0x0001: 162 return "NCPI not supported by current protocol, NCPI ignored"; 163 case 0x0002: 164 return "Flags not supported by current protocol, flags ignored"; 165 case 0x2001: 166 return "Message not supported in current state"; 167 case 0x2002: 168 return "Incorrect Controller/PLCI/NCCI"; 169 case 0x2003: 170 return "No PLCI available"; 171 case 0x2004: 172 return "No NCCI available"; 173 case 0x2005: 174 return "No Listen resources available"; 175 case 0x2007: 176 return "Illegal message parameter coding"; 177 case 0x2008: 178 return "No interconnection resources available"; 179 case 0x3001: 180 return "B1 protocol not supported"; 181 case 0x3002: 182 return "B2 protocol not supported"; 183 case 0x3003: 184 return "B3 protocol not supported"; 185 case 0x3004: 186 return "B1 protocol parameter not supported"; 187 case 0x3005: 188 return "B2 protocol parameter not supported"; 189 case 0x3006: 190 return "B3 protocol parameter not supported"; 191 case 0x3007: 192 return "B protocol combination not supported"; 193 case 0x3008: 194 return "NCPI not supported"; 195 case 0x3009: 196 return "CIP Value unknown"; 197 case 0x300A: 198 return "Flags not supported (reserved bits)"; 199 case 0x300B: 200 return "Facility not supported"; 201 case 0x300C: 202 return "Data length not supported by current protocol"; 203 case 0x300D: 204 return "Reset procedure not supported by current protocol"; 205 case 0x300F: 206 return "Unsupported interoperability"; 207 case 0x3011: 208 return "Facility specific function not supported"; 209 case 0x3301: 210 return "Protocol error, Layer 1"; 211 case 0x3302: 212 return "Protocol error, Layer 2"; 213 case 0x3303: 214 return "Protocol error, Layer 3"; 215 case 0x3304: 216 return "Another application got that call"; 217 case 0x3305: 218 return "Cleared by Call Control Supervision"; 219 case 0x3400: 220 /* The cause value received from the network in a cause 221 * information element (Octet 4) is indicated in the field 00 */ 222 return "Disconnect cause from the network in accordance with Q.850/ETS 300 102-1"; 223 default: 224 return "Unknown"; 225 } 226} 227 228static void profile(int level, struct frame *frm) 229{ 230 uint16_t nctr, nchn; 231 uint32_t value; 232 233 nctr = htons(get_u16(frm)); 234 nchn = htons(get_u16(frm)); 235 236 if (nchn > 0) { 237 p_indent(level, frm); 238 printf("Controller: %d\n", nctr); 239 p_indent(level, frm); 240 printf("Number of B-channels: %d\n", nchn); 241 242 value = htonl(get_u32(frm)); 243 p_indent(level, frm); 244 printf("Global options: 0x%04x\n", value); 245 value = htonl(get_u32(frm)); 246 p_indent(level, frm); 247 printf("B1 protocol support: 0x%08x\n", value); 248 value = htonl(get_u32(frm)); 249 p_indent(level, frm); 250 printf("B2 protocol support: 0x%08x\n", value); 251 value = htonl(get_u32(frm)); 252 p_indent(level, frm); 253 printf("B3 protocol support: 0x%08x\n", value); 254 255 frm->ptr += 24; 256 frm->len -= 24; 257 258 p_indent(level, frm); 259 printf("Manufacturer-specific information:\n"); 260 hex_dump(level, frm, 20); 261 } else { 262 p_indent(level, frm); 263 printf("Number of controllers: %d\n", nctr); 264 } 265} 266 267static void cmd_common(int level, uint8_t subcmd, struct frame *frm) 268{ 269 uint32_t val; 270 uint16_t info, ncci; 271 uint8_t ctr, plci; 272 273 val = htonl(get_u32(frm)); 274 ctr = val & 0xff; 275 plci = (val & 0xff00) >> 8; 276 ncci = (val & 0xffff0000) >> 16; 277 278 p_indent(level, frm); 279 printf("Controller: %d %s\n", ctr & 0x7f, ctr & 0x80 ? "Ext." : "Int."); 280 281 if (plci > 0) { 282 p_indent(level, frm); 283 printf("PLCI: 0x%02x\n", plci); 284 } 285 286 if (ncci > 0) { 287 p_indent(level, frm); 288 printf("NCCI: 0x%04x\n", ncci); 289 } 290 291 if (subcmd == 0x81) { 292 info = htons(get_u16(frm)); 293 p_indent(level, frm); 294 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 295 } 296} 297 298static void cmd_listen(int level, uint8_t subcmd, struct frame *frm) 299{ 300 uint32_t mask; 301 uint8_t len; 302 303 cmd_common(level, subcmd, frm); 304 305 if (subcmd == 0x80) { 306 mask = htonl(get_u32(frm)); 307 p_indent(level, frm); 308 printf("Info mask: 0x%08x\n", mask); 309 310 mask = htonl(get_u32(frm)); 311 p_indent(level, frm); 312 printf("CIP mask: 0x%08x", mask); 313 314 mask = htonl(get_u32(frm)); 315 if (mask > 0) 316 printf(" 0x%08x\n", mask); 317 else 318 printf("\n"); 319 320 len = get_u8(frm); 321 if (len > 0) { 322 p_indent(level, frm); 323 printf("Calling party number:\n"); 324 hex_dump(level, frm, len); 325 } 326 frm->ptr += len; 327 frm->len -= len; 328 329 len = get_u8(frm); 330 if (len > 0) { 331 p_indent(level, frm); 332 printf("Calling party subaddress:\n"); 333 hex_dump(level, frm, len); 334 } 335 frm->ptr += len; 336 frm->len -= len; 337 } 338} 339 340static void cmd_info(int level, uint8_t subcmd, struct frame *frm) 341{ 342 uint8_t len; 343 uint16_t info; 344 345 cmd_common(level, subcmd, frm); 346 347 switch (subcmd) { 348 case 0x80: 349 len = get_u8(frm); 350 if (len > 0) { 351 p_indent(level, frm); 352 printf("Called party number:\n"); 353 hex_dump(level, frm, len); 354 } 355 frm->ptr += len; 356 frm->len -= len; 357 358 len = get_u8(frm); 359 if (len > 0) { 360 p_indent(level, frm); 361 printf("Additional info:\n"); 362 hex_dump(level, frm, len); 363 } 364 break; 365 366 case 0x82: 367 info = htons(get_u16(frm)); 368 p_indent(level, frm); 369 printf("Info number: %d\n", info); 370 371 len = get_u8(frm); 372 if (len > 0) { 373 p_indent(level, frm); 374 printf("Info element:\n"); 375 hex_dump(level, frm, len); 376 } 377 break; 378 } 379} 380 381static void cmd_interoperability(int level, uint8_t subcmd, struct frame *frm) 382{ 383 uint16_t sel, func, info; 384 uint16_t nconn, datablkcnt, datablklen; 385 uint32_t ctr, value, major, minor; 386 387 info = (subcmd == 0x81) ? htons(get_u16(frm)) : 0; 388 sel = htons(get_u16(frm)); 389 get_u8(frm); 390 if (subcmd != 0x83) { 391 func = htons(get_u16(frm)); 392 get_u8(frm); 393 } else 394 func = 0; 395 396 p_indent(level, frm); 397 printf("Selector: 0x%04x (%s)\n", sel, interopsel2str(sel)); 398 399 switch (sel) { 400 case 0x0001: 401 p_indent(level, frm); 402 printf("Function: %d (%s)\n", func, func2str(func)); 403 404 switch (subcmd) { 405 case 0x80: 406 switch (func) { 407 case 0: 408 nconn = htons(get_u16(frm)); 409 p_indent(level + 1, frm); 410 printf("maxLogicalConnections: %d\n", nconn); 411 datablkcnt = htons(get_u16(frm)); 412 p_indent(level + 1, frm); 413 printf("maxBDataBlocks: %d\n", datablkcnt); 414 datablklen = htons(get_u16(frm)); 415 p_indent(level + 1, frm); 416 printf("maxBDataLen: %d\n", datablklen); 417 break; 418 case 2: 419 case 3: 420 case 4: 421 case 5: 422 ctr = htonl(get_u32(frm)); 423 p_indent(level + 1, frm); 424 printf("Controller: %d\n", ctr); 425 break; 426 default: 427 raw_dump(level + 1, frm); 428 break; 429 } 430 break; 431 432 case 0x81: 433 switch (func) { 434 case 0: 435 case 1: 436 info = htons(get_u16(frm)); 437 p_indent(level + 1, frm); 438 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 439 break; 440 case 2: 441 info = htons(get_u16(frm)); 442 p_indent(level + 1, frm); 443 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 444 get_u8(frm); 445 profile(level + 1, frm); 446 break; 447 case 3: 448 info = htons(get_u16(frm)); 449 p_indent(level + 1, frm); 450 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 451 ctr = htonl(get_u32(frm)); 452 p_indent(level + 1, frm); 453 printf("Controller: %d\n", ctr); 454 get_u8(frm); 455 p_indent(level + 1, frm); 456 printf("Identification: \"%s\"\n", (char *) frm->ptr); 457 break; 458 case 4: 459 value = htonl(get_u32(frm)); 460 p_indent(level + 1, frm); 461 printf("Return value: 0x%04x\n", value); 462 ctr = htonl(get_u32(frm)); 463 p_indent(level + 1, frm); 464 printf("Controller: %d\n", ctr); 465 p_indent(level + 1, frm); 466 major = htonl(get_u32(frm)); 467 minor = htonl(get_u32(frm)); 468 printf("CAPI: %d.%d\n", major, minor); 469 major = htonl(get_u32(frm)); 470 minor = htonl(get_u32(frm)); 471 p_indent(level + 1, frm); 472 printf("Manufacture: %u.%01x%01x-%02u (%d.%d)\n", 473 (major & 0xf0) >> 4, (major & 0x0f) << 4, 474 (minor & 0xf0) >> 4, minor & 0x0f, 475 major, minor); 476 break; 477 case 5: 478 value = htonl(get_u32(frm)); 479 p_indent(level + 1, frm); 480 printf("Return value: 0x%04x\n", value); 481 ctr = htonl(get_u32(frm)); 482 p_indent(level + 1, frm); 483 printf("Controller: %d\n", ctr); 484 get_u8(frm); 485 p_indent(level + 1, frm); 486 printf("Serial number: %.7s\n", (char *) frm->ptr); 487 break; 488 default: 489 raw_dump(level + 1, frm); 490 break; 491 } 492 break; 493 494 default: 495 raw_dump(level, frm); 496 break; 497 } 498 break; 499 500 default: 501 p_indent(level, frm); 502 printf("Function: %d\n", func); 503 if (subcmd == 0x81) { 504 p_indent(level, frm); 505 printf("Info: 0x%04x (%s)\n", info, info2str(info)); 506 } 507 raw_dump(level + 1, frm); 508 break; 509 } 510} 511 512static void cmd_facility(int level, uint8_t subcmd, struct frame *frm) 513{ 514 uint16_t sel; 515 516 cmd_common(level, subcmd, frm); 517 518 sel = htons(get_u16(frm)); 519 get_u8(frm); 520 521 p_indent(level, frm); 522 printf("Selector: 0x%04x (%s)\n", sel, facilitysel2str(sel)); 523 524 raw_dump(level, frm); 525} 526 527static void cmd_manufacturer(int level, uint8_t subcmd, struct frame *frm) 528{ 529 uint32_t ctr, class, func; 530 uint16_t len; 531 unsigned char *id; 532 533 ctr = htonl(get_u32(frm)); 534 p_indent(level, frm); 535 printf("Controller: %d\n", ctr); 536 537 id = (unsigned char *) frm->ptr; 538 p_indent(level, frm); 539 if (isprint(id[0]) && isprint(id[1]) && isprint(id[2]) && isprint(id[3])) 540 printf("Manufacturer: %.4s", id); 541 else 542 printf("Manufacturer: 0x%02x 0x%02x 0x%02x 0x%02x", 543 id[0], id[1], id[2], id[3]); 544 frm->ptr += 4; 545 frm->len -= 4; 546 547 if (!strncmp(id, "AVM!", 4)) { 548 class = htonl(get_u32(frm)); 549 func = htonl(get_u32(frm)); 550 len = get_u8(frm); 551 if (len == 0xff) 552 len = htons(get_u16(frm)); 553 554 printf(" [class %d func %d len %d]\n", class, func, len); 555 } else 556 printf("\n"); 557 558 raw_dump(level, frm); 559} 560 561void capi_dump(int level, struct frame *frm) 562{ 563 uint16_t len, appl, msgnum; 564 uint8_t cmd, subcmd; 565 566 len = htons(get_u16(frm)) - 8; 567 appl = htons(get_u16(frm)); 568 cmd = get_u8(frm); 569 subcmd = get_u8(frm); 570 msgnum = htons(get_u16(frm)); 571 572 p_indent(level, frm); 573 574 printf("CAPI_%s_%s: appl %d msgnum %d len %d\n", 575 cmd2str(cmd), subcmd2str(subcmd), appl, msgnum, len); 576 577 switch (cmd) { 578 case 0x05: 579 cmd_listen(level + 1, subcmd, frm); 580 break; 581 case 0x08: 582 cmd_info(level + 1, subcmd, frm); 583 break; 584 case 0x20: 585 cmd_interoperability(level + 1, subcmd, frm); 586 break; 587 case 0x80: 588 cmd_facility(level + 1, subcmd, frm); 589 break; 590 case 0xff: 591 cmd_manufacturer(level + 1, subcmd, frm); 592 break; 593 default: 594 raw_dump(level, frm); 595 frm->ptr += len; 596 frm->len -= len; 597 break; 598 } 599} 600