All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon
@ 2015-11-20 14:13 Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 01/22] monitor/l2cap: Add channel sequence number Andrzej Kaczmarek
                   ` (22 more replies)
  0 siblings, 23 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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 fixed found during development

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     | 640 ++++++++++++++++++++++++++++++++++++++++
 monitor/a2dp.h     |  26 ++
 monitor/avdtp.c    | 836 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 monitor/avdtp.h    |  24 ++
 monitor/l2cap.c    |  48 ++-
 monitor/l2cap.h    |   1 +
 8 files changed, 1566 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


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH v2 01/22] monitor/l2cap: Add channel sequence number
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 02/22] monitor/avdtp: Add basic decoding of AVDTP signalling Andrzej Kaczmarek
                   ` (21 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 02/22] monitor/avdtp: Add basic decoding of AVDTP signalling
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 01/22] monitor/l2cap: Add channel sequence number Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER Andrzej Kaczmarek
                   ` (20 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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    | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 monitor/avdtp.h    |  24 +++++++
 monitor/l2cap.c    |   4 ++
 5 files changed, 209 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..de4edbb
--- /dev/null
+++ b/monitor/avdtp.c
@@ -0,0 +1,179 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  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);
+
+	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 <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 01/22] monitor/l2cap: Add channel sequence number Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 02/22] monitor/avdtp: Add basic decoding of AVDTP signalling Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 16:50   ` Szymon Janc
  2015-11-20 14:13 ` [PATCH v2 04/22] monitor/avdtp: Decode AVDTP_GET_CAPABILITIES Andrzej Kaczmarek
                   ` (19 subsequent siblings)
  22 siblings, 1 reply; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 132 insertions(+), 2 deletions(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index de4edbb..78e3c3b 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -109,6 +109,115 @@ 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;
+
+	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 (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;
+}
+
 static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
 {
 	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
@@ -116,6 +225,7 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
 	uint8_t hdr;
 	uint8_t sig_id;
 	uint8_t nosp = 0;
+	bool ret;
 
 	if (frame->in)
 		pdu_color = COLOR_MAGENTA;
@@ -152,8 +262,28 @@ static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
 			sig_id, msgtype2str(hdr & 0x03), 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 (sig_id) {
+	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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 04/22] monitor/avdtp: Decode AVDTP_GET_CAPABILITIES
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (2 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 05/22] monitor/avdtp: Decode AVDTP_SET_CONFIGURATION Andrzej Kaczmarek
                   ` (18 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 78e3c3b..cf11d2e 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;
 	uint8_t sig_id;
@@ -165,6 +175,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;
@@ -178,6 +212,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 (0x%02x)",
+				servicecat2str(service_cat), 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;
@@ -218,6 +282,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;
@@ -277,6 +366,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 05/22] monitor/avdtp: Decode AVDTP_SET_CONFIGURATION
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (3 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 04/22] monitor/avdtp: Decode AVDTP_GET_CAPABILITIES Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 06/22] monitor/avdtp: Decode AVDTP_GET_CONFIGURATION Andrzej Kaczmarek
                   ` (17 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index cf11d2e..6869183 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -307,6 +307,43 @@ 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 (0x%02x)",
+				servicecat2str(service_cat), 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;
@@ -369,6 +406,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 06/22] monitor/avdtp: Decode AVDTP_GET_CONFIGURATION
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (4 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 05/22] monitor/avdtp: Decode AVDTP_SET_CONFIGURATION Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 07/22] monitor/avdtp: Decode AVDTP_RECONFIGURE Andrzej Kaczmarek
                   ` (16 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 6869183..84378a6 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -344,6 +344,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 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;
@@ -409,6 +434,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 07/22] monitor/avdtp: Decode AVDTP_RECONFIGURE
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (5 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 06/22] monitor/avdtp: Decode AVDTP_GET_CONFIGURATION Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 08/22] monitor/avdtp: Decode AVDTP_OPEN Andrzej Kaczmarek
                   ` (15 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 84378a6..2dc0578 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -369,6 +369,39 @@ 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 (0x%02x)",
+				servicecat2str(service_cat), 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;
@@ -437,6 +470,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 08/22] monitor/avdtp: Decode AVDTP_OPEN
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (6 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 07/22] monitor/avdtp: Decode AVDTP_RECONFIGURE Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 09/22] monitor/avdtp: Decode AVDTP_START Andrzej Kaczmarek
                   ` (14 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 2dc0578..cc51587 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -402,6 +402,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;
@@ -473,6 +499,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 09/22] monitor/avdtp: Decode AVDTP_START
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (7 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 08/22] monitor/avdtp: Decode AVDTP_OPEN Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 10/22] monitor/avdtp: Decode AVDTP_CLOSE Andrzej Kaczmarek
                   ` (13 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index cc51587..3a6816b 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -428,6 +428,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;
@@ -502,6 +540,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 10/22] monitor/avdtp: Decode AVDTP_CLOSE
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (8 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 09/22] monitor/avdtp: Decode AVDTP_START Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 11/22] monitor/avdtp: Decode AVDTP_SUSPEND Andrzej Kaczmarek
                   ` (12 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 3a6816b..4db14dd 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -466,6 +466,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;
@@ -543,6 +569,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 11/22] monitor/avdtp: Decode AVDTP_SUSPEND
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (9 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 10/22] monitor/avdtp: Decode AVDTP_CLOSE Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 12/22] monitor/avdtp: Decode AVDTP_ABORT Andrzej Kaczmarek
                   ` (11 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 | 41 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 4db14dd..4c3665f 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -492,6 +492,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;
@@ -572,6 +610,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 12/22] monitor/avdtp: Decode AVDTP_ABORT
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (10 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 11/22] monitor/avdtp: Decode AVDTP_SUSPEND Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 13/22] monitor/avdtp: Decode AVDTP_SECURITY_CONTROL Andrzej Kaczmarek
                   ` (10 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 4c3665f..3dfae0d 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -530,6 +530,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;
@@ -613,6 +633,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 13/22] monitor/avdtp: Decode AVDTP_SECURITY_CONTROL
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (11 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 12/22] monitor/avdtp: Decode AVDTP_ABORT Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 14/22] monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES Andrzej Kaczmarek
                   ` (9 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 3dfae0d..bb2409e 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -550,6 +550,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;
@@ -636,6 +663,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 14/22] monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (12 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 13/22] monitor/avdtp: Decode AVDTP_SECURITY_CONTROL Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 15/22] monitor/avdtp: Decode AVDTP_DELAYREPORT Andrzej Kaczmarek
                   ` (8 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

< 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 bb2409e..e27dc25 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -637,6 +637,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 15/22] monitor/avdtp: Decode AVDTP_DELAYREPORT
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (13 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 14/22] monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 16/22] monitor/avdtp: Decode basic Media Codec capabilities Andrzej Kaczmarek
                   ` (7 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index e27dc25..a4ff421 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -577,6 +577,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;
@@ -667,6 +698,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 16/22] monitor/avdtp: Decode basic Media Codec capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (14 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 15/22] monitor/avdtp: Decode AVDTP_DELAYREPORT Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 17/22] monitor/avdtp: Decode basic Content Protection capabilities Andrzej Kaczmarek
                   ` (6 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 a4ff421..2e94558 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -175,6 +175,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) {
@@ -212,6 +230,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;
@@ -232,11 +278,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 17/22] monitor/avdtp: Decode basic Content Protection capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (15 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 16/22] monitor/avdtp: Decode basic Media Codec capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities Andrzej Kaczmarek
                   ` (5 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/monitor/avdtp.c b/monitor/avdtp.c
index 2e94558..ed0d792 100644
--- a/monitor/avdtp.c
+++ b/monitor/avdtp.c
@@ -193,6 +193,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) {
@@ -230,6 +242,30 @@ 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 */
+
+	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;
@@ -279,6 +315,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;
@@ -286,7 +326,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (16 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 17/22] monitor/avdtp: Decode basic Content Protection capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 16:35   ` Szymon Janc
  2015-11-20 14:13 ` [PATCH v2 19/22] monitor/a2dp: Decode MPEG-1,2 capabilities Andrzej Kaczmarek
                   ` (4 subsequent siblings)
  22 siblings, 1 reply; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 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..2ef5889
--- /dev/null
+++ b/monitor/a2dp.c
@@ -0,0 +1,217 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  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_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))
+			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))
+			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 <andrzej.kaczmarek@codecoup.pl>
+ *
+ *
+ *  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 ed0d792..e9a355e 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
@@ -69,6 +70,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) {
@@ -286,12 +294,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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 19/22] monitor/a2dp: Decode MPEG-1,2 capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (17 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 20/22] monitor/a2dp: Decode AAC capabilities Andrzej Kaczmarek
                   ` (3 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

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

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index 2ef5889..effdfe7 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_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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 20/22] monitor/a2dp: Decode AAC capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (18 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 19/22] monitor/a2dp: Decode MPEG-1,2 capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 21/22] monitor/a2dp: Decode aptX capabilities Andrzej Kaczmarek
                   ` (2 subsequent siblings)
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 effdfe7..51fffd4 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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 21/22] monitor/a2dp: Decode aptX capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (19 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 20/22] monitor/a2dp: Decode AAC capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 14:13 ` [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities Andrzej Kaczmarek
  2015-11-20 16:37 ` [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 51fffd4..d438db0 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_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) {
+		codec_vendor_aptx_cap(losc, frame);
+	} else {
+		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) {
+		codec_vendor_aptx_cfg(losc, frame);
+	} else {
+		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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (20 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 21/22] monitor/a2dp: Decode aptX capabilities Andrzej Kaczmarek
@ 2015-11-20 14:13 ` Andrzej Kaczmarek
  2015-11-20 16:40   ` Szymon Janc
  2015-11-20 16:37 ` [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
  22 siblings, 1 reply; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 14:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

> 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 | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/monitor/a2dp.c b/monitor/a2dp.c
index d438db0..2077d70 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;
@@ -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,6 +542,8 @@ static bool codec_vendor_cap(uint8_t losc, struct l2cap_frame *frame)
 
 	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
 		codec_vendor_aptx_cap(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);
@@ -573,6 +593,8 @@ static bool codec_vendor_cfg(uint8_t losc, struct l2cap_frame *frame)
 
 	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
 		codec_vendor_aptx_cfg(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


^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities
  2015-11-20 14:13 ` [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities Andrzej Kaczmarek
@ 2015-11-20 16:35   ` Szymon Janc
  0 siblings, 0 replies; 27+ messages in thread
From: Szymon Janc @ 2015-11-20 16:35 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth

Hi Andrzej,

On Friday 20 November 2015 15:13:36 Andrzej Kaczmarek wrote:
> > 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 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..2ef5889
> --- /dev/null
> +++ b/monitor/a2dp.c
> @@ -0,0 +1,217 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2015  Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
> + *
> + *
> + *  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" },

This should be "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))
> +			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))
> +			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 <andrzej.kaczmarek@codecoup.pl>
> + *
> + *
> + *  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 ed0d792..e9a355e 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
> @@ -69,6 +70,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) {
> @@ -286,12 +294,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)

