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