2015-11-22 20:20:12

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 00/22] Add AVDTP/A2DP decoding to btmon

Hi,

Here's series of patches which adds decoding of AVDTP signalling channel
and A2DP codec capabilities information. Few things are missing:
- no fragmentation support
- some rarely used capabilities are not decoded
- ATRAC capabilities are not decoded

Other that above, pretty much everything should be decoded.

Changes in v2:
- fixed formatting according to comments
- updated commit messages to include decoded frames (except for few of
them where I was not able trigger proper signalling)
- some minor issues fixed found during development

Changes in v3:
- fixed comments from Szymon (few more raised offline)
- more minor issues fixed


Andrzej Kaczmarek (22):
monitor/l2cap: Add channel sequence number
monitor/avdtp: Add basic decoding of AVDTP signalling
monitor/avdtp: Decode AVDTP_DISCOVER
monitor/avdtp: Decode AVDTP_GET_CAPABILITIES
monitor/avdtp: Decode AVDTP_SET_CONFIGURATION
monitor/avdtp: Decode AVDTP_GET_CONFIGURATION
monitor/avdtp: Decode AVDTP_RECONFIGURE
monitor/avdtp: Decode AVDTP_OPEN
monitor/avdtp: Decode AVDTP_START
monitor/avdtp: Decode AVDTP_CLOSE
monitor/avdtp: Decode AVDTP_SUSPEND
monitor/avdtp: Decode AVDTP_ABORT
monitor/avdtp: Decode AVDTP_SECURITY_CONTROL
monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES
monitor/avdtp: Decode AVDTP_DELAYREPORT
monitor/avdtp: Decode basic Media Codec capabilities
monitor/avdtp: Decode basic Content Protection capabilities
monitor/a2dp: Decode SBC capabilities
monitor/a2dp: Decode MPEG-1,2 capabilities
monitor/a2dp: Decode AAC capabilities
monitor/a2dp: Decode aptX capabilities
monitor/a2dp: Decode LDAC capabilities

Makefile.tools | 2 +
android/Android.mk | 2 +
monitor/a2dp.c | 638 +++++++++++++++++++++++++++++++++++++++++++
monitor/a2dp.h | 26 ++
monitor/avdtp.c | 787 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/avdtp.h | 24 ++
monitor/l2cap.c | 57 ++--
monitor/l2cap.h | 1 +
8 files changed, 1520 insertions(+), 17 deletions(-)
create mode 100644 monitor/a2dp.c
create mode 100644 monitor/a2dp.h
create mode 100644 monitor/avdtp.c
create mode 100644 monitor/avdtp.h

--
2.6.2



2015-11-22 20:20:32

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 20/22] monitor/a2dp: Decode AAC capabilities

> ACL Data RX: Handle 12 flags 0x02 dlen 22 4.565591
Channel: 67 len 18 [PSM 25 mode 0] {chan 1}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 4 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: MPEG-2,4 AAC (0x02)
Object Type: 0xc0
MPEG-2 AAC LC
MPEG-4 AAC LC
Frequency: 0x180
44100
48000
Channels: 0x0c
1
2
Bitrate: 320000bps
VBR: Yes
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)
---
monitor/a2dp.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 124 insertions(+)

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index 9028238..d053857 100644
--- a/monitor/a2dp.c
+++ b/monitor/a2dp.c
@@ -132,6 +132,40 @@ static const struct bit_desc mpeg12_bitrate_table[] = {
{ }
};

+static const struct bit_desc aac_object_type_table[] = {
+ { 7, "MPEG-2 AAC LC" },
+ { 6, "MPEG-4 AAC LC" },
+ { 5, "MPEG-4 AAC LTP" },
+ { 4, "MPEG-4 AAC scalable" },
+ { 3, "RFA (b3)" },
+ { 2, "RFA (b2)" },
+ { 1, "RFA (b1)" },
+ { 0, "RFA (b0)" },
+ { }
+};
+
+static const struct bit_desc aac_frequency_table[] = {
+ { 15, "8000" },
+ { 14, "11025" },
+ { 13, "12000" },
+ { 12, "16000" },
+ { 11, "22050" },
+ { 10, "24000" },
+ { 9, "32000" },
+ { 8, "44100" },
+ { 7, "48000" },
+ { 6, "64000" },
+ { 5, "88200" },
+ { 4, "96000" },
+ { }
+};
+
+static const struct bit_desc aac_channels_table[] = {
+ { 3, "1" },
+ { 2, "2" },
+ { }
+};
+
static void print_value_bits(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -338,6 +372,92 @@ static bool codec_mpeg12_cfg(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_aac_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t type;
+ uint16_t freq;
+ uint8_t chan;
+ uint32_t bitrate;
+ bool vbr;
+
+ if (losc != 6)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ type = cap >> 8;
+ freq = cap << 8;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ freq |= (cap >> 8) & 0xf0;
+ chan = (cap >> 8) & 0x0c;
+ bitrate = (cap << 16) & 0x7f0000;
+ vbr = cap & 0x0080;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ bitrate |= cap;
+
+ print_field("%*cObject Type: 0x%02x", BASE_INDENT, ' ', type);
+ print_value_bits(BASE_INDENT, type, aac_object_type_table);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+ print_value_bits(BASE_INDENT, freq, aac_frequency_table);
+
+ print_field("%*cChannels: 0x%02x", BASE_INDENT, ' ', chan);
+ print_value_bits(BASE_INDENT, chan, aac_channels_table);
+
+ print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_aac_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t type;
+ uint16_t freq;
+ uint8_t chan;
+ uint32_t bitrate;
+ bool vbr;
+
+ if (losc != 6)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ type = cap >> 8;
+ freq = cap << 8;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ freq |= (cap >> 8) & 0xf0;
+ chan = (cap >> 8) & 0x0c;
+ bitrate = (cap << 16) & 0x7f0000;
+ vbr = cap & 0x0080;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ bitrate |= cap;
+
+ print_field("%*cObject Type: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(type, aac_object_type_table), type);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(freq, aac_frequency_table), freq);
+
+ print_field("%*cChannels: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(chan, aac_channels_table), chan);
+
+ print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
@@ -345,6 +465,8 @@ bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_sbc_cap(losc, frame);
case A2DP_CODEC_MPEG12:
return codec_mpeg12_cap(losc, frame);
+ case A2DP_CODEC_MPEG24:
+ return codec_aac_cap(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
@@ -359,6 +481,8 @@ bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_sbc_cfg(losc, frame);
case A2DP_CODEC_MPEG12:
return codec_mpeg12_cfg(losc, frame);
+ case A2DP_CODEC_MPEG24:
+ return codec_aac_cfg(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-22 20:20:33

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 21/22] monitor/a2dp: Decode aptX capabilities

> ACL Data RX: Handle 5 flags 0x02 dlen 23
Channel: 65 len 19 [PSM 25 mode 0] {chan 1}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 12 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: Non-A2DP (0xff)
Vendor ID: APT Licensing Ltd. (0x0000004f)
Vendor Specific Codec ID: aptX (0x0001)
Frequency: 0x30
44100
48000
Channel Mode: 0x02
Stereo
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)

< ACL Data TX: Handle 5 flags 0x00 dlen 21
Channel: 193 len 17 [PSM 25 mode 0] {chan 1}
AVDTP: Set Configuration (0x03) Command (0x00) type 0x00 label 14 nosp 0
ACP SEID: 3
INT SEID: 1
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: Non-A2DP (0xff)
Vendor ID: APT Licensing Ltd. (0x0000004f)
Vendor Specific Codec ID: aptX (0x0001)
Frequency: 48000 (0x10)
Channel Mode: Stereo (0x02)
---
monitor/a2dp.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 127 insertions(+)

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index d053857..5c9553e 100644
--- a/monitor/a2dp.c
+++ b/monitor/a2dp.c
@@ -47,6 +47,10 @@
#define A2DP_CODEC_ATRAC 0x04
#define A2DP_CODEC_VENDOR 0xff

+/* Vendor Specific A2DP Codecs */
+#define APTX_VENDOR_ID 0x0000004f
+#define APTX_CODEC_ID 0x0001
+
struct bit_desc {
uint8_t bit_num;
const char *str;
@@ -166,6 +170,20 @@ static const struct bit_desc aac_channels_table[] = {
{ }
};

+static const struct bit_desc aptx_frequency_table[] = {
+ { 7, "16000" },
+ { 6, "32000" },
+ { 5, "44100" },
+ { 4, "48000" },
+ { }
+};
+
+static const struct bit_desc aptx_channel_mode_table[] = {
+ { 0, "Mono" },
+ { 1, "Stereo" },
+ { }
+};
+
static void print_value_bits(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -190,6 +208,14 @@ static const char *find_value_bit(uint32_t value,
return "Unknown";
}

+static const char *vndcodec2str(uint32_t vendor_id, uint16_t codec_id)
+{
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return "aptX";
+
+ return "Unknown";
+}
+
static bool codec_sbc_cap(uint8_t losc, struct l2cap_frame *frame)
{
uint8_t cap = 0;
@@ -458,6 +484,103 @@ static bool codec_aac_cfg(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 1)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT + 2, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ',
+ cap & 0x0f);
+ print_value_bits(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table);
+
+ return true;
+}
+
+static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint32_t vendor_id = 0;
+ uint16_t codec_id = 0;
+
+ if (losc < 6)
+ return false;
+
+ l2cap_frame_get_le32(frame, &vendor_id);
+ l2cap_frame_get_le16(frame, &codec_id);
+
+ losc -= 6;
+
+ print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+ bt_compidtostr(vendor_id), vendor_id);
+
+ print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+ ' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return codec_vendor_aptx_cap(losc, frame);
+
+ /* TODO: decode other codecs */
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
+static bool codec_vendor_aptx_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 1)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT + 2, ' ',
+ find_value_bit(cap & 0xf0, aptx_frequency_table),
+ cap & 0xf0);
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT + 2, ' ',
+ find_value_bit(cap & 0x0f, aptx_channel_mode_table),
+ cap & 0x0f);
+
+ return true;
+}
+
+static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint32_t vendor_id = 0;
+ uint16_t codec_id = 0;
+
+ if (losc < 6)
+ return false;
+
+ l2cap_frame_get_le32(frame, &vendor_id);
+ l2cap_frame_get_le16(frame, &codec_id);
+
+ losc -= 6;
+
+ print_field("%*cVendor ID: %s (0x%08x)", BASE_INDENT, ' ',
+ bt_compidtostr(vendor_id), vendor_id);
+
+ print_field("%*cVendor Specific Codec ID: %s (0x%04x)", BASE_INDENT,
+ ' ', vndcodec2str(vendor_id, codec_id), codec_id);
+
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
+ return codec_vendor_aptx_cfg(losc, frame);
+
+ /* TODO: decode other codecs */
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
@@ -467,6 +590,8 @@ bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_mpeg12_cap(losc, frame);
case A2DP_CODEC_MPEG24:
return codec_aac_cap(losc, frame);
+ case A2DP_CODEC_VENDOR:
+ return codec_vendor_cap(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
@@ -483,6 +608,8 @@ bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_mpeg12_cfg(losc, frame);
case A2DP_CODEC_MPEG24:
return codec_aac_cfg(losc, frame);
+ case A2DP_CODEC_VENDOR:
+ return codec_vendor_cfg(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-22 20:20:34

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 22/22] monitor/a2dp: Decode LDAC capabilities

> ACL Data RX: Handle 12 flags 0x02 dlen 24
Channel: 67 len 20 [PSM 25 mode 0] {chan 1}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 2 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: Non-A2DP (0xff)
Vendor ID: Sony Corporation (0x0000012d)
Vendor Specific Codec ID: LDAC (0x00aa)
Unknown: 0x073c
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)

