Home | History | Annotate | Download | only in parser
      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