From: Peter Krystad <pkrystad@codeaurora.org>
To: linux-bluetooth@vger.kernel.org
Cc: andrei.emeltchenko@intel.com, Peter Krystad <pkrystad@codeaurora.org>
Subject: [PATCH 2/4] Add parsing of A2MP signals
Date: Fri, 21 Oct 2011 16:30:00 -0700 [thread overview]
Message-ID: <1319239802-22457-3-git-send-email-pkrystad@codeaurora.org> (raw)
In-Reply-To: <1319239802-22457-1-git-send-email-pkrystad@codeaurora.org>
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
next prev parent reply other threads:[~2011-10-21 23:30 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-10-21 23:29 [PATCH 0/4] Add parsing of BT 3.0+HS signalling Peter Krystad
2011-10-21 23:29 ` [PATCH 1/4] Add parsing of L2CAP Create/Move Channel signals Peter Krystad
2011-10-22 7:21 ` Marcel Holtmann
2011-10-21 23:30 ` Peter Krystad [this message]
2011-10-24 7:34 ` [PATCH 2/4] Add parsing of A2MP signals Andrei Emeltchenko
2011-10-26 13:33 ` Andrei Emeltchenko
2011-10-26 18:49 ` Peter Krystad
2011-10-21 23:30 ` [PATCH 3/4] Add parsing of L2CAP Fixed Channel list Peter Krystad
2011-10-24 7:51 ` Andrei Emeltchenko
2011-10-21 23:30 ` [PATCH 4/4] Minor cleanup of indentation in output Peter Krystad
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1319239802-22457-3-git-send-email-pkrystad@codeaurora.org \
--to=pkrystad@codeaurora.org \
--cc=andrei.emeltchenko@intel.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.