2015-01-07 08:23:14

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 0/6] L2CAP control field + AVRCP browsing PDU parsing

Support for parsing L2CAP extended control field and
AVRCP SetBrowsedPlayer added in Bluetooth monitor.

Vikrampal Yadav (6):
monitor: Make the parameter name generic
monitor: Add functionality to store extented control in DB
monitor: Extract extended L2CAP extended control field
monitor: Add support for parsing L2CAP extended control field
monitor: Add support for parsing L2CAP control field
monitor: Add AVRCP SetBrowsedPlayer support

monitor/avctp.c | 86 +++++++++++++++++++-
monitor/l2cap.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 319 insertions(+), 6 deletions(-)

--
1.9.1



2015-01-12 12:43:56

by Vikrampal Yadav

[permalink] [raw]
Subject: RE: [PATCH 0/6] L2CAP control field + AVRCP browsing PDU parsing

Hi Luiz,

> -----Original Message-----
> From: Luiz Augusto von Dentz [mailto:[email protected]]
> Sent: Monday, January 12, 2015 6:04 PM
> To: Vikrampal Yadav
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH 0/6] L2CAP control field + AVRCP browsing PDU parsing
>
> Hi Vikram,
>
> On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav
> <[email protected]> wrote:
> > Support for parsing L2CAP extended control field and AVRCP
> > SetBrowsedPlayer added in Bluetooth monitor.
> >
> > Vikrampal Yadav (6):
> > monitor: Make the parameter name generic
> > monitor: Add functionality to store extented control in DB
> > monitor: Extract extended L2CAP extended control field
> > monitor: Add support for parsing L2CAP extended control field
> > monitor: Add support for parsing L2CAP control field
> > monitor: Add AVRCP SetBrowsedPlayer support
> >
> > monitor/avctp.c | 86 +++++++++++++++++++- monitor/l2cap.c | 239
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> > 2 files changed, 319 insertions(+), 6 deletions(-)
> >
> > --
> > 1.9.1
>
> Applied, thanks. Please make sure you follow the coding style, I had to fix a
> few lines that were over 80 columns.
>
>
> --
> Luiz Augusto von Dentz

Thanks! I surely will take care.

Regards,
Vikram


2015-01-12 12:34:03

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 0/6] L2CAP control field + AVRCP browsing PDU parsing

Hi Vikram,

On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav <[email protected]> wrote:
> Support for parsing L2CAP extended control field and
> AVRCP SetBrowsedPlayer added in Bluetooth monitor.
>
> Vikrampal Yadav (6):
> monitor: Make the parameter name generic
> monitor: Add functionality to store extented control in DB
> monitor: Extract extended L2CAP extended control field
> monitor: Add support for parsing L2CAP extended control field
> monitor: Add support for parsing L2CAP control field
> monitor: Add AVRCP SetBrowsedPlayer support
>
> monitor/avctp.c | 86 +++++++++++++++++++-
> monitor/l2cap.c | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 319 insertions(+), 6 deletions(-)
>
> --
> 1.9.1

Applied, thanks. Please make sure you follow the coding style, I had
to fix a few lines that were over 80 columns.


--
Luiz Augusto von Dentz

2015-01-08 08:47:11

by Vikrampal Yadav

[permalink] [raw]
Subject: RE: [PATCH 6/6] monitor: Add AVRCP SetBrowsedPlayer support

Hi Luiz,

> -----Original Message-----
> From: Luiz Augusto von Dentz [mailto:[email protected]]
> Sent: Wednesday, January 07, 2015 6:55 PM
> To: Vikrampal Yadav
> Cc: [email protected]; [email protected]
> Subject: Re: [PATCH 6/6] monitor: Add AVRCP SetBrowsedPlayer support
>
> Hi Vikram,
>
> On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav
> <[email protected]> wrote:
> > Support for decoding AVRCP SetBrowsedPlayer added in Bluetooth
> monitor.
> >
> > Channel: 65 len 12 ctrl 0x0102 [PSM 27 mode 3] {chan 1}
> > I-frame: Unsegmented TxSeq 1 ReqSeq 1
> > AVCTP Browsing: Command: type 0x00 label 0 PID 0x110e
> > AVRCP: SetBrowsedPlayer: len 0x0002
> > PlayerID: 0x0001 (1)
>
> Can you please add the response frame as well.

I couldn't find any response, not even in hcidump.

