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 <unistd.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <sys/types.h>
35#include <netinet/in.h>
36
37#include "parser.h"
38
39static char *si2str(uint8_t si)
40{
41	switch (si & 0x7f) {
42	case 0x01:
43		return "Discover";
44	case 0x02:
45		return "Capabilities";
46	case 0x03:
47		return "Set config";
48	case 0x04:
49		return "Get config";
50	case 0x05:
51		return "Reconfigure";
52	case 0x06:
53		return "Open";
54	case 0x07:
55		return "Start";
56	case 0x08:
57		return "Close";
58	case 0x09:
59		return "Suspend";
60	case 0x0a:
61		return "Abort";
62	case 0x0b:
63		return "Security";
64	case 0x0c:
65		return "All Capabilities";
66	case 0x0d:
67		return "Delay Report";
68	default:
69		return "Unknown";
70	}
71}
72
73static char *pt2str(uint8_t hdr)
74{
75	switch (hdr & 0x0c) {
76	case 0x00:
77		return "Single";
78	case 0x04:
79		return "Start";
80	case 0x08:
81		return "Cont";
82	case 0x0c:
83		return "End";
84	default:
85		return "Unk";
86	}
87}
88
89static char *mt2str(uint8_t hdr)
90{
91	switch (hdr & 0x03) {
92	case 0x00:
93		return "cmd";
94	case 0x02:
95		return "rsp";
96	case 0x03:
97		return "rej";
98	default:
99		return "rfd";
100	}
101}
102
103static char *media2str(uint8_t type)
104{
105	switch (type) {
106	case 0:
107		return "Audio";
108	case 1:
109		return "Video";
110	case 2:
111		return "Multimedia";
112	default:
113		return "Reserved";
114	}
115}
116
117static char *codec2str(uint8_t type, uint8_t codec)
118{
119	switch (type) {
120	case 0:
121		switch (codec) {
122		case 0:
123			return "SBC";
124		case 1:
125			return "MPEG-1,2 Audio";
126		case 2:
127			return "MPEG-2,4 AAC";
128		case 4:
129			return "ATRAC family";
130		case 255:
131			return "non-A2DP";
132		default:
133			return "Reserved";
134		}
135		break;
136	case 1:
137		switch (codec) {
138		case 1:
139			return "H.263 baseline";
140		case 2:
141			return "MPEG-4 Visual Simple Profile";
142		case 3:
143			return "H.263 profile 3";
144		case 4:
145			return "H.263 profile 8";
146		case 255:
147			return "Non-VDP";
148		default:
149			return "Reserved";
150		}
151		break;
152	}
153	return "Unknown";
154}
155
156static char *cat2str(uint8_t cat)
157{
158	switch (cat) {
159	case 1:
160		return "Media Transport";
161	case 2:
162		return "Reporting";
163	case 3:
164		return "Recovery";
165	case 4:
166		return "Content Protection";
167	case 5:
168		return "Header Compression";
169	case 6:
170		return "Multiplexing";
171	case 7:
172		return "Media Codec";
173	case 8:
174		return "Delay Reporting";
175	default:
176		return "Reserved";
177	}
178}
179
180static void errorcode(int level, struct frame *frm)
181{
182	uint8_t code;
183
184	p_indent(level, frm);
185	code = get_u8(frm);
186	printf("Error code %d\n", code);
187}
188
189static void acp_seid(int level, struct frame *frm)
190{
191	uint8_t seid;
192
193	p_indent(level, frm);
194	seid = get_u8(frm);
195	printf("ACP SEID %d\n", seid >> 2);
196}
197
198static void acp_int_seid(int level, struct frame *frm)
199{
200	uint8_t acp_seid, int_seid;
201
202	p_indent(level, frm);
203	acp_seid = get_u8(frm);
204	int_seid = get_u8(frm);
205	printf("ACP SEID %d - INT SEID %d\n", acp_seid >> 2, int_seid >> 2);
206}
207
208static void capabilities(int level, struct frame *frm)
209{
210	uint8_t cat, len;
211
212	while (frm->len > 1) {
213		p_indent(level, frm);
214		cat = get_u8(frm);
215		len = get_u8(frm);
216
217		if (cat == 7) {
218			uint8_t type, codec, tmp;
219
220			type  = get_u8(frm);
221			codec = get_u8(frm);
222
223			printf("%s - %s\n", cat2str(cat), codec2str(type, codec));
224
225			switch (codec) {
226			case 0:
227				tmp = get_u8(frm);
228				p_indent(level + 1, frm);
229				if (tmp & 0x80)
230					printf("16kHz ");
231				if (tmp & 0x40)
232					printf("32kHz ");
233				if (tmp & 0x20)
234					printf("44.1kHz ");
235				if (tmp & 0x10)
236					printf("48kHz ");
237				printf("\n");
238				p_indent(level + 1, frm);
239				if (tmp & 0x08)
240					printf("Mono ");
241				if (tmp & 0x04)
242					printf("DualChannel ");
243				if (tmp & 0x02)
244					printf("Stereo ");
245				if (tmp & 0x01)
246					printf("JointStereo ");
247				printf("\n");
248				tmp = get_u8(frm);
249				p_indent(level + 1, frm);
250				if (tmp & 0x80)
251					printf("4 ");
252				if (tmp & 0x40)
253					printf("8 ");
254				if (tmp & 0x20)
255					printf("12 ");
256				if (tmp & 0x10)
257					printf("16 ");
258				printf("Blocks\n");
259				p_indent(level + 1, frm);
260				if (tmp & 0x08)
261					printf("4 ");
262				if (tmp & 0x04)
263					printf("8 ");
264				printf("Subbands\n");
265				p_indent(level + 1, frm);
266				if (tmp & 0x02)
267					printf("SNR ");
268				if (tmp & 0x01)
269					printf("Loudness ");
270				printf("\n");
271				tmp = get_u8(frm);
272				p_indent(level + 1, frm);
273				printf("Bitpool Range %d-%d\n", tmp, get_u8(frm));
274				break;
275			default:
276				hex_dump(level + 1, frm, len - 2);
277				frm->ptr += (len - 2);
278				frm->len -= (len - 2);
279				break;
280			}
281		} else {
282			printf("%s\n", cat2str(cat));
283			hex_dump(level + 1, frm, len);
284
285			frm->ptr += len;
286			frm->len -= len;
287		}
288	}
289}
290
291static inline void discover(int level, uint8_t hdr, struct frame *frm)
292{
293	uint8_t seid, type;
294
295	switch (hdr & 0x03) {
296	case 0x02:
297		while (frm->len > 1) {
298			p_indent(level, frm);
299			seid = get_u8(frm);
300			type = get_u8(frm);
301			printf("ACP SEID %d - %s %s%s\n",
302				seid >> 2, media2str(type >> 4),
303				type & 0x08 ? "Sink" : "Source",
304				seid & 0x02 ? " (InUse)" : "");
305		}
306		break;
307	case 0x03:
308		errorcode(level, frm);
309		break;
310	}
311}
312
313static inline void get_capabilities(int level, uint8_t hdr, struct frame *frm)
314{
315	switch (hdr & 0x03) {
316	case 0x00:
317		acp_seid(level, frm);
318		break;
319	case 0x02:
320		capabilities(level, frm);
321		break;
322	case 0x03:
323		errorcode(level, frm);
324		break;
325	}
326}
327
328static inline void set_configuration(int level, uint8_t hdr, struct frame *frm)
329{
330	uint8_t cat;
331
332	switch (hdr & 0x03) {
333	case 0x00:
334		acp_int_seid(level, frm);
335		capabilities(level, frm);
336		break;
337	case 0x03:
338		p_indent(level, frm);
339		cat = get_u8(frm);
340		printf("%s\n", cat2str(cat));
341		errorcode(level, frm);
342		break;
343	}
344}
345
346static inline void get_configuration(int level, uint8_t hdr, struct frame *frm)
347{
348	switch (hdr & 0x03) {
349	case 0x00:
350		acp_seid(level, frm);
351	case 0x02:
352		capabilities(level, frm);
353		break;
354	case 0x03:
355		errorcode(level, frm);
356		break;
357	}
358}
359
360static inline void reconfigure(int level, uint8_t hdr, struct frame *frm)
361{
362	uint8_t cat;
363
364	switch (hdr & 0x03) {
365	case 0x00:
366		acp_seid(level, frm);
367		capabilities(level, frm);
368		break;
369	case 0x03:
370		p_indent(level, frm);
371		cat = get_u8(frm);
372		printf("%s\n", cat2str(cat));
373		errorcode(level, frm);
374		break;
375	}
376}
377
378static inline void open_close_stream(int level, uint8_t hdr, struct frame *frm)
379{
380	switch (hdr & 0x03) {
381	case 0x00:
382		acp_seid(level, frm);
383		break;
384	case 0x03:
385		errorcode(level, frm);
386		break;
387	}
388}
389
390static inline void start_suspend_stream(int level, uint8_t hdr, struct frame *frm)
391{
392	switch (hdr & 0x03) {
393	case 0x00:
394		while (frm->len > 0)
395			acp_seid(level, frm);
396		break;
397	case 0x03:
398		acp_seid(level, frm);
399		errorcode(level, frm);
400		break;
401	}
402}
403
404static inline void abort_streaming(int level, uint8_t hdr, struct frame *frm)
405{
406	switch (hdr & 0x03) {
407	case 0x00:
408		acp_seid(level, frm);
409		break;
410	}
411}
412
413static inline void security(int level, uint8_t hdr, struct frame *frm)
414{
415	switch (hdr & 0x03) {
416	case 0x00:
417		acp_seid(level, frm);
418	case 0x02:
419		hex_dump(level + 1, frm, frm->len);
420		frm->ptr += frm->len;
421		frm->len = 0;
422		break;
423	case 0x03:
424		errorcode(level, frm);
425		break;
426	}
427}
428
429static inline void delay_report(int level, uint8_t hdr, struct frame *frm)
430{
431	uint8_t seid;
432	uint16_t delay;
433
434	switch (hdr & 0x03) {
435	case 0x00:
436		p_indent(level, frm);
437		seid = get_u8(frm);
438		delay = get_u16(frm);
439		printf("ACP SEID %d delay %u.%ums\n", seid >> 2,
440						delay / 10, delay % 10);
441		break;
442	case 0x03:
443		errorcode(level, frm);
444		break;
445	}
446}
447
448void avdtp_dump(int level, struct frame *frm)
449{
450	uint8_t hdr, sid, nsp, type;
451	uint16_t seqn;
452	uint32_t time, ssrc;
453
454	switch (frm->num) {
455	case 1:
456		p_indent(level, frm);
457		hdr = get_u8(frm);
458
459		nsp = (hdr & 0x0c) == 0x04 ? get_u8(frm) : 0;
460		sid = hdr & 0x08 ? 0x00 : get_u8(frm);
461
462		printf("AVDTP(s): %s %s: transaction %d\n",
463			hdr & 0x08 ? pt2str(hdr) : si2str(sid), mt2str(hdr), hdr >> 4);
464
465		switch (sid & 0x7f) {
466		case 0x01:
467			discover(level + 1, hdr, frm);
468			break;
469		case 0x02:
470		case 0x0c:
471			get_capabilities(level + 1, hdr, frm);
472			break;
473		case 0x03:
474			set_configuration(level + 1, hdr, frm);
475			break;
476		case 0x04:
477			get_configuration(level + 1, hdr, frm);
478			break;
479		case 0x05:
480			reconfigure(level + 1, hdr, frm);
481			break;
482		case 0x06:
483			open_close_stream(level + 1, hdr, frm);
484			break;
485		case 0x07:
486			start_suspend_stream(level + 1, hdr, frm);
487			break;
488		case 0x08:
489			open_close_stream(level + 1, hdr, frm);
490			break;
491		case 0x09:
492			start_suspend_stream(level + 1, hdr, frm);
493			break;
494		case 0x0a:
495			abort_streaming(level + 1, hdr, frm);
496			break;
497		case 0x0b:
498			security(level + 1, hdr, frm);
499			break;
500		case 0x0d:
501			delay_report(level + 1, hdr, frm);
502			break;
503		}
504
505		break;
506
507	case 2:
508		p_indent(level, frm);
509		hdr  = get_u8(frm);
510		type = get_u8(frm);
511		seqn = get_u16(frm);
512		time = get_u32(frm);
513		ssrc = get_u32(frm);
514
515		printf("AVDTP(m): ver %d %s%scc %d %spt %d seqn %d time %d ssrc %d\n",
516			hdr >> 6, hdr & 0x20 ? "pad " : "", hdr & 0x10 ? "ext " : "",
517			hdr & 0xf, type & 0x80 ? "mark " : "", type & 0x7f, seqn, time, ssrc);
518		break;
519	}
520
521	raw_dump(level, frm);
522}
523