avdtp.c revision e5e4f00bb96381f8971b9b1ca674902e9771626c
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