< ACL Data TX: Handle 12 flags 0x02 dlen 26
Channel: 2753 len 22 [PSM 25 mode 0] {chan 1}
AVDTP: Set Configuration (0x03) Command (0x00) type 0x00 label 5 nosp 0
ACP SEID: 5
INT SEID: 3
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: Non-A2DP (0xff)
Vendor ID: Sony Corporation (0x0000012d)
Vendor Specific Codec ID: LDAC (0x00aa0
Unknown: 0x0104
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)
---
monitor/a2dp.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index 5c9553e..94f9758 100644
--- a/monitor/a2dp.c
+++ b/monitor/a2dp.c
@@ -50,6 +50,8 @@
/* Vendor Specific A2DP Codecs */
#define APTX_VENDOR_ID 0x0000004f
#define APTX_CODEC_ID 0x0001
+#define LDAC_VENDOR_ID 0x0000012d
+#define LDAC_CODEC_ID 0x00aa

struct bit_desc {
uint8_t bit_num;
@@ -212,6 +214,8 @@ static const char *vndcodec2str(uint32_t vendor_id, uint16_t codec_id)
{
if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
return "aptX";
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return "LDAC";

return "Unknown";
}
@@ -503,6 +507,20 @@ static bool codec_vendor_aptx_cap(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_vendor_ldac(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+
+ if (losc != 2)
+ return false;
+
+ l2cap_frame_get_le16(frame, &cap);
+
+ print_field("%*cUnknown: 0x%04x", BASE_INDENT + 2, ' ', cap);
+
+ return true;
+}
+
static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)
{
uint32_t vendor_id = 0;
@@ -524,8 +542,9 @@ static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)

if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
return codec_vendor_aptx_cap(losc, frame);
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return codec_vendor_ldac(losc, frame);

- /* TODO: decode other codecs */
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);

@@ -573,8 +592,9 @@ static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame)

if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID)
return codec_vendor_aptx_cfg(losc, frame);
+ else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID)
+ return codec_vendor_ldac(losc, frame);

- /* TODO: decode other codecs */
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);

--
2.6.2


2015-11-22 20:20:31

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 19/22] monitor/a2dp: Decode MPEG-1,2 capabilities

---
monitor/a2dp.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index c89a7c1..9028238 100644
--- a/monitor/a2dp.c
+++ b/monitor/a2dp.c
@@ -88,6 +88,50 @@ static const struct bit_desc sbc_allocation_table[] = {
{ }
};