>
> > ---
> > monitor/avctp.c | 86
> > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> > 1 file changed, 85 insertions(+), 1 deletion(-)
> >
> > diff --git a/monitor/avctp.c b/monitor/avctp.c index af91ecc..0a1e92d
> > 100644
> > --- a/monitor/avctp.c
> > +++ b/monitor/avctp.c
> > @@ -1637,11 +1637,95 @@ static bool avrcp_control_packet(struct
> avctp_frame *avctp_frame)
> > }
> > }
> >
> > +static bool avrcp_set_browsed_player(struct avctp_frame *avctp_frame)
> > +{
> > + struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
> > + uint32_t items;
> > + uint16_t id, uids, charset;
> > + uint8_t status, folders, indent = 2;
> > +
> > + if (avctp_frame->hdr & 0x02)
> > + goto response;
> > +
> > + if (!l2cap_frame_get_be16(frame, &id))
> > + return false;
> > +
> > + print_field("%*cPlayerID: 0x%04x (%u)", indent, ' ', id, id);
> > + return true;
> > +
> > +response:
> > + if (!l2cap_frame_get_u8(frame, &status))
> > + return false;
> > +
> > + print_field("%*cStatus: 0x%02x (%s)", indent, ' ', status,
> > +
> > + error2str(status));
> > +
> > + if (!l2cap_frame_get_be16(frame, &uids))
> > + return false;
> > +
> > + print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ', uids,
> > + uids);
> > +
> > + if (!l2cap_frame_get_be32(frame, &items))
> > + return false;
> > +
> > + print_field("%*cNumber of Items: 0x%08x (%u)", indent, ' ',
> > + items,
> > + items);
> > +
> > + if (!l2cap_frame_get_be16(frame, &charset))
> > + return false;
> > +
> > + print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ', charset,
> > +
> > + charset2str(charset));
> > +
> > + if (!l2cap_frame_get_u8(frame, &folders))
> > + return false;
> > +
> > + print_field("%*cFolder Depth: 0x%02x (%u)", indent, ' ', folders,
> > +
> > + folders);
> > +
> > + for (; folders > 0; folders--) {
> > + uint8_t len;
> > +
> > + if (!l2cap_frame_get_u8(frame, &len))
> > + return false;
> > +
> > + printf("Folder: ");
> > + for (; len > 0; len--) {
> > + uint8_t c;
> > +
> > + if (!l2cap_frame_get_u8(frame, &c))
> > + return false;
> > +
> > + printf("%1c", isprint(c) ? c : '.');
> > + }
> > + printf("\n");
> > + }
> > +
> > + return true;
> > +}
> > +
> > static bool avrcp_browsing_packet(struct avctp_frame *avctp_frame) {
> > struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
> > + uint16_t len;
> > + uint8_t pduid;
> > +
> > + if (!l2cap_frame_get_u8(frame, &pduid))
> > + return false;
> > +
> > + if (!l2cap_frame_get_be16(frame, &len))
> > + return false;
> > +
> > + print_field("AVRCP: %s: len 0x%04x", pdu2str(pduid), len);
> > +
> > + switch (pduid) {
> > + case AVRCP_SET_BROWSED_PLAYER:
> > + avrcp_set_browsed_player(avctp_frame);
> > + break;
> > + default:
> > + packet_hexdump(frame->data, frame->size);
> > + }
> >
> > - packet_hexdump(frame->data, frame->size);
> > return true;
> > }
> >
> > --
> > 1.9.1
> >
>
>
>
> --
> Luiz Augusto von Dentz

Regards,
Vikram


2015-01-07 13:27:45

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 5/6] monitor: Add support for parsing L2CAP control field

Hi Vikram,

