1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2004-2011 Marcel Holtmann <marcel (at) 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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