+static const struct bit_desc mpeg12_layer_table[] = {
+ { 7, "Layer I (mp1)" },
+ { 6, "Layer II (mp2)" },
+ { 5, "Layer III (mp3)" },
+ { }
+};
+
+static const struct bit_desc mpeg12_channel_mode_table[] = {
+ { 3, "Mono" },
+ { 2, "Dual Channel" },
+ { 1, "Stereo" },
+ { 0, "Joint Stereo" },
+ { }
+};
+
+static const struct bit_desc mpeg12_frequency_table[] = {
+ { 5, "16000" },
+ { 4, "22050" },
+ { 3, "24000" },
+ { 2, "32000" },
+ { 1, "44100" },
+ { 0, "48000" },
+ { }
+};
+
+static const struct bit_desc mpeg12_bitrate_table[] = {
+ { 14, "1110" },
+ { 13, "1101" },
+ { 12, "1100" },
+ { 11, "1011" },
+ { 10, "1010" },
+ { 9, "1001" },
+ { 8, "1000" },
+ { 7, "0111" },
+ { 6, "0110" },
+ { 5, "0101" },
+ { 4, "0100" },
+ { 3, "0011" },
+ { 2, "0010" },
+ { 1, "0001" },
+ { 0, "0000" },
+ { }
+};
+
static void print_value_bits(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -192,11 +236,115 @@ static bool codec_sbc_cfg(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_mpeg12_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t layer;
+ uint8_t chan;
+ uint8_t freq;
+ uint16_t bitrate;
+ bool crc, mpf, vbr;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ layer = (cap >> 8) & 0xe0;
+ crc = cap & 0x1000;
+ chan = (cap >> 8) & 0x0f;
+ mpf = cap & 0x0040;
+ freq = cap & 0x003f;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ vbr = cap & 0x8000;
+ bitrate = cap & 0x7fff;
+
+ print_field("%*cLayer: 0x%02x", BASE_INDENT, ' ', layer);
+ print_value_bits(BASE_INDENT, layer, mpeg12_layer_table);
+
+ print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', chan);
+ print_value_bits(BASE_INDENT, chan, mpeg12_channel_mode_table);
+
+ print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+ mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+ print_value_bits(BASE_INDENT, freq, mpeg12_frequency_table);
+
+ if (!vbr) {
+ print_field("%*cBitrate Index: 0x%04x", BASE_INDENT, ' ',
+ bitrate);
+ print_value_bits(BASE_INDENT, freq, mpeg12_bitrate_table);
+ }
+
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
+static bool codec_mpeg12_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint16_t cap = 0;
+ uint8_t layer;
+ uint8_t chan;
+ uint8_t freq;
+ uint16_t bitrate;
+ bool crc, mpf, vbr;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ layer = (cap >> 8) & 0xe0;
+ crc = cap & 0x1000;
+ chan = (cap >> 8) & 0x0f;
+ mpf = cap & 0x0040;
+ freq = cap & 0x003f;
+
+ l2cap_frame_get_be16(frame, &cap);
+
+ vbr = cap & 0x8000;
+ bitrate = cap & 0x7fff;
+
+ print_field("%*cLayer: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(layer, mpeg12_layer_table),
+ layer);
+
+ print_field("%*cCRC: %s", BASE_INDENT, ' ', crc ? "Yes" : "No");
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(chan, mpeg12_channel_mode_table),
+ chan);
+
+ print_field("%*cMedia Payload Format: %s", BASE_INDENT, ' ',
+ mpf ? "RFC-2250 RFC-3119" : "RFC-2250");
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(freq, mpeg12_frequency_table),
+ freq);
+
+ if (!vbr)
+ print_field("%*cBitrate Index: %s (0x%04x)", BASE_INDENT, ' ',
+ find_value_bit(freq, mpeg12_bitrate_table),
+ bitrate);
+
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
case A2DP_CODEC_SBC:
return codec_sbc_cap(losc, frame);
+ case A2DP_CODEC_MPEG12:
+ return codec_mpeg12_cap(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
@@ -209,6 +357,8 @@ bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
switch (codec) {
case A2DP_CODEC_SBC:
return codec_sbc_cfg(losc, frame);
+ case A2DP_CODEC_MPEG12:
+ return codec_mpeg12_cfg(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-22 20:20:30

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 18/22] monitor/a2dp: Decode SBC capabilities

> ACL Data RX: Handle 256 flags 0x02 dlen 20 [hci0] 9.242155
Channel: 66 len 16 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 1 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: SBC (0x00)
Frequency: 0x30
44100
48000
Channel Mode: 0x0f
Mono
Dual Channel
Stereo
Joint Channel
Block Length: 0xf0
4
8
12
16
Subbands: 0x0c
4
8
Allocation Method: 0x03
SNR
Loudness
Minimum Bitpool: 2
Maximum Bitpool: 53
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)

< ACL Data TX: Handle 256 flags 0x00 dlen 18 [hci0] 9.272120
Channel: 258 len 14 [PSM 25 mode 0] {chan 2}
AVDTP: Set Configuration (0x03) Command (0x00) type 0x00 label 5 nosp 0
ACP SEID: 1
INT SEID: 3
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: SBC (0x00)
Frequency: 44100 (0x20)
Channel Mode: Joint Channel (0x01)
Block Length: 16 (0x10)
Subbands: 8 (0x04)
Allocation Method: Loudness (0x01)
Minimum Bitpool: 2
Maximum Bitpool: 53
---
Makefile.tools | 1 +
android/Android.mk | 1 +
monitor/a2dp.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/a2dp.h | 26 +++++++
monitor/avdtp.c | 18 +++--
5 files changed, 257 insertions(+), 6 deletions(-)
create mode 100644 monitor/a2dp.c
create mode 100644 monitor/a2dp.h

diff --git a/Makefile.tools b/Makefile.tools
index 8555a6b..034790a 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -28,6 +28,7 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/sdp.h monitor/sdp.c \
monitor/avctp.h monitor/avctp.c \
monitor/avdtp.h monitor/avdtp.c \
+ monitor/a2dp.h monitor/a2dp.c \
monitor/rfcomm.h monitor/rfcomm.c \
monitor/bnep.h monitor/bnep.c \
monitor/uuid.h monitor/uuid.c \
diff --git a/android/Android.mk b/android/Android.mk
index fa1188b..38ef4aa 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -340,6 +340,7 @@ LOCAL_SRC_FILES := \
bluez/monitor/l2cap.c \
bluez/monitor/avctp.c \
bluez/monitor/avdtp.c \
+ bluez/monitor/a2dp.c \
bluez/monitor/rfcomm.c \
bluez/monitor/bnep.c \
bluez/monitor/uuid.c \
diff --git a/monitor/a2dp.c b/monitor/a2dp.c
new file mode 100644
index 0000000..c89a7c1
--- /dev/null
+++ b/monitor/a2dp.c
@@ -0,0 +1,217 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <[email protected]>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "a2dp.h"
+
+#define BASE_INDENT 4
+
+/* Codec Types */
+#define A2DP_CODEC_SBC 0x00
+#define A2DP_CODEC_MPEG12 0x01
+#define A2DP_CODEC_MPEG24 0x02
+#define A2DP_CODEC_ATRAC 0x04
+#define A2DP_CODEC_VENDOR 0xff
+
+struct bit_desc {
+ uint8_t bit_num;
+ const char *str;
+};
+
+static const struct bit_desc sbc_frequency_table[] = {
+ { 7, "16000" },
+ { 6, "32000" },
+ { 5, "44100" },
+ { 4, "48000" },
+ { }
+};
+
+static const struct bit_desc sbc_channel_mode_table[] = {
+ { 3, "Mono" },
+ { 2, "Dual Channel" },
+ { 1, "Stereo" },
+ { 0, "Joint Stereo" },
+ { }
+};
+
+static const struct bit_desc sbc_blocklen_table[] = {
+ { 7, "4" },
+ { 6, "8" },
+ { 5, "12" },
+ { 4, "16" },
+ { }
+};
+
+static const struct bit_desc sbc_subbands_table[] = {
+ { 3, "4" },
+ { 2, "8" },
+ { }
+};
+
+static const struct bit_desc sbc_allocation_table[] = {
+ { 1, "SNR" },
+ { 0, "Loudness" },
+ { }
+};
+
+static void print_value_bits(uint8_t indent, uint32_t value,
+ const struct bit_desc *table)
+{
+ int i;
+
+ for (i = 0; table[i].str; i++) {
+ if (value & (1 << table[i].bit_num))
+ print_field("%*c%s", indent + 2, ' ', table[i].str);
+ }
+}
+
+static const char *find_value_bit(uint32_t value,
+ const struct bit_desc *table)
+{
+ int i;
+
+ for (i = 0; table[i].str; i++) {
+ if (value & (1 << table[i].bit_num))
+ return table[i].str;
+ }
+
+ return "Unknown";
+}
+
+static bool codec_sbc_cap(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT, cap & 0xf0, sbc_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', cap & 0x0f);
+ print_value_bits(BASE_INDENT, cap & 0x0f, sbc_channel_mode_table);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cBlock Length: 0x%02x", BASE_INDENT, ' ', cap & 0xf0);
+ print_value_bits(BASE_INDENT, cap & 0xf0, sbc_blocklen_table);
+
+ print_field("%*cSubbands: 0x%02x", BASE_INDENT, ' ', cap & 0x0c);
+ print_value_bits(BASE_INDENT, cap & 0x0c, sbc_subbands_table);
+
+ print_field("%*cAllocation Method: 0x%02x", BASE_INDENT, ' ',
+ cap & 0x03);
+ print_value_bits(BASE_INDENT, cap & 0x03, sbc_allocation_table);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ return true;
+}
+
+static bool codec_sbc_cfg(uint8_t losc, struct l2cap_frame *frame)
+{
+ uint8_t cap = 0;
+
+ if (losc != 4)
+ return false;
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cFrequency: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0xf0, sbc_frequency_table),
+ cap & 0xf0);
+
+ print_field("%*cChannel Mode: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x0f, sbc_channel_mode_table),
+ cap & 0x0f);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cBlock Length: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0xf0, sbc_blocklen_table),
+ cap & 0xf0);
+
+ print_field("%*cSubbands: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x0c, sbc_subbands_table),
+ cap & 0x0c);
+
+ print_field("%*cAllocation Method: %s (0x%02x)", BASE_INDENT, ' ',
+ find_value_bit(cap & 0x03, sbc_allocation_table),
+ cap & 0x03);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMinimum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ l2cap_frame_get_u8(frame, &cap);
+
+ print_field("%*cMaximum Bitpool: %d", BASE_INDENT, ' ', cap);
+
+ return true;
+}
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+ switch (codec) {
+ case A2DP_CODEC_SBC:
+ return codec_sbc_cap(losc, frame);
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ return true;
+ }
+}
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+ switch (codec) {
+ case A2DP_CODEC_SBC:
+ return codec_sbc_cfg(losc, frame);
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ return true;
+ }
+}
diff --git a/monitor/a2dp.h b/monitor/a2dp.h
new file mode 100644
index 0000000..72a8f1f
--- /dev/null
+++ b/monitor/a2dp.h
@@ -0,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <[email protected]>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+bool a2dp_codec_cap(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
+
+bool a2dp_codec_cfg(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index f810f0e..3524faa 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -37,6 +37,7 @@
#include "display.h"
#include "l2cap.h"
#include "avdtp.h"
+#include "a2dp.h"

/* Message Types */
#define AVDTP_MSG_TYPE_COMMAND 0x00
@@ -75,6 +76,13 @@ struct avdtp_frame {
struct l2cap_frame l2cap_frame;
};

+static inline bool is_configuration_sig_id(uint8_t sig_id)
+{
+ return (sig_id == AVDTP_SET_CONFIGURATION) ||
+ (sig_id == AVDTP_GET_CONFIGURATION) ||
+ (sig_id == AVDTP_RECONFIGURE);
+}
+
static const char *msgtype2str(uint8_t msgtype)
{
switch (msgtype) {
@@ -293,12 +301,10 @@ static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
print_field("%*cMedia Codec: %s (0x%02x)", 2, ' ',
mediacodec2str(codec), codec);

- /* TODO: decode codec specific information */
-
- packet_hexdump(frame->data, losc);
- l2cap_frame_pull(frame, frame, losc);
-
- return true;
+ if (is_configuration_sig_id(avdtp_frame->sig_id))
+ return a2dp_codec_cfg(codec, losc, frame);
+ else
+ return a2dp_codec_cap(codec, losc, frame);
}

static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
--
2.6.2


2015-11-22 20:20:29

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 17/22] monitor/avdtp: Decode basic Content Protection capabilities

> ACL Data RX: Handle 256 flags 0x02 dlen 20
Channel: 66 len 16 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 1 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: SBC (0x00)
3f ff 02 35 ?..5
Service Category: Content Protection (0x04)
Content Protection Type: SCMS-T (0x0002)
---
monitor/avdtp.c | 42 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 8041d35..f810f0e 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -199,6 +199,18 @@ static const char *mediacodec2str(uint8_t codec)
}
}