On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav <[email protected]> wrote:
> Support for parsing L2CAP control field added.
> ---
> monitor/l2cap.c | 34 ++++++++++++++++++++++++++++++++++
> 1 file changed, 34 insertions(+)
>
> diff --git a/monitor/l2cap.c b/monitor/l2cap.c
> index 17104e2..19cb0a2 100644
> --- a/monitor/l2cap.c
> +++ b/monitor/l2cap.c
> @@ -416,6 +416,38 @@ static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
> printf(" F-bit");
> }
>
> +static void l2cap_ctrl_parse(struct l2cap_frame *frame, uint32_t ctrl)
> +{
> + printf(" %s:",
> + ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
> +
> + if (ctrl & 0x01) {
> + printf(" %s",
> + supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
> + L2CAP_CTRL_SUPER_SHIFT));
> +
> + if (ctrl & L2CAP_CTRL_POLL)
> + printf(" P-bit");
> + } else {
> + uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
> + printf(" %s", sar2str(sar));
> + if (sar == L2CAP_SAR_START) {
> + uint16_t len;
> +
> + if (!l2cap_frame_get_le16(frame, &len))
> + return;
> +
> + printf(" (len %d)", len);
> + }
> + printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> L2CAP_CTRL_TXSEQ_SHIFT);
> + }
> +
> + printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >> L2CAP_CTRL_REQSEQ_SHIFT);
> +
> + if (ctrl & L2CAP_CTRL_FINAL)
> + printf(" F-bit");
> +}
> +
> #define MAX_INDEX 16
>
> struct index_data {
> @@ -2907,6 +2939,8 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
> " [PSM %d mode %d] {chan %d}",
> cid, size, ctrl16, frame.psm,
> frame.mode, frame.chan);
> +
> + l2cap_ctrl_parse(&frame, ctrl16);
> }
>
> printf("\n");
> --
> 1.9.1

WARNING:LONG_LINE: line over 80 characters
#22: FILE: monitor/l2cap.c:432:
+ uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;

WARNING:LINE_SPACING: Missing a blank line after declarations
#23: FILE: monitor/l2cap.c:433:
+ uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
+ printf(" %s", sar2str(sar));

WARNING:LONG_LINE: line over 80 characters
#32: FILE: monitor/l2cap.c:442:
+ printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> L2CAP_CTRL_TXSEQ_SHIFT);

WARNING:LONG_LINE: line over 80 characters
#35: FILE: monitor/l2cap.c:445:
+ printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >>
L2CAP_CTRL_REQSEQ_SHIFT);

--
Luiz Augusto von Dentz

2015-01-07 13:26:32

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 4/6] monitor: Add support for parsing L2CAP extended control field

Hi Vikram,

