2015-11-14 13:44:17

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 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.

And some sample output from decoder:

< ACL Data TX: Handle 256 flags 0x00 dlen 6
Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
ACP SEID 1
Media Type: Audio
SEP Type: SRC
In use: No
ACP SEID 5
Media Type: Audio
SEP Type: SRC
In use: No
ACP SEID 3
Media Type: Audio
SEP Type: SRC
In use: No
ACP SEID 2
Media Type: Audio
SEP Type: SRC
In use: No


< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
ACP SEID: 3
> ACL Data RX: Handle 256 flags 0x02 dlen 23
Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
Service Category: Media Transport
Service Category: Media Codec
Media Type: Audio
Media Codec: Non-A2DP
Vendor ID: 0x0000004f (APT Licensing Ltd.)
Vendor Specific Codec ID: 0x0001 (aptX)
Frequency: 0x30
44100
48000
Channel Mode: 0x02
Stereo
Service Category: Content Protection
Content Protection Type: SCMS-T


< ACL Data TX: Handle 256 flags 0x00 dlen 18
Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
ACP SEID: 1
INT SEID: 1
Service Category: Media Transport
Service Category: Media Codec
Media Type: Audio
Media Codec: SBC
Frequency: 0x20
44100
Channel Mode: 0x01
Joint Channel
Block Length: 0x10
16
Subbands: 0x04
8
Allocation Method: 0x01
Loudness
Minimum Bitpool: 2
Maximum Bitpool: 53
> 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: type 0x00 label 11 nosp 0

> ACL Data RX: Handle 256 flags 0x02 dlen 6
Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0


< ACL Data TX: Handle 256 flags 0x00 dlen 7
Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0



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 | 420 +++++++++++++++++++++++++++
monitor/a2dp.h | 24 ++
monitor/avdtp.c | 819 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/avdtp.h | 24 ++
monitor/l2cap.c | 48 +++-
monitor/l2cap.h | 1 +
8 files changed, 1327 insertions(+), 13 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-17 21:22:07

by Andrzej Kaczmarek

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

Hi Luiz,