+static const char *cptype2str(uint8_t cp)
+{
+ switch (cp) {
+ case 0x0001:
+ return "DTCP";
+ case 0x0002:
+ return "SCMS-T";
+ default:
+ return "Reserved";
+ }
+}
+
static const char *servicecat2str(uint8_t service_cat)
{
switch (service_cat) {
@@ -236,6 +248,31 @@ static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
return true;
}

+static bool service_content_protection(struct avdtp_frame *avdtp_frame,
+ uint8_t losc)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint16_t type = 0;
+
+ if (losc < 2)
+ return false;
+
+ if (!l2cap_frame_get_le16(frame, &type))
+ return false;
+
+ losc -= 2;
+
+ print_field("%*cContent Protection Type: %s (0x%04x)", 2, ' ',
+ cptype2str(type), type);
+
+ /* TODO: decode protection specific information */
+ packet_hexdump(frame->data, losc);
+
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -281,6 +318,10 @@ static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
return false;

switch (service_cat) {
+ case AVDTP_CONTENT_PROTECTION:
+ if (!service_content_protection(avdtp_frame, losc))
+ return false;
+ break;
case AVDTP_MEDIA_CODEC:
if (!service_media_codec(avdtp_frame, losc))
return false;
@@ -288,7 +329,6 @@ static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
case AVDTP_MEDIA_TRANSPORT:
case AVDTP_REPORTING:
case AVDTP_RECOVERY:
- case AVDTP_CONTENT_PROTECTION:
case AVDTP_HEADER_COMPRESSION:
case AVDTP_MULTIPLEXING:
case AVDTP_DELAY_REPORTING:
--
2.6.2


2015-11-22 20:20:28

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 16/22] monitor/avdtp: Decode basic Media Codec capabilities

> ACL Data RX: Handle 256 flags 0x02 dlen 20
Channel: 66 len 16 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 1 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
Media Type: Audio (0x00)
Media Codec: SBC (0x00)
3f ff 02 35 ?..5
Service Category: Content Protection (0x04)
02 00 ..
---
monitor/avdtp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 3b2271e..8041d35 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -181,6 +181,24 @@ static const char *mediatype2str(uint8_t media_type)
}
}

+static const char *mediacodec2str(uint8_t codec)
+{
+ switch (codec) {
+ case 0x00:
+ return "SBC";
+ case 0x01:
+ return "MPEG-1,2 Audio";
+ case 0x02:
+ return "MPEG-2,4 AAC";
+ case 0x04:
+ return "ATRAC Family";
+ case 0xff:
+ return "Non-A2DP";
+ default:
+ return "Reserved";
+ }
+}
+
static const char *servicecat2str(uint8_t service_cat)
{
switch (service_cat) {
@@ -218,6 +236,34 @@ static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
return true;
}

+static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = 0;
+ uint8_t codec = 0;
+
+ if (losc < 2)
+ return false;
+
+ l2cap_frame_get_u8(frame, &type);
+ l2cap_frame_get_u8(frame, &codec);
+
+ losc -= 2;
+
+ print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+ mediatype2str(type >> 4), type >> 4);
+
+ print_field("%*cMedia Codec: %s (0x%02x)", 2, ' ',
+ mediacodec2str(codec), codec);
+
+ /* TODO: decode codec specific information */
+
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+
+ return true;
+}
+
static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -234,11 +280,23 @@ static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
if (frame->size < losc)
return false;