On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav <[email protected]> wrote:
> Support for parsing L2CAP extended control field added.
> ---
> monitor/l2cap.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 111 insertions(+)
>
> diff --git a/monitor/l2cap.c b/monitor/l2cap.c
> index 5f135b0..17104e2 100644
> --- a/monitor/l2cap.c
> +++ b/monitor/l2cap.c
> @@ -44,6 +44,48 @@
> #include "avctp.h"
> #include "rfcomm.h"
>
> +/* L2CAP Control Field bit masks */
> +#define L2CAP_CTRL_SAR_MASK 0xC000
> +#define L2CAP_CTRL_REQSEQ_MASK 0x3F00
> +#define L2CAP_CTRL_TXSEQ_MASK 0x007E
> +#define L2CAP_CTRL_SUPERVISE_MASK 0x000C
> +
> +#define L2CAP_CTRL_RETRANS 0x0080
> +#define L2CAP_CTRL_FINAL 0x0080
> +#define L2CAP_CTRL_POLL 0x0010
> +#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */
> +
> +#define L2CAP_CTRL_TXSEQ_SHIFT 1
> +#define L2CAP_CTRL_SUPER_SHIFT 2
> +#define L2CAP_CTRL_REQSEQ_SHIFT 8
> +#define L2CAP_CTRL_SAR_SHIFT 14
> +
> +#define L2CAP_EXT_CTRL_TXSEQ_MASK 0xFFFC0000
> +#define L2CAP_EXT_CTRL_SAR_MASK 0x00030000
> +#define L2CAP_EXT_CTRL_SUPERVISE_MASK 0x00030000
> +#define L2CAP_EXT_CTRL_REQSEQ_MASK 0x0000FFFC
> +
> +#define L2CAP_EXT_CTRL_POLL 0x00040000
> +#define L2CAP_EXT_CTRL_FINAL 0x00000002
> +#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
> +
> +#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
> +#define L2CAP_EXT_CTRL_SAR_SHIFT 16
> +#define L2CAP_EXT_CTRL_SUPER_SHIFT 16
> +#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
> +
> +/* L2CAP Supervisory Function */
> +#define L2CAP_SUPER_RR 0x00
> +#define L2CAP_SUPER_REJ 0x01
> +#define L2CAP_SUPER_RNR 0x02
> +#define L2CAP_SUPER_SREJ 0x03
> +
> +/* L2CAP Segmentation and Reassembly */
> +#define L2CAP_SAR_UNSEGMENTED 0x00
> +#define L2CAP_SAR_START 0x01
> +#define L2CAP_SAR_END 0x02
> +#define L2CAP_SAR_CONTINUE 0x03
> +
> #define MAX_CHAN 64
>
> struct chan_data {
> @@ -307,6 +349,73 @@ static uint8_t get_ext_ctrl(const struct l2cap_frame *frame)
> return 0;
> }
>
> +static char *sar2str(uint8_t sar)
> +{
> + switch (sar) {
> + case L2CAP_SAR_UNSEGMENTED:
> + return "Unsegmented";
> + case L2CAP_SAR_START:
> + return "Start";
> + case L2CAP_SAR_END:
> + return "End";
> + case L2CAP_SAR_CONTINUE:
> + return "Continuation";
> + default:
> + return "Bad SAR";
> + }
> +}
> +
> +static char *supervisory2str(uint8_t supervisory)
> +{
> + switch (supervisory) {
> + case L2CAP_SUPER_RR:
> + return "Receiver Ready (RR)";
> + case L2CAP_SUPER_REJ:
> + return "Reject (REJ)";
> + case L2CAP_SUPER_RNR:
> + return "Receiver Not Ready (RNR)";
> + case L2CAP_SUPER_SREJ:
> + return "Select Reject (SREJ)";
> + default:
> + return "Bad Supervisory";
> + }
> +}
> +
> +static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
> +{
> + printf(" %s:",
> + ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
> +
> + if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
> + printf(" %s",
> + supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
> + L2CAP_EXT_CTRL_SUPER_SHIFT));
> +
> + if (ctrl & L2CAP_EXT_CTRL_POLL)
> + printf(" P-bit");
> + } else {
> + uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
> + L2CAP_EXT_CTRL_SAR_SHIFT;
> + printf(" %s", sar2str(sar));
> + if (sar == L2CAP_SAR_START) {
> + uint16_t len;
> +
> + if (!l2cap_frame_get_le16(frame, &len))
> + return;
> +
> + printf(" (len %d)", len);
> + }
> + printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
> + L2CAP_EXT_CTRL_TXSEQ_SHIFT);
> + }
> +
> + printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
> + L2CAP_EXT_CTRL_REQSEQ_SHIFT);
> +
> + if (ctrl & L2CAP_EXT_CTRL_FINAL)
> + printf(" F-bit");
> +}
> +
> #define MAX_INDEX 16
>
> struct index_data {
> @@ -2786,6 +2895,8 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
> " [PSM %d mode %d] {chan %d}",
> cid, size, ctrl32, frame.psm,
> frame.mode, frame.chan);
> +
> + l2cap_ctrl_ext_parse(&frame, ctrl32);
> } else {
> if (!l2cap_frame_get_le16(&frame, &ctrl16))
> return;
> --
> 1.9.1


WARNING:SPACE_BEFORE_TAB: please, no space before tabs
#46: FILE: monitor/l2cap.c:84:
+#define L2CAP_SAR_UNSEGMENTED ^I0x00$


--
Luiz Augusto von Dentz

2015-01-07 13:24:46

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH 6/6] monitor: Add AVRCP SetBrowsedPlayer support

Hi Vikram,

On Wed, Jan 7, 2015 at 6:23 AM, Vikrampal Yadav <[email protected]> wrote:
> Support for decoding AVRCP SetBrowsedPlayer added in Bluetooth monitor.
>
> Channel: 65 len 12 ctrl 0x0102 [PSM 27 mode 3] {chan 1}
> I-frame: Unsegmented TxSeq 1 ReqSeq 1
> AVCTP Browsing: Command: type 0x00 label 0 PID 0x110e
> AVRCP: SetBrowsedPlayer: len 0x0002
> PlayerID: 0x0001 (1)

Can you please add the response frame as well.

