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