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