| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include "parser.h"
- static char *si2str(uint8_t si)
- {
- switch (si & 0x7f) {
- case 0x01:
- return "Discover";
- case 0x02:
- return "Capabilities";
- case 0x03:
- return "Set config";
- case 0x04:
- return "Get config";
- case 0x05:
- return "Reconfigure";
- case 0x06:
- return "Open";
- case 0x07:
- return "Start";
- case 0x08:
- return "Close";
- case 0x09:
- return "Suspend";
- case 0x0a:
- return "Abort";
- case 0x0b:
- return "Security";
- case 0x0c:
- return "All Capabilities";
- case 0x0d:
- return "Delay Report";
- default:
- return "Unknown";
- }
- }
- static char *pt2str(uint8_t hdr)
- {
- switch (hdr & 0x0c) {
- case 0x00:
- return "Single";
- case 0x04:
- return "Start";
- case 0x08:
- return "Cont";
- case 0x0c:
- return "End";
- default:
- return "Unk";
- }
- }
- static char *mt2str(uint8_t hdr)
- {
- switch (hdr & 0x03) {
- case 0x00:
- return "cmd";
- case 0x02:
- return "rsp";
- case 0x03:
- return "rej";
- default:
- return "rfd";
- }
- }
- static char *media2str(uint8_t type)
- {
- switch (type) {
- case 0:
- return "Audio";
- case 1:
- return "Video";
- case 2:
- return "Multimedia";
- default:
- return "Reserved";
- }
- }
- static char *codec2str(uint8_t type, uint8_t codec)
- {
- switch (type) {
- case 0:
- switch (codec) {
- case 0:
- return "SBC";
- case 1:
- return "MPEG-1,2 Audio";
- case 2:
- return "MPEG-2,4 AAC";
- case 4:
- return "ATRAC family";
- case 255:
- return "non-A2DP";
- default:
- return "Reserved";
- }
- break;
- case 1:
- switch (codec) {
- case 1:
- return "H.263 baseline";
- case 2:
- return "MPEG-4 Visual Simple Profile";
- case 3:
- return "H.263 profile 3";
- case 4:
- return "H.263 profile 8";
- case 255:
- return "Non-VDP";
- default:
- return "Reserved";
- }
- break;
- }
- return "Unknown";
- }
- static char *vndcodec2str(uint32_t vendor, uint16_t vndcodec)
- {
- if (vendor == 0x0000004f && vndcodec == 0x0001)
- return "aptX";
- else if (vendor == 0x0000012d && vndcodec == 0x00aa)
- return "LDAC";
- return "Unknown";
- }
- static char *cat2str(uint8_t cat)
- {
- switch (cat) {
- case 1:
- return "Media Transport";
- case 2:
- return "Reporting";
- case 3:
- return "Recovery";
- case 4:
- return "Content Protection";
- case 5:
- return "Header Compression";
- case 6:
- return "Multiplexing";
- case 7:
- return "Media Codec";
- case 8:
- return "Delay Reporting";
- default:
- return "Reserved";
- }
- }
- static void errorcode(int level, struct frame *frm)
- {
- uint8_t code;
- p_indent(level, frm);
- code = p_get_u8(frm);
- printf("Error code %d\n", code);
- }
- static void acp_seid(int level, struct frame *frm)
- {
- uint8_t seid;
- p_indent(level, frm);
- seid = p_get_u8(frm);
- printf("ACP SEID %d\n", seid >> 2);
- }
- static void acp_int_seid(int level, struct frame *frm)
- {
- uint8_t acp_seid, int_seid;
- p_indent(level, frm);
- acp_seid = p_get_u8(frm);
- int_seid = p_get_u8(frm);
- printf("ACP SEID %d - INT SEID %d\n", acp_seid >> 2, int_seid >> 2);
- }
- static void capabilities(int level, struct frame *frm)
- {
- uint8_t cat, len;
- while (frm->len > 1) {
- p_indent(level, frm);
- cat = p_get_u8(frm);
- len = p_get_u8(frm);
- if (cat == 7) {
- uint8_t type, codec;
- uint16_t tmp, freq, vndcodec = 0;
- uint32_t bitrate, vendor = 0;
- int i;
- type = p_get_u8(frm);
- codec = p_get_u8(frm);
- if (codec == 255) {
- vendor = btohl(htonl(p_get_u32(frm)));
- vndcodec = btohs(htons(p_get_u16(frm)));
- printf("%s - %s (%s)\n", cat2str(cat),
- codec2str(type, codec),
- vndcodec2str(vendor, vndcodec));
- } else {
- printf("%s - %s\n", cat2str(cat),
- codec2str(type, codec));
- }
- switch (codec) {
- case 0:
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- if (tmp & 0x80)
- printf("16kHz ");
- if (tmp & 0x40)
- printf("32kHz ");
- if (tmp & 0x20)
- printf("44.1kHz ");
- if (tmp & 0x10)
- printf("48kHz ");
- printf("\n");
- p_indent(level + 1, frm);
- if (tmp & 0x08)
- printf("Mono ");
- if (tmp & 0x04)
- printf("DualChannel ");
- if (tmp & 0x02)
- printf("Stereo ");
- if (tmp & 0x01)
- printf("JointStereo ");
- printf("\n");
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- if (tmp & 0x80)
- printf("4 ");
- if (tmp & 0x40)
- printf("8 ");
- if (tmp & 0x20)
- printf("12 ");
- if (tmp & 0x10)
- printf("16 ");
- printf("Blocks\n");
- p_indent(level + 1, frm);
- if (tmp & 0x08)
- printf("4 ");
- if (tmp & 0x04)
- printf("8 ");
- printf("Subbands\n");
- p_indent(level + 1, frm);
- if (tmp & 0x02)
- printf("SNR ");
- if (tmp & 0x01)
- printf("Loudness ");
- printf("\n");
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- printf("Bitpool Range %d-%d\n", tmp, p_get_u8(frm));
- break;
- case 1:
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- printf("Layers: ");
- if (tmp & 0x80)
- printf("1 ");
- if (tmp & 0x40)
- printf("2 ");
- if (tmp & 0x20)
- printf("3 ");
- printf("\n");
- p_indent(level + 1, frm);
- printf("CRC Protection: %s\n",
- tmp & 0x10 ? "Yes" : "No");
- p_indent(level + 1, frm);
- if (tmp & 0x08)
- printf("Mono ");
- if (tmp & 0x04)
- printf("DualChannel ");
- if (tmp & 0x02)
- printf("Stereo ");
- if (tmp & 0x01)
- printf("JointStereo ");
- printf("\n");
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- printf("Media Payload Format: RFC-2250 %s\n",
- tmp & 0x40 ? "RFC-3119" : "");
- p_indent(level + 1, frm);
- if (tmp & 0x20)
- printf("16kHz ");
- if (tmp & 0x10)
- printf("22.05kHz ");
- if (tmp & 0x08)
- printf("24kHz ");
- if (tmp & 0x04)
- printf("32kHz ");
- if (tmp & 0x02)
- printf("44.1kHz ");
- if (tmp & 0x01)
- printf("48kHz ");
- printf("\n");
- tmp = p_get_u16(frm);
- p_indent(level + 1, frm);
- printf("VBR: %s\n",
- tmp & 0x8000 ? "Yes" : "No");
- p_indent(level + 1, frm);
- printf("Bit Rate Indexes: ");
- if (tmp & 0x8000) {
- printf("n/a");
- } else {
- for (i = 0; i < 15; i++, tmp >>= 1)
- if (tmp & 0x0001)
- printf("%d ", i);
- }
- printf("\n");
- break;
- case 2:
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- if (tmp & 0x80)
- printf("MPEG-2 AAC LC ");
- if (tmp & 0x40)
- printf("MPEG-4 AAC LC ");
- if (tmp & 0x20)
- printf("MPEG-4 AAC LTP ");
- if (tmp & 0x10)
- printf("MPEG-4 AAC scalable ");
- printf("\n");
- tmp = p_get_u16(frm);
- freq = tmp >> 4;
- p_indent(level + 1, frm);
- if (freq & 0x0800)
- printf("8kHz ");
- if (freq & 0x0400)
- printf("11.025kHz ");
- if (freq & 0x0200)
- printf("12kHz ");
- if (freq & 0x0100)
- printf("16kHz ");
- if (freq & 0x0080)
- printf("22.05kHz ");
- if (freq & 0x0040)
- printf("24kHz ");
- if (freq & 0x0020)
- printf("32kHz ");
- if (freq & 0x0010)
- printf("44.1kHz ");
- if (freq & 0x0008)
- printf("48kHz ");
- if (freq & 0x0004)
- printf("64kHz ");
- if (freq & 0x0002)
- printf("88.2kHz ");
- if (freq & 0x0001)
- printf("96kHz ");
- printf("\n");
- tmp >>= 2;
- p_indent(level + 1, frm);
- if (tmp & 0x02)
- printf("1 ");
- if (tmp & 0x01)
- printf("2 ");
- printf("Channels\n");
- tmp = p_get_u8(frm);
- bitrate = ((tmp & 0x7f) << 16) | p_get_u16(frm);
- p_indent(level + 1, frm);
- printf("%ubps ", bitrate);
- printf("%s\n", tmp & 0x80 ? "VBR" : "");
- break;
- case 255:
- if (vendor == 0x0000004f &&
- vndcodec == 0x0001) {
- tmp = p_get_u8(frm);
- p_indent(level + 1, frm);
- if (tmp & 0x80)
- printf("16kHz ");
- if (tmp & 0x40)
- printf("32kHz ");
- if (tmp & 0x20)
- printf("44.1kHz ");
- if (tmp & 0x10)
- printf("48kHz ");
- printf("\n");
- p_indent(level + 1, frm);
- if (tmp & 0x02)
- printf("Stereo ");
- if (tmp & 0x01)
- printf("Mono ");
- printf("\n");
- break;
- } else {
- hex_dump(level + 1, frm, len - 8);
- frm->ptr += (len - 8);
- frm->len -= (len - 8);
- }
- break;
- default:
- hex_dump(level + 1, frm, len - 2);
- frm->ptr += (len - 2);
- frm->len -= (len - 2);
- break;
- }
- } else {
- printf("%s\n", cat2str(cat));
- hex_dump(level + 1, frm, len);
- frm->ptr += len;
- frm->len -= len;
- }
- }
- }
- static inline void discover(int level, uint8_t hdr, struct frame *frm)
- {
- uint8_t seid, type;
- switch (hdr & 0x03) {
- case 0x02:
- while (frm->len > 1) {
- p_indent(level, frm);
- seid = p_get_u8(frm);
- type = p_get_u8(frm);
- printf("ACP SEID %d - %s %s%s\n",
- seid >> 2, media2str(type >> 4),
- type & 0x08 ? "Sink" : "Source",
- seid & 0x02 ? " (InUse)" : "");
- }
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- static inline void get_capabilities(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- break;
- case 0x02:
- capabilities(level, frm);
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- static inline void set_configuration(int level, uint8_t hdr, struct frame *frm)
- {
- uint8_t cat;
- switch (hdr & 0x03) {
- case 0x00:
- acp_int_seid(level, frm);
- capabilities(level, frm);
- break;
- case 0x03:
- p_indent(level, frm);
- cat = p_get_u8(frm);
- printf("%s\n", cat2str(cat));
- errorcode(level, frm);
- break;
- }
- }
- static inline void get_configuration(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- break;
- case 0x02:
- capabilities(level, frm);
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- static inline void reconfigure(int level, uint8_t hdr, struct frame *frm)
- {
- uint8_t cat;
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- capabilities(level, frm);
- break;
- case 0x03:
- p_indent(level, frm);
- cat = p_get_u8(frm);
- printf("%s\n", cat2str(cat));
- errorcode(level, frm);
- break;
- }
- }
- static inline void open_close_stream(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- static inline void start_suspend_stream(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- while (frm->len > 0)
- acp_seid(level, frm);
- break;
- case 0x03:
- acp_seid(level, frm);
- errorcode(level, frm);
- break;
- }
- }
- static inline void abort_streaming(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- break;
- }
- }
- static inline void security(int level, uint8_t hdr, struct frame *frm)
- {
- switch (hdr & 0x03) {
- case 0x00:
- acp_seid(level, frm);
- break;
- case 0x02:
- hex_dump(level + 1, frm, frm->len);
- frm->ptr += frm->len;
- frm->len = 0;
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- static inline void delay_report(int level, uint8_t hdr, struct frame *frm)
- {
- uint8_t seid;
- uint16_t delay;
- switch (hdr & 0x03) {
- case 0x00:
- p_indent(level, frm);
- seid = p_get_u8(frm);
- delay = p_get_u16(frm);
- printf("ACP SEID %d delay %u.%ums\n", seid >> 2,
- delay / 10, delay % 10);
- break;
- case 0x03:
- errorcode(level, frm);
- break;
- }
- }
- void avdtp_dump(int level, struct frame *frm)
- {
- uint8_t hdr, sid, nsp, type;
- uint16_t seqn;
- uint32_t time, ssrc;
- switch (frm->num) {
- case 1:
- p_indent(level, frm);
- hdr = p_get_u8(frm);
- nsp = (hdr & 0x0c) == 0x04 ? p_get_u8(frm) : 0;
- sid = hdr & 0x08 ? 0x00 : p_get_u8(frm);
- printf("AVDTP(p): %s %s: transaction %d nsp 0x%02x\n",
- hdr & 0x08 ? pt2str(hdr) : si2str(sid),
- mt2str(hdr), hdr >> 4, nsp);
- switch (sid & 0x7f) {
- case 0x01:
- discover(level + 1, hdr, frm);
- break;
- case 0x02:
- case 0x0c:
- get_capabilities(level + 1, hdr, frm);
- break;
- case 0x03:
- set_configuration(level + 1, hdr, frm);
- break;
- case 0x04:
- get_configuration(level + 1, hdr, frm);
- break;
- case 0x05:
- reconfigure(level + 1, hdr, frm);
- break;
- case 0x06:
- open_close_stream(level + 1, hdr, frm);
- break;
- case 0x07:
- start_suspend_stream(level + 1, hdr, frm);
- break;
- case 0x08:
- open_close_stream(level + 1, hdr, frm);
- break;
- case 0x09:
- start_suspend_stream(level + 1, hdr, frm);
- break;
- case 0x0a:
- abort_streaming(level + 1, hdr, frm);
- break;
- case 0x0b:
- security(level + 1, hdr, frm);
- break;
- case 0x0d:
- delay_report(level + 1, hdr, frm);
- break;
- }
- break;
- case 2:
- p_indent(level, frm);
- hdr = p_get_u8(frm);
- type = p_get_u8(frm);
- seqn = p_get_u16(frm);
- time = p_get_u32(frm);
- ssrc = p_get_u32(frm);
- printf("AVDTP(c): ver %d %s%scc"
- " %d %spt %d seqn %d time %d ssrc %d\n",
- hdr >> 6, hdr & 0x20 ? "pad " : "",
- hdr & 0x10 ? "ext " : "", hdr & 0xf,
- type & 0x80 ? "mark " : "", type & 0x7f,
- seqn, time, ssrc);
- break;
- }
- raw_dump(level, frm);
- }
|