-- 
pozdrawiam
Szymon Janc

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon
  2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
                   ` (21 preceding siblings ...)
  2015-11-20 14:13 ` [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities Andrzej Kaczmarek
@ 2015-11-20 16:37 ` Andrzej Kaczmarek
  22 siblings, 0 replies; 27+ messages in thread
From: Andrzej Kaczmarek @ 2015-11-20 16:37 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andrzej Kaczmarek

Hi,

On Fri, Nov 20, 2015 at 3:13 PM, Andrzej Kaczmarek
<andrzej.kaczmarek@codecoup.pl> 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 fixed found during development

I'll send v3 later which will fix some weird copy&pasted gotos and
for-loops used in commands decoding... I'll make this code look more
sane.

BR,
Andrzej

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities
  2015-11-20 14:13 ` [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities Andrzej Kaczmarek
@ 2015-11-20 16:40   ` Szymon Janc
  0 siblings, 0 replies; 27+ messages in thread
From: Szymon Janc @ 2015-11-20 16:40 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth

Hi Andrzej,

On Friday 20 November 2015 15:13:40 Andrzej Kaczmarek wrote:
> > 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 | 22 ++++++++++++++++++++++
>  1 file changed, 22 insertions(+)
> 
> diff --git a/monitor/a2dp.c b/monitor/a2dp.c
> index d438db0..2077d70 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;
> @@ -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,6 +542,8 @@ static bool codec_vendor_cap(uint8_t losc, struct
> l2cap_frame *frame)
> 
>  	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
>  		codec_vendor_aptx_cap(losc, frame);
> +	} else if (vendor_id == LDAC_VENDOR_ID && codec_id == LDAC_CODEC_ID) {
> +		codec_vendor_ldac(losc, frame);

Should this return value  from function? Otherwise you may silently ignore 
data if length doesn't match.

>  	} else {
>  		packet_hexdump(frame->data, losc);
>  		l2cap_frame_pull(frame, frame, losc);
> @@ -573,6 +593,8 @@ static bool codec_vendor_cfg(uint8_t losc, struct
> l2cap_frame *frame)
> 
>  	if (vendor_id == APTX_VENDOR_ID && codec_id == APTX_CODEC_ID) {
>  		codec_vendor_aptx_cfg(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);

-- 
pozdrawiam
Szymon Janc

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER
  2015-11-20 14:13 ` [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER Andrzej Kaczmarek
@ 2015-11-20 16:50   ` Szymon Janc
  0 siblings, 0 replies; 27+ messages in thread
From: Szymon Janc @ 2015-11-20 16:50 UTC (permalink / raw)
  To: Andrzej Kaczmarek; +Cc: linux-bluetooth

Hi Andrzej,

On Friday 20 November 2015 15:13:21 Andrzej Kaczmarek wrote:
> < 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 | 134
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed,
> 132 insertions(+), 2 deletions(-)
> 
> diff --git a/monitor/avdtp.c b/monitor/avdtp.c
> index de4edbb..78e3c3b 100644
> --- a/monitor/avdtp.c
> +++ b/monitor/avdtp.c
> @@ -109,6 +109,115 @@ 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;
> +
> +	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 (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");
> +	}


Maybe it is a matter of taste, but I'd not abuse goto in such simple 
functions.
ie

/* reject */
if (avdtp_frame->hdr & 0x01)
	return avdtp_reject_common(avdtp_frame);

/* response */
if (avdtp_frame->hdr & 0x02) {
	....
	return true;
}

....
return true;


> +
> +	return true;
> +}
> +
>  static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
>  {
>  	struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
> @@ -116,6 +225,7 @@ static bool avdtp_signalling_packet(struct avdtp_frame
> *avdtp_frame) uint8_t hdr;
>  	uint8_t sig_id;
>  	uint8_t nosp = 0;
> +	bool ret;
> 
>  	if (frame->in)
>  		pdu_color = COLOR_MAGENTA;
> @@ -152,8 +262,28 @@ static bool avdtp_signalling_packet(struct avdtp_frame
> *avdtp_frame) sig_id, msgtype2str(hdr & 0x03), 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 (sig_id) {
> +	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)

-- 
pozdrawiam
Szymon Janc

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2015-11-20 16:50 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-20 14:13 [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 01/22] monitor/l2cap: Add channel sequence number Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 02/22] monitor/avdtp: Add basic decoding of AVDTP signalling Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 03/22] monitor/avdtp: Decode AVDTP_DISCOVER Andrzej Kaczmarek
2015-11-20 16:50   ` Szymon Janc
2015-11-20 14:13 ` [PATCH v2 04/22] monitor/avdtp: Decode AVDTP_GET_CAPABILITIES Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 05/22] monitor/avdtp: Decode AVDTP_SET_CONFIGURATION Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 06/22] monitor/avdtp: Decode AVDTP_GET_CONFIGURATION Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 07/22] monitor/avdtp: Decode AVDTP_RECONFIGURE Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 08/22] monitor/avdtp: Decode AVDTP_OPEN Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 09/22] monitor/avdtp: Decode AVDTP_START Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 10/22] monitor/avdtp: Decode AVDTP_CLOSE Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 11/22] monitor/avdtp: Decode AVDTP_SUSPEND Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 12/22] monitor/avdtp: Decode AVDTP_ABORT Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 13/22] monitor/avdtp: Decode AVDTP_SECURITY_CONTROL Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 14/22] monitor/avdtp: Decode AVDTP_GET_ALL_CAPABILITIES Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 15/22] monitor/avdtp: Decode AVDTP_DELAYREPORT Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 16/22] monitor/avdtp: Decode basic Media Codec capabilities Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 17/22] monitor/avdtp: Decode basic Content Protection capabilities Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 18/22] monitor/a2dp: Decode SBC capabilities Andrzej Kaczmarek
2015-11-20 16:35   ` Szymon Janc
2015-11-20 14:13 ` [PATCH v2 19/22] monitor/a2dp: Decode MPEG-1,2 capabilities Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 20/22] monitor/a2dp: Decode AAC capabilities Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 21/22] monitor/a2dp: Decode aptX capabilities Andrzej Kaczmarek
2015-11-20 14:13 ` [PATCH v2 22/22] monitor/a2dp: Decode LDAC capabilities Andrzej Kaczmarek
2015-11-20 16:40   ` Szymon Janc
2015-11-20 16:37 ` [PATCH v2 00/22] Add AVDTP/A2DP decoding to btmon Andrzej Kaczmarek

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.