> ---
> monitor/avctp.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 85 insertions(+), 1 deletion(-)
>
> diff --git a/monitor/avctp.c b/monitor/avctp.c
> index af91ecc..0a1e92d 100644
> --- a/monitor/avctp.c
> +++ b/monitor/avctp.c
> @@ -1637,11 +1637,95 @@ static bool avrcp_control_packet(struct avctp_frame *avctp_frame)
> }
> }
>
> +static bool avrcp_set_browsed_player(struct avctp_frame *avctp_frame)
> +{
> + struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
> + uint32_t items;
> + uint16_t id, uids, charset;
> + uint8_t status, folders, indent = 2;
> +
> + if (avctp_frame->hdr & 0x02)
> + goto response;
> +
> + if (!l2cap_frame_get_be16(frame, &id))
> + return false;
> +
> + print_field("%*cPlayerID: 0x%04x (%u)", indent, ' ', id, id);
> + return true;
> +
> +response:
> + if (!l2cap_frame_get_u8(frame, &status))
> + return false;
> +
> + print_field("%*cStatus: 0x%02x (%s)", indent, ' ', status,
> + error2str(status));
> +
> + if (!l2cap_frame_get_be16(frame, &uids))
> + return false;
> +
> + print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ', uids, uids);
> +
> + if (!l2cap_frame_get_be32(frame, &items))
> + return false;
> +
> + print_field("%*cNumber of Items: 0x%08x (%u)", indent, ' ',
> + items, items);
> +
> + if (!l2cap_frame_get_be16(frame, &charset))
> + return false;
> +
> + print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ', charset,
> + charset2str(charset));
> +
> + if (!l2cap_frame_get_u8(frame, &folders))
> + return false;
> +
> + print_field("%*cFolder Depth: 0x%02x (%u)", indent, ' ', folders,
> + folders);
> +
> + for (; folders > 0; folders--) {
> + uint8_t len;
> +
> + if (!l2cap_frame_get_u8(frame, &len))
> + return false;
> +
> + printf("Folder: ");
> + for (; len > 0; len--) {
> + uint8_t c;
> +
> + if (!l2cap_frame_get_u8(frame, &c))
> + return false;
> +
> + printf("%1c", isprint(c) ? c : '.');
> + }
> + printf("\n");
> + }
> +
> + return true;
> +}
> +
> static bool avrcp_browsing_packet(struct avctp_frame *avctp_frame)
> {
> struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
> + uint16_t len;
> + uint8_t pduid;
> +
> + if (!l2cap_frame_get_u8(frame, &pduid))
> + return false;
> +
> + if (!l2cap_frame_get_be16(frame, &len))
> + return false;
> +
> + print_field("AVRCP: %s: len 0x%04x", pdu2str(pduid), len);
> +
> + switch (pduid) {
> + case AVRCP_SET_BROWSED_PLAYER:
> + avrcp_set_browsed_player(avctp_frame);
> + break;
> + default:
> + packet_hexdump(frame->data, frame->size);
> + }
>
> - packet_hexdump(frame->data, frame->size);
> return true;
> }
>
> --
> 1.9.1
>



--
Luiz Augusto von Dentz

2015-01-07 08:23:20

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 6/6] monitor: Add AVRCP SetBrowsedPlayer support

Support for decoding AVRCP SetBrowsedPlayer added in Bluetooth monitor.

Channel: 65 len 12 ctrl 0x0102 [PSM 27 mode 3] {chan 1}
I-frame: Unsegmented TxSeq 1 ReqSeq 1
AVCTP Browsing: Command: type 0x00 label 0 PID 0x110e
AVRCP: SetBrowsedPlayer: len 0x0002
PlayerID: 0x0001 (1)
---
monitor/avctp.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/monitor/avctp.c b/monitor/avctp.c
index af91ecc..0a1e92d 100644
--- a/monitor/avctp.c
+++ b/monitor/avctp.c
@@ -1637,11 +1637,95 @@ static bool avrcp_control_packet(struct avctp_frame *avctp_frame)
}
}

