Home | History | Annotate | Download | only in parser
      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