- /* TODO: decode service capabilities */
-
- packet_hexdump(frame->data, losc);
+ switch (service_cat) {
+ case AVDTP_MEDIA_CODEC:
+ if (!service_media_codec(avdtp_frame, losc))
+ return false;
+ break;
+ case AVDTP_MEDIA_TRANSPORT:
+ case AVDTP_REPORTING:
+ case AVDTP_RECOVERY:
+ case AVDTP_CONTENT_PROTECTION:
+ case AVDTP_HEADER_COMPRESSION:
+ case AVDTP_MULTIPLEXING:
+ case AVDTP_DELAY_REPORTING:
+ default:
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ }

- l2cap_frame_pull(frame, frame, losc);
}

return true;
--
2.6.2


2015-11-22 20:20:27

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 15/22] monitor/avdtp: Decode AVDTP_DELAYREPORT

---
monitor/avdtp.c | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 4867c0b..3b2271e 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -544,6 +544,35 @@ static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_delayreport(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint16_t delay;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ if (!l2cap_frame_get_be16(frame, &delay))
+ return false;
+
+ print_field("Delay: %d.%dms", delay / 10, delay % 10);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -622,6 +651,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_abort(avdtp_frame);
case AVDTP_SECURITY_CONTROL:
return avdtp_security_control(avdtp_frame);
+ case AVDTP_DELAYREPORT:
+ return avdtp_delayreport(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:23

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 11/22] monitor/avdtp: Decode AVDTP_SUSPEND

< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 258 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Suspend (0x09) Command (0x00) type 0x00 label 8 nosp 0
ACP SEID: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 6
Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Suspend (0x09) Response Accept (0x02) type 0x00 label 8 nosp 0
---
monitor/avdtp.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 6e2bb25..8051fee 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -465,6 +465,37 @@ static bool avdtp_close(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ while (l2cap_frame_get_u8(frame, &seid))
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -536,6 +567,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_start(avdtp_frame);
case AVDTP_CLOSE:
return avdtp_close(avdtp_frame);
+ case AVDTP_SUSPEND:
+ return avdtp_suspend(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:25

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 13/22] monitor/avdtp: Decode AVDTP_SECURITY_CONTROL

---
monitor/avdtp.c | 29 +++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index a69ddbe..28ddb20 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -517,6 +517,33 @@ static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ /* TODO: decode more information */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ /* TODO: decode more information */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -592,6 +619,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_suspend(avdtp_frame);
case AVDTP_ABORT:
return avdtp_abort(avdtp_frame);
+ case AVDTP_SECURITY_CONTROL:
+ return avdtp_security_control(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:26

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 14/22] monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES

< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 832 len 3 [PSM 25 mode 0] {chan 0}
AVDTP: Get All Capabilities (0x0c) Command (0x00) type 0x00 label 1 nosp 0
ACP SEID: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 20
Channel: 64 len 16 [PSM 25 mode 0] {chan 0}
AVDTP: Get All Capabilities (0x0c) Response Accept (0x02) type 0x00 label 1 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
00 00 3f ff 02 35 ..?..5
Service Category: Content Protection (0x04)
02 00 ..
---
monitor/avdtp.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 28ddb20..4867c0b 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -602,6 +602,7 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_DISCOVER:
return avdtp_discover(avdtp_frame);
case AVDTP_GET_CAPABILITIES:
+ case AVDTP_GET_ALL_CAPABILITIES:
return avdtp_get_capabilities(avdtp_frame);
case AVDTP_SET_CONFIGURATION:
return avdtp_set_configuration(avdtp_frame);
--
2.6.2


2015-11-22 20:20:24

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 12/22] monitor/avdtp: Decode AVDTP_ABORT

> ACL Data RX: Handle 256 flags 0x02 dlen 7
Channel: 66 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Abort (0x0a) Command (0x00) type 0x00 label 3 nosp 0
ACP SEID: 3
< ACL Data TX: Handle 256 flags 0x00 dlen 6
Channel: 258 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Abort (0x0a) Response Accept (0x02) type 0x00 label 3 nosp 0
---
monitor/avdtp.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 8051fee..a69ddbe 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -496,6 +496,27 @@ static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -569,6 +590,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_close(avdtp_frame);
case AVDTP_SUSPEND:
return avdtp_suspend(avdtp_frame);
+ case AVDTP_ABORT:
+ return avdtp_abort(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:21

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 09/22] monitor/avdtp: Decode AVDTP_START

< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 258 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Start (0x07) Command (0x00) type 0x00 label 7 nosp 0
ACP SEID: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 6
Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Start (0x07) Response Accept (0x02) type 0x00 label 7 nosp 0
---
monitor/avdtp.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 00b54a9..c8213fa 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -411,6 +411,37 @@ static bool avdtp_open(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_start(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ while (l2cap_frame_get_u8(frame, &seid))
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -478,6 +509,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_reconfigure(avdtp_frame);
case AVDTP_OPEN:
return avdtp_open(avdtp_frame);
+ case AVDTP_START:
+ return avdtp_start(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:22

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 10/22] monitor/avdtp: Decode AVDTP_CLOSE

< ACL Data TX: Handle 12 flags 0x02 dlen 7
Channel: 2753 len 3 [PSM 25 mode 0] {chan 1}
AVDTP: Close (0x08) Command (0x00) type 0x00 label 8 nosp 0
ACP SEID: 5
> ACL Data RX: Handle 12 flags 0x02 dlen 6
Channel: 67 len 2 [PSM 25 mode 0] {chan 1}
AVDTP: Close (0x08) Response Accept (0x02) type 0x00 label 8 nosp 0
---
monitor/avdtp.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index c8213fa..6e2bb25 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -442,6 +442,29 @@ static bool avdtp_start(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_close(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -511,6 +534,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_open(avdtp_frame);
case AVDTP_START:
return avdtp_start(avdtp_frame);
+ case AVDTP_CLOSE:
+ return avdtp_close(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:20

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 08/22] monitor/avdtp: Decode AVDTP_OPEN

< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 258 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Open (0x06) Command (0x00) type 0x00 label 6 nosp 0
ACP SEID: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 6
Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Open (0x06) Response Accept (0x02) type 0x00 label 6 nosp 0
---
monitor/avdtp.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 413d966..00b54a9 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -388,6 +388,29 @@ static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_open(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -453,6 +476,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_get_configuration(avdtp_frame);
case AVDTP_RECONFIGURE:
return avdtp_reconfigure(avdtp_frame);
+ case AVDTP_OPEN:
+ return avdtp_open(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:19

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 07/22] monitor/avdtp: Decode AVDTP_RECONFIGURE

---
monitor/avdtp.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 8377afe..413d966 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -358,6 +358,36 @@ static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint8_t service_cat;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -421,6 +451,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_set_configuration(avdtp_frame);
case AVDTP_GET_CONFIGURATION:
return avdtp_get_configuration(avdtp_frame);
+ case AVDTP_RECONFIGURE:
+ return avdtp_reconfigure(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:18

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 06/22] monitor/avdtp: Decode AVDTP_GET_CONFIGURATION

---
monitor/avdtp.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 3e71384..8377afe 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -335,6 +335,29 @@ static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -396,6 +419,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_get_capabilities(avdtp_frame);
case AVDTP_SET_CONFIGURATION:
return avdtp_set_configuration(avdtp_frame);
+ case AVDTP_GET_CONFIGURATION:
+ return avdtp_get_configuration(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:15

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 03/22] monitor/avdtp: Decode AVDTP_DISCOVER

< ACL Data TX: Handle 256 flags 0x00 dlen 6
Channel: 258 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Discover (0x01) Command (0x00) type 0x00 label 0 nosp 0
> ACL Data RX: Handle 256 flags 0x02 dlen 14
Channel: 66 len 10 [PSM 25 mode 0] {chan 2}
AVDTP: Discover (0x01) Response Accept (0x02) type 0x00 label 0 nosp 0
ACP SEID: 1
Media Type: Audio (0x00)
SEP Type: SRC (0x01)
In use: No
ACP SEID: 5
Media Type: Audio (0x00)
SEP Type: SRC (0x01)
In use: No
ACP SEID: 3
Media Type: Audio (0x00)
SEP Type: SRC (0x01)
In use: No
ACP SEID: 2
Media Type: Audio (0x00)
SEP Type: SRC (0x01)
In use: No
---
monitor/avdtp.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 113 insertions(+), 1 deletion(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 9d324bc..610bff5 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -38,6 +38,12 @@
#include "l2cap.h"
#include "avdtp.h"

+/* Message Types */
+#define AVDTP_MSG_TYPE_COMMAND 0x00
+#define AVDTP_MSG_TYPE_GENERAL_REJECT 0x01
+#define AVDTP_MSG_TYPE_RESPONSE_ACCEPT 0x02
+#define AVDTP_MSG_TYPE_RESPONSE_REJECT 0x03
+
/* Signal Identifiers */
#define AVDTP_DISCOVER 0x01
#define AVDTP_GET_CAPABILITIES 0x02
@@ -109,6 +115,108 @@ static const char *sigid2str(uint8_t sigid)
}
}

+static const char *error2str(uint8_t error)
+{
+ switch (error) {
+ case 0x01:
+ return "BAD_HEADER_FORMAT";
+ case 0x11:
+ return "BAD_LENGTH";
+ case 0x12:
+ return "BAD_ACP_SEID";
+ case 0x13:
+ return "SEP_IN_USE";
+ case 0x14:
+ return "SEP_NOT_IN_USER";
+ case 0x17:
+ return "BAD_SERV_CATEGORY";
+ case 0x18:
+ return "BAD_PAYLOAD_FORMAT";
+ case 0x19:
+ return "NOT_SUPPORTED_COMMAND";
+ case 0x1a:
+ return "INVALID_CAPABILITIES";
+ case 0x22:
+ return "BAD_RECOVERY_TYPE";
+ case 0x23:
+ return "BAD_MEDIA_TRANSPORT_FORMAT";
+ case 0x25:
+ return "BAD_RECOVERY_FORMAT";
+ case 0x26:
+ return "BAD_ROHC_FORMAT";
+ case 0x27:
+ return "BAD_CP_FORMAT";
+ case 0x28:
+ return "BAD_MULTIPLEXING_FORMAT";
+ case 0x29:
+ return "UNSUPPORTED_CONFIGURATION";
+ case 0x31:
+ return "BAD_STATE";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *mediatype2str(uint8_t media_type)
+{
+ switch (media_type) {
+ case 0x00:
+ return "Audio";
+ case 0x01:
+ return "Video";
+ case 0x02:
+ return "Multimedia";
+ default:
+ return "Reserved";
+ }
+}
+
+static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t error;
+
+ if (!l2cap_frame_get_u8(frame, &error))
+ return false;
+
+ print_field("Error code: %s (0x%02x)", error2str(error), error);
+
+ return true;
+}
+
+static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+ uint8_t info;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ while (l2cap_frame_get_u8(frame, &seid)) {
+ print_field("ACP SEID: %d", seid >> 2);
+
+ if (!l2cap_frame_get_u8(frame, &info))
+ return false;
+
+ print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
+ mediatype2str(info >> 4), info >> 4);
+ print_field("%*cSEP Type: %s (0x%02x)", 2, ' ',
+ info & 0x04 ? "SNK" : "SRC",
+ (info >> 3) & 0x01);
+ print_field("%*cIn use: %s", 2, ' ',
+ seid & 0x02 ? "Yes" : "No");
+ }
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -163,9 +271,13 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
if ((hdr & 0x03) == 0x03)
return true;

- /* TODO: decode signalling messages */
+ switch (sig_id) {
+ case AVDTP_DISCOVER:
+ return avdtp_discover(avdtp_frame);
+ }

packet_hexdump(frame->data, frame->size);
+
return true;
}

--
2.6.2


2015-11-22 20:20:16

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 04/22] monitor/avdtp: Decode AVDTP_GET_CAPABILITIES

< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 258 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Command (0x00) type 0x00 label 1 nosp 0
ACP SEID: 1
> ACL Data RX: Handle 256 flags 0x02 dlen 20
Channel: 66 len 16 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Response Accept (0x02) type 0x00 label 1 nosp 0
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
00 00 3f ff 02 35 ..?..5
Service Category: Content Protection (0x04)
02 00 ..
---
monitor/avdtp.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 610bff5..065e79a 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -59,6 +59,16 @@
#define AVDTP_GET_ALL_CAPABILITIES 0x0c
#define AVDTP_DELAYREPORT 0x0d

+/* Service Categories */
+#define AVDTP_MEDIA_TRANSPORT 0x01
+#define AVDTP_REPORTING 0x02
+#define AVDTP_RECOVERY 0x03
+#define AVDTP_CONTENT_PROTECTION 0x04
+#define AVDTP_HEADER_COMPRESSION 0x05
+#define AVDTP_MULTIPLEXING 0x06
+#define AVDTP_MEDIA_CODEC 0x07
+#define AVDTP_DELAY_REPORTING 0x08
+
struct avdtp_frame {
uint8_t hdr;
uint8_t sig_id;
@@ -171,6 +181,30 @@ static const char *mediatype2str(uint8_t media_type)
}
}

+static const char *servicecat2str(uint8_t service_cat)
+{
+ switch (service_cat) {
+ case AVDTP_MEDIA_TRANSPORT:
+ return "Media Transport";
+ case AVDTP_REPORTING:
+ return "Reporting";
+ case AVDTP_RECOVERY:
+ return "Recovery";
+ case AVDTP_CONTENT_PROTECTION:
+ return "Content Protection";
+ case AVDTP_HEADER_COMPRESSION:
+ return "Header Compression";
+ case AVDTP_MULTIPLEXING:
+ return "Multiplexing";
+ case AVDTP_MEDIA_CODEC:
+ return "Media Codec";
+ case AVDTP_DELAY_REPORTING:
+ return "Delay Reporting";
+ default:
+ return "Reserved";
+ }
+}
+
static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -184,6 +218,32 @@ static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
return true;
}

+static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t service_cat;
+ uint8_t losc;
+
+ while (l2cap_frame_get_u8(frame, &service_cat)) {
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ if (!l2cap_frame_get_u8(frame, &losc))
+ return false;
+
+ if (frame->size < losc)
+ return false;
+
+ /* TODO: decode service capabilities */
+
+ packet_hexdump(frame->data, losc);
+
+ l2cap_frame_pull(frame, frame, losc);
+ }
+
+ return true;
+}
+
static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -217,6 +277,29 @@ static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t seid;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -274,6 +357,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
switch (sig_id) {
case AVDTP_DISCOVER:
return avdtp_discover(avdtp_frame);
+ case AVDTP_GET_CAPABILITIES:
+ return avdtp_get_capabilities(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:17

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 05/22] monitor/avdtp: Decode AVDTP_SET_CONFIGURATION

< ACL Data TX: Handle 256 flags 0x00 dlen 18
Channel: 258 len 14 [PSM 25 mode 0] {chan 2}
AVDTP: Set Configuration (0x03) Command (0x00) type 0x00 label 5 nosp 0
ACP SEID: 1
INT SEID: 3
Service Category: Media Transport (0x01)
Service Category: Media Codec (0x07)
00 00 21 15 02 35 ..!..5
> ACL Data RX: Handle 256 flags 0x02 dlen 6
Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Set Configuration (0x03) Response Accept (0x02) type 0x00 label 5 nosp 0
---
monitor/avdtp.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 065e79a..3e71384 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -300,6 +300,41 @@ static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
return false;
}