+static bool avrcp_set_browsed_player(struct avctp_frame *avctp_frame)
+{
+ struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint32_t items;
+ uint16_t id, uids, charset;
+ uint8_t status, folders, indent = 2;
+
+ if (avctp_frame->hdr & 0x02)
+ goto response;
+
+ if (!l2cap_frame_get_be16(frame, &id))
+ return false;
+
+ print_field("%*cPlayerID: 0x%04x (%u)", indent, ' ', id, id);
+ return true;
+
+response:
+ if (!l2cap_frame_get_u8(frame, &status))
+ return false;
+
+ print_field("%*cStatus: 0x%02x (%s)", indent, ' ', status,
+ error2str(status));
+
+ if (!l2cap_frame_get_be16(frame, &uids))
+ return false;
+
+ print_field("%*cUIDCounter: 0x%04x (%u)", indent, ' ', uids, uids);
+
+ if (!l2cap_frame_get_be32(frame, &items))
+ return false;
+
+ print_field("%*cNumber of Items: 0x%08x (%u)", indent, ' ',
+ items, items);
+
+ if (!l2cap_frame_get_be16(frame, &charset))
+ return false;
+
+ print_field("%*cCharsetID: 0x%04x (%s)", indent, ' ', charset,
+ charset2str(charset));
+
+ if (!l2cap_frame_get_u8(frame, &folders))
+ return false;
+
+ print_field("%*cFolder Depth: 0x%02x (%u)", indent, ' ', folders,
+ folders);
+
+ for (; folders > 0; folders--) {
+ uint8_t len;
+
+ if (!l2cap_frame_get_u8(frame, &len))
+ return false;
+
+ printf("Folder: ");
+ for (; len > 0; len--) {
+ uint8_t c;
+
+ if (!l2cap_frame_get_u8(frame, &c))
+ return false;
+
+ printf("%1c", isprint(c) ? c : '.');
+ }
+ printf("\n");
+ }
+
+ return true;
+}
+
static bool avrcp_browsing_packet(struct avctp_frame *avctp_frame)
{
struct l2cap_frame *frame = &avctp_frame->l2cap_frame;
+ uint16_t len;
+ uint8_t pduid;
+
+ if (!l2cap_frame_get_u8(frame, &pduid))
+ return false;
+
+ if (!l2cap_frame_get_be16(frame, &len))
+ return false;
+
+ print_field("AVRCP: %s: len 0x%04x", pdu2str(pduid), len);
+
+ switch (pduid) {
+ case AVRCP_SET_BROWSED_PLAYER:
+ avrcp_set_browsed_player(avctp_frame);
+ break;
+ default:
+ packet_hexdump(frame->data, frame->size);
+ }

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

--
1.9.1


2015-01-07 08:23:19

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 5/6] monitor: Add support for parsing L2CAP control field

Support for parsing L2CAP control field added.
---
monitor/l2cap.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 17104e2..19cb0a2 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -416,6 +416,38 @@ static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
printf(" F-bit");
}

+static void l2cap_ctrl_parse(struct l2cap_frame *frame, uint32_t ctrl)
+{
+ printf(" %s:",
+ ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
+
+ if (ctrl & 0x01) {
+ printf(" %s",
+ supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
+ L2CAP_CTRL_SUPER_SHIFT));
+
+ if (ctrl & L2CAP_CTRL_POLL)
+ printf(" P-bit");
+ } else {
+ uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
+ printf(" %s", sar2str(sar));
+ if (sar == L2CAP_SAR_START) {
+ uint16_t len;
+
+ if (!l2cap_frame_get_le16(frame, &len))
+ return;
+
+ printf(" (len %d)", len);
+ }
+ printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> L2CAP_CTRL_TXSEQ_SHIFT);
+ }
+
+ printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >> L2CAP_CTRL_REQSEQ_SHIFT);
+
+ if (ctrl & L2CAP_CTRL_FINAL)
+ printf(" F-bit");
+}
+
#define MAX_INDEX 16

struct index_data {
@@ -2907,6 +2939,8 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
" [PSM %d mode %d] {chan %d}",
cid, size, ctrl16, frame.psm,
frame.mode, frame.chan);
+
+ l2cap_ctrl_parse(&frame, ctrl16);
}

printf("\n");
--
1.9.1


2015-01-07 08:23:18

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 4/6] monitor: Add support for parsing L2CAP extended control field

Support for parsing L2CAP extended control field added.
---
monitor/l2cap.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 5f135b0..17104e2 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -44,6 +44,48 @@
#include "avctp.h"
#include "rfcomm.h"

+/* L2CAP Control Field bit masks */
+#define L2CAP_CTRL_SAR_MASK 0xC000
+#define L2CAP_CTRL_REQSEQ_MASK 0x3F00
+#define L2CAP_CTRL_TXSEQ_MASK 0x007E
+#define L2CAP_CTRL_SUPERVISE_MASK 0x000C
+
+#define L2CAP_CTRL_RETRANS 0x0080
+#define L2CAP_CTRL_FINAL 0x0080
+#define L2CAP_CTRL_POLL 0x0010
+#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT 1
+#define L2CAP_CTRL_SUPER_SHIFT 2
+#define L2CAP_CTRL_REQSEQ_SHIFT 8
+#define L2CAP_CTRL_SAR_SHIFT 14
+
+#define L2CAP_EXT_CTRL_TXSEQ_MASK 0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR_MASK 0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE_MASK 0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ_MASK 0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL 0x00040000
+#define L2CAP_EXT_CTRL_FINAL 0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
+#define L2CAP_EXT_CTRL_SAR_SHIFT 16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT 16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
+
+/* L2CAP Supervisory Function */
+#define L2CAP_SUPER_RR 0x00
+#define L2CAP_SUPER_REJ 0x01
+#define L2CAP_SUPER_RNR 0x02
+#define L2CAP_SUPER_SREJ 0x03
+
+/* L2CAP Segmentation and Reassembly */
+#define L2CAP_SAR_UNSEGMENTED 0x00
+#define L2CAP_SAR_START 0x01
+#define L2CAP_SAR_END 0x02
+#define L2CAP_SAR_CONTINUE 0x03
+
#define MAX_CHAN 64

