This patchset adds parsing and display of BT 3.0+HS signalling
Peter Krystad (4):
Add parsing of L2CAP Create/Move Channel signals
Add parsing of A2MP signals
Add parsing of L2CAP Fixed Channel list
Minor cleanup of indentation in output
lib/amp.h | 133 +++++++++++++++
lib/l2cap.h | 50 ++++++
parser/hci.c | 15 +-
parser/l2cap.c | 498 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
parser/parser.h | 1 +
src/hcidump.c | 1 +
6 files changed, 693 insertions(+), 5 deletions(-)
create mode 100644 lib/amp.h
--
1.7.7
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Hi Andrei,
> >
> > +static inline void amp_command_rej(int level, struct frame *frm)
> > +{
> > + amp_cmd_rej_parms *h = frm->ptr;
> > + uint16_t reason = btohs(h->reason);
> > +
> > + if (p_filter(FILT_A2MP))
> > + return;
> > +
> > + printf("Command Reject: reason (%d)- ", reason);
> > + p_indent(level + 1, frm);
>
> This doesn't make sense to use p_indent if you print on the same line.
> Maybe you forgot "\n" ?
>
> > + printf("%s\n", ampreason2str(reason));
> > +}
> > +
>
Will add a '\n'.
I'll repost this patch set after the bluez header patchset is approved.
Peter.
--Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Hi Peter,
On Fri, Oct 21, 2011 at 04:30:00PM -0700, Peter Krystad wrote:
...
> @@ -923,6 +1004,240 @@ static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm
> printf("Move cfm rsp: icid 0x%4.4x\n", icid);
> }
>
> +static inline void amp_command_rej(int level, struct frame *frm)
> +{
> + amp_cmd_rej_parms *h = frm->ptr;
> + uint16_t reason = btohs(h->reason);
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Command Reject: reason (%d)- ", reason);
> + p_indent(level + 1, frm);
This doesn't make sense to use p_indent if you print on the same line.
Maybe you forgot "\n" ?
> + printf("%s\n", ampreason2str(reason));
> +}
> +
Best regards
Andrei Emeltchenko
Hi Peter,
On Fri, Oct 21, 2011 at 04:30:01PM -0700, Peter Krystad wrote:
> Add DUMP_VERBOSE display of L2CAP Fixed Channel list.
> Example output:
>
> 2011-10-21 12:01:50.423246 > ACL data: handle 39 flags 0x02 dlen 20
> L2CAP(s): Info rsp: type 3 result 0
> Fixed channel list
> L2CAP
> CONNLESS
> A2MP
We can be more specific here since each channel is printed on new line
> ---
> parser/l2cap.c | 16 ++++++++++++++++
> 1 files changed, 16 insertions(+), 0 deletions(-)
>
> diff --git a/parser/l2cap.c b/parser/l2cap.c
> index 7915788..ce78d05 100644
> --- a/parser/l2cap.c
> +++ b/parser/l2cap.c
> @@ -811,6 +811,7 @@ static void info_opt(int level, int type, void *ptr, int len)
> {
> uint32_t mask;
> int i;
> + uint8_t list;
>
> p_indent(level, 0);
>
> @@ -830,6 +831,21 @@ static void info_opt(int level, int type, void *ptr, int len)
> break;
> case 0x0003:
> printf("Fixed channel list\n");
> + list = get_val(ptr, 1);
We had discussion about this with Mat Martineau and agreed that we read 8
octets (there is one bit in 8th octet - AMP test manager)
> + if (parser.flags & DUMP_VERBOSE) {
> + if (list & L2CAP_FC_L2CAP) {
> + p_indent(level + 1, 0);
> + printf("L2CAP\n");
> + }
> + if (list & L2CAP_FC_CONNLESS) {
> + p_indent(level + 1, 0);
> + printf("CONNLESS\n");
> + }
> + if (list & L2CAP_FC_A2MP) {
> + p_indent(level + 1, 0);
> + printf("A2MP\n");
> + }
> + }
I know that this is common in hcidump but I do not like current approach.
I have sent similar patch and the difference (beyond mentioned above) is
that I define decode table:
+static struct features l2cap_fix_chan[] = {
+ { "L2CAP Signalling Channel", L2CAP_FC_L2CAP },
+ { "L2CAP Connless", L2CAP_FC_CONNLESS },
+ { "AMP Manager Protocol", L2CAP_FC_A2MP },
+ { 0 }
+};
then:
+ if (parser.flags & DUMP_VERBOSE)
+ for (i=0; l2cap_fix_chan[i].name; i++)
+ if (fc_mask & l2cap_fix_chan[i].flag) {
+ p_indent(level + 1, 0);
+ printf("%s\n", l2cap_fix_chan[i].name);
+ }
http://www.spinics.net/lists/linux-bluetooth/msg17247.html
This is the way how it is done is wireshark network packet analyzer.
Then if you want to add one extra feature (like AMP test manager) => you
just add new table entry. Otherwise you have to create new "if" branch.
Best regards
Andrei Emeltchenko
Hi Peter,
On Fri, Oct 21, 2011 at 04:30:00PM -0700, Peter Krystad wrote:
> Add parsing of A2MP signalling.
> Example output:
>
> 2011-10-18 16:09:44.493202 > ACL data: handle 39 flags 0x02 dlen 16
> A2MP: Discover req: mtu/mps 670 mask: 0x0000
> 2011-10-18 16:09:44.493404 < ACL data: handle 39 flags 0x00 dlen 22
> A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
> Controller list:
> id 0, type 0, status 0x01 (Bluetooth only)
> id 17, type 254, status 0x06 (Full capacity)
> 2011-10-18 16:09:44.697203 > ACL data: handle 39 flags 0x02 dlen 13
> A2MP: Get Info req: id 17
> 2011-10-18 16:09:44.697312 < ACL data: handle 39 flags 0x00 dlen 30
> A2MP: Get Info rsp: id 17 status (0) Success
> total bandwidth 500000
> max guaranteed bandwidth 0
> min latency 100000
> pal capabilities 0x0000
> assoc size 8
> 2011-10-18 16:09:44.893203 > ACL data: handle 39 flags 0x02 dlen 13
> A2MP: Get AMP Assoc req: id 17
> 2011-10-18 16:09:44.893618 < ACL data: handle 39 flags 0x00 dlen 22
> A2MP: Get AMP Assoc rsp: id 17 status (0) Success
> assoc data:
> 08 01 b1 01 0a 04 6c 42
> 2011-10-18 16:09:45.598201 > ACL data: handle 39 flags 0x02 dlen 22
> A2MP: Create Physical Link req: local id 1 remote id 17
> assoc data:
> 08 01 b1 01 0a 04 6d 38
> 2011-10-18 16:09:45.598643 < ACL data: handle 39 flags 0x00 dlen 15
> A2MP: Create Physical Link rsp: local id 17 remote id 1 status 0
> Success
> ---
> lib/amp.h | 133 +++++++++++++++++++
> parser/l2cap.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> parser/parser.h | 1 +
> src/hcidump.c | 1 +
> 4 files changed, 520 insertions(+), 0 deletions(-)
> create mode 100644 lib/amp.h
>
> diff --git a/lib/amp.h b/lib/amp.h
Minor comments. Would it be better to name it a2mp.h and functions below a2mp_*?
Otherwise as Marcel mentioned header patches shall be applied first to
bluez.
Best regards
Andrei Emeltchenko
> new file mode 100644
> index 0000000..0c6300a
> --- /dev/null
> +++ b/lib/amp.h
> @@ -0,0 +1,133 @@
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2010-2011 Code Aurora Forum. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program 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 General Public License for more details.
> + *
> + */
> +
> +#ifndef __AMP_H
> +#define __AMP_H
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#define AMP_MGR_CID 0x03
> +
> +/* AMP manager codes */
> +#define AMP_COMMAND_REJ 0x01
> +#define AMP_DISCOVER_REQ 0x02
> +#define AMP_DISCOVER_RSP 0x03
> +#define AMP_CHANGE_NOTIFY 0x04
> +#define AMP_CHANGE_RSP 0x05
> +#define AMP_INFO_REQ 0x06
> +#define AMP_INFO_RSP 0x07
> +#define AMP_ASSOC_REQ 0x08
> +#define AMP_ASSOC_RSP 0x09
> +#define AMP_LINK_REQ 0x0a
> +#define AMP_LINK_RSP 0x0b
> +#define AMP_DISCONN_REQ 0x0c
> +#define AMP_DISCONN_RSP 0x0d
> +
> +typedef struct {
> + uint8_t code;
> + uint8_t ident;
> + uint16_t len;
> +} __attribute__ ((packed)) amp_mgr_hdr;
> +#define AMP_MGR_HDR_SIZE 4
> +
> +/* AMP ASSOC structure */
> +typedef struct {
> + uint8_t type_id;
> + uint16_t len;
> + uint8_t data[0];
> +} __attribute__ ((packed)) amp_assoc_tlv;
> +
> +typedef struct {
> + uint16_t reason;
> +} __attribute__ ((packed)) amp_cmd_rej_parms;
> +
> +typedef struct {
> + uint16_t mtu;
> + uint16_t mask;
> +} __attribute__ ((packed)) amp_discover_req_parms;
> +
> +typedef struct {
> + uint16_t mtu;
> + uint16_t mask;
> + uint8_t controller_list[0];
> +} __attribute__ ((packed)) amp_discover_rsp_parms;
> +
> +typedef struct {
> + uint8_t id;
> +} __attribute__ ((packed)) amp_info_req_parms;
> +
> +typedef struct {
> + uint8_t id;
> + uint8_t status;
> + uint32_t total_bandwidth;
> + uint32_t max_bandwidth;
> + uint32_t min_latency;
> + uint16_t pal_caps;
> + uint16_t assoc_size;
> +} __attribute__ ((packed)) amp_info_rsp_parms;
> +
> +typedef struct {
> + uint8_t id;
> + uint8_t status;
> + amp_assoc_tlv assoc;
> +} __attribute__ ((packed)) amp_assoc_rsp_parms;
> +
> +typedef struct {
> + uint8_t local_id;
> + uint8_t remote_id;
> + amp_assoc_tlv assoc;
> +} __attribute__ ((packed)) amp_link_req_parms;
> +
> +typedef struct {
> + uint8_t local_id;
> + uint8_t remote_id;
> + uint8_t status;
> +} __attribute__ ((packed)) amp_link_rsp_parms;
> +
> +typedef struct {
> + uint8_t local_id;
> + uint8_t remote_id;
> +} __attribute__ ((packed)) amp_disconn_req_parms;
> +
> +#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
> +
> +/* AMP controller status */
> +#define AMP_CT_POWERED_DOWN 0x00
> +#define AMP_CT_BLUETOOTH_ONLY 0x01
> +#define AMP_CT_NO_CAPACITY 0x02
> +#define AMP_CT_LOW_CAPACITY 0x03
> +#define AMP_CT_MEDIUM_CAPACITY 0x04
> +#define AMP_CT_HIGH_CAPACITY 0x05
> +#define AMP_CT_FULL_CAPACITY 0x06
> +
> +/* AMP response status */
> +#define AMP_STATUS_SUCCESS 0x00
> +#define AMP_STATUS_INVALID_CTRL_ID 0x01
> +#define AMP_STATUS_UNABLE_START_LINK_CREATION 0x02
> +#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
> +#define AMP_STATUS_COLLISION_OCCURED 0x03
> +#define AMP_STATUS_DISCONN_REQ_RECVD 0x04
> +#define AMP_STATUS_PHYS_LINK_EXISTS 0x05
> +#define AMP_STATUS_SECURITY_VIOLATION 0x06
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* __AMP_H */
> diff --git a/parser/l2cap.c b/parser/l2cap.c
> index 7547e8b..7915788 100644
> --- a/parser/l2cap.c
> +++ b/parser/l2cap.c
> @@ -36,6 +36,7 @@
> #include "parser/sdp.h"
> #include "lib/hci.h"
> #include "lib/l2cap.h"
> +#include "lib/amp.h"
>
> typedef struct {
> uint16_t handle;
> @@ -259,6 +260,16 @@ static char *reason2str(uint16_t reason)
> }
> }
>
> +static char *ampreason2str(uint16_t reason)
> +{
> + switch (reason) {
> + case AMP_COMMAND_NOT_RECOGNIZED:
> + return "Command not recognized";
> + default:
> + return "Reserved";
> + }
> +}
> +
> static char *connresult2str(uint16_t result)
> {
> switch (result) {
> @@ -399,6 +410,76 @@ static char *supervisory2str(uint8_t supervisory)
> }
> }
>
> +static char *ampctstatus2str(uint8_t status)
> +{
> + switch (status) {
> + case AMP_CT_POWERED_DOWN:
> + return "Powered down";
> + case AMP_CT_BLUETOOTH_ONLY:
> + return "Bluetooth only";
> + case AMP_CT_NO_CAPACITY:
> + return "No capacity";
> + case AMP_CT_LOW_CAPACITY:
> + return "Low capacity";
> + case AMP_CT_MEDIUM_CAPACITY:
> + return "Medium capacity";
> + case AMP_CT_HIGH_CAPACITY:
> + return "High capacity";
> + case AMP_CT_FULL_CAPACITY:
> + return "Full capacity";
> + default:
> + return "Reserved";
> +
> + }
> +}
> +
> +static char *ampstatus2str(uint8_t status)
> +{
> + switch (status) {
> + case AMP_STATUS_SUCCESS:
> + return "Success";
> + case AMP_STATUS_INVALID_CTRL_ID:
> + return "Invalid Controller ID";
> + default:
> + return "Reserved";
> + }
> +}
> +
> +static char *ampcplstatus2str(uint8_t status)
> +{
> + switch (status) {
> + case AMP_STATUS_SUCCESS:
> + return "Success";
> + case AMP_STATUS_INVALID_CTRL_ID:
> + return "Invalid Controller ID";
> + case AMP_STATUS_UNABLE_START_LINK_CREATION:
> + return "Failed - Unable to start link creation";
> + case AMP_STATUS_COLLISION_OCCURED:
> + return "Failed - Collision occured";
> + case AMP_STATUS_DISCONN_REQ_RECVD:
> + return "Failed - Disconnect physical link received";
> + case AMP_STATUS_PHYS_LINK_EXISTS:
> + return "Failed - Physical link already exists";
> + case AMP_STATUS_SECURITY_VIOLATION:
> + return "Failed - Security violation";
> + default:
> + return "Reserved";
> + }
> +}
> +
> +static char *ampdplstatus2str(uint8_t status)
> +{
> + switch (status) {
> + case AMP_STATUS_SUCCESS:
> + return "Success";
> + case AMP_STATUS_INVALID_CTRL_ID:
> + return "Invalid Controller ID";
> + case AMP_STATUS_NO_PHYSICAL_LINK_EXISTS:
> + return "Failed - No Physical Link exists";
> + default:
> + return "Reserved";
> + }
> +}
>
> static inline void command_rej(int level, struct frame *frm)
> {
> @@ -923,6 +1004,240 @@ static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm
> printf("Move cfm rsp: icid 0x%4.4x\n", icid);
> }
>
> +static inline void amp_command_rej(int level, struct frame *frm)
> +{
> + amp_cmd_rej_parms *h = frm->ptr;
> + uint16_t reason = btohs(h->reason);
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Command Reject: reason (%d)- ", reason);
> + p_indent(level + 1, frm);
> + printf("%s\n", ampreason2str(reason));
> +}
> +
> +static inline void amp_discover_req(int level, struct frame *frm, uint16_t len)
> +{
> + amp_discover_req_parms *h = frm->ptr;
> + uint16_t mtu = btohs(h->mtu);
> + uint8_t *octet = (uint8_t *)&(h->mask);
> + uint16_t mask;
> + uint8_t extension;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Discover req: mtu/mps %d ", mtu);
> + len -= 2;
> +
> + printf("mask:");
> +
> + do {
> + len -= 2;
> + mask = btohs(*(uint16_t *)(&octet[0]));
> + printf(" 0x%4.4x", mask);
> +
> + extension = octet[1] & 0x80;
> + octet += 2;
> + } while ((extension != 0) && (len >= 2));
> +
> + printf("\n");
> +}
> +
> +static inline void controller_list_dump (int level, uint8_t *octet, uint16_t len)
> +{
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + p_indent(level, 0);
> + printf("Controller list:\n");
> +
> + while (len >= 3) {
> + p_indent(level + 1, 0);
> + printf("id %d, type %d, status 0x%2.2x (%s)\n",
> + octet[0], octet[1], octet[2], ampctstatus2str(octet[2]));
> + octet += 3;
> + len -= 3;
> + }
> +
> +}
> +
> +static inline void amp_discover_rsp(int level, struct frame *frm, uint16_t len)
> +{
> + amp_discover_rsp_parms *h = frm->ptr;
> + uint16_t mtu = btohs(h->mtu);
> + uint8_t *octet = (uint8_t *)&(h->mask);
> + uint16_t mask;
> + uint8_t extension;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Discover rsp: mtu/mps %d ", mtu);
> + len -= 2;
> +
> + printf("mask:");
> +
> + do {
> + len -= 2;
> + mask = btohs(*(uint16_t *)(&octet[0]));
> + printf(" 0x%4.4x", mask);
> +
> + extension = octet[1] & 0x80;
> + octet += 2;
> + } while ((extension != 0) && (len >= 2));
> +
> + printf("\n");
> +
> + if (len >= 3) {
> + controller_list_dump (level + 1, octet, len);
> + }
> +}
> +
> +static inline void amp_change_notify(int level, struct frame *frm, uint16_t len)
> +{
> + uint8_t *octet = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Change Notify\n");
> +
> + if (len >= 3) {
> + controller_list_dump (level + 1, octet, len);
> + }
> +}
> +
> +static inline void amp_change_rsp(int level, struct frame *frm)
> +{
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Change Response\n");
> +}
> +
> +static inline void amp_info_req(int level, struct frame *frm)
> +{
> + amp_info_req_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Get Info req: id %d\n", h->id);
> +}
> +
> +static inline void amp_info_rsp(int level, struct frame *frm)
> +{
> + amp_info_rsp_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Get Info rsp: id %d status (%d) %s\n",
> + h->id, h->status, ampstatus2str(h->status));
> +
> + p_indent(level + 1, frm);
> + printf("total bandwidth %d\n", btohl(h->total_bandwidth));
> + p_indent(level + 1, frm);
> + printf("max guaranteed bandwidth %d\n", btohl(h->max_bandwidth));
> + p_indent(level + 1, frm);
> + printf("min latency %d\n", btohl(h->min_latency));
> + p_indent(level + 1, frm);
> + printf("pal capabilities 0x%4.4x\n", btohs(h->pal_caps));
> + p_indent(level + 1, frm);
> + printf("assoc size %d\n", btohs(h->assoc_size));
> +}
> +
> +static inline void amp_assoc_req(int level, struct frame *frm)
> +{
> + amp_info_req_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Get AMP Assoc req: id %d\n", h->id);
> +}
> +
> +static inline void amp_assoc_dump(int level, uint8_t *assoc, uint16_t len)
> +{
> + int i;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + p_indent(level, 0);
> + printf("assoc data:");
> + for (i = 0; i < len; i++) {
> + if (!(i%16)) printf("\n");
> + if (!(i%16)) p_indent(level+1, 0);
> + printf("%2.2x ",*assoc++);
> + }
> + printf("\n");
> +
> +}
> +
> +static inline void amp_assoc_rsp(int level, struct frame *frm, uint16_t len)
> +{
> + amp_assoc_rsp_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Get AMP Assoc rsp: id %d status (%d) %s \n",
> + h->id, h->status, ampstatus2str(h->status));
> + amp_assoc_dump(level + 1, (uint8_t *) &h->assoc, len - 2);
> +}
> +
> +static inline void amp_link_req(int level, struct frame *frm, uint16_t len)
> +{
> + amp_link_req_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Create Physical Link req: local id %d remote id %d\n",
> + h->local_id, h->remote_id);
> + amp_assoc_dump(level + 1, (uint8_t *) &h->assoc, len - 2);
> +}
> +
> +static inline void amp_link_rsp(int level, struct frame *frm)
> +{
> + amp_link_rsp_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Create Physical Link rsp: local id %d remote id %d status %d\n",
> + h->local_id, h->remote_id, h->status);
> + p_indent(level+1, 0);
> + printf("%s\n", ampcplstatus2str(h->status));
> +}
> +
> +static inline void amp_disconn_req(int level, struct frame *frm)
> +{
> + amp_disconn_req_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Disconnect Physical Link req: local id %d remote id %d\n",
> + h->local_id, h->remote_id);
> +}
> +
> +static inline void amp_disconn_rsp(int level, struct frame *frm)
> +{
> + amp_link_rsp_parms *h = frm->ptr;
> +
> + if (p_filter(FILT_A2MP))
> + return;
> +
> + printf("Disconnect Physical Link rsp: local id %d remote id %d status %d\n",
> + h->local_id, h->remote_id, h->status);
> + p_indent(level+1, 0);
> + printf("%s\n", ampdplstatus2str(h->status));
> +}
> +
> static void l2cap_parse(int level, struct frame *frm)
> {
> l2cap_hdr *hdr = (void *)frm->ptr;
> @@ -1043,6 +1358,76 @@ static void l2cap_parse(int level, struct frame *frm)
> p_indent(level, frm);
> printf("L2CAP(c): len %d psm %d\n", dlen, psm);
> raw_dump(level, frm);
> + } else if ((cid == 0x3) && (frm->len > 4)) {
> +
> + /* Adjust for extra ERTM control bytes */
> + frm->ptr += 2;
> + frm->len -= 2;
> +
> + while (frm->len >= AMP_MGR_HDR_SIZE) {
> + amp_mgr_hdr *hdr = frm->ptr;
> +
> + frm->ptr += AMP_MGR_HDR_SIZE;
> + frm->len -= AMP_MGR_HDR_SIZE;
> +
> + if (!p_filter(FILT_A2MP)) {
> + p_indent(level, frm);
> + printf("A2MP: ");
> + }
> + switch (hdr->code) {
> + case AMP_COMMAND_REJ:
> + amp_command_rej(level, frm);
> + break;
> + case AMP_DISCOVER_REQ:
> + amp_discover_req(level, frm, hdr->len);
> + break;
> + case AMP_DISCOVER_RSP:
> + amp_discover_rsp(level, frm, hdr->len);
> + break;
> + case AMP_CHANGE_NOTIFY:
> + amp_change_notify(level, frm, hdr->len);
> + break;
> + case AMP_CHANGE_RSP:
> + amp_change_rsp(level, frm);
> + break;
> + case AMP_INFO_REQ:
> + amp_info_req(level, frm);
> + break;
> + case AMP_INFO_RSP:
> + amp_info_rsp(level, frm);
> + break;
> + case AMP_ASSOC_REQ:
> + amp_assoc_req(level, frm);
> + break;
> + case AMP_ASSOC_RSP:
> + amp_assoc_rsp(level, frm, hdr->len);
> + break;
> + case AMP_LINK_REQ:
> + amp_link_req(level, frm, hdr->len);
> + break;
> + case AMP_LINK_RSP:
> + amp_link_rsp(level, frm);
> + break;
> + case AMP_DISCONN_REQ:
> + amp_disconn_req(level, frm);
> + break;
> + case AMP_DISCONN_RSP:
> + amp_disconn_rsp(level, frm);
> + break;
> + default:
> + if (p_filter(FILT_A2MP))
> + break;
> + printf("code 0x%2.2x ident %d len %d\n",
> + hdr->code, hdr->ident, btohs(hdr->len));
> + raw_dump(level, frm);
> + }
> +
> + if (frm->len > btohs(hdr->len)) {
> + frm->len -= btohs(hdr->len);
> + frm->ptr += btohs(hdr->len);
> + } else
> + frm->len = 0;
> + }
> } else if (cid == 0x04) {
> if (!p_filter(FILT_ATT))
> att_dump(level, frm);
> diff --git a/parser/parser.h b/parser/parser.h
> index e975808..22d18c3 100644
> --- a/parser/parser.h
> +++ b/parser/parser.h
> @@ -80,6 +80,7 @@ struct frame {
> #define FILT_AVCTP 0x0800
> #define FILT_ATT 0x1000
> #define FILT_SMP 0x2000
> +#define FILT_A2MP 0x4000
>
> #define FILT_OBEX 0x00010000
> #define FILT_CAPI 0x00020000
> diff --git a/src/hcidump.c b/src/hcidump.c
> index 0c13360..2513c7c 100644
> --- a/src/hcidump.c
> +++ b/src/hcidump.c
> @@ -802,6 +802,7 @@ static struct {
> { "hci", FILT_HCI },
> { "sco", FILT_SCO },
> { "l2cap", FILT_L2CAP },
> + { "a2mp", FILT_A2MP },
> { "rfcomm", FILT_RFCOMM },
> { "sdp", FILT_SDP },
> { "bnep", FILT_BNEP },
> --
> 1.7.7
>
> --
> Peter Krystad
> Employee of Qualcomm Innovation Center, Inc.
> Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Peter,
> Add parsing of L2CAP Create/Move Channel signalling.
> Example output:
>
> 2011-10-18 16:09:47.810208 > ACL data: handle 39 flags 0x02 dlen 13
> L2CAP(s): Create req: psm 4097 scid 0x4201 id 17
> 2011-10-18 16:09:47.810269 < ACL data: handle 39 flags 0x00 dlen 16
> L2CAP(s): Create rsp: dcid 0x0040 scid 0x4201 result 1 status 0
> 2011-10-18 16:09:47.898308 < ACL data: handle 39 flags 0x00 dlen 16
> L2CAP(s): Create rsp: dcid 0x0040 scid 0x4201 result 0 status 0
>
> ....
>
> 2011-10-18 14:25:24.646869 > ACL data: handle 39 flags 0x02 dlen 11
> L2CAP(s): Move req: icid 0x4000 id 17
> 2011-10-18 14:25:24.646987 < ACL data: handle 39 flags 0x00 dlen 12
> L2CAP(s): Move rsp: icid 0x4000 result 1
> 2011-10-18 14:25:24.846873 < ACL data: handle 39 flags 0x00 dlen 12
> L2CAP(s): Move rsp: icid 0x4000 result 0
> 2011-10-18 14:25:25.041844 > ACL data: handle 39 flags 0x02 dlen 12
> L2CAP(s): Move cfm: icid 0x4000 result 0
> 2011-10-18 14:25:25.041945 < ACL data: handle 39 flags 0x00 dlen 10
> L2CAP(s): Move cfm rsp: icid 0x4000
> ---
> lib/l2cap.h | 50 +++++++++++++++++++++++++++++
> parser/l2cap.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 147 insertions(+), 0 deletions(-)
same requirement as with Andrei's patches before. First get them
accepted into bluez.git and then we port them over here.
Regards
Marcel
Minor indentation cleanup and fix display of physical link key
---
parser/hci.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/parser/hci.c b/parser/hci.c
index a0e3034..e459e9e 100644
--- a/parser/hci.c
+++ b/parser/hci.c
@@ -1124,12 +1124,11 @@ static inline void create_physical_link_dump(int level, struct frame *frm)
int i;
p_indent(level, frm);
-
printf("handle %d key length %d key type %d\n",
cp->handle, cp->key_length, cp->key_type);
+ p_indent(level, frm);
printf("key ");
-
- for (i = 0; i < cp->key_length && cp->key_length < 32; i++)
+ for (i = 0; i < cp->key_length && cp->key_length <= 32; i++)
printf("%2.2x", cp->key[i]);
printf("\n");
}
@@ -1140,12 +1139,16 @@ static inline void create_logical_link_dump(int level, struct frame *frm)
int i;
p_indent(level, frm);
-
printf("handle %d\n", cp->handle);
+
+ p_indent(level, frm);
printf("tx_flow ");
for (i = 0; i < 16; i++)
printf("%2.2x", cp->tx_flow[i]);
- printf("\nrx_flow ");
+ printf("\n");
+
+ p_indent(level, frm);
+ printf("rx_flow ");
for (i = 0; i < 16; i++)
printf("%2.2x", cp->rx_flow[i]);
printf("\n");
@@ -2605,6 +2608,8 @@ static inline void read_local_amp_assoc_dump(int level, struct frame *frm)
p_indent(level, frm);
printf("Error: %s\n", status2str(rp->status));
} else {
+ p_indent(level, frm);
+ printf("assoc data");
for (i = 0; i < len; i++) {
if (!(i % 16)) {
printf("\n");
--
1.7.7
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Add parsing of A2MP signalling.
Example output:
2011-10-18 16:09:44.493202 > ACL data: handle 39 flags 0x02 dlen 16
A2MP: Discover req: mtu/mps 670 mask: 0x0000
2011-10-18 16:09:44.493404 < ACL data: handle 39 flags 0x00 dlen 22
A2MP: Discover rsp: mtu/mps 670 mask: 0x0000
Controller list:
id 0, type 0, status 0x01 (Bluetooth only)
id 17, type 254, status 0x06 (Full capacity)
2011-10-18 16:09:44.697203 > ACL data: handle 39 flags 0x02 dlen 13
A2MP: Get Info req: id 17
2011-10-18 16:09:44.697312 < ACL data: handle 39 flags 0x00 dlen 30
A2MP: Get Info rsp: id 17 status (0) Success
total bandwidth 500000
max guaranteed bandwidth 0
min latency 100000
pal capabilities 0x0000
assoc size 8
2011-10-18 16:09:44.893203 > ACL data: handle 39 flags 0x02 dlen 13
A2MP: Get AMP Assoc req: id 17
2011-10-18 16:09:44.893618 < ACL data: handle 39 flags 0x00 dlen 22
A2MP: Get AMP Assoc rsp: id 17 status (0) Success
assoc data:
08 01 b1 01 0a 04 6c 42
2011-10-18 16:09:45.598201 > ACL data: handle 39 flags 0x02 dlen 22
A2MP: Create Physical Link req: local id 1 remote id 17
assoc data:
08 01 b1 01 0a 04 6d 38
2011-10-18 16:09:45.598643 < ACL data: handle 39 flags 0x00 dlen 15
A2MP: Create Physical Link rsp: local id 17 remote id 1 status 0
Success
---
lib/amp.h | 133 +++++++++++++++++++
parser/l2cap.c | 385 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
parser/parser.h | 1 +
src/hcidump.c | 1 +
4 files changed, 520 insertions(+), 0 deletions(-)
create mode 100644 lib/amp.h
diff --git a/lib/amp.h b/lib/amp.h
new file mode 100644
index 0000000..0c6300a
--- /dev/null
+++ b/lib/amp.h
@@ -0,0 +1,133 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2010-2011 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program 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 General Public License for more details.
+ *
+ */
+
+#ifndef __AMP_H
+#define __AMP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AMP_MGR_CID 0x03
+
+/* AMP manager codes */
+#define AMP_COMMAND_REJ 0x01
+#define AMP_DISCOVER_REQ 0x02
+#define AMP_DISCOVER_RSP 0x03
+#define AMP_CHANGE_NOTIFY 0x04
+#define AMP_CHANGE_RSP 0x05
+#define AMP_INFO_REQ 0x06
+#define AMP_INFO_RSP 0x07
+#define AMP_ASSOC_REQ 0x08
+#define AMP_ASSOC_RSP 0x09
+#define AMP_LINK_REQ 0x0a
+#define AMP_LINK_RSP 0x0b
+#define AMP_DISCONN_REQ 0x0c
+#define AMP_DISCONN_RSP 0x0d
+
+typedef struct {
+ uint8_t code;
+ uint8_t ident;
+ uint16_t len;
+} __attribute__ ((packed)) amp_mgr_hdr;
+#define AMP_MGR_HDR_SIZE 4
+
+/* AMP ASSOC structure */
+typedef struct {
+ uint8_t type_id;
+ uint16_t len;
+ uint8_t data[0];
+} __attribute__ ((packed)) amp_assoc_tlv;
+
+typedef struct {
+ uint16_t reason;
+} __attribute__ ((packed)) amp_cmd_rej_parms;
+
+typedef struct {
+ uint16_t mtu;
+ uint16_t mask;
+} __attribute__ ((packed)) amp_discover_req_parms;
+
+typedef struct {
+ uint16_t mtu;
+ uint16_t mask;
+ uint8_t controller_list[0];
+} __attribute__ ((packed)) amp_discover_rsp_parms;
+
+typedef struct {
+ uint8_t id;
+} __attribute__ ((packed)) amp_info_req_parms;
+
+typedef struct {
+ uint8_t id;
+ uint8_t status;
+ uint32_t total_bandwidth;
+ uint32_t max_bandwidth;
+ uint32_t min_latency;
+ uint16_t pal_caps;
+ uint16_t assoc_size;
+} __attribute__ ((packed)) amp_info_rsp_parms;
+
+typedef struct {
+ uint8_t id;
+ uint8_t status;
+ amp_assoc_tlv assoc;
+} __attribute__ ((packed)) amp_assoc_rsp_parms;
+
+typedef struct {
+ uint8_t local_id;
+ uint8_t remote_id;
+ amp_assoc_tlv assoc;
+} __attribute__ ((packed)) amp_link_req_parms;
+
+typedef struct {
+ uint8_t local_id;
+ uint8_t remote_id;
+ uint8_t status;
+} __attribute__ ((packed)) amp_link_rsp_parms;
+
+typedef struct {
+ uint8_t local_id;
+ uint8_t remote_id;
+} __attribute__ ((packed)) amp_disconn_req_parms;
+
+#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
+
+/* AMP controller status */
+#define AMP_CT_POWERED_DOWN 0x00
+#define AMP_CT_BLUETOOTH_ONLY 0x01
+#define AMP_CT_NO_CAPACITY 0x02
+#define AMP_CT_LOW_CAPACITY 0x03
+#define AMP_CT_MEDIUM_CAPACITY 0x04
+#define AMP_CT_HIGH_CAPACITY 0x05
+#define AMP_CT_FULL_CAPACITY 0x06
+
+/* AMP response status */
+#define AMP_STATUS_SUCCESS 0x00
+#define AMP_STATUS_INVALID_CTRL_ID 0x01
+#define AMP_STATUS_UNABLE_START_LINK_CREATION 0x02
+#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
+#define AMP_STATUS_COLLISION_OCCURED 0x03
+#define AMP_STATUS_DISCONN_REQ_RECVD 0x04
+#define AMP_STATUS_PHYS_LINK_EXISTS 0x05
+#define AMP_STATUS_SECURITY_VIOLATION 0x06
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AMP_H */
diff --git a/parser/l2cap.c b/parser/l2cap.c
index 7547e8b..7915788 100644
--- a/parser/l2cap.c
+++ b/parser/l2cap.c
@@ -36,6 +36,7 @@
#include "parser/sdp.h"
#include "lib/hci.h"
#include "lib/l2cap.h"
+#include "lib/amp.h"
typedef struct {
uint16_t handle;
@@ -259,6 +260,16 @@ static char *reason2str(uint16_t reason)
}
}
+static char *ampreason2str(uint16_t reason)
+{
+ switch (reason) {
+ case AMP_COMMAND_NOT_RECOGNIZED:
+ return "Command not recognized";
+ default:
+ return "Reserved";
+ }
+}
+
static char *connresult2str(uint16_t result)
{
switch (result) {
@@ -399,6 +410,76 @@ static char *supervisory2str(uint8_t supervisory)
}
}
+static char *ampctstatus2str(uint8_t status)
+{
+ switch (status) {
+ case AMP_CT_POWERED_DOWN:
+ return "Powered down";
+ case AMP_CT_BLUETOOTH_ONLY:
+ return "Bluetooth only";
+ case AMP_CT_NO_CAPACITY:
+ return "No capacity";
+ case AMP_CT_LOW_CAPACITY:
+ return "Low capacity";
+ case AMP_CT_MEDIUM_CAPACITY:
+ return "Medium capacity";
+ case AMP_CT_HIGH_CAPACITY:
+ return "High capacity";
+ case AMP_CT_FULL_CAPACITY:
+ return "Full capacity";
+ default:
+ return "Reserved";
+
+ }
+}
+
+static char *ampstatus2str(uint8_t status)
+{
+ switch (status) {
+ case AMP_STATUS_SUCCESS:
+ return "Success";
+ case AMP_STATUS_INVALID_CTRL_ID:
+ return "Invalid Controller ID";
+ default:
+ return "Reserved";
+ }
+}
+
+static char *ampcplstatus2str(uint8_t status)
+{
+ switch (status) {
+ case AMP_STATUS_SUCCESS:
+ return "Success";
+ case AMP_STATUS_INVALID_CTRL_ID:
+ return "Invalid Controller ID";
+ case AMP_STATUS_UNABLE_START_LINK_CREATION:
+ return "Failed - Unable to start link creation";
+ case AMP_STATUS_COLLISION_OCCURED:
+ return "Failed - Collision occured";
+ case AMP_STATUS_DISCONN_REQ_RECVD:
+ return "Failed - Disconnect physical link received";
+ case AMP_STATUS_PHYS_LINK_EXISTS:
+ return "Failed - Physical link already exists";
+ case AMP_STATUS_SECURITY_VIOLATION:
+ return "Failed - Security violation";
+ default:
+ return "Reserved";
+ }
+}
+
+static char *ampdplstatus2str(uint8_t status)
+{
+ switch (status) {
+ case AMP_STATUS_SUCCESS:
+ return "Success";
+ case AMP_STATUS_INVALID_CTRL_ID:
+ return "Invalid Controller ID";
+ case AMP_STATUS_NO_PHYSICAL_LINK_EXISTS:
+ return "Failed - No Physical Link exists";
+ default:
+ return "Reserved";
+ }
+}
static inline void command_rej(int level, struct frame *frm)
{
@@ -923,6 +1004,240 @@ static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm
printf("Move cfm rsp: icid 0x%4.4x\n", icid);
}
+static inline void amp_command_rej(int level, struct frame *frm)
+{
+ amp_cmd_rej_parms *h = frm->ptr;
+ uint16_t reason = btohs(h->reason);
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Command Reject: reason (%d)- ", reason);
+ p_indent(level + 1, frm);
+ printf("%s\n", ampreason2str(reason));
+}
+
+static inline void amp_discover_req(int level, struct frame *frm, uint16_t len)
+{
+ amp_discover_req_parms *h = frm->ptr;
+ uint16_t mtu = btohs(h->mtu);
+ uint8_t *octet = (uint8_t *)&(h->mask);
+ uint16_t mask;
+ uint8_t extension;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Discover req: mtu/mps %d ", mtu);
+ len -= 2;
+
+ printf("mask:");
+
+ do {
+ len -= 2;
+ mask = btohs(*(uint16_t *)(&octet[0]));
+ printf(" 0x%4.4x", mask);
+
+ extension = octet[1] & 0x80;
+ octet += 2;
+ } while ((extension != 0) && (len >= 2));
+
+ printf("\n");
+}
+
+static inline void controller_list_dump (int level, uint8_t *octet, uint16_t len)
+{
+ if (p_filter(FILT_A2MP))
+ return;
+
+ p_indent(level, 0);
+ printf("Controller list:\n");
+
+ while (len >= 3) {
+ p_indent(level + 1, 0);
+ printf("id %d, type %d, status 0x%2.2x (%s)\n",
+ octet[0], octet[1], octet[2], ampctstatus2str(octet[2]));
+ octet += 3;
+ len -= 3;
+ }
+
+}
+
+static inline void amp_discover_rsp(int level, struct frame *frm, uint16_t len)
+{
+ amp_discover_rsp_parms *h = frm->ptr;
+ uint16_t mtu = btohs(h->mtu);
+ uint8_t *octet = (uint8_t *)&(h->mask);
+ uint16_t mask;
+ uint8_t extension;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Discover rsp: mtu/mps %d ", mtu);
+ len -= 2;
+
+ printf("mask:");
+
+ do {
+ len -= 2;
+ mask = btohs(*(uint16_t *)(&octet[0]));
+ printf(" 0x%4.4x", mask);
+
+ extension = octet[1] & 0x80;
+ octet += 2;
+ } while ((extension != 0) && (len >= 2));
+
+ printf("\n");
+
+ if (len >= 3) {
+ controller_list_dump (level + 1, octet, len);
+ }
+}
+
+static inline void amp_change_notify(int level, struct frame *frm, uint16_t len)
+{
+ uint8_t *octet = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Change Notify\n");
+
+ if (len >= 3) {
+ controller_list_dump (level + 1, octet, len);
+ }
+}
+
+static inline void amp_change_rsp(int level, struct frame *frm)
+{
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Change Response\n");
+}
+
+static inline void amp_info_req(int level, struct frame *frm)
+{
+ amp_info_req_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Get Info req: id %d\n", h->id);
+}
+
+static inline void amp_info_rsp(int level, struct frame *frm)
+{
+ amp_info_rsp_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Get Info rsp: id %d status (%d) %s\n",
+ h->id, h->status, ampstatus2str(h->status));
+
+ p_indent(level + 1, frm);
+ printf("total bandwidth %d\n", btohl(h->total_bandwidth));
+ p_indent(level + 1, frm);
+ printf("max guaranteed bandwidth %d\n", btohl(h->max_bandwidth));
+ p_indent(level + 1, frm);
+ printf("min latency %d\n", btohl(h->min_latency));
+ p_indent(level + 1, frm);
+ printf("pal capabilities 0x%4.4x\n", btohs(h->pal_caps));
+ p_indent(level + 1, frm);
+ printf("assoc size %d\n", btohs(h->assoc_size));
+}
+
+static inline void amp_assoc_req(int level, struct frame *frm)
+{
+ amp_info_req_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Get AMP Assoc req: id %d\n", h->id);
+}
+
+static inline void amp_assoc_dump(int level, uint8_t *assoc, uint16_t len)
+{
+ int i;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ p_indent(level, 0);
+ printf("assoc data:");
+ for (i = 0; i < len; i++) {
+ if (!(i%16)) printf("\n");
+ if (!(i%16)) p_indent(level+1, 0);
+ printf("%2.2x ",*assoc++);
+ }
+ printf("\n");
+
+}
+
+static inline void amp_assoc_rsp(int level, struct frame *frm, uint16_t len)
+{
+ amp_assoc_rsp_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Get AMP Assoc rsp: id %d status (%d) %s \n",
+ h->id, h->status, ampstatus2str(h->status));
+ amp_assoc_dump(level + 1, (uint8_t *) &h->assoc, len - 2);
+}
+
+static inline void amp_link_req(int level, struct frame *frm, uint16_t len)
+{
+ amp_link_req_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Create Physical Link req: local id %d remote id %d\n",
+ h->local_id, h->remote_id);
+ amp_assoc_dump(level + 1, (uint8_t *) &h->assoc, len - 2);
+}
+
+static inline void amp_link_rsp(int level, struct frame *frm)
+{
+ amp_link_rsp_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Create Physical Link rsp: local id %d remote id %d status %d\n",
+ h->local_id, h->remote_id, h->status);
+ p_indent(level+1, 0);
+ printf("%s\n", ampcplstatus2str(h->status));
+}
+
+static inline void amp_disconn_req(int level, struct frame *frm)
+{
+ amp_disconn_req_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Disconnect Physical Link req: local id %d remote id %d\n",
+ h->local_id, h->remote_id);
+}
+
+static inline void amp_disconn_rsp(int level, struct frame *frm)
+{
+ amp_link_rsp_parms *h = frm->ptr;
+
+ if (p_filter(FILT_A2MP))
+ return;
+
+ printf("Disconnect Physical Link rsp: local id %d remote id %d status %d\n",
+ h->local_id, h->remote_id, h->status);
+ p_indent(level+1, 0);
+ printf("%s\n", ampdplstatus2str(h->status));
+}
+
static void l2cap_parse(int level, struct frame *frm)
{
l2cap_hdr *hdr = (void *)frm->ptr;
@@ -1043,6 +1358,76 @@ static void l2cap_parse(int level, struct frame *frm)
p_indent(level, frm);
printf("L2CAP(c): len %d psm %d\n", dlen, psm);
raw_dump(level, frm);
+ } else if ((cid == 0x3) && (frm->len > 4)) {
+
+ /* Adjust for extra ERTM control bytes */
+ frm->ptr += 2;
+ frm->len -= 2;
+
+ while (frm->len >= AMP_MGR_HDR_SIZE) {
+ amp_mgr_hdr *hdr = frm->ptr;
+
+ frm->ptr += AMP_MGR_HDR_SIZE;
+ frm->len -= AMP_MGR_HDR_SIZE;
+
+ if (!p_filter(FILT_A2MP)) {
+ p_indent(level, frm);
+ printf("A2MP: ");
+ }
+ switch (hdr->code) {
+ case AMP_COMMAND_REJ:
+ amp_command_rej(level, frm);
+ break;
+ case AMP_DISCOVER_REQ:
+ amp_discover_req(level, frm, hdr->len);
+ break;
+ case AMP_DISCOVER_RSP:
+ amp_discover_rsp(level, frm, hdr->len);
+ break;
+ case AMP_CHANGE_NOTIFY:
+ amp_change_notify(level, frm, hdr->len);
+ break;
+ case AMP_CHANGE_RSP:
+ amp_change_rsp(level, frm);
+ break;
+ case AMP_INFO_REQ:
+ amp_info_req(level, frm);
+ break;
+ case AMP_INFO_RSP:
+ amp_info_rsp(level, frm);
+ break;
+ case AMP_ASSOC_REQ:
+ amp_assoc_req(level, frm);
+ break;
+ case AMP_ASSOC_RSP:
+ amp_assoc_rsp(level, frm, hdr->len);
+ break;
+ case AMP_LINK_REQ:
+ amp_link_req(level, frm, hdr->len);
+ break;
+ case AMP_LINK_RSP:
+ amp_link_rsp(level, frm);
+ break;
+ case AMP_DISCONN_REQ:
+ amp_disconn_req(level, frm);
+ break;
+ case AMP_DISCONN_RSP:
+ amp_disconn_rsp(level, frm);
+ break;
+ default:
+ if (p_filter(FILT_A2MP))
+ break;
+ printf("code 0x%2.2x ident %d len %d\n",
+ hdr->code, hdr->ident, btohs(hdr->len));
+ raw_dump(level, frm);
+ }
+
+ if (frm->len > btohs(hdr->len)) {
+ frm->len -= btohs(hdr->len);
+ frm->ptr += btohs(hdr->len);
+ } else
+ frm->len = 0;
+ }
} else if (cid == 0x04) {
if (!p_filter(FILT_ATT))
att_dump(level, frm);
diff --git a/parser/parser.h b/parser/parser.h
index e975808..22d18c3 100644
--- a/parser/parser.h
+++ b/parser/parser.h
@@ -80,6 +80,7 @@ struct frame {
#define FILT_AVCTP 0x0800
#define FILT_ATT 0x1000
#define FILT_SMP 0x2000
+#define FILT_A2MP 0x4000
#define FILT_OBEX 0x00010000
#define FILT_CAPI 0x00020000
diff --git a/src/hcidump.c b/src/hcidump.c
index 0c13360..2513c7c 100644
--- a/src/hcidump.c
+++ b/src/hcidump.c
@@ -802,6 +802,7 @@ static struct {
{ "hci", FILT_HCI },
{ "sco", FILT_SCO },
{ "l2cap", FILT_L2CAP },
+ { "a2mp", FILT_A2MP },
{ "rfcomm", FILT_RFCOMM },
{ "sdp", FILT_SDP },
{ "bnep", FILT_BNEP },
--
1.7.7
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Add DUMP_VERBOSE display of L2CAP Fixed Channel list.
Example output:
2011-10-21 12:01:50.423246 > ACL data: handle 39 flags 0x02 dlen 20
L2CAP(s): Info rsp: type 3 result 0
Fixed channel list
L2CAP
CONNLESS
A2MP
---
parser/l2cap.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/parser/l2cap.c b/parser/l2cap.c
index 7915788..ce78d05 100644
--- a/parser/l2cap.c
+++ b/parser/l2cap.c
@@ -811,6 +811,7 @@ static void info_opt(int level, int type, void *ptr, int len)
{
uint32_t mask;
int i;
+ uint8_t list;
p_indent(level, 0);
@@ -830,6 +831,21 @@ static void info_opt(int level, int type, void *ptr, int len)
break;
case 0x0003:
printf("Fixed channel list\n");
+ list = get_val(ptr, 1);
+ if (parser.flags & DUMP_VERBOSE) {
+ if (list & L2CAP_FC_L2CAP) {
+ p_indent(level + 1, 0);
+ printf("L2CAP\n");
+ }
+ if (list & L2CAP_FC_CONNLESS) {
+ p_indent(level + 1, 0);
+ printf("CONNLESS\n");
+ }
+ if (list & L2CAP_FC_A2MP) {
+ p_indent(level + 1, 0);
+ printf("A2MP\n");
+ }
+ }
break;
default:
printf("Unknown (len %d)\n", len);
--
1.7.7
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
Add parsing of L2CAP Create/Move Channel signalling.
Example output:
2011-10-18 16:09:47.810208 > ACL data: handle 39 flags 0x02 dlen 13
L2CAP(s): Create req: psm 4097 scid 0x4201 id 17
2011-10-18 16:09:47.810269 < ACL data: handle 39 flags 0x00 dlen 16
L2CAP(s): Create rsp: dcid 0x0040 scid 0x4201 result 1 status 0
2011-10-18 16:09:47.898308 < ACL data: handle 39 flags 0x00 dlen 16
L2CAP(s): Create rsp: dcid 0x0040 scid 0x4201 result 0 status 0
....
2011-10-18 14:25:24.646869 > ACL data: handle 39 flags 0x02 dlen 11
L2CAP(s): Move req: icid 0x4000 id 17
2011-10-18 14:25:24.646987 < ACL data: handle 39 flags 0x00 dlen 12
L2CAP(s): Move rsp: icid 0x4000 result 1
2011-10-18 14:25:24.846873 < ACL data: handle 39 flags 0x00 dlen 12
L2CAP(s): Move rsp: icid 0x4000 result 0
2011-10-18 14:25:25.041844 > ACL data: handle 39 flags 0x02 dlen 12
L2CAP(s): Move cfm: icid 0x4000 result 0
2011-10-18 14:25:25.041945 < ACL data: handle 39 flags 0x00 dlen 10
L2CAP(s): Move cfm rsp: icid 0x4000
---
lib/l2cap.h | 50 +++++++++++++++++++++++++++++
parser/l2cap.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/lib/l2cap.h b/lib/l2cap.h
index 3880551..b970a6e 100644
--- a/lib/l2cap.h
+++ b/lib/l2cap.h
@@ -82,6 +82,12 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b
+#define L2CAP_CREATE_REQ 0x0c
+#define L2CAP_CREATE_RSP 0x0d
+#define L2CAP_MOVE_REQ 0x0e
+#define L2CAP_MOVE_RSP 0x0f
+#define L2CAP_MOVE_CFM 0x10
+#define L2CAP_MOVE_CFM_RSP 0x11
/* L2CAP extended feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
@@ -270,6 +276,50 @@ typedef struct {
#define L2CAP_IR_SUCCESS 0x0000
#define L2CAP_IR_NOTSUPP 0x0001
+typedef struct {
+ uint16_t psm;
+ uint16_t scid;
+ uint8_t id;
+} __attribute__ ((packed)) l2cap_create_req;
+#define L2CAP_CREATE_REQ_SIZE 5
+
+typedef struct {
+ uint16_t dcid;
+ uint16_t scid;
+ uint16_t result;
+ uint16_t status;
+} __attribute__ ((packed)) l2cap_create_rsp;
+#define L2CAP_CREATE_RSP_SIZE 8
+
+typedef struct {
+ uint16_t icid;
+ uint8_t id;
+} __attribute__ ((packed)) l2cap_move_req;
+#define L2CAP_MOVE_REQ_SIZE 3
+
+typedef struct {
+ uint16_t icid;
+ uint16_t result;
+} __attribute__ ((packed)) l2cap_move_rsp;
+#define L2CAP_MOVE_RSP_SIZE 4
+
+typedef struct {
+ uint16_t icid;
+ uint16_t result;
+} __attribute__ ((packed)) l2cap_move_cfm;
+#define L2CAP_MOVE_CFM_SIZE 4
+
+typedef struct {
+ uint16_t icid;
+} __attribute__ ((packed)) l2cap_move_cfm_rsp;
+#define L2CAP_MOVE_CFM_RSP_SIZE 2
+
+/* info type */
+#define L2CAP_IT_CL_MTU 0x0001
+#define L2CAP_IT_FEAT_MASK 0x0002
+
+/* info result */
+#define L2CAP_IR_SUCCESS 0x0000
#ifdef __cplusplus
}
#endif
diff --git a/parser/l2cap.c b/parser/l2cap.c
index 6a5a4b2..7547e8b 100644
--- a/parser/l2cap.c
+++ b/parser/l2cap.c
@@ -399,6 +399,7 @@ static char *supervisory2str(uint8_t supervisory)
}
}
+
static inline void command_rej(int level, struct frame *frm)
{
l2cap_cmd_rej *h = frm->ptr;
@@ -850,6 +851,78 @@ static void l2cap_ctrl_parse(int level, struct frame *frm, uint32_t ctrl)
printf(" F-bit");
}
+static inline void create_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_create_req *h = frm->ptr;
+ uint16_t psm = btohs(h->psm);
+ uint16_t scid = btohs(h->scid);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Create req: psm %d scid 0x%4.4x id %d\n", psm, scid, h->id);
+}
+
+static inline void create_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_create_rsp *h = frm->ptr;
+ uint16_t scid = btohs(h->scid);
+ uint16_t dcid = btohs(h->dcid);
+ uint16_t result = btohs(h->result);
+ uint16_t status = btohs(h->status);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Create rsp: dcid 0x%4.4x scid 0x%4.4x result %d status %d\n", dcid, scid, result, status);
+}
+
+static inline void move_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_move_req *h = frm->ptr;
+ uint16_t icid = btohs(h->icid);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Move req: icid 0x%4.4x id %d\n", icid, h->id);
+}
+
+static inline void move_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_move_rsp *h = frm->ptr;
+ uint16_t icid = btohs(h->icid);
+ uint16_t result = btohs(h->result);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Move rsp: icid 0x%4.4x result %d\n", icid, result);
+}
+
+static inline void move_cfm(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_move_cfm *h = frm->ptr;
+ uint16_t icid = btohs(h->icid);
+ uint16_t result = btohs(h->result);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Move cfm: icid 0x%4.4x result %d\n", icid, result);
+}
+
+static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+ l2cap_move_cfm_rsp *h = frm->ptr;
+ uint16_t icid = btohs(h->icid);
+
+ if (p_filter(FILT_L2CAP))
+ return;
+
+ printf("Move cfm rsp: icid 0x%4.4x\n", icid);
+}
+
static void l2cap_parse(int level, struct frame *frm)
{
l2cap_hdr *hdr = (void *)frm->ptr;
@@ -919,6 +992,30 @@ static void l2cap_parse(int level, struct frame *frm)
info_rsp(level, hdr, frm);
break;
+ case L2CAP_CREATE_REQ:
+ create_req(level, hdr, frm);
+ break;
+
+ case L2CAP_CREATE_RSP:
+ create_rsp(level, hdr, frm);
+ break;
+
+ case L2CAP_MOVE_REQ:
+ move_req(level, hdr, frm);
+ break;
+
+ case L2CAP_MOVE_RSP:
+ move_rsp(level, hdr, frm);
+ break;
+
+ case L2CAP_MOVE_CFM:
+ move_cfm(level, hdr, frm);
+ break;
+
+ case L2CAP_MOVE_CFM_RSP:
+ move_cfm_rsp(level, hdr, frm);
+ break;
+
default:
if (p_filter(FILT_L2CAP))
break;
--
1.7.7
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum