• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *  BlueZ - Bluetooth protocol stack for Linux
4  *
5  *  Copyright (C) 2004-2007  Marcel Holtmann <marcel@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 
cmd2str(uint8_t cmd)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 
subcmd2str(uint8_t subcmd)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 
interopsel2str(uint16_t sel)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 
func2str(uint16_t func)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 
facilitysel2str(uint16_t sel)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 
info2str(uint16_t info)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 
profile(int level,struct frame * frm)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 
cmd_common(int level,uint8_t subcmd,struct frame * frm)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 
cmd_alert(int level,uint8_t subcmd,struct frame * frm)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 
cmd_connect(int level,uint8_t subcmd,struct frame * frm)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 
cmd_disconnect(int level,uint8_t subcmd,struct frame * frm)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 
cmd_connect_active(int level,uint8_t subcmd,struct frame * frm)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 
cmd_listen(int level,uint8_t subcmd,struct frame * frm)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 
cmd_info(int level,uint8_t subcmd,struct frame * frm)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 
cmd_interoperability(int level,uint8_t subcmd,struct frame * frm)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 
cmd_facility(int level,uint8_t subcmd,struct frame * frm)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 
cmd_connect_b3(int level,uint8_t subcmd,struct frame * frm)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 
cmd_connect_b3_active(int level,uint8_t subcmd,struct frame * frm)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 
cmd_disconnect_b3(int level,uint8_t subcmd,struct frame * frm)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 
cmd_data_b3(int level,uint8_t subcmd,struct frame * frm)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 
cmd_reset_b3(int level,uint8_t subcmd,struct frame * frm)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 
cmd_manufacturer(int level,uint8_t subcmd,struct frame * frm)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 
capi_dump(int level,struct frame * frm)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