struct chan_data {
@@ -307,6 +349,73 @@ static uint8_t get_ext_ctrl(const struct l2cap_frame *frame)
return 0;
}

+static char *sar2str(uint8_t sar)
+{
+ switch (sar) {
+ case L2CAP_SAR_UNSEGMENTED:
+ return "Unsegmented";
+ case L2CAP_SAR_START:
+ return "Start";
+ case L2CAP_SAR_END:
+ return "End";
+ case L2CAP_SAR_CONTINUE:
+ return "Continuation";
+ default:
+ return "Bad SAR";
+ }
+}
+
+static char *supervisory2str(uint8_t supervisory)
+{
+ switch (supervisory) {
+ case L2CAP_SUPER_RR:
+ return "Receiver Ready (RR)";
+ case L2CAP_SUPER_REJ:
+ return "Reject (REJ)";
+ case L2CAP_SUPER_RNR:
+ return "Receiver Not Ready (RNR)";
+ case L2CAP_SUPER_SREJ:
+ return "Select Reject (SREJ)";
+ default:
+ return "Bad Supervisory";
+ }
+}
+
+static void l2cap_ctrl_ext_parse(struct l2cap_frame *frame, uint32_t ctrl)
+{
+ printf(" %s:",
+ ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
+
+ if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
+ printf(" %s",
+ supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
+ L2CAP_EXT_CTRL_SUPER_SHIFT));
+
+ if (ctrl & L2CAP_EXT_CTRL_POLL)
+ printf(" P-bit");
+ } else {
+ uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
+ L2CAP_EXT_CTRL_SAR_SHIFT;
+ printf(" %s", sar2str(sar));
+ if (sar == L2CAP_SAR_START) {
+ uint16_t len;
+
+ if (!l2cap_frame_get_le16(frame, &len))
+ return;
+
+ printf(" (len %d)", len);
+ }
+ printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
+ L2CAP_EXT_CTRL_TXSEQ_SHIFT);
+ }
+
+ printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
+ L2CAP_EXT_CTRL_REQSEQ_SHIFT);
+
+ if (ctrl & L2CAP_EXT_CTRL_FINAL)
+ printf(" F-bit");
+}
+
#define MAX_INDEX 16

struct index_data {
@@ -2786,6 +2895,8 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
" [PSM %d mode %d] {chan %d}",
cid, size, ctrl32, frame.psm,
frame.mode, frame.chan);
+
+ l2cap_ctrl_ext_parse(&frame, ctrl32);
} else {
if (!l2cap_frame_get_le16(&frame, &ctrl16))
return;
--
1.9.1


2015-01-07 08:23:17

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 3/6] monitor: Extract extended L2CAP extended control field

Support for extracting extended L2CAP extended control field.
---
monitor/l2cap.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 58 insertions(+), 2 deletions(-)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index c0bc9a8..5f135b0 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -282,6 +282,31 @@ static void assign_ext_ctrl(const struct l2cap_frame *frame,
}
}

+static uint8_t get_ext_ctrl(const struct l2cap_frame *frame)
+{
+ int i;
+
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (chan_list[i].index != frame->index &&
+ chan_list[i].ctrlid == 0)
+ continue;
+
+ if (chan_list[i].handle != frame->handle &&
+ chan_list[i].ctrlid != frame->index)
+ continue;
+
+ if (frame->in) {
+ if (chan_list[i].scid == frame->cid)
+ return chan_list[i].ext_ctrl;
+ } else {
+ if (chan_list[i].dcid == frame->cid)
+ return chan_list[i].ext_ctrl;
+ }
+ }
+
+ return 0;
+}
+
#define MAX_INDEX 16