+static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t type = avdtp_frame->hdr & 0x03;
+ uint8_t acp_seid, int_seid;
+ uint8_t service_cat;
+
+ switch (type) {
+ case AVDTP_MSG_TYPE_COMMAND:
+ if (!l2cap_frame_get_u8(frame, &acp_seid))
+ return false;
+
+ print_field("ACP SEID: %d", acp_seid >> 2);
+
+ if (!l2cap_frame_get_u8(frame, &int_seid))
+ return false;
+
+ print_field("INT SEID: %d", int_seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+ case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
+ return true;
+ case AVDTP_MSG_TYPE_RESPONSE_REJECT:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s (0x%02x)",
+ servicecat2str(service_cat), service_cat);
+
+ return avdtp_reject_common(avdtp_frame);
+ }
+
+ return false;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -359,6 +394,8 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
return avdtp_discover(avdtp_frame);
case AVDTP_GET_CAPABILITIES:
return avdtp_get_capabilities(avdtp_frame);
+ case AVDTP_SET_CONFIGURATION:
+ return avdtp_set_configuration(avdtp_frame);
}

packet_hexdump(frame->data, frame->size);
--
2.6.2


2015-11-22 20:20:14

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 02/22] monitor/avdtp: Add basic decoding of AVDTP signalling

