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