struct index_data {
@@ -2721,6 +2746,9 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
uint16_t cid, const void *data, uint16_t size)
{
struct l2cap_frame frame;
+ uint32_t ctrl32 = 0;
+ uint16_t ctrl16 = 0;
+ uint8_t ext_ctrl;

switch (cid) {
case 0x0001:
@@ -2745,10 +2773,38 @@ static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
default:
l2cap_frame_init(&frame, index, in, handle, cid, data, size);

- print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
- " %d len %d [PSM %d mode %d] {chan %d}",
+ if (frame.mode > 0) {
+ ext_ctrl = get_ext_ctrl(&frame);
+
+ if (ext_ctrl) {
+ if (!l2cap_frame_get_le32(&frame, &ctrl32))
+ return;
+
+ print_indent(6, COLOR_CYAN, "Channel:", "",
+ COLOR_OFF, " %d len %d"
+ " ext_ctrl 0x%8.8x"
+ " [PSM %d mode %d] {chan %d}",
+ cid, size, ctrl32, frame.psm,
+ frame.mode, frame.chan);
+ } else {
+ if (!l2cap_frame_get_le16(&frame, &ctrl16))
+ return;
+
+ print_indent(6, COLOR_CYAN, "Channel:", "",
+ COLOR_OFF, " %d len %d"
+ " ctrl 0x%4.4x"
+ " [PSM %d mode %d] {chan %d}",
+ cid, size, ctrl16, frame.psm,
+ frame.mode, frame.chan);
+ }
+
+ printf("\n");
+ } else {
+ print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
+ " %d len %d [PSM %d mode %d] {chan %d}",
cid, size, frame.psm,
frame.mode, frame.chan);
+ }

switch (frame.psm) {
case 0x0001:
--
1.9.1


2015-01-07 08:23:16

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 2/6] monitor: Add functionality to store extented control in DB

A function added to store extented control in DB.
---
monitor/l2cap.c | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index a09bbbc..c0bc9a8 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -54,6 +54,7 @@ struct chan_data {
uint16_t psm;
uint8_t ctrlid;
uint8_t mode;
+ uint8_t ext_ctrl;
};

static struct chan_data chan_list[MAX_CHAN];
@@ -255,6 +256,32 @@ static uint16_t get_chan(const struct l2cap_frame *frame)
return 0;
}

+static void assign_ext_ctrl(const struct l2cap_frame *frame,
+ uint8_t ext_ctrl, uint16_t dcid)
+{
+ int i;
+
+ for (i = 0; i < MAX_CHAN; i++) {
+ if (chan_list[i].index != frame->index)
+ continue;
+
+ if (chan_list[i].handle != frame->handle)
+ continue;
+
+ if (frame->in) {
+ if (chan_list[i].scid == dcid) {
+ chan_list[i].ext_ctrl = ext_ctrl;
+ break;
+ }
+ } else {
+ if (chan_list[i].dcid == dcid) {
+ chan_list[i].ext_ctrl = ext_ctrl;
+ break;
+ }
+ }
+ }
+}
+
#define MAX_INDEX 16

struct index_data {
@@ -573,8 +600,9 @@ static void print_config_options(const struct l2cap_frame *frame,
get_le32(data + consumed + 14));
break;
case 0x07:
- print_field(" Max window size: %d",
+ print_field(" Extended window size: %d",
get_le16(data + consumed + 2));
+ assign_ext_ctrl(frame, 1, cid);
break;
default:
packet_hexdump(data + consumed + 2, len);
--
1.9.1


2015-01-07 08:23:15

by Vikrampal Yadav

[permalink] [raw]
Subject: [PATCH 1/6] monitor: Make the parameter name generic

Changed dcid to cid to make it sound generic as this function is called
with both dcid and scid.
---
monitor/l2cap.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/monitor/l2cap.c b/monitor/l2cap.c
index 0b6f752..a09bbbc 100644
--- a/monitor/l2cap.c
+++ b/monitor/l2cap.c
@@ -421,7 +421,7 @@ static struct {
};

static void print_config_options(const struct l2cap_frame *frame,
- uint8_t offset, uint16_t dcid, bool response)
+ uint8_t offset, uint16_t cid, bool response)
{
const uint8_t *data = frame->data + offset;
uint16_t size = frame->size - offset;
@@ -496,7 +496,7 @@ static void print_config_options(const struct l2cap_frame *frame,
break;
case 0x04:
if (response)
- assign_mode(frame, data[consumed + 2], dcid);
+ assign_mode(frame, data[consumed + 2], cid);

switch (data[consumed + 2]) {
case 0x00:
--
1.9.1