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
si2str(uint8_t si)39 static 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
pt2str(uint8_t hdr)73 static 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
mt2str(uint8_t hdr)89 static 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
media2str(uint8_t type)103 static 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
codec2str(uint8_t type,uint8_t codec)117 static 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
cat2str(uint8_t cat)156 static 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
errorcode(int level,struct frame * frm)180 static 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
acp_seid(int level,struct frame * frm)189 static 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
acp_int_seid(int level,struct frame * frm)198 static 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
capabilities(int level,struct frame * frm)208 static 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
discover(int level,uint8_t hdr,struct frame * frm)291 static 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
get_capabilities(int level,uint8_t hdr,struct frame * frm)313 static 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
set_configuration(int level,uint8_t hdr,struct frame * frm)328 static 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
get_configuration(int level,uint8_t hdr,struct frame * frm)346 static 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
reconfigure(int level,uint8_t hdr,struct frame * frm)360 static 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
open_close_stream(int level,uint8_t hdr,struct frame * frm)378 static 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
start_suspend_stream(int level,uint8_t hdr,struct frame * frm)390 static 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
abort_streaming(int level,uint8_t hdr,struct frame * frm)404 static 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
security(int level,uint8_t hdr,struct frame * frm)413 static 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
delay_report(int level,uint8_t hdr,struct frame * frm)429 static 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
avdtp_dump(int level,struct frame * frm)448 void 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