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