< ACL Data TX: Handle 256 flags 0x00 dlen 6
Channel: 258 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Discover (0x01) Command (0x00) type 0x00 label 0 nosp 0
> ACL Data RX: Handle 256 flags 0x02 dlen 14
Channel: 66 len 10 [PSM 25 mode 0] {chan 2}
AVDTP: Discover (0x01) Response Accept (0x02) type 0x00 label 0 nosp 0
04 08 14 08 0c 08 08 08 ........
---
Makefile.tools | 1 +
android/Android.mk | 1 +
monitor/avdtp.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/avdtp.h | 24 +++++++
monitor/l2cap.c | 4 ++
5 files changed, 222 insertions(+)
create mode 100644 monitor/avdtp.c
create mode 100644 monitor/avdtp.h

diff --git a/Makefile.tools b/Makefile.tools
index 6ebbe9f..8555a6b 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -27,6 +27,7 @@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
monitor/l2cap.h monitor/l2cap.c \
monitor/sdp.h monitor/sdp.c \
monitor/avctp.h monitor/avctp.c \
+ monitor/avdtp.h monitor/avdtp.c \
monitor/rfcomm.h monitor/rfcomm.c \
monitor/bnep.h monitor/bnep.c \
monitor/uuid.h monitor/uuid.c \
diff --git a/android/Android.mk b/android/Android.mk
index 694a94e..fa1188b 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -339,6 +339,7 @@ LOCAL_SRC_FILES := \
bluez/monitor/packet.c \
bluez/monitor/l2cap.c \
bluez/monitor/avctp.c \
+ bluez/monitor/avdtp.c \
bluez/monitor/rfcomm.c \
bluez/monitor/bnep.c \
bluez/monitor/uuid.c \
diff --git a/monitor/avdtp.c b/monitor/avdtp.c
new file mode 100644
index 0000000..9d324bc
--- /dev/null
+++ b/monitor/avdtp.c
@@ -0,0 +1,192 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <[email protected]>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "lib/bluetooth.h"
+
+#include "src/shared/util.h"
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "avdtp.h"
+
+/* Signal Identifiers */
+#define AVDTP_DISCOVER 0x01
+#define AVDTP_GET_CAPABILITIES 0x02
+#define AVDTP_SET_CONFIGURATION 0x03
+#define AVDTP_GET_CONFIGURATION 0x04
+#define AVDTP_RECONFIGURE 0x05
+#define AVDTP_OPEN 0x06
+#define AVDTP_START 0x07
+#define AVDTP_CLOSE 0x08
+#define AVDTP_SUSPEND 0x09
+#define AVDTP_ABORT 0x0a
+#define AVDTP_SECURITY_CONTROL 0x0b
+#define AVDTP_GET_ALL_CAPABILITIES 0x0c
+#define AVDTP_DELAYREPORT 0x0d
+
+struct avdtp_frame {
+ uint8_t hdr;
+ uint8_t sig_id;
+ struct l2cap_frame l2cap_frame;
+};
+
+static const char *msgtype2str(uint8_t msgtype)
+{
+ switch (msgtype) {
+ case 0:
+ return "Command";
+ case 1:
+ return "General Reject";
+ case 2:
+ return "Response Accept";
+ case 3:
+ return "Response Reject";
+ }
+
+ return "";
+}
+
+static const char *sigid2str(uint8_t sigid)
+{
+ switch (sigid) {
+ case AVDTP_DISCOVER:
+ return "Discover";
+ case AVDTP_GET_CAPABILITIES:
+ return "Get Capabilities";
+ case AVDTP_SET_CONFIGURATION:
+ return "Set Configuration";
+ case AVDTP_GET_CONFIGURATION:
+ return "Get Configuration";
+ case AVDTP_RECONFIGURE:
+ return "Reconfigure";
+ case AVDTP_OPEN:
+ return "Open";
+ case AVDTP_START:
+ return "Start";
+ case AVDTP_CLOSE:
+ return "Close";
+ case AVDTP_SUSPEND:
+ return "Suspend";
+ case AVDTP_ABORT:
+ return "Abort";
+ case AVDTP_SECURITY_CONTROL:
+ return "Security Control";
+ case AVDTP_GET_ALL_CAPABILITIES:
+ return "Get All Capabilities";
+ case AVDTP_DELAYREPORT:
+ return "Delay Report";
+ default:
+ return "Reserved";
+ }
+}
+
+static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ const char *pdu_color;
+ uint8_t hdr;
+ uint8_t sig_id;
+ uint8_t nosp = 0;
+
+ if (frame->in)
+ pdu_color = COLOR_MAGENTA;
+ else
+ pdu_color = COLOR_BLUE;
+
+ if (!l2cap_frame_get_u8(frame, &hdr))
+ return false;
+
+ avdtp_frame->hdr = hdr;
+
+ /* Continue Packet || End Packet */
+ if (((hdr & 0x0c) == 0x08) || ((hdr & 0x0c) == 0x0c)) {
+ /* TODO: handle fragmentation */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ }
+
+ /* Start Packet */
+ if ((hdr & 0x0c) == 0x04) {
+ if (!l2cap_frame_get_u8(frame, &nosp))
+ return false;
+ }
+
+ if (!l2cap_frame_get_u8(frame, &sig_id))
+ return false;
+
+ sig_id &= 0x3f;
+
+ avdtp_frame->sig_id = sig_id;
+
+ print_indent(6, pdu_color, "AVDTP: ", sigid2str(sig_id), COLOR_OFF,
+ " (0x%02x) %s (0x%02x) type 0x%02x label %d nosp %d",
+ sig_id, msgtype2str(hdr & 0x03), hdr & 0x03,
+ hdr & 0x0c, hdr >> 4, nosp);
+
+ /* Start Packet */
+ if ((hdr & 0x0c) == 0x04) {
+ /* TODO: handle fragmentation */
+ packet_hexdump(frame->data, frame->size);
+ return true;
+ }
+
+ /* General Reject */
+ if ((hdr & 0x03) == 0x03)
+ return true;
+
+ /* TODO: decode signalling messages */
+
+ packet_hexdump(frame->data, frame->size);
+ return true;
+}
+
+void avdtp_packet(const struct l2cap_frame *frame)
+{
+ struct avdtp_frame avdtp_frame;
+ bool ret;
+
+ l2cap_frame_pull(&avdtp_frame.l2cap_frame, frame, 0);
+
+ switch (frame->seq_num) {
+ case 1:
+ ret = avdtp_signalling_packet(&avdtp_frame);
+ break;
+ default:
+ packet_hexdump(frame->data, frame->size);
+ return;
+ }
+
+ if (!ret) {
+ print_text(COLOR_ERROR, "PDU malformed");
+ packet_hexdump(frame->data, frame->size);
+ }
+}
diff --git a/monitor/avdtp.h b/monitor/avdtp.h
new file mode 100644
index 0000000..f77d82e
--- /dev/null
+++ b/monitor/avdtp.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2015 Andrzej Kaczmarek <[email protected]>
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void avdtp_packet(const struct l2cap_frame *frame);
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 79f7051..93a1b20 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -42,6 +42,7 @@
#include "keys.h"
#include "sdp.h"
#include "avctp.h"
+#include "avdtp.h"
#include "rfcomm.h"
#include "bnep.h"