On Tue, Nov 17, 2015 at 3:06 PM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Andrzej,
>
> On Tue, Nov 17, 2015 at 11:11 AM, Andrzej Kaczmarek
> <[email protected]> wrote:
>> Hi Marcel,
>>
>> On Tue, Nov 17, 2015 at 9:40 AM, Marcel Holtmann <[email protected]> wrote:
>>> Hi Luiz,
>>>
>>>>> 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.
>>>>>
>>>>> And some sample output from decoder:
>>>>>
>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 6
>>>>> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
>>>>> ACP SEID 1
>>>>> Media Type: Audio
>>>>> SEP Type: SRC
>>>>> In use: No
>>>>> ACP SEID 5
>>>>> Media Type: Audio
>>>>> SEP Type: SRC
>>>>> In use: No
>>>>> ACP SEID 3
>>>>> Media Type: Audio
>>>>> SEP Type: SRC
>>>>> In use: No
>>>>> ACP SEID 2
>>>>> Media Type: Audio
>>>>> SEP Type: SRC
>>>>> In use: No
>>>>
>>>> I guess we can add it In use flag only when set.
>>>
>>> actually btmon is suppose to decode and not be smart about when to show things. So lets really do print all parameters and not leave them out because they are unset.
>>>
>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
>>>>> ACP SEID: 3
>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 23
>>>>> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
>>>>> Service Category: Media Transport
>>>>> Service Category: Media Codec
>>>>> Media Type: Audio
>>>>> Media Codec: Non-A2DP
>>>>> Vendor ID: 0x0000004f (APT Licensing Ltd.)
>>>>> Vendor Specific Codec ID: 0x0001 (aptX)
>>>>> Frequency: 0x30
>>>>> 44100
>>>>> 48000
>>>>> Channel Mode: 0x02
>>>>> Stereo
>>>>> Service Category: Content Protection
>>>>> Content Protection Type: SCMS-T
>>>>>
>>>>>
>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 18
>>>>> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
>>>>> ACP SEID: 1
>>>>> INT SEID: 1
>>>>> Service Category: Media Transport
>>>>> Service Category: Media Codec
>>>>> Media Type: Audio
>>>>> Media Codec: SBC
>>>>> Frequency: 0x20
>>>>> 44100
>>>>> Channel Mode: 0x01
>>>>> Joint Channel
>>>>> Block Length: 0x10
>>>>> 16
>>>>> Subbands: 0x04
>>>>> 8
>>>>> Allocation Method: 0x01
>>>>> Loudness
>>>>> Minimum Bitpool: 2
>>>>> Maximum Bitpool: 53
>>>>
>>>> Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
>>>> overall Id make this more compact instead of having another line for
>>>> the decoded value just input in the same line with the hex value in
>>>> parenthesis.
>>>
>>> Actually the problem is not the bit pool. It is the others. It should be like this:
>>>
>>> Frequency: 44100 (0x20(
>>> Block length: 16 (0x10)
>>> Allocation method: Loudness (0x01)
>>>
>>> And please follow the styles I have introduced in the HCI portion and not make up new stuff. I actually want the strings to primary and also show the raw values.
>>
>> Ok, I'll fix it.
>>
>>>
>>>>
>>>>>> 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: type 0x00 label 11 nosp 0
>>>>>
>>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 6
>>>>> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>>>>>
>>>>>
>>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>>>> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0
>>>>
>>>> Would you be able to include the output above into the patch that
>>>> introduce it? I think it is a bit better to see the formatting each
>>>> patch is introducing and then have proper comments to them.
>>>
>>> Why are we falling back into trying to cramp all stuff into a single line. btmon is verbose on purpose. Deal with i.
>>
>> You mean the" AVDTP: Start ..." line? I wasn't sure which protocol to
>> follow here so "AVDTP: Start" is what you have in HCI and L2CAP
>> (protocol + command), then "Response Accept" is what AVRCP does. And
>> the other parameters from frame header are used the same in all
>> protocols actually. For decoding of AVDTP Transport headers I planned
>> to make it "AVDTP Media: <codec>".
>>
>> Any other idea how this should look like?
>
> I assumed it is a common practice to decode the headers in a single line:
>
> L2CAP: Configure Response (0x05) ident 14 len 6
> SDP: Service Search Attribute Request (0x06) tid 0 len 25
> AVCTP Control: Response: type 0x00 label 7 PID 0x110e
>
> But the format is not very strict, at least not up to now, so perhaps
> we should always follow decode string (raw hex) when decoding fields
> that means AVCTP line about should be:
>
> AVCTP Control: Response (code) type 0x00 label 7 PID 0x110e
>
> I guess for the media it would be fine to have AVDTP Media as the
> header but I wonder how you will be able to detect the codec? Or are
> you planning to decode the RTP headers?

I plan to add simple tracking for streams by storing (some)
information from AVDTP_SET_CONFIGURATION - this way I can identify
contents of transport channel and try to decode relevant headers. I
don't want to just decode RTP since IIRC aptX does not use RTP header
so this would not work properly.

> Btw, we could perhaps have an option to discard audio packets or make
> them 0 length if we want to keep the timestamps, or maybe have this by
> default since it makes the traces much smaller and reconstructing the
> audio stream is something btmon will probably never do although it
> seems wireshark has support to do it Ive never seen it working.

I guess for now we can add option similar to -S (dump SCO traffic),
i.e. do not dump media data by default and enable on request. Perhaps
-M (--media)?

BR,
Andrzej

2015-11-17 14:06:10

by Luiz Augusto von Dentz

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

Hi Andrzej,

On Tue, Nov 17, 2015 at 11:11 AM, Andrzej Kaczmarek
<[email protected]> wrote:
> Hi Marcel,
>
> On Tue, Nov 17, 2015 at 9:40 AM, Marcel Holtmann <[email protected]> wrote:
>> Hi Luiz,
>>
>>>> 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.
>>>>
>>>> And some sample output from decoder:
>>>>
>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 6
>>>> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
>>>> ACP SEID 1
>>>> Media Type: Audio
>>>> SEP Type: SRC
>>>> In use: No
>>>> ACP SEID 5
>>>> Media Type: Audio
>>>> SEP Type: SRC
>>>> In use: No
>>>> ACP SEID 3
>>>> Media Type: Audio
>>>> SEP Type: SRC
>>>> In use: No
>>>> ACP SEID 2
>>>> Media Type: Audio
>>>> SEP Type: SRC
>>>> In use: No
>>>
>>> I guess we can add it In use flag only when set.
>>
>> actually btmon is suppose to decode and not be smart about when to show things. So lets really do print all parameters and not leave them out because they are unset.
>>
>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
>>>> ACP SEID: 3
>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 23
>>>> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
>>>> Service Category: Media Transport
>>>> Service Category: Media Codec
>>>> Media Type: Audio
>>>> Media Codec: Non-A2DP
>>>> Vendor ID: 0x0000004f (APT Licensing Ltd.)
>>>> Vendor Specific Codec ID: 0x0001 (aptX)
>>>> Frequency: 0x30
>>>> 44100
>>>> 48000
>>>> Channel Mode: 0x02
>>>> Stereo
>>>> Service Category: Content Protection
>>>> Content Protection Type: SCMS-T
>>>>
>>>>
>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 18
>>>> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
>>>> ACP SEID: 1
>>>> INT SEID: 1
>>>> Service Category: Media Transport
>>>> Service Category: Media Codec
>>>> Media Type: Audio
>>>> Media Codec: SBC
>>>> Frequency: 0x20
>>>> 44100
>>>> Channel Mode: 0x01
>>>> Joint Channel
>>>> Block Length: 0x10
>>>> 16
>>>> Subbands: 0x04
>>>> 8
>>>> Allocation Method: 0x01
>>>> Loudness
>>>> Minimum Bitpool: 2
>>>> Maximum Bitpool: 53
>>>
>>> Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
>>> overall Id make this more compact instead of having another line for
>>> the decoded value just input in the same line with the hex value in
>>> parenthesis.
>>
>> Actually the problem is not the bit pool. It is the others. It should be like this:
>>
>> Frequency: 44100 (0x20(
>> Block length: 16 (0x10)
>> Allocation method: Loudness (0x01)
>>
>> And please follow the styles I have introduced in the HCI portion and not make up new stuff. I actually want the strings to primary and also show the raw values.
>
> Ok, I'll fix it.
>
>>
>>>
>>>>> 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: type 0x00 label 11 nosp 0
>>>>
>>>>> ACL Data RX: Handle 256 flags 0x02 dlen 6
>>>> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>>>>
>>>>
>>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>>> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0
>>>
>>> Would you be able to include the output above into the patch that
>>> introduce it? I think it is a bit better to see the formatting each
>>> patch is introducing and then have proper comments to them.
>>
>> Why are we falling back into trying to cramp all stuff into a single line. btmon is verbose on purpose. Deal with i.
>
> You mean the" AVDTP: Start ..." line? I wasn't sure which protocol to
> follow here so "AVDTP: Start" is what you have in HCI and L2CAP
> (protocol + command), then "Response Accept" is what AVRCP does. And
> the other parameters from frame header are used the same in all
> protocols actually. For decoding of AVDTP Transport headers I planned
> to make it "AVDTP Media: <codec>".
>
> Any other idea how this should look like?

I assumed it is a common practice to decode the headers in a single line:

L2CAP: Configure Response (0x05) ident 14 len 6
SDP: Service Search Attribute Request (0x06) tid 0 len 25
AVCTP Control: Response: type 0x00 label 7 PID 0x110e

But the format is not very strict, at least not up to now, so perhaps
we should always follow decode string (raw hex) when decoding fields
that means AVCTP line about should be:

AVCTP Control: Response (code) type 0x00 label 7 PID 0x110e

I guess for the media it would be fine to have AVDTP Media as the
header but I wonder how you will be able to detect the codec? Or are
you planning to decode the RTP headers?

Btw, we could perhaps have an option to discard audio packets or make
them 0 length if we want to keep the timestamps, or maybe have this by
default since it makes the traces much smaller and reconstructing the
audio stream is something btmon will probably never do although it
seems wireshark has support to do it Ive never seen it working.

--
Luiz Augusto von Dentz

2015-11-17 09:11:58

by Andrzej Kaczmarek

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

Hi Marcel,

On Tue, Nov 17, 2015 at 9:40 AM, Marcel Holtmann <[email protected]> wrote:
> Hi Luiz,
>
>>> 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.
>>>
>>> And some sample output from decoder:
>>>
>>> < ACL Data TX: Handle 256 flags 0x00 dlen 6
>>> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
>>> ACP SEID 1
>>> Media Type: Audio
>>> SEP Type: SRC
>>> In use: No
>>> ACP SEID 5
>>> Media Type: Audio
>>> SEP Type: SRC
>>> In use: No
>>> ACP SEID 3
>>> Media Type: Audio
>>> SEP Type: SRC
>>> In use: No
>>> ACP SEID 2
>>> Media Type: Audio
>>> SEP Type: SRC
>>> In use: No
>>
>> I guess we can add it In use flag only when set.
>
> actually btmon is suppose to decode and not be smart about when to show things. So lets really do print all parameters and not leave them out because they are unset.
>
>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
>>> ACP SEID: 3
>>>> ACL Data RX: Handle 256 flags 0x02 dlen 23
>>> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
>>> Service Category: Media Transport
>>> Service Category: Media Codec
>>> Media Type: Audio
>>> Media Codec: Non-A2DP
>>> Vendor ID: 0x0000004f (APT Licensing Ltd.)
>>> Vendor Specific Codec ID: 0x0001 (aptX)
>>> Frequency: 0x30
>>> 44100
>>> 48000
>>> Channel Mode: 0x02
>>> Stereo
>>> Service Category: Content Protection
>>> Content Protection Type: SCMS-T
>>>
>>>
>>> < ACL Data TX: Handle 256 flags 0x00 dlen 18
>>> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
>>> ACP SEID: 1
>>> INT SEID: 1
>>> Service Category: Media Transport
>>> Service Category: Media Codec
>>> Media Type: Audio
>>> Media Codec: SBC
>>> Frequency: 0x20
>>> 44100
>>> Channel Mode: 0x01
>>> Joint Channel
>>> Block Length: 0x10
>>> 16
>>> Subbands: 0x04
>>> 8
>>> Allocation Method: 0x01
>>> Loudness
>>> Minimum Bitpool: 2
>>> Maximum Bitpool: 53
>>
>> Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
>> overall Id make this more compact instead of having another line for
>> the decoded value just input in the same line with the hex value in
>> parenthesis.
>
> Actually the problem is not the bit pool. It is the others. It should be like this:
>
> Frequency: 44100 (0x20(
> Block length: 16 (0x10)
> Allocation method: Loudness (0x01)
>
> And please follow the styles I have introduced in the HCI portion and not make up new stuff. I actually want the strings to primary and also show the raw values.

Ok, I'll fix it.

>
>>
>>>> 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: type 0x00 label 11 nosp 0
>>>
>>>> ACL Data RX: Handle 256 flags 0x02 dlen 6
>>> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>>>
>>>
>>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>>> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0
>>
>> Would you be able to include the output above into the patch that
>> introduce it? I think it is a bit better to see the formatting each
>> patch is introducing and then have proper comments to them.
>
> Why are we falling back into trying to cramp all stuff into a single line. btmon is verbose on purpose. Deal with i.

You mean the" AVDTP: Start ..." line? I wasn't sure which protocol to
follow here so "AVDTP: Start" is what you have in HCI and L2CAP
(protocol + command), then "Response Accept" is what AVRCP does. And
the other parameters from frame header are used the same in all
protocols actually. For decoding of AVDTP Transport headers I planned
to make it "AVDTP Media: <codec>".

Any other idea how this should look like?

BR,
Andrzej

2015-11-17 09:06:37

by Andrzej Kaczmarek

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

Hi Luiz,

On Tue, Nov 17, 2015 at 9:33 AM, Luiz Augusto von Dentz
<[email protected]> wrote:
> Hi Andrzej,
>
> On Sat, Nov 14, 2015 at 3:44 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.
>>
>> And some sample output from decoder:
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 6
>> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
>> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
>> ACP SEID 1
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 5
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 3
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 2
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>
> I guess we can add it In use flag only when set.
>
>>
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
>> ACP SEID: 3
>>> ACL Data RX: Handle 256 flags 0x02 dlen 23
>> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
>> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
>> Service Category: Media Transport
>> Service Category: Media Codec
>> Media Type: Audio
>> Media Codec: Non-A2DP
>> Vendor ID: 0x0000004f (APT Licensing Ltd.)
>> Vendor Specific Codec ID: 0x0001 (aptX)
>> Frequency: 0x30
>> 44100
>> 48000
>> Channel Mode: 0x02
>> Stereo
>> Service Category: Content Protection
>> Content Protection Type: SCMS-T
>>
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 18
>> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
>> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
>> ACP SEID: 1
>> INT SEID: 1
>> Service Category: Media Transport
>> Service Category: Media Codec
>> Media Type: Audio
>> Media Codec: SBC
>> Frequency: 0x20
>> 44100
>> Channel Mode: 0x01
>> Joint Channel
>> Block Length: 0x10
>> 16
>> Subbands: 0x04
>> 8
>> Allocation Method: 0x01
>> Loudness
>> Minimum Bitpool: 2
>> Maximum Bitpool: 53
>
> Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
> overall Id make this more compact instead of having another line for
> the decoded value just input in the same line with the hex value in
> parenthesis.
>
>>> 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: type 0x00 label 11 nosp 0
>>
>>> ACL Data RX: Handle 256 flags 0x02 dlen 6
>> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
>> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>>
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0
>
> Would you be able to include the output above into the patch that
> introduce it? I think it is a bit better to see the formatting each
> patch is introducing and then have proper comments to them.

Sure, I'll do this in v2.

For the other comments I'll go with Marcel''s suggestions.

BR,
Andrzej

2015-11-17 08:40:25

by Marcel Holtmann

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

Hi Luiz,

>> 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.
>>
>> And some sample output from decoder:
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 6
>> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
>> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
>> ACP SEID 1
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 5
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 3
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>> ACP SEID 2
>> Media Type: Audio
>> SEP Type: SRC
>> In use: No
>
> I guess we can add it In use flag only when set.

actually btmon is suppose to decode and not be smart about when to show things. So lets really do print all parameters and not leave them out because they are unset.

>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
>> ACP SEID: 3
>>> ACL Data RX: Handle 256 flags 0x02 dlen 23
>> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
>> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
>> Service Category: Media Transport
>> Service Category: Media Codec
>> Media Type: Audio
>> Media Codec: Non-A2DP
>> Vendor ID: 0x0000004f (APT Licensing Ltd.)
>> Vendor Specific Codec ID: 0x0001 (aptX)
>> Frequency: 0x30
>> 44100
>> 48000
>> Channel Mode: 0x02
>> Stereo
>> Service Category: Content Protection
>> Content Protection Type: SCMS-T
>>
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 18
>> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
>> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
>> ACP SEID: 1
>> INT SEID: 1
>> Service Category: Media Transport
>> Service Category: Media Codec
>> Media Type: Audio
>> Media Codec: SBC
>> Frequency: 0x20
>> 44100
>> Channel Mode: 0x01
>> Joint Channel
>> Block Length: 0x10
>> 16
>> Subbands: 0x04
>> 8
>> Allocation Method: 0x01
>> Loudness
>> Minimum Bitpool: 2
>> Maximum Bitpool: 53
>
> Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
> overall Id make this more compact instead of having another line for
> the decoded value just input in the same line with the hex value in
> parenthesis.

Actually the problem is not the bit pool. It is the others. It should be like this:

Frequency: 44100 (0x20(
Block length: 16 (0x10)
Allocation method: Loudness (0x01)

And please follow the styles I have introduced in the HCI portion and not make up new stuff. I actually want the strings to primary and also show the raw values.

>
>>> 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: type 0x00 label 11 nosp 0
>>
>>> ACL Data RX: Handle 256 flags 0x02 dlen 6
>> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
>> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>>
>>
>> < ACL Data TX: Handle 256 flags 0x00 dlen 7
>> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
>> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0
>
> Would you be able to include the output above into the patch that
> introduce it? I think it is a bit better to see the formatting each
> patch is introducing and then have proper comments to them.

Why are we falling back into trying to cramp all stuff into a single line. btmon is verbose on purpose. Deal with i.

Regards

Marcel


2015-11-17 08:33:01

by Luiz Augusto von Dentz

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

Hi Andrzej,

On Sat, Nov 14, 2015 at 3:44 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.
>
> And some sample output from decoder:
>
> < ACL Data TX: Handle 256 flags 0x00 dlen 6
> Channel: 1602 len 2 [PSM 25 mode 0] {chan 2}
> AVDTP: Discover (0x01) Command: type 0x00 label 6 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: type 0x00 label 6 nosp 0
> ACP SEID 1
> Media Type: Audio
> SEP Type: SRC
> In use: No
> ACP SEID 5
> Media Type: Audio
> SEP Type: SRC
> In use: No
> ACP SEID 3
> Media Type: Audio
> SEP Type: SRC
> In use: No
> ACP SEID 2
> Media Type: Audio
> SEP Type: SRC
> In use: No

I guess we can add it In use flag only when set.

>
>
> < ACL Data TX: Handle 256 flags 0x00 dlen 7
> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
> AVDTP: Get Capabilities (0x02) Command: type 0x00 label 9 nosp 0
> ACP SEID: 3
>> ACL Data RX: Handle 256 flags 0x02 dlen 23
> Channel: 66 len 19 [PSM 25 mode 0] {chan 2}
> AVDTP: Get Capabilities (0x02) Response Accept: type 0x00 label 9 nosp 0
> Service Category: Media Transport
> Service Category: Media Codec
> Media Type: Audio
> Media Codec: Non-A2DP
> Vendor ID: 0x0000004f (APT Licensing Ltd.)
> Vendor Specific Codec ID: 0x0001 (aptX)
> Frequency: 0x30
> 44100
> 48000
> Channel Mode: 0x02
> Stereo
> Service Category: Content Protection
> Content Protection Type: SCMS-T
>
>
> < ACL Data TX: Handle 256 flags 0x00 dlen 18
> Channel: 1602 len 14 [PSM 25 mode 0] {chan 2}
> AVDTP: Set Configuration (0x03) Command: type 0x00 label 11 nosp 0
> ACP SEID: 1
> INT SEID: 1
> Service Category: Media Transport
> Service Category: Media Codec
> Media Type: Audio
> Media Codec: SBC
> Frequency: 0x20
> 44100
> Channel Mode: 0x01
> Joint Channel
> Block Length: 0x10
> 16
> Subbands: 0x04
> 8
> Allocation Method: 0x01
> Loudness
> Minimum Bitpool: 2
> Maximum Bitpool: 53

Id got with a range instead of 2 field e.g. Bitpool: 2-53. Actually
overall Id make this more compact instead of having another line for
the decoded value just input in the same line with the hex value in
parenthesis.

>> 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: type 0x00 label 11 nosp 0
>
>> ACL Data RX: Handle 256 flags 0x02 dlen 6
> Channel: 66 len 2 [PSM 25 mode 0] {chan 2}
> AVDTP: Open (0x06) Response Accept: type 0x00 label 12 nosp 0
>
>
> < ACL Data TX: Handle 256 flags 0x00 dlen 7
> Channel: 1602 len 3 [PSM 25 mode 0] {chan 2}
> AVDTP: Start (0x07) Command: type 0x00 label 13 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: type 0x00 label 13 nosp 0

Would you be able to include the output above into the patch that
introduce it? I think it is a bit better to see the formatting each
patch is introducing and then have proper comments to them.

>
>
> 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 | 420 +++++++++++++++++++++++++++
> monitor/a2dp.h | 24 ++
> monitor/avdtp.c | 819 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> monitor/avdtp.h | 24 ++
> monitor/l2cap.c | 48 +++-
> monitor/l2cap.h | 1 +
> 8 files changed, 1327 insertions(+), 13 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
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html



--
Luiz Augusto von Dentz

2015-11-14 13:44:28

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index e065d8b..e48e507 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -488,6 +488,44 @@ response:
return true;
}

+static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ for (;;) {
+ if (!l2cap_frame_get_u8(frame, &seid))
+ break;
+
+ print_field("ACP SEID: %d", seid >> 2);
+ }
+
+ return true;
+
+reject:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -566,6 +604,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_CLOSE:
ret = avdtp_close(avdtp_frame);
break;
+ case AVDTP_SUSPEND:
+ ret = avdtp_suspend(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:32

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index a44fd1a..e5bc13e 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -573,6 +573,37 @@ response:
return true;
}

+static bool avdtp_delayreport(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+ uint16_t delay;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &delay))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+ print_field("Delay: %d.%dms", delay / 10, delay % 10);
+
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -661,6 +692,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_SECURITY_CONTROL:
ret = avdtp_security_control(avdtp_frame);
break;
+ case AVDTP_DELAYREPORT:
+ ret = avdtp_delayreport(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:33

by Andrzej Kaczmarek

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

---
monitor/avdtp.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 62 insertions(+), 4 deletions(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index e5bc13e..003134f 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -174,6 +174,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) {
@@ -211,6 +229,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", 2, ' ',
+ mediatype2str(type >> 4));
+
+ print_field("%*cMedia Codec: %s", 2, ' ',
+ mediacodec2str(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;
@@ -231,11 +277,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-14 13:44:34

by Andrzej Kaczmarek

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

---
monitor/avdtp.c | 40 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 003134f..e216a1b 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -192,6 +192,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) {
@@ -229,6 +241,29 @@ 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", 2, ' ', cptype2str(type));
+
+ /* TODO: decode protection specific information */
+
+ 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;
@@ -278,6 +313,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;
@@ -285,7 +324,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-14 13:44:37

by Andrzej Kaczmarek

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

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

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index 10eca42..b6b01ee 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_bit_table(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -229,6 +263,49 @@ static bool codec_mpeg12(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_aac(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_bit_table(BASE_INDENT, type, aac_object_type_table);
+
+ print_field("%*cFrequency: 0x%02x", BASE_INDENT, ' ', freq);
+ print_bit_table(BASE_INDENT, freq, aac_frequency_table);
+
+ print_field("%*cChannels: 0x%02x", BASE_INDENT, ' ', chan);
+ print_bit_table(BASE_INDENT, chan, aac_channels_table);
+
+ print_field("%*cBitrate: %ubps", BASE_INDENT, ' ', bitrate);
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
@@ -236,6 +313,8 @@ bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_sbc(losc, frame);
case A2DP_CODEC_MPEG12:
return codec_mpeg12(losc, frame);
+ case A2DP_CODEC_MPEG24:
+ return codec_aac(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-14 13:44:38

by Andrzej Kaczmarek

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

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

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index b6b01ee..ab93097 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;
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_bit_table(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -177,6 +195,14 @@ static void print_bit_table(uint8_t indent, uint32_t value,
}
}

+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(uint8_t losc, struct l2cap_frame *frame)
{
uint8_t cap = 0;
@@ -306,6 +332,55 @@ static bool codec_aac(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_vendor_aptx(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_bit_table(BASE_INDENT + 2, cap & 0xf0, aptx_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT + 2, ' ',
+ cap & 0x0f);
+ print_bit_table(BASE_INDENT + 2, cap & 0x0f, aptx_channel_mode_table);
+
+ return true;
+}
+
+static bool codec_vendor(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: 0x%08x (%s)", BASE_INDENT, ' ', vendor_id,
+ bt_compidtostr(vendor_id));
+
+ print_field("%*cVendor Specific Codec ID: 0x%04x (%s)",
+ BASE_INDENT, ' ', codec_id,
+ vndcodec2str(vendor_id, codec_id));
+
+ if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
+ codec_vendor_aptx(losc, frame);
+ } else {
+ packet_hexdump(frame->data, losc);
+ l2cap_frame_pull(frame, frame, losc);
+ }
+
+ return true;
+}
+
bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
@@ -315,6 +390,8 @@ bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
return codec_mpeg12(losc, frame);
case A2DP_CODEC_MPEG24:
return codec_aac(losc, frame);
+ case A2DP_CODEC_VENDOR:
+ return codec_vendor(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-14 13:44:35

by Andrzej Kaczmarek

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

---
Makefile.tools | 1 +
android/Android.mk | 1 +
monitor/a2dp.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/a2dp.h | 24 +++++++++
monitor/avdtp.c | 8 +--
5 files changed, 178 insertions(+), 6 deletions(-)
create mode 100644 monitor/a2dp.c
create mode 100644 monitor/a2dp.h

diff --git a/Makefile.tools b/Makefile.tools
index 387917e..46cdb53 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..60ebe94
--- /dev/null
+++ b/monitor/a2dp.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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;
+ 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 Channel" },
+ { }
+};
+
+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_bit_table(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))
+ print_field("%*c%s", indent + 2, ' ', table[i].str);
+ }
+}
+
+static bool codec_sbc(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_bit_table(BASE_INDENT, cap & 0xf0, sbc_frequency_table);
+
+ print_field("%*cChannel Mode: 0x%02x", BASE_INDENT, ' ', cap & 0x0f);
+ print_bit_table(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_bit_table(BASE_INDENT, cap & 0xf0, sbc_blocklen_table);
+
+ print_field("%*cSubbands: 0x%02x", BASE_INDENT, ' ', cap & 0x0c);
+ print_bit_table(BASE_INDENT, cap & 0x0c, sbc_subbands_table);
+
+ print_field("%*cAllocation Method: 0x%02x", BASE_INDENT, ' ',
+ cap & 0x03);
+ print_bit_table(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;
+}
+
+bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
+{
+ switch (codec) {
+ case A2DP_CODEC_SBC:
+ return codec_sbc(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..4376ab2
--- /dev/null
+++ b/monitor/a2dp.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
+ *
+ */
+
+bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame);
diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index e216a1b..061b3f6 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"

/* Signal Identifiers */
#define AVDTP_DISCOVER 0x01
@@ -284,12 +285,7 @@ static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
print_field("%*cMedia Codec: %s", 2, ' ',
mediacodec2str(codec));

- /* TODO: decode codec specific information */
-
- packet_hexdump(frame->data, losc);
- l2cap_frame_pull(frame, frame, losc);
-
- return true;
+ return a2dp_codec_caps(codec, losc, frame);
}

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


2015-11-14 13:44:39

by Andrzej Kaczmarek

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

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

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index ab93097..86ae39d 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;
@@ -199,6 +201,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";
}
@@ -351,6 +355,20 @@ static bool codec_vendor_aptx(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(uint8_t losc, struct l2cap_frame *frame)
{
uint32_t vendor_id = 0;
@@ -373,6 +391,8 @@ static bool codec_vendor(uint8_t losc, struct l2cap_frame *frame)

if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
codec_vendor_aptx(losc, frame);
+ } else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) {
+ codec_vendor_ldac(losc, frame);
} else {
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-14 13:44:36

by Andrzej Kaczmarek

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

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

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index 60ebe94..10eca42 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 Channel" },
+ { }
+};
+
+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_bit_table(uint8_t indent, uint32_t value,
const struct bit_desc *table)
{
@@ -137,11 +181,61 @@ static bool codec_sbc(uint8_t losc, struct l2cap_frame *frame)
return true;
}

+static bool codec_mpeg12(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_bit_table(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_bit_table(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_bit_table(BASE_INDENT, freq, mpeg12_frequency_table);
+
+ print_field("%*cBitrate: 0x%04x", BASE_INDENT, ' ', bitrate);
+ if (!vbr)
+ print_bit_table(BASE_INDENT, freq, mpeg12_bitrate_table);
+
+ print_field("%*cVBR: %s", BASE_INDENT, ' ', vbr ? "Yes" : "No");
+
+ return true;
+}
+
bool a2dp_codec_caps(uint8_t codec, uint8_t losc, struct l2cap_frame *frame)
{
switch (codec) {
case A2DP_CODEC_SBC:
return codec_sbc(losc, frame);
+ case A2DP_CODEC_MPEG12:
+ return codec_mpeg12(losc, frame);
default:
packet_hexdump(frame->data, losc);
l2cap_frame_pull(frame, frame, losc);
--
2.6.2


2015-11-14 13:44:27

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 8641f9a..e065d8b 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -462,6 +462,32 @@ response:
return true;
}

+static bool avdtp_close(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -537,6 +563,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_START:
ret = avdtp_start(avdtp_frame);
break;
+ case AVDTP_CLOSE:
+ ret = avdtp_close(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:30

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index bd91265..ecd55de 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -546,6 +546,33 @@ response:
return true;
}

+static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ packet_hexdump(frame->data, frame->size);
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ packet_hexdump(frame->data, frame->size);
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -630,6 +657,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_ABORT:
ret = avdtp_abort(avdtp_frame);
break;
+ case AVDTP_SECURITY_CONTROL:
+ ret = avdtp_security_control(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:31

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index ecd55de..a44fd1a 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -631,6 +631,7 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
ret = avdtp_discover(avdtp_frame);
break;
case AVDTP_GET_CAPABILITIES:
+ case AVDTP_GET_ALL_CAPABILITIES:
ret = avdtp_get_capabilities(avdtp_frame);
break;
case AVDTP_SET_CONFIGURATION:
--
2.6.2


2015-11-14 13:44:29

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index e48e507..bd91265 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -526,6 +526,26 @@ response:
return true;
}

+static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -607,6 +627,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_SUSPEND:
ret = avdtp_suspend(avdtp_frame);
break;
+ case AVDTP_ABORT:
+ ret = avdtp_abort(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:26

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index f44da2a..8641f9a 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -424,6 +424,44 @@ response:
return true;
}

+static bool avdtp_start(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ for (;;) {
+ if (!l2cap_frame_get_u8(frame, &seid))
+ break;
+
+ print_field("ACP SEID: %d", seid >> 2);
+ }
+
+ return true;
+
+reject:
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -496,6 +534,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_OPEN:
ret = avdtp_open(avdtp_frame);
break;
+ case AVDTP_START:
+ ret = avdtp_start(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:25

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 9c28c64..f44da2a 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -398,6 +398,32 @@ response:
return true;
}

+static bool avdtp_open(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -467,6 +493,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_RECONFIGURE:
ret = avdtp_reconfigure(avdtp_frame);
break;
+ case AVDTP_OPEN:
+ ret = avdtp_open(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:24

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 89c5eb7..9c28c64 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -366,6 +366,38 @@ response:
return decode_capabilities(avdtp_frame);
}

+static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+ uint8_t service_cat;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+
+reject:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s", servicecat2str(service_cat));
+
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -432,6 +464,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_GET_CONFIGURATION:
ret = avdtp_get_configuration(avdtp_frame);
break;
+ case AVDTP_RECONFIGURE:
+ ret = avdtp_reconfigure(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:22

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index cae704a..f38d359 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -305,6 +305,42 @@ response:
return decode_capabilities(avdtp_frame);
}

+static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t acp_seid, int_seid;
+ uint8_t service_cat;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &acp_seid))
+ return false;
+
+ if (!l2cap_frame_get_u8(frame, &int_seid))
+ return false;
+
+ print_field("ACP SEID: %d", acp_seid >> 2);
+ print_field("INT SEID: %d", int_seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+
+reject:
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ return false;
+
+ print_field("Service Category: %s", servicecat2str(service_cat));
+
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ /* no extra parameters */
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -365,6 +401,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_GET_CAPABILITIES:
ret = avdtp_get_capabilities(avdtp_frame);
break;
+ case AVDTP_SET_CONFIGURATION:
+ ret = avdtp_set_configuration(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:23

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index f38d359..89c5eb7 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -341,6 +341,31 @@ response:
return true;
}

+static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return decode_capabilities(avdtp_frame);
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ return decode_capabilities(avdtp_frame);
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -404,6 +429,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_SET_CONFIGURATION:
ret = avdtp_set_configuration(avdtp_frame);
break;
+ case AVDTP_GET_CONFIGURATION:
+ ret = avdtp_get_configuration(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:20

by Andrzej Kaczmarek

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

---
monitor/avdtp.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 131 insertions(+), 2 deletions(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 209bbab..f851107 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -108,6 +108,114 @@ 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 "Reserver";
+ }
+}
+
+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;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ /* no extra parameters */
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ for (;;) {
+ uint8_t seid;
+ uint8_t info;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ break;
+
+ if (!l2cap_frame_get_u8(frame, &info))
+ return false;
+
+ print_field("ACP SEID %d", seid >> 2);
+ print_field("%*cMedia Type: %s", 2, ' ',
+ mediatype2str(info >> 4));
+ print_field("%*cSEP Type: %s", 2, ' ',
+ info & 0x04 ? "SNK" : "SRC");
+ print_field("%*cIn use: %s", 2, ' ',
+ seid & 0x02 ? "Yes" : "No");
+ }
+
+ return true;
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -115,6 +223,7 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
uint8_t hdr;
uint8_t nosp = 0;
uint8_t sigid;
+ bool ret;

if (frame->in)
pdu_color = COLOR_MAGENTA;
@@ -149,8 +258,28 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
sigid, msgtype2str(hdr & 0x03),
hdr & 0x0c, hdr >> 4, nosp);

- packet_hexdump(frame->data, frame->size);
- return true;
+ /* 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;
+
+ switch (sigid) {
+ case AVDTP_DISCOVER:
+ ret = avdtp_discover(avdtp_frame);
+ break;
+ default:
+ packet_hexdump(frame->data, frame->size);
+ ret = true;
+ break;
+ }
+
+ return ret;
}

void avdtp_packet(const struct l2cap_frame *frame)
--
2.6.2


2015-11-14 13:44:21

by Andrzej Kaczmarek

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

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index f851107..cae704a 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -53,6 +53,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;
struct l2cap_frame l2cap_frame;
@@ -164,6 +174,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;
@@ -177,6 +211,36 @@ 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;
+
+ for (;;) {
+ uint8_t service_cat;
+ uint8_t losc;
+
+ if (!l2cap_frame_get_u8(frame, &service_cat))
+ break;
+
+ if (!l2cap_frame_get_u8(frame, &losc))
+ return false;
+
+ print_field("Service Category: %s",
+ servicecat2str(service_cat));
+
+ 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;
@@ -216,6 +280,31 @@ response:
return true;
}

+static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
+{
+ struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
+ uint8_t seid;
+
+ if (avdtp_frame->hdr & 0x01)
+ goto reject;
+
+ if (avdtp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_u8(frame, &seid))
+ return false;
+
+ print_field("ACP SEID: %d", seid >> 2);
+
+ return true;
+
+reject:
+ return avdtp_reject_common(avdtp_frame);
+
+response:
+ return decode_capabilities(avdtp_frame);
+}
+
static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
{
struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -273,6 +362,9 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
case AVDTP_DISCOVER:
ret = avdtp_discover(avdtp_frame);
break;
+ case AVDTP_GET_CAPABILITIES:
+ ret = avdtp_get_capabilities(avdtp_frame);
+ break;
default:
packet_hexdump(frame->data, frame->size);
ret = true;
--
2.6.2


2015-11-14 13:44:18

by Andrzej Kaczmarek

[permalink] [raw]
Subject: [PATCH 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 | 44 +++++++++++++++++++++++++++++++-------------
monitor/l2cap.h | 1 +
2 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 894c741..de86e64 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,15 +122,16 @@ 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++;
+
if (frame->in) {
if (chan_list[i].dcid == scid) {
n = i;
- break;
}
} else {
if (chan_list[i].scid == scid) {
n = i;
- break;
}
}
}
@@ -147,6 +152,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 +308,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 +1401,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-11-14 13:44:19

by Andrzej Kaczmarek

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

---
Makefile.tools | 1 +
android/Android.mk | 1 +
monitor/avdtp.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++
monitor/avdtp.h | 24 ++++++++
monitor/l2cap.c | 4 ++
5 files changed, 206 insertions(+)
create mode 100644 monitor/avdtp.c
create mode 100644 monitor/avdtp.h

diff --git a/Makefile.tools b/Makefile.tools
index d849bd9..387917e 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..209bbab
--- /dev/null
+++ b/monitor/avdtp.c
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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;
+ 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 nosp = 0;
+ uint8_t sigid;
+
+ 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, &sigid))
+ return false;
+
+ sigid &= 0x3f;
+
+ print_indent(6, pdu_color, "AVDTP: ", sigid2str(sigid), COLOR_OFF,
+ " (0x%02x) %s: type 0x%02x label %d nosp %d",
+ sigid, msgtype2str(hdr & 0x03),
+ hdr & 0x0c, hdr >> 4, nosp);
+
+ 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 de86e64..ba8feb7 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"

@@ -3098,6 +3099,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