@@ -3099,6 +3100,9 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
case 0x001B:
avctp_packet(&frame);
break;
+ case 0x0019:
+ avdtp_packet(&frame);
+ break;
default:
packet_hexdump(data, size);
break;
--
2.6.2


2015-11-22 20:20:13

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH v3 01/22] monitor/l2cap: Add channel sequence number

This patch adds sequence number to channels structure which determines
order in which channels for the same PSM were created. It will be used
for protocols like AVDTP where there is single PSM used for multiple
channels and order it which they were created is important.
---
monitor/l2cap.c | 53 ++++++++++++++++++++++++++++++++++++-----------------
monitor/l2cap.h | 1 +
2 files changed, 37 insertions(+), 17 deletions(-)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 894c741..79f7051 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -99,6 +99,7 @@ struct chan_data {
uint8_t ctrlid;
uint8_t mode;
uint8_t ext_ctrl;
+ uint8_t seq_num;
};

static struct chan_data chan_list[MAX_CHAN];
@@ -107,10 +108,13 @@ static void assign_scid(const struct l2cap_frame *frame,
uint16_t scid, uint16_t psm, uint8_t ctrlid)
{
int i, n = -1;
+ uint8_t seq_num = 1;

for (i = 0; i < MAX_CHAN; i++) {
- if (n < 0 && chan_list[i].handle == 0x0000)
+ if (n < 0 && chan_list[i].handle == 0x0000) {
n = i;
+ continue;
+ }

if (chan_list[i].index != frame->index)
continue;
@@ -118,16 +122,18 @@ static void assign_scid(const struct l2cap_frame *frame,
if (chan_list[i].handle != frame->handle)
continue;

+ if (chan_list[i].psm == psm)
+ seq_num++;
+
+ /* Don't break on match - we still need to go through all
+ * channels to find proper seq_num.
+ */
if (frame->in) {
- if (chan_list[i].dcid == scid) {
+ if (chan_list[i].dcid == scid)
n = i;
- break;
- }
} else {
- if (chan_list[i].scid == scid) {
+ if (chan_list[i].scid == scid)
n = i;
- break;
- }
}
}

@@ -147,6 +153,8 @@ static void assign_scid(const struct l2cap_frame *frame,
chan_list[n].psm = psm;
chan_list[n].ctrlid = ctrlid;
chan_list[n].mode = 0;
+
+ chan_list[n].seq_num = seq_num;
}

static void release_scid(const struct l2cap_frame *frame, uint16_t scid)
@@ -301,6 +309,16 @@ static uint16_t get_chan(const struct l2cap_frame *frame)
return i;
}

+static uint8_t get_seq_num(const struct l2cap_frame *frame)
+{
+ int i = get_chan_data_index(frame);
+
+ if (i < 0)
+ return 0;
+
+ return chan_list[i].seq_num;
+}
+
static void assign_ext_ctrl(const struct l2cap_frame *frame,
uint8_t ext_ctrl, uint16_t dcid)
{
@@ -1384,16 +1402,17 @@ static void l2cap_frame_init(struct l2cap_frame *frame, uint16_t index, bool in,
uint16_t handle, uint8_t ident,
uint16_t cid, const void *data, uint16_t size)
{
- frame->index = index;
- frame->in = in;
- frame->handle = handle;
- frame->ident = ident;
- frame->cid = cid;
- frame->data = data;
- frame->size = size;
- frame->psm = get_psm(frame);
- frame->mode = get_mode(frame);
- frame->chan = get_chan(frame);
+ frame->index = index;
+ frame->in = in;
+ frame->handle = handle;
+ frame->ident = ident;
+ frame->cid = cid;
+ frame->data = data;
+ frame->size = size;
+ frame->psm = get_psm(frame);
+ frame->mode = get_mode(frame);
+ frame->chan = get_chan(frame);
+ frame->seq_num = get_seq_num(frame);
}

static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,
diff --git a/monitor/l2cap.h b/monitor/l2cap.h
index 0364454..813c793 100644
--- a/monitor/l2cap.h
+++ b/monitor/l2cap.h
@@ -34,6 +34,7 @@ struct l2cap_frame {
uint16_t psm;
uint16_t chan;
uint8_t mode;
+ uint8_t seq_num;
const void *data;
uint16_t size;
};
--
2.6.2


2015-12-01 09:32:44

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v3 00/22] Add AVDTP/A2DP decoding to btmon

Hi Andrzej,

On Sun, Nov 22, 2015 at 10:20 PM, Andrzej Kaczmarek
<[email protected]> wrote:
> Hi,
>
> Here's series of patches which adds decoding of AVDTP signalling channel
> and A2DP codec capabilities information. Few things are missing:
> - no fragmentation support
> - some rarely used capabilities are not decoded
> - ATRAC capabilities are not decoded
>
> Other that above, pretty much everything should be decoded.
>
> Changes in v2:
> - fixed formatting according to comments
> - updated commit messages to include decoded frames (except for few of
> them where I was not able trigger proper signalling)
> - some minor issues fixed found during development
>
> Changes in v3:
> - fixed comments from Szymon (few more raised offline)
> - more minor issues fixed
>
>
> Andrzej Kaczmarek (22):
> monitor/l2cap: Add channel sequence number
> monitor/avdtp: Add basic decoding of AVDTP signalling
> monitor/avdtp: Decode AVDTP_DISCOVER
> monitor/avdtp: Decode AVDTP_GET_CAPABILITIES
> monitor/avdtp: Decode AVDTP_SET_CONFIGURATION
> monitor/avdtp: Decode AVDTP_GET_CONFIGURATION
> monitor/avdtp: Decode AVDTP_RECONFIGURE
> monitor/avdtp: Decode AVDTP_OPEN
> monitor/avdtp: Decode AVDTP_START
> monitor/avdtp: Decode AVDTP_CLOSE
> monitor/avdtp: Decode AVDTP_SUSPEND
> monitor/avdtp: Decode AVDTP_ABORT
> monitor/avdtp: Decode AVDTP_SECURITY_CONTROL
> monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES
> monitor/avdtp: Decode AVDTP_DELAYREPORT
> monitor/avdtp: Decode basic Media Codec capabilities
> monitor/avdtp: Decode basic Content Protection capabilities
> monitor/a2dp: Decode SBC capabilities
> monitor/a2dp: Decode MPEG-1,2 capabilities
> monitor/a2dp: Decode AAC capabilities
> monitor/a2dp: Decode aptX capabilities
> monitor/a2dp: Decode LDAC capabilities
>
> Makefile.tools | 2 +
> android/Android.mk | 2 +
> monitor/a2dp.c | 638 +++++++++++++++++++++++++++++++++++++++++++
> monitor/a2dp.h | 26 ++
> monitor/avdtp.c | 787 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> monitor/avdtp.h | 24 ++
> monitor/l2cap.c | 57 ++--
> monitor/l2cap.h | 1 +
> 8 files changed, 1520 insertions(+), 17 deletions(-)
> create mode 100644 monitor/a2dp.c
> create mode 100644 monitor/a2dp.h
> create mode 100644 monitor/avdtp.c
> create mode 100644 monitor/avdtp.h
>
> --
> 2.6.2

Applied, thanks.


--
Luiz Augusto von Dentz